@1aboveio/skills 0.20.3 → 0.20.4
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/README.md +6 -5
- package/package.json +1 -1
- package/runtime/skills/distribution/generated/recipes.json +21 -21
- package/runtime/skills/distribution/scripts/bundles.mjs +126 -51
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
package/README.md
CHANGED
|
@@ -57,8 +57,9 @@ Running `install` with no `--group` opens the interactive bundle picker; `update
|
|
|
57
57
|
- `--disable-tdd` — keep TDD installed but allow only explicit user invocation.
|
|
58
58
|
|
|
59
59
|
Selecting several groups (interactive picker, repeated `--group`, or `--all`) installs their
|
|
60
|
-
members
|
|
61
|
-
|
|
60
|
+
members in bulk: adjacent members from one source share one native `skills add` from the unpacked
|
|
61
|
+
package. Every member is digest-verified afterward, so a failure remains attributed by name,
|
|
62
|
+
blocks only transitive dependents, and never aborts unrelated source batches. Every native add uses `--yes` because
|
|
62
63
|
`skills@1.5.22` has no independent `--symlink` flag: this selects the default canonical store plus
|
|
63
64
|
per-harness symlinks without an installation-method prompt, and also confirms replacement of each
|
|
64
65
|
planned same-named skill. The coordinator still owns group and new-member consent before planning.
|
|
@@ -104,11 +105,11 @@ copy. The default is No; `--yes` accepts archival non-interactively. Removal is
|
|
|
104
105
|
same pinned native Skills CLI, only after the declared replacement is installed or already current.
|
|
105
106
|
Declined or failed archival remains in selection memory so a later update offers it again.
|
|
106
107
|
|
|
107
|
-
Install and update are best-effort per
|
|
108
|
-
skills whose required dependency is unavailable, summarize
|
|
108
|
+
Install and update are best-effort per member over bulk source commands: they continue after a
|
|
109
|
+
member failure except for skills whose required dependency is unavailable, summarize
|
|
109
110
|
every skill as succeeded, unchanged, declined, or failed, and exit non-zero if anything failed. There
|
|
110
111
|
is no rollback or transactional group update; the native CLI remains the sole filesystem write
|
|
111
|
-
authority. Selection memory follows the same per-
|
|
112
|
+
authority. Selection memory follows the same per-member rule: it is rewritten when
|
|
112
113
|
at least one user-facing member succeeded or was already unchanged, holding exactly those members —
|
|
113
114
|
failed and declined members are omitted — and a run with no user-facing success leaves the prior
|
|
114
115
|
file untouched.
|
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"id": "first-party",
|
|
25
25
|
"type": "first-party",
|
|
26
26
|
"package": "@1aboveio/skills",
|
|
27
|
-
"version": "0.20.
|
|
27
|
+
"version": "0.20.4",
|
|
28
28
|
"updatePolicy": "pinned-npm-version",
|
|
29
29
|
"members": [
|
|
30
30
|
{
|
|
@@ -263,7 +263,7 @@
|
|
|
263
263
|
"sourceId": "first-party",
|
|
264
264
|
"sourceType": "first-party",
|
|
265
265
|
"package": "@1aboveio/skills",
|
|
266
|
-
"version": "0.20.
|
|
266
|
+
"version": "0.20.4",
|
|
267
267
|
"installPath": null,
|
|
268
268
|
"members": [
|
|
269
269
|
"harness-runtime",
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
"sourceId": "first-party",
|
|
298
298
|
"sourceType": "first-party",
|
|
299
299
|
"package": "@1aboveio/skills",
|
|
300
|
-
"version": "0.20.
|
|
300
|
+
"version": "0.20.4",
|
|
301
301
|
"installPath": null,
|
|
302
302
|
"members": [
|
|
303
303
|
"harness-runtime",
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
"sourceId": "first-party",
|
|
342
342
|
"sourceType": "first-party",
|
|
343
343
|
"package": "@1aboveio/skills",
|
|
344
|
-
"version": "0.20.
|
|
344
|
+
"version": "0.20.4",
|
|
345
345
|
"installPath": null,
|
|
346
346
|
"members": [
|
|
347
347
|
"harness-runtime",
|
|
@@ -374,7 +374,7 @@
|
|
|
374
374
|
"sourceId": "first-party",
|
|
375
375
|
"sourceType": "first-party",
|
|
376
376
|
"package": "@1aboveio/skills",
|
|
377
|
-
"version": "0.20.
|
|
377
|
+
"version": "0.20.4",
|
|
378
378
|
"installPath": null,
|
|
379
379
|
"members": [
|
|
380
380
|
"harness-runtime",
|
|
@@ -417,7 +417,7 @@
|
|
|
417
417
|
"sourceId": "first-party",
|
|
418
418
|
"sourceType": "first-party",
|
|
419
419
|
"package": "@1aboveio/skills",
|
|
420
|
-
"version": "0.20.
|
|
420
|
+
"version": "0.20.4",
|
|
421
421
|
"installPath": null,
|
|
422
422
|
"members": [
|
|
423
423
|
"harness-runtime",
|
|
@@ -445,7 +445,7 @@
|
|
|
445
445
|
"sourceId": "first-party",
|
|
446
446
|
"sourceType": "first-party",
|
|
447
447
|
"package": "@1aboveio/skills",
|
|
448
|
-
"version": "0.20.
|
|
448
|
+
"version": "0.20.4",
|
|
449
449
|
"installPath": null,
|
|
450
450
|
"members": [
|
|
451
451
|
"harness-runtime",
|
|
@@ -483,7 +483,7 @@
|
|
|
483
483
|
"sourceId": "first-party",
|
|
484
484
|
"sourceType": "first-party",
|
|
485
485
|
"package": "@1aboveio/skills",
|
|
486
|
-
"version": "0.20.
|
|
486
|
+
"version": "0.20.4",
|
|
487
487
|
"installPath": null,
|
|
488
488
|
"members": [
|
|
489
489
|
"harness-runtime",
|
|
@@ -511,7 +511,7 @@
|
|
|
511
511
|
"sourceId": "first-party",
|
|
512
512
|
"sourceType": "first-party",
|
|
513
513
|
"package": "@1aboveio/skills",
|
|
514
|
-
"version": "0.20.
|
|
514
|
+
"version": "0.20.4",
|
|
515
515
|
"installPath": null,
|
|
516
516
|
"members": [
|
|
517
517
|
"harness-runtime",
|
|
@@ -549,7 +549,7 @@
|
|
|
549
549
|
"sourceId": "first-party",
|
|
550
550
|
"sourceType": "first-party",
|
|
551
551
|
"package": "@1aboveio/skills",
|
|
552
|
-
"version": "0.20.
|
|
552
|
+
"version": "0.20.4",
|
|
553
553
|
"installPath": null,
|
|
554
554
|
"members": [
|
|
555
555
|
"harness-runtime",
|
|
@@ -579,7 +579,7 @@
|
|
|
579
579
|
"sourceId": "first-party",
|
|
580
580
|
"sourceType": "first-party",
|
|
581
581
|
"package": "@1aboveio/skills",
|
|
582
|
-
"version": "0.20.
|
|
582
|
+
"version": "0.20.4",
|
|
583
583
|
"installPath": null,
|
|
584
584
|
"members": [
|
|
585
585
|
"harness-runtime",
|
|
@@ -619,7 +619,7 @@
|
|
|
619
619
|
"sourceId": "first-party",
|
|
620
620
|
"sourceType": "first-party",
|
|
621
621
|
"package": "@1aboveio/skills",
|
|
622
|
-
"version": "0.20.
|
|
622
|
+
"version": "0.20.4",
|
|
623
623
|
"installPath": null,
|
|
624
624
|
"members": [
|
|
625
625
|
"harness-runtime",
|
|
@@ -647,7 +647,7 @@
|
|
|
647
647
|
"sourceId": "first-party",
|
|
648
648
|
"sourceType": "first-party",
|
|
649
649
|
"package": "@1aboveio/skills",
|
|
650
|
-
"version": "0.20.
|
|
650
|
+
"version": "0.20.4",
|
|
651
651
|
"installPath": null,
|
|
652
652
|
"members": [
|
|
653
653
|
"harness-runtime",
|
|
@@ -685,7 +685,7 @@
|
|
|
685
685
|
"sourceId": "first-party",
|
|
686
686
|
"sourceType": "first-party",
|
|
687
687
|
"package": "@1aboveio/skills",
|
|
688
|
-
"version": "0.20.
|
|
688
|
+
"version": "0.20.4",
|
|
689
689
|
"installPath": null,
|
|
690
690
|
"members": [
|
|
691
691
|
"harness-runtime",
|
|
@@ -715,7 +715,7 @@
|
|
|
715
715
|
"sourceId": "first-party",
|
|
716
716
|
"sourceType": "first-party",
|
|
717
717
|
"package": "@1aboveio/skills",
|
|
718
|
-
"version": "0.20.
|
|
718
|
+
"version": "0.20.4",
|
|
719
719
|
"installPath": null,
|
|
720
720
|
"members": [
|
|
721
721
|
"harness-runtime",
|
|
@@ -755,7 +755,7 @@
|
|
|
755
755
|
"sourceId": "first-party",
|
|
756
756
|
"sourceType": "first-party",
|
|
757
757
|
"package": "@1aboveio/skills",
|
|
758
|
-
"version": "0.20.
|
|
758
|
+
"version": "0.20.4",
|
|
759
759
|
"installPath": null,
|
|
760
760
|
"members": [
|
|
761
761
|
"harness-runtime",
|
|
@@ -787,7 +787,7 @@
|
|
|
787
787
|
"sourceId": "first-party",
|
|
788
788
|
"sourceType": "first-party",
|
|
789
789
|
"package": "@1aboveio/skills",
|
|
790
|
-
"version": "0.20.
|
|
790
|
+
"version": "0.20.4",
|
|
791
791
|
"installPath": null,
|
|
792
792
|
"members": [
|
|
793
793
|
"harness-runtime",
|
|
@@ -827,7 +827,7 @@
|
|
|
827
827
|
"sourceId": "first-party",
|
|
828
828
|
"sourceType": "first-party",
|
|
829
829
|
"package": "@1aboveio/skills",
|
|
830
|
-
"version": "0.20.
|
|
830
|
+
"version": "0.20.4",
|
|
831
831
|
"installPath": null,
|
|
832
832
|
"members": [
|
|
833
833
|
"harness-runtime"
|
|
@@ -853,7 +853,7 @@
|
|
|
853
853
|
"sourceId": "first-party",
|
|
854
854
|
"sourceType": "first-party",
|
|
855
855
|
"package": "@1aboveio/skills",
|
|
856
|
-
"version": "0.20.
|
|
856
|
+
"version": "0.20.4",
|
|
857
857
|
"installPath": null,
|
|
858
858
|
"members": [
|
|
859
859
|
"harness-runtime"
|
|
@@ -885,7 +885,7 @@
|
|
|
885
885
|
"sourceId": "first-party",
|
|
886
886
|
"sourceType": "first-party",
|
|
887
887
|
"package": "@1aboveio/skills",
|
|
888
|
-
"version": "0.20.
|
|
888
|
+
"version": "0.20.4",
|
|
889
889
|
"installPath": null,
|
|
890
890
|
"members": [
|
|
891
891
|
"harness-runtime",
|
|
@@ -945,7 +945,7 @@
|
|
|
945
945
|
"sourceId": "first-party",
|
|
946
946
|
"sourceType": "first-party",
|
|
947
947
|
"package": "@1aboveio/skills",
|
|
948
|
-
"version": "0.20.
|
|
948
|
+
"version": "0.20.4",
|
|
949
949
|
"installPath": null,
|
|
950
950
|
"members": [
|
|
951
951
|
"harness-runtime",
|
|
@@ -305,19 +305,14 @@ function localFirstPartyCommand(command, localRoot, groupId) {
|
|
|
305
305
|
return command.replace(NATIVE_ADD_SOURCE, (_match, prefix) => `${prefix}${shellArgument(localRoot)}`);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
// The coordinator
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
// planned exactly once, at its first occurrence. The pinned native CLI has no `--symlink` selector,
|
|
314
|
-
// so the coordinator adds `--yes` to choose its default symlink deployment without one installation-
|
|
315
|
-
// method prompt per skill. Attribution, ordering and deduplication remain coordinator-owned.
|
|
316
|
-
const SKILL_TAIL = /^(.*? --skill )(.+?)( && .*)?$/;
|
|
308
|
+
// The coordinator preserves generated dependency/member order, then coalesces each contiguous run
|
|
309
|
+
// from one source into a native add. A member shared by groups is included once and retains every
|
|
310
|
+
// owning selection for memory. Per-member attribution comes from post-install digest verification,
|
|
311
|
+
// not process count.
|
|
312
|
+
const SKILL_TAIL = /^(.*? --skill )(.+?)( --yes)?( && .*)?$/;
|
|
317
313
|
|
|
318
|
-
// The generated step binds its runtime suffix (` && npm ci ...`) to
|
|
319
|
-
//
|
|
320
|
-
// engineering-runtime itself was actually added — never after a sibling, never when it was skipped.
|
|
314
|
+
// The generated step binds its runtime suffix (` && npm ci ...`) to engineering-runtime. Keep it on
|
|
315
|
+
// the source batch only when that member remains selected after digest and consent filtering.
|
|
321
316
|
const RUNTIME_MEMBER = 'engineering-runtime';
|
|
322
317
|
|
|
323
318
|
function skillsFromCommand(command) {
|
|
@@ -329,14 +324,14 @@ function skillsFromCommand(command) {
|
|
|
329
324
|
function withSkills(command, skills) {
|
|
330
325
|
const match = SKILL_TAIL.exec(command);
|
|
331
326
|
if (!match) throw new Error(`Native add has no --skill list to rewrite: ${command}`);
|
|
332
|
-
return `${match[1]}${skills.join(' ')}${match[3] || ''}`;
|
|
327
|
+
return `${match[1]}${skills.join(' ')}${match[3] || ''}${match[4] || ''}`;
|
|
333
328
|
}
|
|
334
329
|
|
|
335
330
|
function withYesFlag(command) {
|
|
336
331
|
// --yes must bind to `skills`, not to a trailing `&& npm ci ...`.
|
|
337
332
|
const match = SKILL_TAIL.exec(command);
|
|
338
333
|
if (!match) return `${command} --yes`;
|
|
339
|
-
return `${match[1]}${match[2]} --yes${match[
|
|
334
|
+
return `${match[1]}${match[2]} --yes${match[4] || ''}`;
|
|
340
335
|
}
|
|
341
336
|
|
|
342
337
|
export function planBundleCommands(action, groupIds, {
|
|
@@ -363,12 +358,10 @@ export function planBundleCommands(action, groupIds, {
|
|
|
363
358
|
if (!requested.includes(groupId)) requested.push(groupId);
|
|
364
359
|
}
|
|
365
360
|
|
|
366
|
-
// Plan
|
|
367
|
-
//
|
|
368
|
-
// would install skills that are not in the selection / not in the package.
|
|
361
|
+
// Plan individual member records first. The execution boundary coalesces adjacent records from
|
|
362
|
+
// the same source without weakening per-member dependency, policy, or selection metadata.
|
|
369
363
|
const planned = [];
|
|
370
364
|
const plannedByMember = new Map();
|
|
371
|
-
|
|
372
365
|
for (const groupId of requested) {
|
|
373
366
|
const group = groups.get(groupId);
|
|
374
367
|
for (const step of group[action].steps) {
|
|
@@ -379,14 +372,10 @@ export function planBundleCommands(action, groupIds, {
|
|
|
379
372
|
const command = step.sourceId === 'first-party'
|
|
380
373
|
? localFirstPartyCommand(generated.command, localRoot, groupId)
|
|
381
374
|
: generated.command;
|
|
382
|
-
// An explicit member subset (the digest skip) removes members from the native add but never
|
|
383
|
-
// reorders the rest: the remaining skills keep recipe order, support dependency first.
|
|
384
|
-
// Declined new members (#1128) are also filtered out, but consent never applies to support
|
|
385
|
-
// dependencies (harness-runtime): they are silent install dependencies, not capabilities.
|
|
386
375
|
const skills = skillsFromCommand(command)
|
|
387
376
|
.filter((skill) => !skipMembers?.has(skill))
|
|
388
377
|
.filter((skill) => SUPPORT_GROUPS.has(skill) || !omit.has(skill));
|
|
389
|
-
const suffix = SKILL_TAIL.exec(command)?.[
|
|
378
|
+
const suffix = SKILL_TAIL.exec(command)?.[4] || '';
|
|
390
379
|
const bare = suffix ? command.slice(0, command.length - suffix.length) : command;
|
|
391
380
|
for (const skill of skills) {
|
|
392
381
|
const existing = plannedByMember.get(skill);
|
|
@@ -396,8 +385,6 @@ export function planBundleCommands(action, groupIds, {
|
|
|
396
385
|
}
|
|
397
386
|
let skillCommand = withSkills(bare, [skill]);
|
|
398
387
|
if (suffix && skill === RUNTIME_MEMBER) skillCommand = `${skillCommand}${suffix}`;
|
|
399
|
-
// The pinned CLI has no --symlink flag. --yes is its only supported way to select the
|
|
400
|
-
// default symlink deployment without presenting the install-method chooser.
|
|
401
388
|
skillCommand = withYesFlag(skillCommand);
|
|
402
389
|
const invocationPolicy = skill === 'tdd' && enableTdd
|
|
403
390
|
? undefined
|
|
@@ -415,22 +402,51 @@ export function planBundleCommands(action, groupIds, {
|
|
|
415
402
|
...(memberMetadata.get(skill)?.requires?.length > 0
|
|
416
403
|
? { requires: memberMetadata.get(skill).requires }
|
|
417
404
|
: {}),
|
|
405
|
+
metadata: memberMetadata.get(skill) ?? { installName: skill },
|
|
418
406
|
};
|
|
419
407
|
plannedByMember.set(skill, entry);
|
|
420
408
|
planned.push(entry);
|
|
421
409
|
}
|
|
422
410
|
}
|
|
423
411
|
}
|
|
424
|
-
|
|
425
412
|
return planned;
|
|
426
413
|
}
|
|
427
414
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
415
|
+
export function coalesceBundleCommands(commands) {
|
|
416
|
+
const batches = [];
|
|
417
|
+
for (const planned of commands) {
|
|
418
|
+
const previous = batches.at(-1);
|
|
419
|
+
if (!previous || previous.sourceId !== planned.sourceId || previous.cwd !== planned.cwd) {
|
|
420
|
+
batches.push({
|
|
421
|
+
sourceId: planned.sourceId,
|
|
422
|
+
members: [planned],
|
|
423
|
+
command: planned.command,
|
|
424
|
+
cwd: planned.cwd,
|
|
425
|
+
failureMessage: planned.failureMessage,
|
|
426
|
+
});
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
previous.members.push(planned);
|
|
430
|
+
const suffix = previous.members.map(({ command }) => SKILL_TAIL.exec(command)?.[4] || '').find(Boolean) || '';
|
|
431
|
+
const bare = suffix && previous.command.endsWith(suffix)
|
|
432
|
+
? previous.command.slice(0, previous.command.length - suffix.length)
|
|
433
|
+
: previous.command;
|
|
434
|
+
previous.command = withSkills(bare, previous.members.map(({ member }) => member));
|
|
435
|
+
if (suffix) previous.command = `${previous.command}${suffix}`;
|
|
436
|
+
}
|
|
437
|
+
for (const batch of batches) {
|
|
438
|
+
batch.groupIds = [...new Set(batch.members.flatMap((member) => member.groupIds))];
|
|
439
|
+
batch.groupName = [...new Set(batch.members.map((member) => member.groupName))].join(', ');
|
|
440
|
+
}
|
|
441
|
+
return batches;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Source batches continue independently. Within each batch, command status is only process evidence;
|
|
445
|
+
// installed-content verification is the per-member authority used for attribution and memory.
|
|
446
|
+
export function runBundleCommands(batches, {
|
|
432
447
|
execute = (command, cwd) => spawnSync('/bin/bash', ['-lc', command], { cwd, stdio: 'inherit' }),
|
|
433
448
|
applyPolicy = applyInvocationPolicy,
|
|
449
|
+
verifyMember,
|
|
434
450
|
skillsRoot,
|
|
435
451
|
stdout = process.stdout,
|
|
436
452
|
stderr = process.stderr,
|
|
@@ -439,35 +455,79 @@ export function runBundleCommands(commands, {
|
|
|
439
455
|
const succeeded = [];
|
|
440
456
|
const failed = [];
|
|
441
457
|
const available = new Set(satisfiedMembers);
|
|
442
|
-
for (const
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
458
|
+
for (const candidate of batches) {
|
|
459
|
+
const legacySingle = !Array.isArray(candidate.members);
|
|
460
|
+
const batch = legacySingle ? { ...candidate, members: [candidate] } : candidate;
|
|
461
|
+
let runnable = [...batch.members];
|
|
462
|
+
let changed = true;
|
|
463
|
+
while (changed) {
|
|
464
|
+
changed = false;
|
|
465
|
+
const runnableNames = new Set(runnable.map(({ member }) => member));
|
|
466
|
+
for (const planned of [...runnable]) {
|
|
467
|
+
const blockedBy = (planned.requires ?? [])
|
|
468
|
+
.filter((dependency) => !available.has(dependency) && !runnableNames.has(dependency));
|
|
469
|
+
if (blockedBy.length === 0) continue;
|
|
470
|
+
stderr.write(`Dependency failed for ${planned.member}: ${blockedBy.join(', ')} is not available\n`);
|
|
471
|
+
failed.push({ planned, status: 1, blockedBy });
|
|
472
|
+
runnable = runnable.filter((candidate) => candidate !== planned);
|
|
473
|
+
changed = true;
|
|
474
|
+
}
|
|
448
475
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
476
|
+
if (runnable.length === 0) continue;
|
|
477
|
+
let command = batch.command;
|
|
478
|
+
let batchSuffix = '';
|
|
479
|
+
if (!legacySingle) {
|
|
480
|
+
batchSuffix = SKILL_TAIL.exec(batch.command)?.[4] || '';
|
|
481
|
+
command = withSkills(batch.command, runnable.map(({ member }) => member));
|
|
482
|
+
if (batchSuffix && !runnable.some(({ member }) => member === RUNTIME_MEMBER)) {
|
|
483
|
+
command = command.slice(0, command.length - batchSuffix.length);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
stdout.write(`\nInstalling ${runnable.map(({ member }) => member).join(', ')} (${batch.sourceId})...\n`);
|
|
487
|
+
const result = execute(command, batch.cwd);
|
|
488
|
+
const status = Number.isInteger(result.status) ? result.status : 1;
|
|
489
|
+
const policyFailures = new Set();
|
|
490
|
+
if (status === 0) {
|
|
491
|
+
for (const planned of runnable) {
|
|
492
|
+
if (!planned.invocationPolicy) continue;
|
|
493
|
+
try {
|
|
454
494
|
applyPolicy({
|
|
455
495
|
installName: planned.member,
|
|
456
496
|
policy: planned.invocationPolicy,
|
|
457
497
|
...(skillsRoot ? { skillsRoot } : {}),
|
|
458
498
|
});
|
|
499
|
+
} catch (error) {
|
|
500
|
+
stderr.write(`Invocation policy failed for ${planned.member}: ${error.message}\n`);
|
|
501
|
+
policyFailures.add(planned.member);
|
|
459
502
|
}
|
|
460
|
-
|
|
461
|
-
|
|
503
|
+
}
|
|
504
|
+
} else {
|
|
505
|
+
stderr.write(`${batch.failureMessage}\n`);
|
|
506
|
+
}
|
|
507
|
+
for (const planned of runnable) {
|
|
508
|
+
if (policyFailures.has(planned.member)) {
|
|
509
|
+
failed.push({ planned, status: 1 });
|
|
462
510
|
continue;
|
|
511
|
+
}
|
|
512
|
+
if (status !== 0 && batchSuffix && planned.member === RUNTIME_MEMBER) {
|
|
513
|
+
stderr.write(`Post-install command failed for ${planned.member}\n`);
|
|
514
|
+
failed.push({ planned, status });
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const verified = verifyMember ? verifyMember(planned) : status === 0;
|
|
519
|
+
if (verified) {
|
|
520
|
+
succeeded.push(planned);
|
|
521
|
+
available.add(planned.member);
|
|
522
|
+
} else {
|
|
523
|
+
stderr.write(`Post-install verification failed for ${planned.member}\n`);
|
|
524
|
+
failed.push({ planned, status: status || 1 });
|
|
525
|
+
}
|
|
463
526
|
} catch (error) {
|
|
464
|
-
stderr.write(`
|
|
527
|
+
stderr.write(`Post-install verification failed for ${planned.member}: ${error.message}\n`);
|
|
465
528
|
failed.push({ planned, status: 1 });
|
|
466
|
-
continue;
|
|
467
529
|
}
|
|
468
530
|
}
|
|
469
|
-
stderr.write(`${planned.failureMessage}\n`);
|
|
470
|
-
failed.push({ planned, status: Number.isInteger(result.status) ? result.status : 1 });
|
|
471
531
|
}
|
|
472
532
|
return { succeeded, failed };
|
|
473
533
|
}
|
|
@@ -873,6 +933,7 @@ function selectionIncludesTdd(groupIds, catalog) {
|
|
|
873
933
|
export async function runCli(args, {
|
|
874
934
|
execute,
|
|
875
935
|
applyPolicy,
|
|
936
|
+
verifyMember,
|
|
876
937
|
stdin = process.stdin,
|
|
877
938
|
stdout = process.stdout,
|
|
878
939
|
stderr = process.stderr,
|
|
@@ -968,10 +1029,11 @@ export async function runCli(args, {
|
|
|
968
1029
|
skipMembers,
|
|
969
1030
|
omitMembers: declined,
|
|
970
1031
|
});
|
|
1032
|
+
const batches = coalesceBundleCommands(commands);
|
|
971
1033
|
if (parsed.dryRun) {
|
|
972
1034
|
if (buckets) printUpdateBuckets(stdout, buckets);
|
|
973
|
-
for (const
|
|
974
|
-
stdout.write(`\n${
|
|
1035
|
+
for (const batch of batches) {
|
|
1036
|
+
stdout.write(`\n${batch.groupName} / ${batch.sourceId} / ${batch.members.map(({ member }) => member).join(', ')}\n${batch.command}\n`);
|
|
975
1037
|
}
|
|
976
1038
|
if (buckets && commands.length === 0 && archiveCandidates.length === 0) {
|
|
977
1039
|
stdout.write('Nothing to do: every accepted skill is already up to date.\n');
|
|
@@ -984,9 +1046,21 @@ export async function runCli(args, {
|
|
|
984
1046
|
const skipping = buckets.unchanged.map((entry) => entry.member).filter((member) => !SUPPORT_GROUPS.has(member));
|
|
985
1047
|
if (skipping.length > 0) stdout.write(`Up to date, skipping: ${skipping.join(', ')}\n`);
|
|
986
1048
|
}
|
|
987
|
-
const
|
|
1049
|
+
const verificationTransport = resolveBundleTransport(transport);
|
|
1050
|
+
const verificationSources = new Map(readRecipes(verificationTransport.recipesPath).sources
|
|
1051
|
+
.map((source) => [source.id, source]));
|
|
1052
|
+
const verifyInstalledMember = verifyMember ?? (execute ? undefined : (planned) => {
|
|
1053
|
+
const source = verificationSources.get(planned.sourceId);
|
|
1054
|
+
return classifyInstalledMember(source, planned.metadata, {
|
|
1055
|
+
enableTdd,
|
|
1056
|
+
localRoot: verificationTransport.localRoot,
|
|
1057
|
+
skillsRoot,
|
|
1058
|
+
}).status === 'unchanged';
|
|
1059
|
+
});
|
|
1060
|
+
const { succeeded, failed } = runBundleCommands(batches, {
|
|
988
1061
|
execute,
|
|
989
1062
|
applyPolicy,
|
|
1063
|
+
verifyMember: verifyInstalledMember,
|
|
990
1064
|
skillsRoot,
|
|
991
1065
|
stdout,
|
|
992
1066
|
stderr,
|
|
@@ -1001,13 +1075,14 @@ export async function runCli(args, {
|
|
|
1001
1075
|
[...commands, ...(buckets?.unchanged ?? [])],
|
|
1002
1076
|
stderr,
|
|
1003
1077
|
));
|
|
1078
|
+
const coherentSucceeded = succeeded.filter((planned) => readyMembers.has(planned.member));
|
|
1004
1079
|
const archives = runArchiveCommands(
|
|
1005
1080
|
archiveCandidates.filter((candidate) => !declinedArchives.has(candidate.installName)),
|
|
1006
1081
|
readyMembers,
|
|
1007
1082
|
{ execute, skillsRoot, stdout, stderr },
|
|
1008
1083
|
);
|
|
1009
1084
|
printRunSummary(stdout, {
|
|
1010
|
-
succeeded,
|
|
1085
|
+
succeeded: coherentSucceeded,
|
|
1011
1086
|
failed,
|
|
1012
1087
|
unchanged: buckets?.unchanged.map((entry) => entry.member),
|
|
1013
1088
|
declined: [...declined],
|
|
@@ -342,7 +342,7 @@
|
|
|
342
342
|
"id": "first-party",
|
|
343
343
|
"type": "first-party",
|
|
344
344
|
"package": "@1aboveio/skills",
|
|
345
|
-
"version": "0.20.
|
|
345
|
+
"version": "0.20.4"
|
|
346
346
|
},
|
|
347
347
|
"contentDigest": "eff6c7b5931bce5b2265a619bccddd371a89df6ce7bc2edc74f11d00060a71dd",
|
|
348
348
|
"digestExcludes": []
|
|
@@ -355,7 +355,7 @@
|
|
|
355
355
|
"id": "first-party",
|
|
356
356
|
"type": "first-party",
|
|
357
357
|
"package": "@1aboveio/skills",
|
|
358
|
-
"version": "0.20.
|
|
358
|
+
"version": "0.20.4"
|
|
359
359
|
},
|
|
360
360
|
"contentDigest": "d97abeff7bdc5ae2e4be2f631d09dba46d4753ce1e67334793364329af59f066",
|
|
361
361
|
"digestExcludes": []
|
|
@@ -368,7 +368,7 @@
|
|
|
368
368
|
"id": "first-party",
|
|
369
369
|
"type": "first-party",
|
|
370
370
|
"package": "@1aboveio/skills",
|
|
371
|
-
"version": "0.20.
|
|
371
|
+
"version": "0.20.4"
|
|
372
372
|
},
|
|
373
373
|
"contentDigest": "fe2ec3bae2bfec2dbef19db30ab0272391d7c1d9b6893341a76a9f339adefc57",
|
|
374
374
|
"digestExcludes": []
|
|
@@ -381,7 +381,7 @@
|
|
|
381
381
|
"id": "first-party",
|
|
382
382
|
"type": "first-party",
|
|
383
383
|
"package": "@1aboveio/skills",
|
|
384
|
-
"version": "0.20.
|
|
384
|
+
"version": "0.20.4"
|
|
385
385
|
},
|
|
386
386
|
"contentDigest": "58b0556228a9271cf9e33727a05fc08a4fdfd29512ec0936b169f0a55d60e6ef",
|
|
387
387
|
"digestExcludes": []
|
|
@@ -394,7 +394,7 @@
|
|
|
394
394
|
"id": "first-party",
|
|
395
395
|
"type": "first-party",
|
|
396
396
|
"package": "@1aboveio/skills",
|
|
397
|
-
"version": "0.20.
|
|
397
|
+
"version": "0.20.4"
|
|
398
398
|
},
|
|
399
399
|
"contentDigest": "d28dd4d3c4394df0cc7e6b48d0e5daa7d2277701ea459e39fba99acf1d8ff670",
|
|
400
400
|
"digestExcludes": []
|
|
@@ -407,7 +407,7 @@
|
|
|
407
407
|
"id": "first-party",
|
|
408
408
|
"type": "first-party",
|
|
409
409
|
"package": "@1aboveio/skills",
|
|
410
|
-
"version": "0.20.
|
|
410
|
+
"version": "0.20.4"
|
|
411
411
|
},
|
|
412
412
|
"contentDigest": "56fb5843788c9073b0d5a65ffa72bd7d2fa80dc6a1ff06fb0e19fab513c51502",
|
|
413
413
|
"digestExcludes": []
|
|
@@ -420,7 +420,7 @@
|
|
|
420
420
|
"id": "first-party",
|
|
421
421
|
"type": "first-party",
|
|
422
422
|
"package": "@1aboveio/skills",
|
|
423
|
-
"version": "0.20.
|
|
423
|
+
"version": "0.20.4"
|
|
424
424
|
},
|
|
425
425
|
"contentDigest": "f048fd00c69f2dc666fc7a3096cfeee6dfba73933bfb69602f3f0e26159798cc",
|
|
426
426
|
"digestExcludes": []
|
|
@@ -433,7 +433,7 @@
|
|
|
433
433
|
"id": "first-party",
|
|
434
434
|
"type": "first-party",
|
|
435
435
|
"package": "@1aboveio/skills",
|
|
436
|
-
"version": "0.20.
|
|
436
|
+
"version": "0.20.4"
|
|
437
437
|
},
|
|
438
438
|
"contentDigest": "d533684db4483cfc90be2aa7161980b6548057ef18a4b54f0cdbcd53c79dd46d",
|
|
439
439
|
"digestExcludes": []
|
|
@@ -446,15 +446,15 @@
|
|
|
446
446
|
"id": "first-party",
|
|
447
447
|
"type": "first-party",
|
|
448
448
|
"package": "@1aboveio/skills",
|
|
449
|
-
"version": "0.20.
|
|
449
|
+
"version": "0.20.4"
|
|
450
450
|
},
|
|
451
|
-
"contentDigest": "
|
|
451
|
+
"contentDigest": "86a91b567eabe6143a4ecac3cbec7271da252978202f292e287bb3a8da95a797",
|
|
452
452
|
"digestExcludes": [
|
|
453
453
|
"coherence/workflow.json"
|
|
454
454
|
]
|
|
455
455
|
}
|
|
456
456
|
],
|
|
457
|
-
"releaseIdentity": "
|
|
457
|
+
"releaseIdentity": "ffa735d74d402c79fbd8cbca332b415422884ee88f914412d4aa88c2d1353cb9",
|
|
458
458
|
"lifecycleAuthority": "native-skills-cli",
|
|
459
459
|
"repairRecipe": {
|
|
460
460
|
"id": "engineering-workflow-dependency-first",
|
|
@@ -512,7 +512,7 @@
|
|
|
512
512
|
"sourceId": "first-party",
|
|
513
513
|
"sourceType": "first-party",
|
|
514
514
|
"package": "@1aboveio/skills",
|
|
515
|
-
"version": "0.20.
|
|
515
|
+
"version": "0.20.4",
|
|
516
516
|
"installPath": null,
|
|
517
517
|
"members": [
|
|
518
518
|
"harness-runtime",
|
|
@@ -528,7 +528,7 @@
|
|
|
528
528
|
"commands": [
|
|
529
529
|
{
|
|
530
530
|
"transport": "npm",
|
|
531
|
-
"command": "npx @1aboveio/skills@0.20.
|
|
531
|
+
"command": "npx @1aboveio/skills@0.20.4 install --group engineering-workflow --yes"
|
|
532
532
|
}
|
|
533
533
|
],
|
|
534
534
|
"onFailure": {
|