@aiwg/cli 2026.8.1 → 2026.8.3
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/src/cli/handlers/install.js +42 -4
- package/dist/src/cli/handlers/marketplace.js +375 -122
- package/dist/src/cli/handlers/subcommands.js +1 -0
- package/dist/src/cli/handlers/use.js +3 -1
- package/dist/src/config/aiwg-config.js +5 -0
- package/dist/src/extensions/project-local-doctor.js +10 -26
- package/dist/src/extensions/project-local-remove.js +42 -5
- package/dist/src/marketplace/exchange.js +602 -0
- package/dist/src/marketplace/provenance-types.js +19 -0
- package/dist/src/marketplace/provenance.js +834 -0
- package/dist/src/packages/adapters/git.js +79 -29
- package/dist/src/packages/package-discovery.js +81 -0
- package/dist/src/packages/package-registry.js +2 -0
- package/dist/src/packages/registry.js +119 -20
- package/package.json +2 -2
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { execFile } from 'child_process';
|
|
13
13
|
import { promisify } from 'util';
|
|
14
|
-
import { mkdir, readFile } from 'fs/promises';
|
|
14
|
+
import { mkdir, mkdtemp, readFile, rename, rm } from 'fs/promises';
|
|
15
15
|
import { join } from 'path';
|
|
16
16
|
import { homedir } from 'os';
|
|
17
17
|
import { existsSync } from 'fs';
|
|
@@ -82,6 +82,41 @@ async function resolveLatestTag(gitUrl) {
|
|
|
82
82
|
}
|
|
83
83
|
return 'latest';
|
|
84
84
|
}
|
|
85
|
+
async function resolveRemoteCommit(gitUrl, requestedRef) {
|
|
86
|
+
if (/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(requestedRef))
|
|
87
|
+
return requestedRef;
|
|
88
|
+
const patterns = requestedRef === 'HEAD'
|
|
89
|
+
? ['HEAD']
|
|
90
|
+
: [`refs/tags/${requestedRef}^{}`, `refs/tags/${requestedRef}`, `refs/heads/${requestedRef}`, requestedRef];
|
|
91
|
+
try {
|
|
92
|
+
const output = await git(['ls-remote', gitUrl, ...patterns]);
|
|
93
|
+
const rows = output.split('\n').filter(Boolean).map((line) => {
|
|
94
|
+
const [oid = '', ref = ''] = line.split(/\s+/, 2);
|
|
95
|
+
return { oid, ref };
|
|
96
|
+
});
|
|
97
|
+
const peeled = rows.find((row) => row.ref.endsWith('^{}'));
|
|
98
|
+
const selected = peeled ?? rows[0];
|
|
99
|
+
return selected && /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(selected.oid)
|
|
100
|
+
? selected.oid
|
|
101
|
+
: undefined;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function urlCacheIdentity(gitUrl) {
|
|
108
|
+
const urlKey = gitUrl
|
|
109
|
+
.replace(/^https?:\/\//, '')
|
|
110
|
+
.replace(/^ssh:\/\//, '')
|
|
111
|
+
.replace(/^git@/, '')
|
|
112
|
+
.replace(/\.git$/, '')
|
|
113
|
+
.replace(/[:/]/g, '_');
|
|
114
|
+
const parts = urlKey.split('_').filter(Boolean);
|
|
115
|
+
return {
|
|
116
|
+
name: parts[parts.length - 1] ?? 'package',
|
|
117
|
+
owner: parts[parts.length - 2] ?? 'unknown',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
85
120
|
/**
|
|
86
121
|
* GitAdapter
|
|
87
122
|
*
|
|
@@ -111,38 +146,53 @@ export class GitAdapter {
|
|
|
111
146
|
};
|
|
112
147
|
}
|
|
113
148
|
async fetch(source, options = {}) {
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.replace(/^https?:\/\//, '')
|
|
122
|
-
.replace(/^git@/, '')
|
|
123
|
-
.replace(/\.git$/, '')
|
|
124
|
-
.replace(/[:/]/g, '_');
|
|
125
|
-
const parts = urlKey.split('_');
|
|
126
|
-
const name = parts[parts.length - 1] ?? 'package';
|
|
127
|
-
const owner = parts[parts.length - 2] ?? 'unknown';
|
|
128
|
-
const cachePath = buildCachePath(owner, name, version);
|
|
129
|
-
if (!options.refresh && existsSync(cachePath)) {
|
|
130
|
-
return cachePath;
|
|
149
|
+
// Resolve discovery inputs before any deployment and cache by immutable
|
|
150
|
+
// commit rather than by a movable tag/branch name (#2009).
|
|
151
|
+
let requestedRef = source.ref;
|
|
152
|
+
if (!requestedRef) {
|
|
153
|
+
const latest = await resolveLatestTag(source.gitUrl);
|
|
154
|
+
requestedRef = latest === 'latest' ? 'HEAD' : latest;
|
|
155
|
+
source.ref = requestedRef;
|
|
131
156
|
}
|
|
132
|
-
await
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
157
|
+
const advertisedCommit = await resolveRemoteCommit(source.gitUrl, requestedRef);
|
|
158
|
+
const { owner, name } = urlCacheIdentity(source.gitUrl);
|
|
159
|
+
if (advertisedCommit) {
|
|
160
|
+
const existing = buildCachePath(owner, name, advertisedCommit);
|
|
161
|
+
if (!options.refresh && existsSync(join(existing, '.git'))) {
|
|
162
|
+
const existingCommit = await git(['rev-parse', 'HEAD^{commit}'], existing);
|
|
163
|
+
if (existingCommit !== advertisedCommit)
|
|
164
|
+
throw new Error(`Immutable package cache mismatch at ${existing}`);
|
|
165
|
+
return existing;
|
|
166
|
+
}
|
|
136
167
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
168
|
+
const ownerDir = join(getCacheRoot(), owner);
|
|
169
|
+
await mkdir(ownerDir, { recursive: true });
|
|
170
|
+
const stage = await mkdtemp(join(ownerDir, `.${name}.resolve-`));
|
|
171
|
+
try {
|
|
172
|
+
await git(['clone', '--no-checkout', source.gitUrl, stage]);
|
|
173
|
+
await git(['checkout', '--detach', requestedRef], stage);
|
|
174
|
+
const resolvedCommit = await git(['rev-parse', 'HEAD^{commit}'], stage);
|
|
175
|
+
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(resolvedCommit)) {
|
|
176
|
+
throw new Error(`Git resolved '${requestedRef}' to invalid commit '${resolvedCommit}'`);
|
|
177
|
+
}
|
|
178
|
+
if (advertisedCommit && resolvedCommit !== advertisedCommit) {
|
|
179
|
+
throw new Error(`Git ref '${requestedRef}' moved during resolution (${advertisedCommit} -> ${resolvedCommit})`);
|
|
180
|
+
}
|
|
181
|
+
const cachePath = buildCachePath(owner, name, resolvedCommit);
|
|
182
|
+
if (existsSync(join(cachePath, '.git'))) {
|
|
183
|
+
const cachedCommit = await git(['rev-parse', 'HEAD^{commit}'], cachePath);
|
|
184
|
+
if (cachedCommit !== resolvedCommit)
|
|
185
|
+
throw new Error(`Immutable package cache mismatch at ${cachePath}`);
|
|
186
|
+
await rm(stage, { recursive: true, force: true });
|
|
187
|
+
return cachePath;
|
|
188
|
+
}
|
|
189
|
+
await rename(stage, cachePath);
|
|
190
|
+
return cachePath;
|
|
140
191
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
192
|
+
catch (error) {
|
|
193
|
+
await rm(stage, { recursive: true, force: true });
|
|
194
|
+
throw error;
|
|
144
195
|
}
|
|
145
|
-
return cachePath;
|
|
146
196
|
}
|
|
147
197
|
/** GitAdapter does not list packages */
|
|
148
198
|
async list() {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a fetched Git checkout to one deployable package without executing it.
|
|
3
|
+
* Supports root bundles and the documented standalone .aiwg/plugins layout.
|
|
4
|
+
*
|
|
5
|
+
* @implements #1997
|
|
6
|
+
* @implements #2009
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { discoverProjectLocalBundles, loadAndValidateManifest } from '../extensions/project-local-discovery.js';
|
|
11
|
+
const TYPES = new Set(['framework', 'addon', 'extension', 'plugin', 'provider']);
|
|
12
|
+
function formatErrors(errors) {
|
|
13
|
+
return errors.map((error) => `${error.field}: expected ${error.expected}, got ${error.actual}${error.hint ? `; ${error.hint}` : ''}`).join('\n - ');
|
|
14
|
+
}
|
|
15
|
+
async function rootManifest(checkoutPath) {
|
|
16
|
+
try {
|
|
17
|
+
const value = JSON.parse(await readFile(path.join(checkoutPath, 'manifest.json'), 'utf8'));
|
|
18
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function discoverInstallablePackage(checkoutPath, selector) {
|
|
25
|
+
const checkout = path.resolve(checkoutPath);
|
|
26
|
+
const root = await rootManifest(checkout);
|
|
27
|
+
if (root) {
|
|
28
|
+
const declaredType = String(root.type ?? '');
|
|
29
|
+
if (root.manifestVersion === '1' && TYPES.has(declaredType)) {
|
|
30
|
+
const validation = await loadAndValidateManifest(path.join(checkout, 'manifest.json'), declaredType, checkout);
|
|
31
|
+
if (!validation.bundle) {
|
|
32
|
+
throw new Error(`Root package manifest validation failed:\n - ${formatErrors(validation.errors)}`);
|
|
33
|
+
}
|
|
34
|
+
if (selector && selector !== validation.bundle.id) {
|
|
35
|
+
throw new Error(`Package selector '${selector}' does not match root package '${validation.bundle.id}'`);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
manifest: validation.bundle.manifest,
|
|
39
|
+
type: validation.bundle.type === 'provider' ? 'unknown' : validation.bundle.type,
|
|
40
|
+
wrapperPath: checkout,
|
|
41
|
+
artifactPath: validation.bundle.artifactPath,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Legacy root manifests remain installable for compatibility, but unknown
|
|
45
|
+
// roots no longer report a successful zero-artifact deployment.
|
|
46
|
+
if (['framework', 'addon', 'extension'].includes(String(root.type))) {
|
|
47
|
+
const name = String(root.id ?? root.name ?? '');
|
|
48
|
+
if (selector && selector !== name)
|
|
49
|
+
throw new Error(`Package selector '${selector}' does not match root package '${name}'`);
|
|
50
|
+
return {
|
|
51
|
+
manifest: root,
|
|
52
|
+
type: root.type,
|
|
53
|
+
wrapperPath: checkout,
|
|
54
|
+
artifactPath: checkout,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const discovery = await discoverProjectLocalBundles(checkout);
|
|
59
|
+
if (discovery.errors.length) {
|
|
60
|
+
throw new Error(`Standalone package discovery failed:\n - ${formatErrors(discovery.errors)}`);
|
|
61
|
+
}
|
|
62
|
+
let candidates = discovery.bundles.filter((bundle) => bundle.type === 'plugin');
|
|
63
|
+
if (selector)
|
|
64
|
+
candidates = candidates.filter((bundle) => bundle.id === selector);
|
|
65
|
+
if (candidates.length === 0) {
|
|
66
|
+
throw new Error(selector
|
|
67
|
+
? `No valid standalone plugin '${selector}' exists in this Git repository`
|
|
68
|
+
: 'Git repository contains no valid root package or standalone .aiwg/plugins wrapper');
|
|
69
|
+
}
|
|
70
|
+
if (candidates.length > 1) {
|
|
71
|
+
throw new Error(`Git repository contains multiple standalone plugins (${candidates.map((bundle) => bundle.id).sort().join(', ')}); select one with --package <id>`);
|
|
72
|
+
}
|
|
73
|
+
const selected = candidates[0];
|
|
74
|
+
return {
|
|
75
|
+
manifest: selected.manifest,
|
|
76
|
+
type: 'plugin',
|
|
77
|
+
wrapperPath: selected.bundlePath,
|
|
78
|
+
artifactPath: selected.artifactPath,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=package-discovery.js.map
|
|
@@ -137,6 +137,8 @@ export async function listPackages(configDir) {
|
|
|
137
137
|
source: entry.source,
|
|
138
138
|
installedAt: entry.installedAt,
|
|
139
139
|
deployCount: entry.deployedTo?.length ?? 0,
|
|
140
|
+
...(entry.provenance?.lockId ? { lockId: entry.provenance.lockId } : {}),
|
|
141
|
+
...(entry.provenance?.verificationStatus ? { verificationStatus: entry.provenance.verificationStatus } : {}),
|
|
140
142
|
};
|
|
141
143
|
});
|
|
142
144
|
}
|
|
@@ -7,13 +7,17 @@
|
|
|
7
7
|
* @implements #557
|
|
8
8
|
*/
|
|
9
9
|
import { readFile } from 'fs/promises';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { join, relative, sep } from 'path';
|
|
12
|
+
import { GitAdapter } from './adapters/git.js';
|
|
12
13
|
import { GiteaAdapter } from './adapters/gitea.js';
|
|
13
14
|
import { GitHubAdapter } from './adapters/github.js';
|
|
14
15
|
import { ClawHubPackageAdapter } from './adapters/clawhub.js';
|
|
15
16
|
import { LocalCacheAdapter } from './adapters/local-cache.js';
|
|
16
|
-
import { setPackageEntry, listPackages as listFromRegistry, removePackageEntry, } from './package-registry.js';
|
|
17
|
+
import { getPackageEntry, setPackageEntry, listPackages as listFromRegistry, removePackageEntry, } from './package-registry.js';
|
|
18
|
+
import { discoverInstallablePackage } from './package-discovery.js';
|
|
19
|
+
import { buildFortemiEnvelopeShard, canonicalJson, createOperationReceipt, createProvenanceEnvelope, sha256, validateProvenanceEnvelope, verifyProvenanceEnvelope, } from '../marketplace/provenance.js';
|
|
20
|
+
import { findIndexedPackage, readMarketplaceIndex, readTrustStore, recordInstalledPackage, } from '../marketplace/exchange.js';
|
|
17
21
|
/**
|
|
18
22
|
* All adapters in resolution priority order
|
|
19
23
|
* (Scheme-prefixed adapters first so explicit prefixes are matched before
|
|
@@ -26,6 +30,9 @@ const ALL_ADAPTERS = [
|
|
|
26
30
|
new GitAdapter(),
|
|
27
31
|
];
|
|
28
32
|
const CACHE_ADAPTER = new LocalCacheAdapter();
|
|
33
|
+
function pathSeparatorSafe(parent, child) {
|
|
34
|
+
return relative(parent, child).replaceAll(sep, '/') || '.';
|
|
35
|
+
}
|
|
29
36
|
/**
|
|
30
37
|
* Parse a raw reference string into a PackageRef
|
|
31
38
|
*
|
|
@@ -176,26 +183,118 @@ export async function installPackage(rawRef, options = {}) {
|
|
|
176
183
|
` git@host:owner/name.git (SSH URL)`);
|
|
177
184
|
}
|
|
178
185
|
const { source, adapter } = resolved;
|
|
186
|
+
if (options.ref)
|
|
187
|
+
source.ref = options.ref;
|
|
179
188
|
const cachePath = await adapter.fetch(source, { refresh: options.refresh });
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
const discovered = await discoverInstallablePackage(cachePath, options.packageSelector);
|
|
190
|
+
const standardEnvelopePaths = [
|
|
191
|
+
join(cachePath, '.aiwg', 'marketplace', 'envelope.json'),
|
|
192
|
+
join(cachePath, 'aiwg-marketplace-envelope.json'),
|
|
193
|
+
];
|
|
194
|
+
let envelope = options.expectedEnvelope;
|
|
195
|
+
if (!envelope) {
|
|
196
|
+
for (const filename of standardEnvelopePaths) {
|
|
197
|
+
if (!existsSync(filename))
|
|
198
|
+
continue;
|
|
199
|
+
const value = JSON.parse(await readFile(filename, 'utf8'));
|
|
200
|
+
validateProvenanceEnvelope(value);
|
|
201
|
+
envelope = value;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (!envelope) {
|
|
206
|
+
envelope = await createProvenanceEnvelope({
|
|
207
|
+
checkoutPath: cachePath,
|
|
208
|
+
artifactPath: discovered.artifactPath,
|
|
209
|
+
wrapperPath: pathSeparatorSafe(cachePath, discovered.wrapperPath),
|
|
210
|
+
manifest: discovered.manifest,
|
|
211
|
+
requestedRef: source.ref ?? ref.version ?? 'HEAD',
|
|
212
|
+
remote: source.gitUrl,
|
|
213
|
+
publisher: String(discovered.manifest.author ?? discovered.manifest.namespace ?? ref.owner ?? 'unverified'),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const key = `${envelope.package.namespace}/${envelope.package.name}`;
|
|
217
|
+
const namespace = envelope.package.namespace;
|
|
218
|
+
const type = discovered.type;
|
|
219
|
+
const existingEntry = await getPackageEntry(key, options.configDir);
|
|
220
|
+
let previousLock;
|
|
221
|
+
if (existingEntry?.provenance?.lockId) {
|
|
222
|
+
previousLock = (await findIndexedPackage(existingEntry.provenance.lockId, { configDir: options.configDir }))?.lock;
|
|
223
|
+
}
|
|
224
|
+
const localIndex = await readMarketplaceIndex({ configDir: options.configDir });
|
|
225
|
+
const installedLocks = Object.fromEntries(Object.values(localIndex.packages).map((entry) => [entry.lock.identity, entry.lock.lockId]));
|
|
226
|
+
const trustStore = options.trustStore ?? await readTrustStore({ configDir: options.configDir });
|
|
227
|
+
const verification = await verifyProvenanceEnvelope({
|
|
228
|
+
envelope,
|
|
229
|
+
contentRoot: discovered.artifactPath,
|
|
230
|
+
checkoutPath: cachePath,
|
|
231
|
+
trustStore,
|
|
232
|
+
policy: options.verify
|
|
233
|
+
? { requireSignature: true, allowIntegrityOnly: false, ...options.verificationPolicy }
|
|
234
|
+
: options.verificationPolicy,
|
|
235
|
+
installedLocks,
|
|
236
|
+
previousLock,
|
|
237
|
+
});
|
|
238
|
+
if (!verification.ok)
|
|
239
|
+
throw new Error(`Package verification failed: ${verification.errors.join('; ')}`);
|
|
240
|
+
if (options.expectedLockId && verification.lock.lockId !== options.expectedLockId) {
|
|
241
|
+
throw new Error(`Catalog/direct lock mismatch: expected ${options.expectedLockId}, got ${verification.lock.lockId}`);
|
|
242
|
+
}
|
|
243
|
+
if (options.expectedEnvelope && sha256(canonicalJson(options.expectedEnvelope)) !== verification.envelopeSha256) {
|
|
244
|
+
throw new Error('Catalog envelope changed before installation');
|
|
245
|
+
}
|
|
246
|
+
const fortemi = await buildFortemiEnvelopeShard(envelope);
|
|
247
|
+
const receipt = createOperationReceipt({
|
|
248
|
+
operation: 'install',
|
|
249
|
+
lock: verification.lock,
|
|
250
|
+
actor: options.actor ?? 'aiwg',
|
|
251
|
+
verificationStatus: verification.status,
|
|
252
|
+
evidence: {
|
|
253
|
+
source: source.gitUrl,
|
|
254
|
+
requestedRef: envelope.source.requestedRef,
|
|
255
|
+
resolvedCommit: envelope.source.resolvedCommit,
|
|
256
|
+
catalog: options.catalogId ?? null,
|
|
257
|
+
directGit: !options.catalogId,
|
|
258
|
+
},
|
|
259
|
+
conformance: fortemi.conformance,
|
|
260
|
+
});
|
|
261
|
+
await recordInstalledPackage({
|
|
262
|
+
configDir: options.configDir,
|
|
263
|
+
envelope,
|
|
264
|
+
lock: verification.lock,
|
|
265
|
+
receipt,
|
|
194
266
|
cachePath,
|
|
195
|
-
|
|
196
|
-
|
|
267
|
+
artifactPath: discovered.artifactPath,
|
|
268
|
+
verificationStatus: verification.status,
|
|
269
|
+
fortemiShard: fortemi.archive,
|
|
270
|
+
catalogId: options.catalogId,
|
|
271
|
+
});
|
|
272
|
+
await setPackageEntry(key, {
|
|
273
|
+
version: envelope.package.version,
|
|
274
|
+
source: envelope.source.canonicalRemote,
|
|
275
|
+
type: type === 'plugin' ? 'extension' : type,
|
|
276
|
+
cachePath: discovered.artifactPath,
|
|
277
|
+
installedAt: receipt.occurredAt,
|
|
278
|
+
deployedTo: existingEntry?.deployedTo ?? [],
|
|
279
|
+
provenance: {
|
|
280
|
+
lockId: verification.lock.lockId,
|
|
281
|
+
resolvedCommit: verification.lock.resolvedCommit,
|
|
282
|
+
treeSha256: verification.lock.treeSha256,
|
|
283
|
+
artifactSha256: verification.lock.artifactSha256,
|
|
284
|
+
envelopeSha256: verification.lock.envelopeSha256,
|
|
285
|
+
verificationStatus: verification.status,
|
|
286
|
+
},
|
|
197
287
|
}, options.configDir);
|
|
198
|
-
return {
|
|
288
|
+
return {
|
|
289
|
+
cachePath: discovered.artifactPath,
|
|
290
|
+
checkoutPath: cachePath,
|
|
291
|
+
key,
|
|
292
|
+
type,
|
|
293
|
+
namespace,
|
|
294
|
+
envelope,
|
|
295
|
+
lock: verification.lock,
|
|
296
|
+
verification,
|
|
297
|
+
};
|
|
199
298
|
}
|
|
200
299
|
/**
|
|
201
300
|
* Refresh all registered remote packages (used by `aiwg sync`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiwg/cli",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.3",
|
|
4
4
|
"description": "Lightweight AIWG CLI for signed, versioned web-backed resources.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@fortemi/core": "2026.7.15",
|
|
67
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
68
68
|
"chalk": "^4.1.2",
|
|
69
69
|
"chokidar": "^4.0.3",
|
|
70
70
|
"commander": "^12.1.0",
|