yam-flow 2.3.0 → 2.3.1
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/AGENTS.md +18 -0
- package/CHANGELOG.md +22 -0
- package/README.md +6 -12
- package/ROADMAP.md +2 -0
- package/dist/bin/yam.js +56 -49
- package/dist/lib/skill-installation.d.ts +76 -0
- package/dist/lib/skill-installation.js +554 -0
- package/package.json +3 -2
- package/src/bin/yam.ts +55 -50
- package/src/lib/skill-installation.ts +638 -0
- package/yam.manifest.json +2 -1
package/src/bin/yam.ts
CHANGED
|
@@ -33,6 +33,12 @@ import {
|
|
|
33
33
|
verifyUeyeAssetManifest,
|
|
34
34
|
verifyUeyeRevisionHistory
|
|
35
35
|
} from '../lib/ueye-artifacts.js';
|
|
36
|
+
import {
|
|
37
|
+
INSTALL_LOCK_NAME,
|
|
38
|
+
INSTALL_RECEIPT_NAME,
|
|
39
|
+
inspectSkillInstallation,
|
|
40
|
+
installSkillSetTransactional
|
|
41
|
+
} from '../lib/skill-installation.js';
|
|
36
42
|
|
|
37
43
|
type AnyRecord = Record<string, any>;
|
|
38
44
|
|
|
@@ -199,75 +205,73 @@ async function rmrf(target) {
|
|
|
199
205
|
await fsp.rm(target, { recursive: true, force: true });
|
|
200
206
|
}
|
|
201
207
|
|
|
202
|
-
async function copyDir(source, target) {
|
|
203
|
-
await fsp.mkdir(target, { recursive: true });
|
|
204
|
-
const entries = await fsp.readdir(source, { withFileTypes: true });
|
|
205
|
-
for (const entry of entries) {
|
|
206
|
-
const from = path.join(source, entry.name);
|
|
207
|
-
const to = path.join(target, entry.name);
|
|
208
|
-
if (entry.isDirectory()) {
|
|
209
|
-
await copyDir(from, to);
|
|
210
|
-
} else if (entry.isFile()) {
|
|
211
|
-
await fsp.copyFile(from, to);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async function installSkill(skill) {
|
|
217
|
-
const source = path.join(ROOT, 'skills', skill);
|
|
218
|
-
const target = path.join(DEST, skill);
|
|
219
|
-
const references = path.join(ROOT, 'references');
|
|
220
|
-
|
|
221
|
-
if (!await exists(path.join(source, 'SKILL.md'))) {
|
|
222
|
-
throw new Error(`missing skill source: ${source}`);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
await rmrf(target);
|
|
226
|
-
await fsp.mkdir(target, { recursive: true });
|
|
227
|
-
await fsp.copyFile(path.join(source, 'SKILL.md'), path.join(target, 'SKILL.md'));
|
|
228
|
-
await copyDir(references, path.join(target, 'references'));
|
|
229
|
-
}
|
|
230
|
-
|
|
231
208
|
async function install() {
|
|
232
|
-
await
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
if (CODEX_MIRROR !== DEST && fs.existsSync(CODEX_MIRROR)) {
|
|
243
|
-
for (const skill of [...SKILLS, ...LEGACY_SKILLS, ...RETIRED_SKILLS]) {
|
|
244
|
-
await rmrf(path.join(CODEX_MIRROR, skill));
|
|
245
|
-
}
|
|
246
|
-
}
|
|
209
|
+
const result = await installSkillSetTransactional({
|
|
210
|
+
sourceRoot: ROOT,
|
|
211
|
+
destination: DEST,
|
|
212
|
+
codexMirror: CODEX_MIRROR,
|
|
213
|
+
packageName: String(PACKAGE_JSON.name || 'yam-flow'),
|
|
214
|
+
version: VERSION,
|
|
215
|
+
skills: SKILLS,
|
|
216
|
+
legacySkills: LEGACY_SKILLS,
|
|
217
|
+
retiredSkills: RETIRED_SKILLS
|
|
218
|
+
});
|
|
247
219
|
console.log(`yam installed to ${DEST}`);
|
|
220
|
+
console.log(`install receipt: ${result.receiptPath}`);
|
|
221
|
+
console.log(`integrity: ${result.installedFiles} files, sha256:${result.sourceDigest}`);
|
|
222
|
+
for (const warning of result.cleanupWarnings) console.warn(`warning: ${warning}`);
|
|
248
223
|
console.log('Restart Codex to reload skills.');
|
|
249
224
|
}
|
|
250
225
|
|
|
251
226
|
async function uninstall() {
|
|
227
|
+
const lockPath = path.join(DEST, INSTALL_LOCK_NAME);
|
|
228
|
+
if (await exists(lockPath)) {
|
|
229
|
+
throw new Error(`cannot uninstall while an install lock exists: ${lockPath}`);
|
|
230
|
+
}
|
|
252
231
|
for (const skill of [...SKILLS, ...LEGACY_SKILLS, ...RETIRED_SKILLS]) {
|
|
253
232
|
await rmrf(path.join(DEST, skill));
|
|
254
233
|
if (CODEX_MIRROR !== DEST) {
|
|
255
234
|
await rmrf(path.join(CODEX_MIRROR, skill));
|
|
256
235
|
}
|
|
257
236
|
}
|
|
237
|
+
await rmrf(path.join(DEST, INSTALL_RECEIPT_NAME));
|
|
258
238
|
console.log(`yam removed from ${DEST}`);
|
|
259
239
|
if (CODEX_MIRROR !== DEST) console.log(`yam mirror entries removed from ${CODEX_MIRROR}`);
|
|
260
240
|
console.log('Restart Codex to unload skills.');
|
|
261
241
|
}
|
|
262
242
|
|
|
263
243
|
async function status({ quiet = false } = {}) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
244
|
+
const report = await inspectSkillInstallation({
|
|
245
|
+
sourceRoot: ROOT,
|
|
246
|
+
destination: DEST,
|
|
247
|
+
packageName: String(PACKAGE_JSON.name || 'yam-flow'),
|
|
248
|
+
version: VERSION,
|
|
249
|
+
skills: SKILLS
|
|
250
|
+
});
|
|
251
|
+
if (!quiet) {
|
|
252
|
+
for (const skill of report.skills) {
|
|
253
|
+
const label = skill.status === 'ok' ? 'ok ' : skill.status === 'missing' ? 'missing' : 'drift ';
|
|
254
|
+
console.log(`${label} ${skill.skill}`);
|
|
255
|
+
}
|
|
256
|
+
if (report.receiptStatus === 'ok' && report.receipt) {
|
|
257
|
+
console.log(`ok install receipt ${report.receipt.package.name}@${report.receipt.package.version}`);
|
|
258
|
+
console.log(` sha256:${report.receipt.integrity.source_digest}`);
|
|
259
|
+
} else {
|
|
260
|
+
console.log(`${report.receiptStatus === 'missing' ? 'missing' : 'drift '} install receipt`);
|
|
261
|
+
}
|
|
262
|
+
if (report.issues.length) {
|
|
263
|
+
console.log('');
|
|
264
|
+
console.log('Install integrity issues:');
|
|
265
|
+
for (const issue of report.issues.slice(0, 12)) console.log(`- ${issue}`);
|
|
266
|
+
if (report.issues.length > 12) console.log(`- ... ${report.issues.length - 12} more issue(s)`);
|
|
267
|
+
if (report.recoveryArtifacts.length) {
|
|
268
|
+
console.log('Confirm no install is running, then inspect and preserve the transaction backup before retrying.');
|
|
269
|
+
} else {
|
|
270
|
+
console.log('Run `yam install` to restore the package-bundled skill set.');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
269
273
|
}
|
|
270
|
-
return
|
|
274
|
+
return report.ok ? 0 : Math.max(1, report.issues.length);
|
|
271
275
|
}
|
|
272
276
|
|
|
273
277
|
async function list() {
|
|
@@ -316,6 +320,7 @@ async function verify({ quiet = false } = {}) {
|
|
|
316
320
|
|
|
317
321
|
if (!manifest) return failOrReport('yam verify', issues, quiet);
|
|
318
322
|
if (manifest.name !== 'yam') issues.push('manifest name must be yam');
|
|
323
|
+
if (manifest.version !== VERSION) issues.push(`manifest version must match package version: ${manifest.version || 'missing'} != ${VERSION}`);
|
|
319
324
|
if (manifest.defaultHooks !== false) issues.push('manifest defaultHooks must be false');
|
|
320
325
|
if (!Array.isArray(manifest.routes) || manifest.routes.length !== SKILLS.length) {
|
|
321
326
|
issues.push(`manifest routes must contain ${SKILLS.length} routes`);
|