@kb-labs/marketplace-core 2.31.0 → 2.32.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/dist/index.d.ts +107 -19
- package/dist/index.js +241 -84
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,54 +1,142 @@
|
|
|
1
1
|
import { EntityKind, MarketplaceEntry } from '@kb-labs/core-discovery';
|
|
2
|
-
import { MarketplaceServiceAPI, PackageSource, EntityKindStrategy, InstallResult, InstallResultEntry,
|
|
2
|
+
import { MarketplaceServiceAPI, PackageSource, EntityKindStrategy, ScopeContext, InstallResult, InstallResultEntry, QueryScopeContext, ScopedMarketplaceEntry, SyncResult, DoctorReport, MarketplaceScope, MarketplaceEntryWithId, MarketplaceDiagnostic, ManifestCache, ManifestCacheEntry } from '@kb-labs/marketplace-contracts';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @module @kb-labs/marketplace-core/marketplace-service
|
|
6
6
|
* Unified marketplace service — install/uninstall/enable/disable for all entity types.
|
|
7
|
+
*
|
|
8
|
+
* Every mutating method is explicitly scope-bound (`platform` or `project`).
|
|
9
|
+
* There is no implicit default: callers pass a `ScopeContext` per call so
|
|
10
|
+
* the service can target the right `.kb/marketplace.lock`.
|
|
11
|
+
*
|
|
7
12
|
* Works through PackageSource abstraction — never calls pnpm directly.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
interface MarketplaceServiceOptions {
|
|
11
|
-
/**
|
|
12
|
-
|
|
16
|
+
/** Platform workspace root — always required. Used for `scope: 'platform'`. */
|
|
17
|
+
platformRoot: string;
|
|
18
|
+
/**
|
|
19
|
+
* Default project root. Optional — a daemon serving multiple projects can
|
|
20
|
+
* leave this unset and pass `ctx.projectRoot` per call. When both are
|
|
21
|
+
* provided, per-call `ctx.projectRoot` wins.
|
|
22
|
+
*/
|
|
23
|
+
projectRoot?: string;
|
|
13
24
|
/** Package source (npm, registry, etc.) */
|
|
14
25
|
source: PackageSource;
|
|
15
26
|
/** Additional strategies beyond built-in plugin/adapter */
|
|
16
27
|
strategies?: EntityKindStrategy[];
|
|
17
28
|
}
|
|
18
29
|
declare class MarketplaceService implements MarketplaceServiceAPI {
|
|
19
|
-
private readonly
|
|
30
|
+
private readonly roots;
|
|
20
31
|
private readonly source;
|
|
21
32
|
private readonly strategies;
|
|
22
33
|
constructor(opts: MarketplaceServiceOptions);
|
|
23
34
|
registerStrategy(strategy: EntityKindStrategy): void;
|
|
24
|
-
install(specs: string[], opts?: {
|
|
35
|
+
install(ctx: ScopeContext, specs: string[], opts?: {
|
|
25
36
|
dev?: boolean;
|
|
26
37
|
}): Promise<InstallResult>;
|
|
27
|
-
uninstall(packageIds: string[]): Promise<void>;
|
|
28
|
-
link(packagePath: string): Promise<InstallResultEntry>;
|
|
29
|
-
unlink(packageId: string): Promise<void>;
|
|
30
|
-
update(packageIds?: string[]): Promise<InstallResult>;
|
|
31
|
-
enable(packageId: string): Promise<void>;
|
|
32
|
-
disable(packageId: string): Promise<void>;
|
|
33
|
-
list(filter?: {
|
|
38
|
+
uninstall(ctx: ScopeContext, packageIds: string[]): Promise<void>;
|
|
39
|
+
link(ctx: ScopeContext, packagePath: string): Promise<InstallResultEntry>;
|
|
40
|
+
unlink(ctx: ScopeContext, packageId: string): Promise<void>;
|
|
41
|
+
update(ctx: ScopeContext, packageIds?: string[]): Promise<InstallResult>;
|
|
42
|
+
enable(ctx: ScopeContext, packageId: string): Promise<void>;
|
|
43
|
+
disable(ctx: ScopeContext, packageId: string): Promise<void>;
|
|
44
|
+
list(ctx: QueryScopeContext, filter?: {
|
|
34
45
|
kind?: EntityKind;
|
|
35
|
-
}): Promise<
|
|
36
|
-
getEntry(packageId: string): Promise<MarketplaceEntry | null>;
|
|
46
|
+
}): Promise<ScopedMarketplaceEntry[]>;
|
|
47
|
+
getEntry(ctx: ScopeContext, packageId: string): Promise<MarketplaceEntry | null>;
|
|
37
48
|
/**
|
|
38
49
|
* Scan workspace for plugins and adapters using glob patterns.
|
|
39
50
|
* Existing entries are preserved (not overwritten).
|
|
40
51
|
* Patterns come from kb.config.json marketplace.sync.include.
|
|
52
|
+
*
|
|
53
|
+
* Sync is scope-bound: globs resolve against the scope root and results go
|
|
54
|
+
* into that scope's lock. Adapter discovery in `project` scope is refused
|
|
55
|
+
* with a clear error to preserve the adapters-are-platform-only invariant.
|
|
41
56
|
*/
|
|
42
|
-
sync(opts: {
|
|
57
|
+
sync(ctx: ScopeContext, opts: {
|
|
43
58
|
include: string[];
|
|
44
59
|
exclude?: string[];
|
|
45
60
|
autoEnable?: boolean;
|
|
46
61
|
}): Promise<SyncResult>;
|
|
47
62
|
private _syncPackage;
|
|
48
|
-
doctor(): Promise<DoctorReport>;
|
|
63
|
+
doctor(ctx: ScopeContext): Promise<DoctorReport>;
|
|
49
64
|
private detectKind;
|
|
65
|
+
/**
|
|
66
|
+
* Hard guard: adapters may only be installed/linked in platform scope.
|
|
67
|
+
* Lives in one place so adapter-scope policy is not duplicated across
|
|
68
|
+
* `link`, `install`, and `sync`.
|
|
69
|
+
*/
|
|
70
|
+
private assertScopeAllowsKind;
|
|
50
71
|
private cacheManifest;
|
|
51
72
|
}
|
|
73
|
+
declare class AdapterScopeError extends Error {
|
|
74
|
+
readonly code = "MARKETPLACE_ADAPTER_PROJECT_SCOPE";
|
|
75
|
+
constructor(message: string);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Merge per-scope entries with platform-wins precedence.
|
|
79
|
+
*
|
|
80
|
+
* For a given package id present in both platform and project, the platform
|
|
81
|
+
* entry is kept and a diagnostic is emitted so the caller can surface the
|
|
82
|
+
* conflict.
|
|
83
|
+
*/
|
|
84
|
+
declare function mergeScopedEntries(perScope: Array<{
|
|
85
|
+
scope: MarketplaceScope;
|
|
86
|
+
entries: MarketplaceEntryWithId[];
|
|
87
|
+
}>): {
|
|
88
|
+
entries: ScopedMarketplaceEntry[];
|
|
89
|
+
diagnostics: MarketplaceDiagnostic[];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @module @kb-labs/marketplace-core/scope
|
|
94
|
+
* Scope resolution helpers for the platform/project marketplace split.
|
|
95
|
+
*
|
|
96
|
+
* Every mutating service method is explicitly scope-bound — there is no
|
|
97
|
+
* implicit default. The helpers below compute the absolute root directory
|
|
98
|
+
* for a given ScopeContext and enforce the invariants that the rest of the
|
|
99
|
+
* service relies on (distinct platform/project roots, project has a `.kb/`).
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Roots known to the MarketplaceService at construction time.
|
|
104
|
+
* `platformRoot` is always known. `projectRoot` is optional at construction
|
|
105
|
+
* (daemon may serve multiple projects); per-call `ctx.projectRoot` can
|
|
106
|
+
* override it.
|
|
107
|
+
*/
|
|
108
|
+
interface ServiceRoots {
|
|
109
|
+
platformRoot: string;
|
|
110
|
+
projectRoot?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Resolve the absolute scope root for a single mutating call.
|
|
114
|
+
*
|
|
115
|
+
* - `scope: 'platform'` — returns `roots.platformRoot`. `projectRoot` in
|
|
116
|
+
* the context is ignored.
|
|
117
|
+
* - `scope: 'project'` — prefers `ctx.projectRoot`, falls back to
|
|
118
|
+
* `roots.projectRoot` from construction. Throws if neither is set,
|
|
119
|
+
* if the path isn't absolute, doesn't exist, lacks a `.kb/kb.config.*`,
|
|
120
|
+
* or equals `roots.platformRoot`.
|
|
121
|
+
*/
|
|
122
|
+
declare function resolveScopeRoot(roots: ServiceRoots, ctx: ScopeContext): string;
|
|
123
|
+
/**
|
|
124
|
+
* Resolve the set of roots to read from for a query context (`list`,
|
|
125
|
+
* `getEntry`). `'all'` returns both; the caller is responsible for merging
|
|
126
|
+
* with a platform-wins precedence.
|
|
127
|
+
*/
|
|
128
|
+
declare function resolveQueryRoots(roots: ServiceRoots, ctx: QueryScopeContext): Array<{
|
|
129
|
+
scope: MarketplaceScope;
|
|
130
|
+
root: string;
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* Thrown when a scope context cannot be resolved to a concrete root.
|
|
134
|
+
* Uses a stable `code` so API/CLI can surface actionable errors.
|
|
135
|
+
*/
|
|
136
|
+
declare class ScopeResolutionError extends Error {
|
|
137
|
+
readonly code: string;
|
|
138
|
+
constructor(code: string, message: string);
|
|
139
|
+
}
|
|
52
140
|
|
|
53
141
|
/**
|
|
54
142
|
* @module @kb-labs/marketplace-core/manifest-cache
|
|
@@ -97,8 +185,8 @@ declare class AdapterStrategy implements EntityKindStrategy {
|
|
|
97
185
|
kind: EntityKind;
|
|
98
186
|
detectKind(packageRoot: string): Promise<EntityKind | null>;
|
|
99
187
|
extractProvides(_packageRoot: string): Promise<EntityKind[]>;
|
|
100
|
-
afterInstall(packageId: string, packageRoot: string, service: MarketplaceServiceAPI): Promise<void>;
|
|
101
|
-
beforeUninstall(packageId: string, service: MarketplaceServiceAPI): Promise<void>;
|
|
188
|
+
afterInstall(packageId: string, packageRoot: string, service: MarketplaceServiceAPI, ctx: ScopeContext): Promise<void>;
|
|
189
|
+
beforeUninstall(packageId: string, service: MarketplaceServiceAPI, ctx: ScopeContext): Promise<void>;
|
|
102
190
|
}
|
|
103
191
|
|
|
104
|
-
export { AdapterStrategy, MarketplaceService, type MarketplaceServiceOptions, PluginStrategy, createEmptyManifestCache, readManifestCache, removeCacheEntry, setCacheEntry, writeManifestCache };
|
|
192
|
+
export { AdapterScopeError, AdapterStrategy, MarketplaceService, type MarketplaceServiceOptions, PluginStrategy, ScopeResolutionError, type ServiceRoots, createEmptyManifestCache, mergeScopedEntries, readManifestCache, removeCacheEntry, resolveQueryRoots, resolveScopeRoot, setCacheEntry, writeManifestCache };
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import * as fs from 'fs/promises';
|
|
2
|
-
import * as
|
|
2
|
+
import * as path4 from 'path';
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
4
|
import { randomUUID } from 'crypto';
|
|
5
5
|
import { pathToFileURL } from 'url';
|
|
6
6
|
import { glob } from 'glob';
|
|
7
7
|
import { DiagnosticCollector, loadManifest, extractEntityKinds, createMarketplaceEntry, addToMarketplaceLock, removeFromMarketplaceLock, readMarketplaceLock, enablePlugin, disablePlugin, createEmptyLock, writeMarketplaceLock } from '@kb-labs/core-discovery';
|
|
8
|
+
import { accessSync, constants } from 'fs';
|
|
8
9
|
|
|
9
10
|
// src/marketplace-service.ts
|
|
10
11
|
var CACHE_FILE = ".kb/marketplace.manifests.json";
|
|
11
12
|
var SCHEMA_VERSION = "kb.marketplace.manifests/1";
|
|
12
13
|
async function readManifestCache(root) {
|
|
13
|
-
const cachePath =
|
|
14
|
+
const cachePath = path4.join(root, CACHE_FILE);
|
|
14
15
|
try {
|
|
15
16
|
const raw = await fs.readFile(cachePath, "utf-8");
|
|
16
17
|
const parsed = JSON.parse(raw);
|
|
@@ -23,8 +24,8 @@ async function readManifestCache(root) {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
async function writeManifestCache(root, cache) {
|
|
26
|
-
const cachePath =
|
|
27
|
-
const dir =
|
|
27
|
+
const cachePath = path4.join(root, CACHE_FILE);
|
|
28
|
+
const dir = path4.dirname(cachePath);
|
|
28
29
|
await fs.mkdir(dir, { recursive: true });
|
|
29
30
|
const tmpPath = `${cachePath}.tmp.${randomUUID()}`;
|
|
30
31
|
await fs.writeFile(tmpPath, JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
@@ -76,16 +77,16 @@ var AdapterStrategy = class {
|
|
|
76
77
|
async extractProvides(_packageRoot) {
|
|
77
78
|
return ["adapter"];
|
|
78
79
|
}
|
|
79
|
-
async afterInstall(packageId, packageRoot, service) {
|
|
80
|
+
async afterInstall(packageId, packageRoot, service, ctx) {
|
|
80
81
|
const manifest = await loadAdapterManifest(packageRoot);
|
|
81
82
|
if (!manifest?.requires?.adapters) {
|
|
82
83
|
return;
|
|
83
84
|
}
|
|
84
|
-
const installed = await service.list({ kind: "adapter" });
|
|
85
|
+
const installed = await service.list(ctx, { kind: "adapter" });
|
|
85
86
|
const installedIds = new Set(installed.map((e) => e.id));
|
|
86
87
|
for (const dep of manifest.requires.adapters) {
|
|
87
88
|
const depId = typeof dep === "string" ? dep : dep.id;
|
|
88
|
-
const found = installedIds.has(depId) || installed.some((e) => e.id
|
|
89
|
+
const found = installedIds.has(depId) || installed.some((e) => e.id.includes(`adapters-${depId}`));
|
|
89
90
|
if (!found) {
|
|
90
91
|
console.warn(
|
|
91
92
|
`[marketplace] Adapter "${packageId}" requires adapter "${depId}" which is not installed. Run: kb marketplace link <adapter-package-that-provides-${depId}>`
|
|
@@ -93,8 +94,8 @@ var AdapterStrategy = class {
|
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
|
-
async beforeUninstall(packageId, service) {
|
|
97
|
-
const installed = await service.list({ kind: "adapter" });
|
|
97
|
+
async beforeUninstall(packageId, service, ctx) {
|
|
98
|
+
const installed = await service.list(ctx, { kind: "adapter" });
|
|
98
99
|
if (installed.length > 1) {
|
|
99
100
|
console.warn(
|
|
100
101
|
`[marketplace] Removing adapter "${packageId}" \u2014 verify no other adapters depend on it`
|
|
@@ -104,7 +105,7 @@ var AdapterStrategy = class {
|
|
|
104
105
|
};
|
|
105
106
|
async function loadAdapterManifest(packageRoot) {
|
|
106
107
|
try {
|
|
107
|
-
const distPath =
|
|
108
|
+
const distPath = path4.join(packageRoot, "dist", "index.js");
|
|
108
109
|
await fs.access(distPath);
|
|
109
110
|
const mod = await import(pathToFileURL(distPath).href);
|
|
110
111
|
if (mod.manifest && typeof mod.manifest === "object" && mod.manifest.implements) {
|
|
@@ -115,14 +116,95 @@ async function loadAdapterManifest(packageRoot) {
|
|
|
115
116
|
return null;
|
|
116
117
|
}
|
|
117
118
|
}
|
|
119
|
+
var CONFIG_FILE_CANDIDATES = ["kb.config.jsonc", "kb.config.json"];
|
|
120
|
+
function resolveScopeRoot(roots, ctx) {
|
|
121
|
+
if (ctx.scope === "platform") {
|
|
122
|
+
return roots.platformRoot;
|
|
123
|
+
}
|
|
124
|
+
const candidate = ctx.projectRoot ?? roots.projectRoot;
|
|
125
|
+
if (!candidate) {
|
|
126
|
+
throw new ScopeResolutionError(
|
|
127
|
+
"SCOPE_PROJECT_ROOT_MISSING",
|
|
128
|
+
'scope="project" requires a projectRoot (pass ctx.projectRoot or configure the service with projectRoot).'
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (!path4.isAbsolute(candidate)) {
|
|
132
|
+
throw new ScopeResolutionError(
|
|
133
|
+
"SCOPE_PROJECT_ROOT_NOT_ABSOLUTE",
|
|
134
|
+
`projectRoot must be absolute, got "${candidate}".`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
accessSync(candidate, constants.F_OK);
|
|
139
|
+
} catch {
|
|
140
|
+
throw new ScopeResolutionError(
|
|
141
|
+
"SCOPE_PROJECT_ROOT_NOT_FOUND",
|
|
142
|
+
`projectRoot does not exist: "${candidate}".`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
const hasConfig = CONFIG_FILE_CANDIDATES.some((name) => {
|
|
146
|
+
try {
|
|
147
|
+
accessSync(path4.join(candidate, ".kb", name), constants.F_OK);
|
|
148
|
+
return true;
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
if (!hasConfig) {
|
|
154
|
+
throw new ScopeResolutionError(
|
|
155
|
+
"SCOPE_PROJECT_ROOT_NO_KB_DIR",
|
|
156
|
+
`projectRoot "${candidate}" does not contain .kb/kb.config.{json,jsonc} \u2014 refusing to treat it as a project.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (path4.resolve(candidate) === path4.resolve(roots.platformRoot)) {
|
|
160
|
+
throw new ScopeResolutionError(
|
|
161
|
+
"SCOPE_PROJECT_EQUALS_PLATFORM",
|
|
162
|
+
'projectRoot must not equal platformRoot; use scope="platform" for platform-level operations.'
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return path4.resolve(candidate);
|
|
166
|
+
}
|
|
167
|
+
function resolveQueryRoots(roots, ctx) {
|
|
168
|
+
if (ctx.scope === "platform") {
|
|
169
|
+
return [{ scope: "platform", root: roots.platformRoot }];
|
|
170
|
+
}
|
|
171
|
+
if (ctx.scope === "project") {
|
|
172
|
+
return [
|
|
173
|
+
{
|
|
174
|
+
scope: "project",
|
|
175
|
+
root: resolveScopeRoot(roots, { scope: "project", projectRoot: ctx.projectRoot })
|
|
176
|
+
}
|
|
177
|
+
];
|
|
178
|
+
}
|
|
179
|
+
const out = [
|
|
180
|
+
{ scope: "platform", root: roots.platformRoot }
|
|
181
|
+
];
|
|
182
|
+
const projectCandidate = ctx.projectRoot ?? roots.projectRoot;
|
|
183
|
+
if (projectCandidate) {
|
|
184
|
+
try {
|
|
185
|
+
const projectRoot = resolveScopeRoot(roots, { scope: "project", projectRoot: projectCandidate });
|
|
186
|
+
out.push({ scope: "project", root: projectRoot });
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
var ScopeResolutionError = class extends Error {
|
|
193
|
+
code;
|
|
194
|
+
constructor(code, message) {
|
|
195
|
+
super(message);
|
|
196
|
+
this.code = code;
|
|
197
|
+
this.name = "ScopeResolutionError";
|
|
198
|
+
}
|
|
199
|
+
};
|
|
118
200
|
|
|
119
201
|
// src/marketplace-service.ts
|
|
120
202
|
var MarketplaceService = class {
|
|
121
|
-
|
|
203
|
+
roots;
|
|
122
204
|
source;
|
|
123
205
|
strategies = /* @__PURE__ */ new Map();
|
|
124
206
|
constructor(opts) {
|
|
125
|
-
this.
|
|
207
|
+
this.roots = { platformRoot: opts.platformRoot, projectRoot: opts.projectRoot };
|
|
126
208
|
this.source = opts.source;
|
|
127
209
|
this.registerStrategy(new PluginStrategy());
|
|
128
210
|
this.registerStrategy(new AdapterStrategy());
|
|
@@ -138,28 +220,31 @@ var MarketplaceService = class {
|
|
|
138
220
|
// -------------------------------------------------------------------------
|
|
139
221
|
// Install
|
|
140
222
|
// -------------------------------------------------------------------------
|
|
141
|
-
async install(specs, opts) {
|
|
223
|
+
async install(ctx, specs, opts) {
|
|
224
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
142
225
|
const installed = [];
|
|
143
226
|
const warnings = [];
|
|
227
|
+
const diagnostics = [];
|
|
144
228
|
for (const spec of specs) {
|
|
145
229
|
const resolved = await this.source.resolve(spec);
|
|
146
|
-
const result = await this.source.install(resolved,
|
|
230
|
+
const result = await this.source.install(resolved, scopeRoot, opts);
|
|
147
231
|
const primaryKind = await this.detectKind(result.packageRoot);
|
|
232
|
+
this.assertScopeAllowsKind(ctx.scope, primaryKind);
|
|
148
233
|
const strategy = this.strategies.get(primaryKind);
|
|
149
234
|
const provides = strategy ? await strategy.extractProvides(result.packageRoot) : [primaryKind];
|
|
150
235
|
const entry = createMarketplaceEntry({
|
|
151
236
|
version: result.version,
|
|
152
237
|
integrity: result.integrity,
|
|
153
|
-
resolvedPath: relativeToRoot(
|
|
238
|
+
resolvedPath: relativeToRoot(scopeRoot, result.packageRoot),
|
|
154
239
|
source: resolved.source,
|
|
155
240
|
primaryKind,
|
|
156
241
|
provides
|
|
157
242
|
});
|
|
158
|
-
await addToMarketplaceLock(
|
|
159
|
-
await this.cacheManifest(result.id, result.packageRoot, primaryKind, result.integrity);
|
|
243
|
+
await addToMarketplaceLock(scopeRoot, result.id, entry);
|
|
244
|
+
await this.cacheManifest(scopeRoot, result.id, result.packageRoot, primaryKind, result.integrity);
|
|
160
245
|
if (strategy?.afterInstall) {
|
|
161
246
|
try {
|
|
162
|
-
await strategy.afterInstall(result.id, result.packageRoot, this);
|
|
247
|
+
await strategy.afterInstall(result.id, result.packageRoot, this, ctx);
|
|
163
248
|
} catch (err) {
|
|
164
249
|
warnings.push(`afterInstall for ${result.id}: ${err.message}`);
|
|
165
250
|
}
|
|
@@ -169,113 +254,126 @@ var MarketplaceService = class {
|
|
|
169
254
|
version: result.version,
|
|
170
255
|
primaryKind,
|
|
171
256
|
provides,
|
|
172
|
-
packageRoot: result.packageRoot
|
|
257
|
+
packageRoot: result.packageRoot,
|
|
258
|
+
scope: ctx.scope
|
|
173
259
|
});
|
|
174
260
|
}
|
|
175
|
-
return { installed, warnings };
|
|
261
|
+
return { installed, warnings, scope: ctx.scope, diagnostics: diagnostics.length ? diagnostics : void 0 };
|
|
176
262
|
}
|
|
177
263
|
// -------------------------------------------------------------------------
|
|
178
264
|
// Uninstall
|
|
179
265
|
// -------------------------------------------------------------------------
|
|
180
|
-
async uninstall(packageIds) {
|
|
266
|
+
async uninstall(ctx, packageIds) {
|
|
267
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
181
268
|
for (const id of packageIds) {
|
|
182
|
-
const entry = await this.getEntry(id);
|
|
269
|
+
const entry = await this.getEntry(ctx, id);
|
|
183
270
|
if (entry) {
|
|
184
271
|
const strategy = this.strategies.get(entry.primaryKind);
|
|
185
272
|
if (strategy?.beforeUninstall) {
|
|
186
|
-
await strategy.beforeUninstall(id, this);
|
|
273
|
+
await strategy.beforeUninstall(id, this, ctx);
|
|
187
274
|
}
|
|
188
275
|
}
|
|
189
|
-
await removeFromMarketplaceLock(
|
|
190
|
-
await removeCacheEntry(
|
|
191
|
-
await this.source.remove(id,
|
|
276
|
+
await removeFromMarketplaceLock(scopeRoot, id);
|
|
277
|
+
await removeCacheEntry(scopeRoot, id);
|
|
278
|
+
await this.source.remove(id, scopeRoot);
|
|
192
279
|
}
|
|
193
280
|
}
|
|
194
281
|
// -------------------------------------------------------------------------
|
|
195
282
|
// Link / Unlink
|
|
196
283
|
// -------------------------------------------------------------------------
|
|
197
|
-
async link(packagePath) {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
284
|
+
async link(ctx, packagePath) {
|
|
285
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
286
|
+
const absPath = path4.resolve(scopeRoot, packagePath);
|
|
287
|
+
if (!isPathInside(scopeRoot, absPath)) {
|
|
288
|
+
throw new Error(
|
|
289
|
+
`Path "${packagePath}" is outside ${ctx.scope} root "${scopeRoot}" \u2014 refusing to link`
|
|
290
|
+
);
|
|
201
291
|
}
|
|
202
292
|
const pkgJson = JSON.parse(
|
|
203
|
-
await fs.readFile(
|
|
204
|
-
path3.join(absPath, "package.json"),
|
|
205
|
-
"utf-8"
|
|
206
|
-
)
|
|
293
|
+
await fs.readFile(path4.join(absPath, "package.json"), "utf-8")
|
|
207
294
|
);
|
|
208
295
|
const id = pkgJson.name;
|
|
209
296
|
const version = pkgJson.version ?? "0.0.0";
|
|
210
297
|
const primaryKind = await this.detectKind(absPath);
|
|
298
|
+
this.assertScopeAllowsKind(ctx.scope, primaryKind);
|
|
211
299
|
const strategy = this.strategies.get(primaryKind);
|
|
212
300
|
const provides = strategy ? await strategy.extractProvides(absPath) : [primaryKind];
|
|
213
301
|
const integrity = await computeIntegrity(absPath);
|
|
214
302
|
const entry = createMarketplaceEntry({
|
|
215
303
|
version,
|
|
216
304
|
integrity,
|
|
217
|
-
resolvedPath: relativeToRoot(
|
|
305
|
+
resolvedPath: relativeToRoot(scopeRoot, absPath),
|
|
218
306
|
source: "local",
|
|
219
307
|
primaryKind,
|
|
220
308
|
provides
|
|
221
309
|
});
|
|
222
|
-
await addToMarketplaceLock(
|
|
223
|
-
await this.cacheManifest(id, absPath, primaryKind, integrity);
|
|
310
|
+
await addToMarketplaceLock(scopeRoot, id, entry);
|
|
311
|
+
await this.cacheManifest(scopeRoot, id, absPath, primaryKind, integrity);
|
|
224
312
|
if (strategy?.afterInstall) {
|
|
225
|
-
await strategy.afterInstall(id, absPath, this);
|
|
313
|
+
await strategy.afterInstall(id, absPath, this, ctx);
|
|
226
314
|
}
|
|
227
|
-
return { id, version, primaryKind, provides, packageRoot: absPath };
|
|
315
|
+
return { id, version, primaryKind, provides, packageRoot: absPath, scope: ctx.scope };
|
|
228
316
|
}
|
|
229
|
-
async unlink(packageId) {
|
|
230
|
-
|
|
231
|
-
await
|
|
317
|
+
async unlink(ctx, packageId) {
|
|
318
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
319
|
+
await removeFromMarketplaceLock(scopeRoot, packageId);
|
|
320
|
+
await removeCacheEntry(scopeRoot, packageId);
|
|
232
321
|
}
|
|
233
322
|
// -------------------------------------------------------------------------
|
|
234
323
|
// Update
|
|
235
324
|
// -------------------------------------------------------------------------
|
|
236
|
-
async update(packageIds) {
|
|
325
|
+
async update(ctx, packageIds) {
|
|
326
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
237
327
|
const diag = new DiagnosticCollector();
|
|
238
|
-
const lock = await readMarketplaceLock(
|
|
328
|
+
const lock = await readMarketplaceLock(scopeRoot, diag);
|
|
239
329
|
if (!lock) {
|
|
240
|
-
return { installed: [], warnings: ["No marketplace.lock found"] };
|
|
330
|
+
return { installed: [], warnings: ["No marketplace.lock found"], scope: ctx.scope };
|
|
241
331
|
}
|
|
242
332
|
const ids = packageIds ?? Object.keys(lock.installed);
|
|
243
333
|
const specs = ids.filter((id) => id in lock.installed);
|
|
244
|
-
return this.install(specs);
|
|
334
|
+
return this.install(ctx, specs);
|
|
245
335
|
}
|
|
246
336
|
// -------------------------------------------------------------------------
|
|
247
337
|
// Enable / Disable
|
|
248
338
|
// -------------------------------------------------------------------------
|
|
249
|
-
async enable(packageId) {
|
|
250
|
-
const
|
|
339
|
+
async enable(ctx, packageId) {
|
|
340
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
341
|
+
const ok = await enablePlugin(scopeRoot, packageId);
|
|
251
342
|
if (!ok) {
|
|
252
|
-
throw new Error(`Package "${packageId}" not found in marketplace.lock`);
|
|
343
|
+
throw new Error(`Package "${packageId}" not found in ${ctx.scope} marketplace.lock`);
|
|
253
344
|
}
|
|
254
345
|
}
|
|
255
|
-
async disable(packageId) {
|
|
256
|
-
const
|
|
346
|
+
async disable(ctx, packageId) {
|
|
347
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
348
|
+
const ok = await disablePlugin(scopeRoot, packageId);
|
|
257
349
|
if (!ok) {
|
|
258
|
-
throw new Error(`Package "${packageId}" not found in marketplace.lock`);
|
|
350
|
+
throw new Error(`Package "${packageId}" not found in ${ctx.scope} marketplace.lock`);
|
|
259
351
|
}
|
|
260
352
|
}
|
|
261
353
|
// -------------------------------------------------------------------------
|
|
262
354
|
// List / GetEntry (MarketplaceServiceAPI)
|
|
263
355
|
// -------------------------------------------------------------------------
|
|
264
|
-
async list(filter) {
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
356
|
+
async list(ctx, filter) {
|
|
357
|
+
const targets = resolveQueryRoots(this.roots, ctx);
|
|
358
|
+
const perScope = [];
|
|
359
|
+
for (const { scope, root } of targets) {
|
|
360
|
+
const diag = new DiagnosticCollector();
|
|
361
|
+
const lock = await readMarketplaceLock(root, diag);
|
|
362
|
+
if (!lock) {
|
|
363
|
+
perScope.push({ scope, entries: [] });
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const entries = Object.entries(lock.installed).map(([id, entry]) => ({ ...entry, id }));
|
|
367
|
+
perScope.push({ scope, entries });
|
|
273
368
|
}
|
|
274
|
-
|
|
369
|
+
const merged = mergeScopedEntries(perScope);
|
|
370
|
+
const filtered = filter?.kind ? merged.entries.filter((e) => e.primaryKind === filter.kind) : merged.entries;
|
|
371
|
+
return filtered;
|
|
275
372
|
}
|
|
276
|
-
async getEntry(packageId) {
|
|
373
|
+
async getEntry(ctx, packageId) {
|
|
374
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
277
375
|
const diag = new DiagnosticCollector();
|
|
278
|
-
const lock = await readMarketplaceLock(
|
|
376
|
+
const lock = await readMarketplaceLock(scopeRoot, diag);
|
|
279
377
|
return lock?.installed[packageId] ?? null;
|
|
280
378
|
}
|
|
281
379
|
// -------------------------------------------------------------------------
|
|
@@ -285,33 +383,38 @@ var MarketplaceService = class {
|
|
|
285
383
|
* Scan workspace for plugins and adapters using glob patterns.
|
|
286
384
|
* Existing entries are preserved (not overwritten).
|
|
287
385
|
* Patterns come from kb.config.json marketplace.sync.include.
|
|
386
|
+
*
|
|
387
|
+
* Sync is scope-bound: globs resolve against the scope root and results go
|
|
388
|
+
* into that scope's lock. Adapter discovery in `project` scope is refused
|
|
389
|
+
* with a clear error to preserve the adapters-are-platform-only invariant.
|
|
288
390
|
*/
|
|
289
|
-
async sync(opts) {
|
|
391
|
+
async sync(ctx, opts) {
|
|
392
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
290
393
|
const autoEnable = opts.autoEnable ?? false;
|
|
291
394
|
const diag = new DiagnosticCollector();
|
|
292
|
-
const lock = await readMarketplaceLock(
|
|
395
|
+
const lock = await readMarketplaceLock(scopeRoot, diag) ?? createEmptyLock();
|
|
293
396
|
const existingIds = new Set(Object.keys(lock.installed));
|
|
294
397
|
const added = [];
|
|
295
398
|
const skipped = [];
|
|
296
|
-
const includePatterns = opts.include.map((p) =>
|
|
399
|
+
const includePatterns = opts.include.map((p) => path4.join(p, "package.json"));
|
|
297
400
|
const excludePatterns = opts.exclude ?? [];
|
|
298
401
|
const packageJsonPaths = await glob(includePatterns, {
|
|
299
|
-
cwd:
|
|
402
|
+
cwd: scopeRoot,
|
|
300
403
|
ignore: excludePatterns,
|
|
301
404
|
absolute: false
|
|
302
405
|
});
|
|
303
406
|
for (const relPkgJson of packageJsonPaths) {
|
|
304
|
-
const pkgDir =
|
|
305
|
-
await this._syncPackage(pkgDir, relPkgJson, existingIds, autoEnable, lock, added, skipped);
|
|
407
|
+
const pkgDir = path4.resolve(scopeRoot, path4.dirname(relPkgJson));
|
|
408
|
+
await this._syncPackage(ctx.scope, scopeRoot, pkgDir, relPkgJson, existingIds, autoEnable, lock, added, skipped);
|
|
306
409
|
}
|
|
307
|
-
await writeMarketplaceLock(
|
|
410
|
+
await writeMarketplaceLock(scopeRoot, lock);
|
|
308
411
|
return { added, skipped, total: Object.keys(lock.installed).length };
|
|
309
412
|
}
|
|
310
|
-
async _syncPackage(pkgDir, _relPkgJson, existingIds, autoEnable, lock, added, skipped) {
|
|
413
|
+
async _syncPackage(scope, scopeRoot, pkgDir, _relPkgJson, existingIds, autoEnable, lock, added, skipped) {
|
|
311
414
|
let pkgName;
|
|
312
415
|
let pkgVersion;
|
|
313
416
|
try {
|
|
314
|
-
const pkgJson = JSON.parse(await fs.readFile(
|
|
417
|
+
const pkgJson = JSON.parse(await fs.readFile(path4.join(pkgDir, "package.json"), "utf-8"));
|
|
315
418
|
pkgName = pkgJson.name;
|
|
316
419
|
pkgVersion = pkgJson.version ?? "0.0.0";
|
|
317
420
|
if (!pkgName) {
|
|
@@ -336,6 +439,10 @@ var MarketplaceService = class {
|
|
|
336
439
|
return;
|
|
337
440
|
}
|
|
338
441
|
const primaryKind = await this.detectKind(pkgDir);
|
|
442
|
+
if (scope === "project" && primaryKind === "adapter") {
|
|
443
|
+
skipped.push({ id: pkgName, reason: "adapter not allowed in project scope" });
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
339
446
|
const strategy = this.strategies.get(primaryKind);
|
|
340
447
|
const provides = strategy ? await strategy.extractProvides(pkgDir) : [primaryKind];
|
|
341
448
|
const integrity = await computeIntegrity(pkgDir);
|
|
@@ -347,7 +454,7 @@ var MarketplaceService = class {
|
|
|
347
454
|
const entry = createMarketplaceEntry({
|
|
348
455
|
version: pkgVersion,
|
|
349
456
|
integrity,
|
|
350
|
-
resolvedPath: relativeToRoot(
|
|
457
|
+
resolvedPath: relativeToRoot(scopeRoot, pkgDir),
|
|
351
458
|
source: "local",
|
|
352
459
|
primaryKind,
|
|
353
460
|
provides
|
|
@@ -361,16 +468,17 @@ var MarketplaceService = class {
|
|
|
361
468
|
// -------------------------------------------------------------------------
|
|
362
469
|
// Doctor
|
|
363
470
|
// -------------------------------------------------------------------------
|
|
364
|
-
async doctor() {
|
|
471
|
+
async doctor(ctx) {
|
|
472
|
+
const scopeRoot = resolveScopeRoot(this.roots, ctx);
|
|
365
473
|
const diag = new DiagnosticCollector();
|
|
366
|
-
const lock = await readMarketplaceLock(
|
|
474
|
+
const lock = await readMarketplaceLock(scopeRoot, diag);
|
|
367
475
|
const issues = [];
|
|
368
476
|
if (!lock) {
|
|
369
477
|
return { ok: true, total: 0, issues: [{ severity: "info", packageId: "", message: "No marketplace.lock found" }] };
|
|
370
478
|
}
|
|
371
479
|
const entries = Object.entries(lock.installed);
|
|
372
480
|
for (const [id, entry] of entries) {
|
|
373
|
-
const pkgRoot =
|
|
481
|
+
const pkgRoot = path4.resolve(scopeRoot, entry.resolvedPath);
|
|
374
482
|
try {
|
|
375
483
|
await fs.access(pkgRoot);
|
|
376
484
|
} catch {
|
|
@@ -420,13 +528,25 @@ var MarketplaceService = class {
|
|
|
420
528
|
}
|
|
421
529
|
return "plugin";
|
|
422
530
|
}
|
|
423
|
-
|
|
531
|
+
/**
|
|
532
|
+
* Hard guard: adapters may only be installed/linked in platform scope.
|
|
533
|
+
* Lives in one place so adapter-scope policy is not duplicated across
|
|
534
|
+
* `link`, `install`, and `sync`.
|
|
535
|
+
*/
|
|
536
|
+
assertScopeAllowsKind(scope, kind) {
|
|
537
|
+
if (scope === "project" && kind === "adapter") {
|
|
538
|
+
throw new AdapterScopeError(
|
|
539
|
+
"Adapters can only be installed in platform scope. Use --scope platform or install globally via the platform marketplace."
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
async cacheManifest(scopeRoot, packageId, packageRoot, primaryKind, integrity) {
|
|
424
544
|
try {
|
|
425
545
|
if (primaryKind === "plugin") {
|
|
426
546
|
const diag = new DiagnosticCollector();
|
|
427
547
|
const manifest = await loadManifest(packageRoot, diag);
|
|
428
548
|
if (manifest) {
|
|
429
|
-
await setCacheEntry(
|
|
549
|
+
await setCacheEntry(scopeRoot, packageId, {
|
|
430
550
|
manifestType: "plugin",
|
|
431
551
|
manifest,
|
|
432
552
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -434,10 +554,10 @@ var MarketplaceService = class {
|
|
|
434
554
|
});
|
|
435
555
|
}
|
|
436
556
|
} else if (primaryKind === "adapter") {
|
|
437
|
-
const distPath =
|
|
557
|
+
const distPath = path4.join(packageRoot, "dist", "index.js");
|
|
438
558
|
const mod = await import(pathToFileURL(distPath).href);
|
|
439
559
|
if (mod.manifest) {
|
|
440
|
-
await setCacheEntry(
|
|
560
|
+
await setCacheEntry(scopeRoot, packageId, {
|
|
441
561
|
manifestType: "adapter",
|
|
442
562
|
manifest: mod.manifest,
|
|
443
563
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -450,19 +570,56 @@ var MarketplaceService = class {
|
|
|
450
570
|
}
|
|
451
571
|
}
|
|
452
572
|
};
|
|
573
|
+
var AdapterScopeError = class extends Error {
|
|
574
|
+
code = "MARKETPLACE_ADAPTER_PROJECT_SCOPE";
|
|
575
|
+
constructor(message) {
|
|
576
|
+
super(message);
|
|
577
|
+
this.name = "AdapterScopeError";
|
|
578
|
+
}
|
|
579
|
+
};
|
|
453
580
|
function relativeToRoot(root, absPath) {
|
|
454
|
-
const rel =
|
|
581
|
+
const rel = path4.relative(root, absPath);
|
|
455
582
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
456
583
|
}
|
|
584
|
+
function isPathInside(parent, child) {
|
|
585
|
+
const rel = path4.relative(path4.resolve(parent), path4.resolve(child));
|
|
586
|
+
return !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
587
|
+
}
|
|
457
588
|
async function computeIntegrity(packageRoot) {
|
|
458
589
|
try {
|
|
459
|
-
const content = await fs.readFile(
|
|
590
|
+
const content = await fs.readFile(path4.join(packageRoot, "package.json"));
|
|
460
591
|
return `sha256-${crypto.createHash("sha256").update(content).digest("base64")}`;
|
|
461
592
|
} catch {
|
|
462
593
|
return "";
|
|
463
594
|
}
|
|
464
595
|
}
|
|
596
|
+
function mergeScopedEntries(perScope) {
|
|
597
|
+
const out = /* @__PURE__ */ new Map();
|
|
598
|
+
const diagnostics = [];
|
|
599
|
+
const ordered = [...perScope].sort((a, b) => {
|
|
600
|
+
if (a.scope === b.scope) {
|
|
601
|
+
return 0;
|
|
602
|
+
}
|
|
603
|
+
return a.scope === "platform" ? -1 : 1;
|
|
604
|
+
});
|
|
605
|
+
for (const { scope, entries } of ordered) {
|
|
606
|
+
for (const e of entries) {
|
|
607
|
+
const existing = out.get(e.id);
|
|
608
|
+
if (existing) {
|
|
609
|
+
diagnostics.push({
|
|
610
|
+
code: "MARKETPLACE_SCOPE_COLLISION",
|
|
611
|
+
message: `Package "${e.id}" exists in both platform and ${scope} scopes \u2014 platform wins.`,
|
|
612
|
+
packageId: e.id,
|
|
613
|
+
scope
|
|
614
|
+
});
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
out.set(e.id, { ...e, scope });
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return { entries: Array.from(out.values()), diagnostics };
|
|
621
|
+
}
|
|
465
622
|
|
|
466
|
-
export { AdapterStrategy, MarketplaceService, PluginStrategy, createEmptyManifestCache, readManifestCache, removeCacheEntry, setCacheEntry, writeManifestCache };
|
|
623
|
+
export { AdapterScopeError, AdapterStrategy, MarketplaceService, PluginStrategy, ScopeResolutionError, createEmptyManifestCache, mergeScopedEntries, readManifestCache, removeCacheEntry, resolveQueryRoots, resolveScopeRoot, setCacheEntry, writeManifestCache };
|
|
467
624
|
//# sourceMappingURL=index.js.map
|
|
468
625
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manifest-cache.ts","../src/strategies/plugin-strategy.ts","../src/strategies/adapter-strategy.ts","../src/marketplace-service.ts"],"names":["path","path2","fs2","fs3","DiagnosticCollector","strategy","loadManifest","pathToFileURL"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/marketplace-core/manifest-cache\n * Read/write .kb/marketplace.manifests.json — cached manifests for fast discovery.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { ManifestCache, ManifestCacheEntry } from '@kb-labs/marketplace-contracts';\n\nconst CACHE_FILE = '.kb/marketplace.manifests.json';\nconst SCHEMA_VERSION = 'kb.marketplace.manifests/1' as const;\n\n/**\n * Read the manifest cache from disk. Returns null if missing or invalid.\n */\nexport async function readManifestCache(root: string): Promise<ManifestCache | null> {\n const cachePath = path.join(root, CACHE_FILE);\n try {\n const raw = await fs.readFile(cachePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed?.schema !== SCHEMA_VERSION) {return null;}\n return parsed as ManifestCache;\n } catch {\n return null;\n }\n}\n\n/**\n * Write the manifest cache atomically (tmp → rename).\n */\nexport async function writeManifestCache(root: string, cache: ManifestCache): Promise<void> {\n const cachePath = path.join(root, CACHE_FILE);\n const dir = path.dirname(cachePath);\n await fs.mkdir(dir, { recursive: true });\n\n const tmpPath = `${cachePath}.tmp.${randomUUID()}`;\n await fs.writeFile(tmpPath, JSON.stringify(cache, null, 2) + '\\n', 'utf-8');\n await fs.rename(tmpPath, cachePath);\n}\n\n/**\n * Create an empty manifest cache.\n */\nexport function createEmptyManifestCache(): ManifestCache {\n return { schema: SCHEMA_VERSION, entries: {} };\n}\n\n/**\n * Set a single entry in the manifest cache and persist.\n */\nexport async function setCacheEntry(\n root: string,\n packageId: string,\n entry: ManifestCacheEntry,\n): Promise<void> {\n const existing = await readManifestCache(root) ?? createEmptyManifestCache();\n existing.entries[packageId] = entry;\n await writeManifestCache(root, existing);\n}\n\n/**\n * Remove a single entry from the manifest cache and persist.\n */\nexport async function removeCacheEntry(\n root: string,\n packageId: string,\n): Promise<void> {\n const existing = await readManifestCache(root);\n if (!existing || !(packageId in existing.entries)) {return;}\n delete existing.entries[packageId];\n await writeManifestCache(root, existing);\n}\n","/**\n * @module @kb-labs/marketplace-core/strategies/plugin-strategy\n * Strategy for plugins — detects ManifestV3 and extracts entity kinds.\n */\n\nimport type { EntityKind } from '@kb-labs/core-discovery';\nimport type { EntityKindStrategy } from '@kb-labs/marketplace-contracts';\nimport { loadManifest, DiagnosticCollector, extractEntityKinds } from '@kb-labs/core-discovery';\n\nexport class PluginStrategy implements EntityKindStrategy {\n kind: EntityKind = 'plugin';\n\n async detectKind(packageRoot: string): Promise<EntityKind | null> {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n return manifest ? 'plugin' : null;\n }\n\n async extractProvides(packageRoot: string): Promise<EntityKind[]> {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n if (!manifest) {return ['plugin'];}\n return extractEntityKinds(manifest);\n }\n\n async resolveId(packageRoot: string): Promise<string | null> {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n return manifest?.id ?? null;\n }\n}\n","/**\n * @module @kb-labs/marketplace-core/strategies/adapter-strategy\n * Strategy for adapters — detects AdapterManifest, validates dependencies.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { EntityKind } from '@kb-labs/core-discovery';\nimport type { EntityKindStrategy, MarketplaceServiceAPI } from '@kb-labs/marketplace-contracts';\n\nexport class AdapterStrategy implements EntityKindStrategy {\n kind: EntityKind = 'adapter';\n\n async detectKind(packageRoot: string): Promise<EntityKind | null> {\n const manifest = await loadAdapterManifest(packageRoot);\n return manifest ? 'adapter' : null;\n }\n\n async extractProvides(_packageRoot: string): Promise<EntityKind[]> {\n return ['adapter'];\n }\n\n async afterInstall(\n packageId: string,\n packageRoot: string,\n service: MarketplaceServiceAPI,\n ): Promise<void> {\n const manifest = await loadAdapterManifest(packageRoot);\n if (!manifest?.requires?.adapters) {return;}\n\n const installed = await service.list({ kind: 'adapter' });\n const installedIds = new Set(installed.map(e => (e as any).id as string));\n\n for (const dep of manifest.requires.adapters) {\n const depId = typeof dep === 'string' ? dep : dep.id;\n // Check by package ID (exact match), not by path substring\n const found = installedIds.has(depId) ||\n installed.some(e => (e as any).id?.includes(`adapters-${depId}`));\n\n if (!found) {\n console.warn(\n `[marketplace] Adapter \"${packageId}\" requires adapter \"${depId}\" which is not installed. ` +\n `Run: kb marketplace link <adapter-package-that-provides-${depId}>`\n );\n }\n }\n }\n\n async beforeUninstall(\n packageId: string,\n service: MarketplaceServiceAPI,\n ): Promise<void> {\n // Check if any other installed adapter depends on this one\n // This requires loading manifests — for now, warn about potential breakage\n const installed = await service.list({ kind: 'adapter' });\n if (installed.length > 1) {\n console.warn(\n `[marketplace] Removing adapter \"${packageId}\" — verify no other adapters depend on it`\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface AdapterManifestLike {\n id?: string;\n type?: 'core' | 'extension' | 'proxy';\n implements?: string;\n requires?: {\n adapters?: Array<string | { id: string; alias?: string }>;\n };\n}\n\nasync function loadAdapterManifest(packageRoot: string): Promise<AdapterManifestLike | null> {\n try {\n const distPath = path.join(packageRoot, 'dist', 'index.js');\n await fs.access(distPath);\n const mod = await import(pathToFileURL(distPath).href);\n if (mod.manifest && typeof mod.manifest === 'object' && mod.manifest.implements) {\n return mod.manifest as AdapterManifestLike;\n }\n return null;\n } catch {\n return null;\n }\n}\n","/**\n * @module @kb-labs/marketplace-core/marketplace-service\n * Unified marketplace service — install/uninstall/enable/disable for all entity types.\n * Works through PackageSource abstraction — never calls pnpm directly.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { pathToFileURL } from 'node:url';\nimport { glob } from 'glob';\nimport type { EntityKind, MarketplaceEntry, MarketplaceLock } from '@kb-labs/core-discovery';\nimport {\n readMarketplaceLock,\n writeMarketplaceLock,\n createEmptyLock,\n createMarketplaceEntry,\n addToMarketplaceLock,\n removeFromMarketplaceLock,\n enablePlugin,\n disablePlugin,\n DiagnosticCollector,\n loadManifest,\n} from '@kb-labs/core-discovery';\nimport type {\n PackageSource,\n EntityKindStrategy,\n MarketplaceServiceAPI,\n MarketplaceEntryWithId,\n InstallResult,\n InstallResultEntry,\n SyncResult,\n DoctorReport,\n DoctorIssue,\n} from '@kb-labs/marketplace-contracts';\nimport { setCacheEntry, removeCacheEntry } from './manifest-cache.js';\nimport { PluginStrategy } from './strategies/plugin-strategy.js';\nimport { AdapterStrategy } from './strategies/adapter-strategy.js';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface MarketplaceServiceOptions {\n /** Workspace root directory */\n root: string;\n /** Package source (npm, registry, etc.) */\n source: PackageSource;\n /** Additional strategies beyond built-in plugin/adapter */\n strategies?: EntityKindStrategy[];\n}\n\n// ---------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------\n\nexport class MarketplaceService implements MarketplaceServiceAPI {\n private readonly root: string;\n private readonly source: PackageSource;\n private readonly strategies = new Map<EntityKind, EntityKindStrategy>();\n\n constructor(opts: MarketplaceServiceOptions) {\n this.root = opts.root;\n this.source = opts.source;\n\n // Built-in strategies\n this.registerStrategy(new PluginStrategy());\n this.registerStrategy(new AdapterStrategy());\n\n // User-supplied strategies\n if (opts.strategies) {\n for (const s of opts.strategies) {\n this.registerStrategy(s);\n }\n }\n }\n\n registerStrategy(strategy: EntityKindStrategy): void {\n this.strategies.set(strategy.kind, strategy);\n }\n\n // -------------------------------------------------------------------------\n // Install\n // -------------------------------------------------------------------------\n\n async install(specs: string[], opts?: { dev?: boolean }): Promise<InstallResult> {\n const installed: InstallResultEntry[] = [];\n const warnings: string[] = [];\n\n for (const spec of specs) {\n const resolved = await this.source.resolve(spec);\n const result = await this.source.install(resolved, this.root, opts);\n\n // Detect primary kind via strategies\n const primaryKind = await this.detectKind(result.packageRoot);\n const strategy = this.strategies.get(primaryKind);\n const provides = strategy\n ? await strategy.extractProvides(result.packageRoot)\n : [primaryKind];\n\n // Write to marketplace.lock\n const entry = createMarketplaceEntry({\n version: result.version,\n integrity: result.integrity,\n resolvedPath: relativeToRoot(this.root, result.packageRoot),\n source: resolved.source,\n primaryKind,\n provides,\n });\n\n await addToMarketplaceLock(this.root, result.id, entry);\n\n // Cache manifest\n await this.cacheManifest(result.id, result.packageRoot, primaryKind, result.integrity);\n\n // Run post-install hook\n if (strategy?.afterInstall) {\n try {\n await strategy.afterInstall(result.id, result.packageRoot, this);\n } catch (err) {\n warnings.push(`afterInstall for ${result.id}: ${(err as Error).message}`);\n }\n }\n\n installed.push({\n id: result.id,\n version: result.version,\n primaryKind,\n provides,\n packageRoot: result.packageRoot,\n });\n }\n\n return { installed, warnings };\n }\n\n // -------------------------------------------------------------------------\n // Uninstall\n // -------------------------------------------------------------------------\n\n async uninstall(packageIds: string[]): Promise<void> {\n for (const id of packageIds) {\n // Run pre-uninstall hook\n const entry = await this.getEntry(id);\n if (entry) {\n const strategy = this.strategies.get(entry.primaryKind);\n if (strategy?.beforeUninstall) {\n await strategy.beforeUninstall(id, this);\n }\n }\n\n // Remove from lock\n await removeFromMarketplaceLock(this.root, id);\n\n // Remove from manifest cache\n await removeCacheEntry(this.root, id);\n\n // Remove from disk\n await this.source.remove(id, this.root);\n }\n }\n\n // -------------------------------------------------------------------------\n // Link / Unlink\n // -------------------------------------------------------------------------\n\n async link(packagePath: string): Promise<InstallResultEntry> {\n const absPath = path.resolve(this.root, packagePath);\n\n // Path traversal guard — linked path must be within workspace root\n if (!absPath.startsWith(this.root)) {\n throw new Error(`Path \"${packagePath}\" is outside workspace root — refusing to link`);\n }\n\n const pkgJson = JSON.parse(\n await fs.readFile(\n path.join(absPath, 'package.json'), 'utf-8',\n ),\n );\n const id: string = pkgJson.name;\n const version: string = pkgJson.version ?? '0.0.0';\n\n const primaryKind = await this.detectKind(absPath);\n const strategy = this.strategies.get(primaryKind);\n const provides = strategy\n ? await strategy.extractProvides(absPath)\n : [primaryKind];\n\n const integrity = await computeIntegrity(absPath);\n\n const entry = createMarketplaceEntry({\n version,\n integrity,\n resolvedPath: relativeToRoot(this.root, absPath),\n source: 'local',\n primaryKind,\n provides,\n });\n\n await addToMarketplaceLock(this.root, id, entry);\n await this.cacheManifest(id, absPath, primaryKind, integrity);\n\n if (strategy?.afterInstall) {\n await strategy.afterInstall(id, absPath, this);\n }\n\n return { id, version, primaryKind, provides, packageRoot: absPath };\n }\n\n async unlink(packageId: string): Promise<void> {\n await removeFromMarketplaceLock(this.root, packageId);\n await removeCacheEntry(this.root, packageId);\n }\n\n // -------------------------------------------------------------------------\n // Update\n // -------------------------------------------------------------------------\n\n async update(packageIds?: string[]): Promise<InstallResult> {\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(this.root, diag);\n if (!lock) {return { installed: [], warnings: ['No marketplace.lock found'] };}\n\n const ids = packageIds ?? Object.keys(lock.installed);\n const specs = ids.filter(id => id in lock.installed);\n\n // Re-install at latest\n return this.install(specs);\n }\n\n // -------------------------------------------------------------------------\n // Enable / Disable\n // -------------------------------------------------------------------------\n\n async enable(packageId: string): Promise<void> {\n const ok = await enablePlugin(this.root, packageId);\n if (!ok) {\n throw new Error(`Package \"${packageId}\" not found in marketplace.lock`);\n }\n }\n\n async disable(packageId: string): Promise<void> {\n const ok = await disablePlugin(this.root, packageId);\n if (!ok) {\n throw new Error(`Package \"${packageId}\" not found in marketplace.lock`);\n }\n }\n\n // -------------------------------------------------------------------------\n // List / GetEntry (MarketplaceServiceAPI)\n // -------------------------------------------------------------------------\n\n async list(filter?: { kind?: EntityKind }): Promise<MarketplaceEntryWithId[]> {\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(this.root, diag);\n if (!lock) {return [];}\n\n let entries = Object.entries(lock.installed).map(([id, entry]) => ({ ...entry, id }));\n if (filter?.kind) {\n entries = entries.filter(e => e.primaryKind === filter.kind);\n }\n return entries;\n }\n\n async getEntry(packageId: string): Promise<MarketplaceEntry | null> {\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(this.root, diag);\n return lock?.installed[packageId] ?? null;\n }\n\n // -------------------------------------------------------------------------\n // Sync (scan workspace → populate lock from config-driven globs)\n // -------------------------------------------------------------------------\n\n /**\n * Scan workspace for plugins and adapters using glob patterns.\n * Existing entries are preserved (not overwritten).\n * Patterns come from kb.config.json marketplace.sync.include.\n */\n async sync(opts: {\n include: string[];\n exclude?: string[];\n autoEnable?: boolean;\n }): Promise<SyncResult> {\n const autoEnable = opts.autoEnable ?? false;\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(this.root, diag) ?? createEmptyLock();\n const existingIds = new Set(Object.keys(lock.installed));\n\n const added: SyncResult['added'] = [];\n const skipped: SyncResult['skipped'] = [];\n\n // Resolve glob patterns to package directories\n const includePatterns = opts.include.map(p => path.join(p, 'package.json'));\n const excludePatterns = opts.exclude ?? [];\n\n const packageJsonPaths = await glob(includePatterns, {\n cwd: this.root,\n ignore: excludePatterns,\n absolute: false,\n });\n\n for (const relPkgJson of packageJsonPaths) {\n const pkgDir = path.resolve(this.root, path.dirname(relPkgJson));\n await this._syncPackage(pkgDir, relPkgJson, existingIds, autoEnable, lock, added, skipped);\n }\n\n await writeMarketplaceLock(this.root, lock);\n\n return { added, skipped, total: Object.keys(lock.installed).length };\n }\n\n private async _syncPackage(\n pkgDir: string,\n _relPkgJson: string,\n existingIds: Set<string>,\n autoEnable: boolean,\n lock: MarketplaceLock,\n added: SyncResult['added'],\n skipped: SyncResult['skipped'],\n ): Promise<void> {\n let pkgName: string;\n let pkgVersion: string;\n try {\n const pkgJson = JSON.parse(await fs.readFile(path.join(pkgDir, 'package.json'), 'utf-8'));\n pkgName = pkgJson.name;\n pkgVersion = pkgJson.version ?? '0.0.0';\n if (!pkgName) { return; }\n } catch {\n return;\n }\n\n if (existingIds.has(pkgName)) {\n skipped.push({ id: pkgName, reason: 'already in lock' });\n return;\n }\n\n let detected = false;\n for (const strategy of this.strategies.values()) {\n const kind = await strategy.detectKind(pkgDir);\n if (kind) { detected = true; break; }\n }\n if (!detected) { return; }\n\n const primaryKind = await this.detectKind(pkgDir);\n const strategy = this.strategies.get(primaryKind);\n const provides = strategy ? await strategy.extractProvides(pkgDir) : [primaryKind];\n const integrity = await computeIntegrity(pkgDir);\n\n // Use manifest ID as lock key if the strategy can resolve it.\n // This keeps discovery working even when package.json name differs from manifest.id\n // (e.g. after folder renames like cli/ → entry/).\n const resolvedId = (strategy?.resolveId ? await strategy.resolveId(pkgDir) : null) ?? pkgName;\n\n if (existingIds.has(resolvedId) && resolvedId !== pkgName) {\n skipped.push({ id: resolvedId, reason: 'already in lock' });\n return;\n }\n\n const entry = createMarketplaceEntry({\n version: pkgVersion,\n integrity,\n resolvedPath: relativeToRoot(this.root, pkgDir),\n source: 'local',\n primaryKind,\n provides,\n });\n\n if (!autoEnable) { entry.enabled = false; }\n\n lock.installed[resolvedId] = entry;\n added.push({ id: resolvedId, primaryKind, version: pkgVersion });\n }\n\n // -------------------------------------------------------------------------\n // Doctor\n // -------------------------------------------------------------------------\n\n async doctor(): Promise<DoctorReport> {\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(this.root, diag);\n const issues: DoctorIssue[] = [];\n\n if (!lock) {\n return { ok: true, total: 0, issues: [{ severity: 'info', packageId: '', message: 'No marketplace.lock found' }] };\n }\n\n const entries = Object.entries(lock.installed);\n\n for (const [id, entry] of entries) {\n const pkgRoot = path.resolve(this.root, entry.resolvedPath);\n\n // Check package exists\n try {\n await fs.access(pkgRoot);\n } catch {\n issues.push({\n severity: 'error',\n packageId: id,\n message: `Package directory not found: ${pkgRoot}`,\n remediation: `Run \"kb marketplace install ${id}\" to restore`,\n });\n continue;\n }\n\n // Check integrity\n if (entry.integrity) {\n const computed = await computeIntegrity(pkgRoot);\n if (computed && computed !== entry.integrity) {\n issues.push({\n severity: 'warning',\n packageId: id,\n message: `Integrity mismatch: expected ${entry.integrity}, got ${computed}`,\n remediation: `Re-install: kb marketplace install ${id}`,\n });\n }\n }\n\n // Check signature\n if (!entry.signature) {\n issues.push({\n severity: 'info',\n packageId: id,\n message: 'Package is not signed',\n remediation: 'Publish through the official marketplace to get a platform signature',\n });\n }\n }\n\n return {\n ok: issues.filter(i => i.severity === 'error').length === 0,\n total: entries.length,\n issues,\n };\n }\n\n // -------------------------------------------------------------------------\n // Private\n // -------------------------------------------------------------------------\n\n private async detectKind(packageRoot: string): Promise<EntityKind> {\n // Try each strategy in registration order\n for (const strategy of this.strategies.values()) {\n const kind = await strategy.detectKind(packageRoot);\n if (kind) {return kind;}\n }\n // Default: plugin\n return 'plugin';\n }\n\n private async cacheManifest(\n packageId: string,\n packageRoot: string,\n primaryKind: EntityKind,\n integrity: string,\n ): Promise<void> {\n try {\n if (primaryKind === 'plugin') {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n if (manifest) {\n await setCacheEntry(this.root, packageId, {\n manifestType: 'plugin',\n manifest,\n cachedAt: new Date().toISOString(),\n integrity,\n });\n }\n } else if (primaryKind === 'adapter') {\n const distPath = path.join(packageRoot, 'dist', 'index.js');\n const mod = await import(pathToFileURL(distPath).href);\n if (mod.manifest) {\n await setCacheEntry(this.root, packageId, {\n manifestType: 'adapter',\n manifest: mod.manifest,\n cachedAt: new Date().toISOString(),\n integrity,\n });\n }\n }\n } catch (err) {\n // Non-fatal — cache miss means slower next discovery, but log for diagnostics\n console.warn(`[marketplace] Failed to cache manifest for \"${packageId}\": ${(err as Error).message}`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction relativeToRoot(root: string, absPath: string): string {\n const rel = path.relative(root, absPath);\n return rel.startsWith('.') ? rel : `./${rel}`;\n}\n\nasync function computeIntegrity(packageRoot: string): Promise<string> {\n try {\n const content = await fs.readFile(path.join(packageRoot, 'package.json'));\n return `sha256-${crypto.createHash('sha256').update(content).digest('base64')}`;\n } catch {\n return '';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/manifest-cache.ts","../src/strategies/plugin-strategy.ts","../src/strategies/adapter-strategy.ts","../src/scope.ts","../src/marketplace-service.ts"],"names":["path","path2","fs2","path3","fs3","DiagnosticCollector","strategy","loadManifest","pathToFileURL"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/marketplace-core/manifest-cache\n * Read/write .kb/marketplace.manifests.json — cached manifests for fast discovery.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { ManifestCache, ManifestCacheEntry } from '@kb-labs/marketplace-contracts';\n\nconst CACHE_FILE = '.kb/marketplace.manifests.json';\nconst SCHEMA_VERSION = 'kb.marketplace.manifests/1' as const;\n\n/**\n * Read the manifest cache from disk. Returns null if missing or invalid.\n */\nexport async function readManifestCache(root: string): Promise<ManifestCache | null> {\n const cachePath = path.join(root, CACHE_FILE);\n try {\n const raw = await fs.readFile(cachePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed?.schema !== SCHEMA_VERSION) {return null;}\n return parsed as ManifestCache;\n } catch {\n return null;\n }\n}\n\n/**\n * Write the manifest cache atomically (tmp → rename).\n */\nexport async function writeManifestCache(root: string, cache: ManifestCache): Promise<void> {\n const cachePath = path.join(root, CACHE_FILE);\n const dir = path.dirname(cachePath);\n await fs.mkdir(dir, { recursive: true });\n\n const tmpPath = `${cachePath}.tmp.${randomUUID()}`;\n await fs.writeFile(tmpPath, JSON.stringify(cache, null, 2) + '\\n', 'utf-8');\n await fs.rename(tmpPath, cachePath);\n}\n\n/**\n * Create an empty manifest cache.\n */\nexport function createEmptyManifestCache(): ManifestCache {\n return { schema: SCHEMA_VERSION, entries: {} };\n}\n\n/**\n * Set a single entry in the manifest cache and persist.\n */\nexport async function setCacheEntry(\n root: string,\n packageId: string,\n entry: ManifestCacheEntry,\n): Promise<void> {\n const existing = await readManifestCache(root) ?? createEmptyManifestCache();\n existing.entries[packageId] = entry;\n await writeManifestCache(root, existing);\n}\n\n/**\n * Remove a single entry from the manifest cache and persist.\n */\nexport async function removeCacheEntry(\n root: string,\n packageId: string,\n): Promise<void> {\n const existing = await readManifestCache(root);\n if (!existing || !(packageId in existing.entries)) {return;}\n delete existing.entries[packageId];\n await writeManifestCache(root, existing);\n}\n","/**\n * @module @kb-labs/marketplace-core/strategies/plugin-strategy\n * Strategy for plugins — detects ManifestV3 and extracts entity kinds.\n */\n\nimport type { EntityKind } from '@kb-labs/core-discovery';\nimport type { EntityKindStrategy } from '@kb-labs/marketplace-contracts';\nimport { loadManifest, DiagnosticCollector, extractEntityKinds } from '@kb-labs/core-discovery';\n\nexport class PluginStrategy implements EntityKindStrategy {\n kind: EntityKind = 'plugin';\n\n async detectKind(packageRoot: string): Promise<EntityKind | null> {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n return manifest ? 'plugin' : null;\n }\n\n async extractProvides(packageRoot: string): Promise<EntityKind[]> {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n if (!manifest) {return ['plugin'];}\n return extractEntityKinds(manifest);\n }\n\n async resolveId(packageRoot: string): Promise<string | null> {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n return manifest?.id ?? null;\n }\n}\n","/**\n * @module @kb-labs/marketplace-core/strategies/adapter-strategy\n * Strategy for adapters — detects AdapterManifest, validates dependencies.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { EntityKind } from '@kb-labs/core-discovery';\nimport type {\n EntityKindStrategy,\n MarketplaceServiceAPI,\n ScopeContext,\n} from '@kb-labs/marketplace-contracts';\n\nexport class AdapterStrategy implements EntityKindStrategy {\n kind: EntityKind = 'adapter';\n\n async detectKind(packageRoot: string): Promise<EntityKind | null> {\n const manifest = await loadAdapterManifest(packageRoot);\n return manifest ? 'adapter' : null;\n }\n\n async extractProvides(_packageRoot: string): Promise<EntityKind[]> {\n return ['adapter'];\n }\n\n async afterInstall(\n packageId: string,\n packageRoot: string,\n service: MarketplaceServiceAPI,\n ctx: ScopeContext,\n ): Promise<void> {\n const manifest = await loadAdapterManifest(packageRoot);\n if (!manifest?.requires?.adapters) {return;}\n\n // Adapters only live in platform scope (guarded in MarketplaceService),\n // so we query the same scope we were invoked with.\n const installed = await service.list(ctx, { kind: 'adapter' });\n const installedIds = new Set(installed.map(e => e.id));\n\n for (const dep of manifest.requires.adapters) {\n const depId = typeof dep === 'string' ? dep : dep.id;\n const found = installedIds.has(depId) ||\n installed.some(e => e.id.includes(`adapters-${depId}`));\n\n if (!found) {\n console.warn(\n `[marketplace] Adapter \"${packageId}\" requires adapter \"${depId}\" which is not installed. ` +\n `Run: kb marketplace link <adapter-package-that-provides-${depId}>`,\n );\n }\n }\n }\n\n async beforeUninstall(\n packageId: string,\n service: MarketplaceServiceAPI,\n ctx: ScopeContext,\n ): Promise<void> {\n const installed = await service.list(ctx, { kind: 'adapter' });\n if (installed.length > 1) {\n console.warn(\n `[marketplace] Removing adapter \"${packageId}\" — verify no other adapters depend on it`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface AdapterManifestLike {\n id?: string;\n type?: 'core' | 'extension' | 'proxy';\n implements?: string;\n requires?: {\n adapters?: Array<string | { id: string; alias?: string }>;\n };\n}\n\nasync function loadAdapterManifest(packageRoot: string): Promise<AdapterManifestLike | null> {\n try {\n const distPath = path.join(packageRoot, 'dist', 'index.js');\n await fs.access(distPath);\n const mod = await import(pathToFileURL(distPath).href);\n if (mod.manifest && typeof mod.manifest === 'object' && mod.manifest.implements) {\n return mod.manifest as AdapterManifestLike;\n }\n return null;\n } catch {\n return null;\n }\n}\n","/**\n * @module @kb-labs/marketplace-core/scope\n * Scope resolution helpers for the platform/project marketplace split.\n *\n * Every mutating service method is explicitly scope-bound — there is no\n * implicit default. The helpers below compute the absolute root directory\n * for a given ScopeContext and enforce the invariants that the rest of the\n * service relies on (distinct platform/project roots, project has a `.kb/`).\n */\n\nimport * as path from 'node:path';\nimport { accessSync, constants } from 'node:fs';\nimport type {\n MarketplaceScope,\n MarketplaceQueryScope,\n ScopeContext,\n QueryScopeContext,\n} from '@kb-labs/marketplace-contracts';\n\nconst CONFIG_FILE_CANDIDATES = ['kb.config.jsonc', 'kb.config.json'] as const;\n\n/**\n * Roots known to the MarketplaceService at construction time.\n * `platformRoot` is always known. `projectRoot` is optional at construction\n * (daemon may serve multiple projects); per-call `ctx.projectRoot` can\n * override it.\n */\nexport interface ServiceRoots {\n platformRoot: string;\n projectRoot?: string;\n}\n\n/**\n * Resolve the absolute scope root for a single mutating call.\n *\n * - `scope: 'platform'` — returns `roots.platformRoot`. `projectRoot` in\n * the context is ignored.\n * - `scope: 'project'` — prefers `ctx.projectRoot`, falls back to\n * `roots.projectRoot` from construction. Throws if neither is set,\n * if the path isn't absolute, doesn't exist, lacks a `.kb/kb.config.*`,\n * or equals `roots.platformRoot`.\n */\nexport function resolveScopeRoot(roots: ServiceRoots, ctx: ScopeContext): string {\n if (ctx.scope === 'platform') {\n return roots.platformRoot;\n }\n\n const candidate = ctx.projectRoot ?? roots.projectRoot;\n if (!candidate) {\n throw new ScopeResolutionError(\n 'SCOPE_PROJECT_ROOT_MISSING',\n 'scope=\"project\" requires a projectRoot (pass ctx.projectRoot or configure the service with projectRoot).',\n );\n }\n\n if (!path.isAbsolute(candidate)) {\n throw new ScopeResolutionError(\n 'SCOPE_PROJECT_ROOT_NOT_ABSOLUTE',\n `projectRoot must be absolute, got \"${candidate}\".`,\n );\n }\n\n try {\n accessSync(candidate, constants.F_OK);\n } catch {\n throw new ScopeResolutionError(\n 'SCOPE_PROJECT_ROOT_NOT_FOUND',\n `projectRoot does not exist: \"${candidate}\".`,\n );\n }\n\n const hasConfig = CONFIG_FILE_CANDIDATES.some((name) => {\n try {\n accessSync(path.join(candidate, '.kb', name), constants.F_OK);\n return true;\n } catch {\n return false;\n }\n });\n if (!hasConfig) {\n throw new ScopeResolutionError(\n 'SCOPE_PROJECT_ROOT_NO_KB_DIR',\n `projectRoot \"${candidate}\" does not contain .kb/kb.config.{json,jsonc} — refusing to treat it as a project.`,\n );\n }\n\n if (path.resolve(candidate) === path.resolve(roots.platformRoot)) {\n throw new ScopeResolutionError(\n 'SCOPE_PROJECT_EQUALS_PLATFORM',\n 'projectRoot must not equal platformRoot; use scope=\"platform\" for platform-level operations.',\n );\n }\n\n return path.resolve(candidate);\n}\n\n/**\n * Resolve the set of roots to read from for a query context (`list`,\n * `getEntry`). `'all'` returns both; the caller is responsible for merging\n * with a platform-wins precedence.\n */\nexport function resolveQueryRoots(\n roots: ServiceRoots,\n ctx: QueryScopeContext,\n): Array<{ scope: MarketplaceScope; root: string }> {\n if (ctx.scope === 'platform') {\n return [{ scope: 'platform', root: roots.platformRoot }];\n }\n if (ctx.scope === 'project') {\n return [\n {\n scope: 'project',\n root: resolveScopeRoot(roots, { scope: 'project', projectRoot: ctx.projectRoot }),\n },\n ];\n }\n // 'all' — platform is always included. Project is included only when a\n // project root is available (explicitly via ctx or implicitly from the\n // service). If no project context is known, 'all' degrades to platform-only.\n const out: Array<{ scope: MarketplaceScope; root: string }> = [\n { scope: 'platform', root: roots.platformRoot },\n ];\n const projectCandidate = ctx.projectRoot ?? roots.projectRoot;\n if (projectCandidate) {\n try {\n const projectRoot = resolveScopeRoot(roots, { scope: 'project', projectRoot: projectCandidate });\n out.push({ scope: 'project', root: projectRoot });\n } catch {\n // For 'all' we swallow resolution errors — a missing or invalid project\n // context should not block a platform-only listing.\n }\n }\n return out;\n}\n\n/**\n * Thrown when a scope context cannot be resolved to a concrete root.\n * Uses a stable `code` so API/CLI can surface actionable errors.\n */\nexport class ScopeResolutionError extends Error {\n readonly code: string;\n constructor(code: string, message: string) {\n super(message);\n this.code = code;\n this.name = 'ScopeResolutionError';\n }\n}\n","/**\n * @module @kb-labs/marketplace-core/marketplace-service\n * Unified marketplace service — install/uninstall/enable/disable for all entity types.\n *\n * Every mutating method is explicitly scope-bound (`platform` or `project`).\n * There is no implicit default: callers pass a `ScopeContext` per call so\n * the service can target the right `.kb/marketplace.lock`.\n *\n * Works through PackageSource abstraction — never calls pnpm directly.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { pathToFileURL } from 'node:url';\nimport { glob } from 'glob';\nimport type { EntityKind, MarketplaceEntry, MarketplaceLock } from '@kb-labs/core-discovery';\nimport {\n readMarketplaceLock,\n writeMarketplaceLock,\n createEmptyLock,\n createMarketplaceEntry,\n addToMarketplaceLock,\n removeFromMarketplaceLock,\n enablePlugin,\n disablePlugin,\n DiagnosticCollector,\n loadManifest,\n} from '@kb-labs/core-discovery';\nimport type {\n PackageSource,\n EntityKindStrategy,\n MarketplaceServiceAPI,\n MarketplaceEntryWithId,\n ScopedMarketplaceEntry,\n ScopeContext,\n QueryScopeContext,\n MarketplaceScope,\n MarketplaceDiagnostic,\n InstallResult,\n InstallResultEntry,\n SyncResult,\n DoctorReport,\n DoctorIssue,\n} from '@kb-labs/marketplace-contracts';\nimport { setCacheEntry, removeCacheEntry } from './manifest-cache.js';\nimport { PluginStrategy } from './strategies/plugin-strategy.js';\nimport { AdapterStrategy } from './strategies/adapter-strategy.js';\nimport { resolveScopeRoot, resolveQueryRoots, type ServiceRoots } from './scope.js';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface MarketplaceServiceOptions {\n /** Platform workspace root — always required. Used for `scope: 'platform'`. */\n platformRoot: string;\n /**\n * Default project root. Optional — a daemon serving multiple projects can\n * leave this unset and pass `ctx.projectRoot` per call. When both are\n * provided, per-call `ctx.projectRoot` wins.\n */\n projectRoot?: string;\n /** Package source (npm, registry, etc.) */\n source: PackageSource;\n /** Additional strategies beyond built-in plugin/adapter */\n strategies?: EntityKindStrategy[];\n}\n\n// ---------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------\n\nexport class MarketplaceService implements MarketplaceServiceAPI {\n private readonly roots: ServiceRoots;\n private readonly source: PackageSource;\n private readonly strategies = new Map<EntityKind, EntityKindStrategy>();\n\n constructor(opts: MarketplaceServiceOptions) {\n this.roots = { platformRoot: opts.platformRoot, projectRoot: opts.projectRoot };\n this.source = opts.source;\n\n // Built-in strategies\n this.registerStrategy(new PluginStrategy());\n this.registerStrategy(new AdapterStrategy());\n\n // User-supplied strategies\n if (opts.strategies) {\n for (const s of opts.strategies) {\n this.registerStrategy(s);\n }\n }\n }\n\n registerStrategy(strategy: EntityKindStrategy): void {\n this.strategies.set(strategy.kind, strategy);\n }\n\n // -------------------------------------------------------------------------\n // Install\n // -------------------------------------------------------------------------\n\n async install(\n ctx: ScopeContext,\n specs: string[],\n opts?: { dev?: boolean },\n ): Promise<InstallResult> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const installed: InstallResultEntry[] = [];\n const warnings: string[] = [];\n const diagnostics: MarketplaceDiagnostic[] = [];\n\n for (const spec of specs) {\n const resolved = await this.source.resolve(spec);\n const result = await this.source.install(resolved, scopeRoot, opts);\n\n // Detect primary kind via strategies\n const primaryKind = await this.detectKind(result.packageRoot);\n this.assertScopeAllowsKind(ctx.scope, primaryKind);\n\n const strategy = this.strategies.get(primaryKind);\n const provides = strategy\n ? await strategy.extractProvides(result.packageRoot)\n : [primaryKind];\n\n // Write to marketplace.lock\n const entry = createMarketplaceEntry({\n version: result.version,\n integrity: result.integrity,\n resolvedPath: relativeToRoot(scopeRoot, result.packageRoot),\n source: resolved.source,\n primaryKind,\n provides,\n });\n\n await addToMarketplaceLock(scopeRoot, result.id, entry);\n\n // Cache manifest\n await this.cacheManifest(scopeRoot, result.id, result.packageRoot, primaryKind, result.integrity);\n\n // Run post-install hook\n if (strategy?.afterInstall) {\n try {\n await strategy.afterInstall(result.id, result.packageRoot, this, ctx);\n } catch (err) {\n warnings.push(`afterInstall for ${result.id}: ${(err as Error).message}`);\n }\n }\n\n installed.push({\n id: result.id,\n version: result.version,\n primaryKind,\n provides,\n packageRoot: result.packageRoot,\n scope: ctx.scope,\n });\n }\n\n return { installed, warnings, scope: ctx.scope, diagnostics: diagnostics.length ? diagnostics : undefined };\n }\n\n // -------------------------------------------------------------------------\n // Uninstall\n // -------------------------------------------------------------------------\n\n async uninstall(ctx: ScopeContext, packageIds: string[]): Promise<void> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n for (const id of packageIds) {\n // Run pre-uninstall hook\n const entry = await this.getEntry(ctx, id);\n if (entry) {\n const strategy = this.strategies.get(entry.primaryKind);\n if (strategy?.beforeUninstall) {\n await strategy.beforeUninstall(id, this, ctx);\n }\n }\n\n await removeFromMarketplaceLock(scopeRoot, id);\n await removeCacheEntry(scopeRoot, id);\n await this.source.remove(id, scopeRoot);\n }\n }\n\n // -------------------------------------------------------------------------\n // Link / Unlink\n // -------------------------------------------------------------------------\n\n async link(ctx: ScopeContext, packagePath: string): Promise<InstallResultEntry> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const absPath = path.resolve(scopeRoot, packagePath);\n\n // Path traversal guard — linked path must be within the scope root.\n if (!isPathInside(scopeRoot, absPath)) {\n throw new Error(\n `Path \"${packagePath}\" is outside ${ctx.scope} root \"${scopeRoot}\" — refusing to link`,\n );\n }\n\n const pkgJson = JSON.parse(\n await fs.readFile(path.join(absPath, 'package.json'), 'utf-8'),\n );\n const id: string = pkgJson.name;\n const version: string = pkgJson.version ?? '0.0.0';\n\n const primaryKind = await this.detectKind(absPath);\n this.assertScopeAllowsKind(ctx.scope, primaryKind);\n\n const strategy = this.strategies.get(primaryKind);\n const provides = strategy\n ? await strategy.extractProvides(absPath)\n : [primaryKind];\n\n const integrity = await computeIntegrity(absPath);\n\n const entry = createMarketplaceEntry({\n version,\n integrity,\n resolvedPath: relativeToRoot(scopeRoot, absPath),\n source: 'local',\n primaryKind,\n provides,\n });\n\n await addToMarketplaceLock(scopeRoot, id, entry);\n await this.cacheManifest(scopeRoot, id, absPath, primaryKind, integrity);\n\n if (strategy?.afterInstall) {\n await strategy.afterInstall(id, absPath, this, ctx);\n }\n\n return { id, version, primaryKind, provides, packageRoot: absPath, scope: ctx.scope };\n }\n\n async unlink(ctx: ScopeContext, packageId: string): Promise<void> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n await removeFromMarketplaceLock(scopeRoot, packageId);\n await removeCacheEntry(scopeRoot, packageId);\n }\n\n // -------------------------------------------------------------------------\n // Update\n // -------------------------------------------------------------------------\n\n async update(ctx: ScopeContext, packageIds?: string[]): Promise<InstallResult> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(scopeRoot, diag);\n if (!lock) {\n return { installed: [], warnings: ['No marketplace.lock found'], scope: ctx.scope };\n }\n\n const ids = packageIds ?? Object.keys(lock.installed);\n const specs = ids.filter(id => id in lock.installed);\n\n return this.install(ctx, specs);\n }\n\n // -------------------------------------------------------------------------\n // Enable / Disable\n // -------------------------------------------------------------------------\n\n async enable(ctx: ScopeContext, packageId: string): Promise<void> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const ok = await enablePlugin(scopeRoot, packageId);\n if (!ok) {\n throw new Error(`Package \"${packageId}\" not found in ${ctx.scope} marketplace.lock`);\n }\n }\n\n async disable(ctx: ScopeContext, packageId: string): Promise<void> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const ok = await disablePlugin(scopeRoot, packageId);\n if (!ok) {\n throw new Error(`Package \"${packageId}\" not found in ${ctx.scope} marketplace.lock`);\n }\n }\n\n // -------------------------------------------------------------------------\n // List / GetEntry (MarketplaceServiceAPI)\n // -------------------------------------------------------------------------\n\n async list(\n ctx: QueryScopeContext,\n filter?: { kind?: EntityKind },\n ): Promise<ScopedMarketplaceEntry[]> {\n const targets = resolveQueryRoots(this.roots, ctx);\n\n // Collect per-scope entries. For 'all' we later apply platform-wins.\n const perScope: Array<{ scope: MarketplaceScope; entries: MarketplaceEntryWithId[] }> = [];\n for (const { scope, root } of targets) {\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(root, diag);\n if (!lock) {\n perScope.push({ scope, entries: [] });\n continue;\n }\n const entries = Object.entries(lock.installed).map(([id, entry]) => ({ ...entry, id }));\n perScope.push({ scope, entries });\n }\n\n const merged = mergeScopedEntries(perScope);\n const filtered = filter?.kind\n ? merged.entries.filter(e => e.primaryKind === filter.kind)\n : merged.entries;\n return filtered;\n }\n\n async getEntry(ctx: ScopeContext, packageId: string): Promise<MarketplaceEntry | null> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(scopeRoot, diag);\n return lock?.installed[packageId] ?? null;\n }\n\n // -------------------------------------------------------------------------\n // Sync (scan workspace → populate lock from config-driven globs)\n // -------------------------------------------------------------------------\n\n /**\n * Scan workspace for plugins and adapters using glob patterns.\n * Existing entries are preserved (not overwritten).\n * Patterns come from kb.config.json marketplace.sync.include.\n *\n * Sync is scope-bound: globs resolve against the scope root and results go\n * into that scope's lock. Adapter discovery in `project` scope is refused\n * with a clear error to preserve the adapters-are-platform-only invariant.\n */\n async sync(\n ctx: ScopeContext,\n opts: {\n include: string[];\n exclude?: string[];\n autoEnable?: boolean;\n },\n ): Promise<SyncResult> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const autoEnable = opts.autoEnable ?? false;\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(scopeRoot, diag) ?? createEmptyLock();\n const existingIds = new Set(Object.keys(lock.installed));\n\n const added: SyncResult['added'] = [];\n const skipped: SyncResult['skipped'] = [];\n\n const includePatterns = opts.include.map(p => path.join(p, 'package.json'));\n const excludePatterns = opts.exclude ?? [];\n\n const packageJsonPaths = await glob(includePatterns, {\n cwd: scopeRoot,\n ignore: excludePatterns,\n absolute: false,\n });\n\n for (const relPkgJson of packageJsonPaths) {\n const pkgDir = path.resolve(scopeRoot, path.dirname(relPkgJson));\n await this._syncPackage(ctx.scope, scopeRoot, pkgDir, relPkgJson, existingIds, autoEnable, lock, added, skipped);\n }\n\n await writeMarketplaceLock(scopeRoot, lock);\n\n return { added, skipped, total: Object.keys(lock.installed).length };\n }\n\n private async _syncPackage(\n scope: MarketplaceScope,\n scopeRoot: string,\n pkgDir: string,\n _relPkgJson: string,\n existingIds: Set<string>,\n autoEnable: boolean,\n lock: MarketplaceLock,\n added: SyncResult['added'],\n skipped: SyncResult['skipped'],\n ): Promise<void> {\n let pkgName: string;\n let pkgVersion: string;\n try {\n const pkgJson = JSON.parse(await fs.readFile(path.join(pkgDir, 'package.json'), 'utf-8'));\n pkgName = pkgJson.name;\n pkgVersion = pkgJson.version ?? '0.0.0';\n if (!pkgName) { return; }\n } catch {\n return;\n }\n\n if (existingIds.has(pkgName)) {\n skipped.push({ id: pkgName, reason: 'already in lock' });\n return;\n }\n\n let detected = false;\n for (const strategy of this.strategies.values()) {\n const kind = await strategy.detectKind(pkgDir);\n if (kind) { detected = true; break; }\n }\n if (!detected) { return; }\n\n const primaryKind = await this.detectKind(pkgDir);\n\n // Adapters can only live in platform scope.\n if (scope === 'project' && primaryKind === 'adapter') {\n skipped.push({ id: pkgName, reason: 'adapter not allowed in project scope' });\n return;\n }\n\n const strategy = this.strategies.get(primaryKind);\n const provides = strategy ? await strategy.extractProvides(pkgDir) : [primaryKind];\n const integrity = await computeIntegrity(pkgDir);\n\n // Use manifest ID as lock key if the strategy can resolve it.\n // This keeps discovery working even when package.json name differs from manifest.id\n // (e.g. after folder renames like cli/ → entry/).\n const resolvedId = (strategy?.resolveId ? await strategy.resolveId(pkgDir) : null) ?? pkgName;\n\n if (existingIds.has(resolvedId) && resolvedId !== pkgName) {\n skipped.push({ id: resolvedId, reason: 'already in lock' });\n return;\n }\n\n const entry = createMarketplaceEntry({\n version: pkgVersion,\n integrity,\n resolvedPath: relativeToRoot(scopeRoot, pkgDir),\n source: 'local',\n primaryKind,\n provides,\n });\n\n if (!autoEnable) { entry.enabled = false; }\n\n lock.installed[resolvedId] = entry;\n added.push({ id: resolvedId, primaryKind, version: pkgVersion });\n }\n\n // -------------------------------------------------------------------------\n // Doctor\n // -------------------------------------------------------------------------\n\n async doctor(ctx: ScopeContext): Promise<DoctorReport> {\n const scopeRoot = resolveScopeRoot(this.roots, ctx);\n const diag = new DiagnosticCollector();\n const lock = await readMarketplaceLock(scopeRoot, diag);\n const issues: DoctorIssue[] = [];\n\n if (!lock) {\n return { ok: true, total: 0, issues: [{ severity: 'info', packageId: '', message: 'No marketplace.lock found' }] };\n }\n\n const entries = Object.entries(lock.installed);\n\n for (const [id, entry] of entries) {\n const pkgRoot = path.resolve(scopeRoot, entry.resolvedPath);\n\n try {\n await fs.access(pkgRoot);\n } catch {\n issues.push({\n severity: 'error',\n packageId: id,\n message: `Package directory not found: ${pkgRoot}`,\n remediation: `Run \"kb marketplace install ${id}\" to restore`,\n });\n continue;\n }\n\n if (entry.integrity) {\n const computed = await computeIntegrity(pkgRoot);\n if (computed && computed !== entry.integrity) {\n issues.push({\n severity: 'warning',\n packageId: id,\n message: `Integrity mismatch: expected ${entry.integrity}, got ${computed}`,\n remediation: `Re-install: kb marketplace install ${id}`,\n });\n }\n }\n\n if (!entry.signature) {\n issues.push({\n severity: 'info',\n packageId: id,\n message: 'Package is not signed',\n remediation: 'Publish through the official marketplace to get a platform signature',\n });\n }\n }\n\n return {\n ok: issues.filter(i => i.severity === 'error').length === 0,\n total: entries.length,\n issues,\n };\n }\n\n // -------------------------------------------------------------------------\n // Private\n // -------------------------------------------------------------------------\n\n private async detectKind(packageRoot: string): Promise<EntityKind> {\n for (const strategy of this.strategies.values()) {\n const kind = await strategy.detectKind(packageRoot);\n if (kind) { return kind; }\n }\n return 'plugin';\n }\n\n /**\n * Hard guard: adapters may only be installed/linked in platform scope.\n * Lives in one place so adapter-scope policy is not duplicated across\n * `link`, `install`, and `sync`.\n */\n private assertScopeAllowsKind(scope: MarketplaceScope, kind: EntityKind): void {\n if (scope === 'project' && kind === 'adapter') {\n throw new AdapterScopeError(\n 'Adapters can only be installed in platform scope. ' +\n 'Use --scope platform or install globally via the platform marketplace.',\n );\n }\n }\n\n private async cacheManifest(\n scopeRoot: string,\n packageId: string,\n packageRoot: string,\n primaryKind: EntityKind,\n integrity: string,\n ): Promise<void> {\n try {\n if (primaryKind === 'plugin') {\n const diag = new DiagnosticCollector();\n const manifest = await loadManifest(packageRoot, diag);\n if (manifest) {\n await setCacheEntry(scopeRoot, packageId, {\n manifestType: 'plugin',\n manifest,\n cachedAt: new Date().toISOString(),\n integrity,\n });\n }\n } else if (primaryKind === 'adapter') {\n const distPath = path.join(packageRoot, 'dist', 'index.js');\n const mod = await import(pathToFileURL(distPath).href);\n if (mod.manifest) {\n await setCacheEntry(scopeRoot, packageId, {\n manifestType: 'adapter',\n manifest: mod.manifest,\n cachedAt: new Date().toISOString(),\n integrity,\n });\n }\n }\n } catch (err) {\n console.warn(`[marketplace] Failed to cache manifest for \"${packageId}\": ${(err as Error).message}`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class AdapterScopeError extends Error {\n readonly code = 'MARKETPLACE_ADAPTER_PROJECT_SCOPE';\n constructor(message: string) {\n super(message);\n this.name = 'AdapterScopeError';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction relativeToRoot(root: string, absPath: string): string {\n const rel = path.relative(root, absPath);\n return rel.startsWith('.') ? rel : `./${rel}`;\n}\n\nfunction isPathInside(parent: string, child: string): boolean {\n const rel = path.relative(path.resolve(parent), path.resolve(child));\n return !rel.startsWith('..') && !path.isAbsolute(rel);\n}\n\nasync function computeIntegrity(packageRoot: string): Promise<string> {\n try {\n const content = await fs.readFile(path.join(packageRoot, 'package.json'));\n return `sha256-${crypto.createHash('sha256').update(content).digest('base64')}`;\n } catch {\n return '';\n }\n}\n\n/**\n * Merge per-scope entries with platform-wins precedence.\n *\n * For a given package id present in both platform and project, the platform\n * entry is kept and a diagnostic is emitted so the caller can surface the\n * conflict.\n */\nexport function mergeScopedEntries(\n perScope: Array<{ scope: MarketplaceScope; entries: MarketplaceEntryWithId[] }>,\n): { entries: ScopedMarketplaceEntry[]; diagnostics: MarketplaceDiagnostic[] } {\n const out = new Map<string, ScopedMarketplaceEntry>();\n const diagnostics: MarketplaceDiagnostic[] = [];\n\n // Process platform first so platform entries land first and project\n // duplicates are rejected with a diagnostic.\n const ordered = [...perScope].sort((a, b) => {\n if (a.scope === b.scope) { return 0; }\n return a.scope === 'platform' ? -1 : 1;\n });\n\n for (const { scope, entries } of ordered) {\n for (const e of entries) {\n const existing = out.get(e.id);\n if (existing) {\n // platform-wins: ignore subsequent duplicates, emit a diagnostic.\n diagnostics.push({\n code: 'MARKETPLACE_SCOPE_COLLISION',\n message: `Package \"${e.id}\" exists in both platform and ${scope} scopes — platform wins.`,\n packageId: e.id,\n scope,\n });\n continue;\n }\n out.set(e.id, { ...e, scope });\n }\n }\n\n return { entries: Array.from(out.values()), diagnostics };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"glob": "^11.0.0",
|
|
4
|
-
"@kb-labs/
|
|
5
|
-
"@kb-labs/
|
|
6
|
-
"@kb-labs/core-platform": "2.
|
|
7
|
-
"@kb-labs/
|
|
4
|
+
"@kb-labs/core-discovery": "2.32.0",
|
|
5
|
+
"@kb-labs/marketplace-contracts": "2.32.0",
|
|
6
|
+
"@kb-labs/core-platform": "2.32.0",
|
|
7
|
+
"@kb-labs/plugin-contracts": "2.32.0"
|
|
8
8
|
},
|
|
9
9
|
"description": "Marketplace service — unified install/uninstall/enable/disable for all entity types",
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"tsup": "^8.5.0",
|
|
12
12
|
"typescript": "^5",
|
|
13
13
|
"vitest": "^3.2.4",
|
|
14
|
-
"@kb-labs/devkit": "2.
|
|
14
|
+
"@kb-labs/devkit": "2.32.0"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=20.0.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"sideEffects": false,
|
|
34
34
|
"type": "module",
|
|
35
35
|
"types": "./dist/index.d.ts",
|
|
36
|
-
"version": "2.
|
|
36
|
+
"version": "2.32.0",
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsup",
|
|
39
39
|
"clean": "rimraf dist",
|