novahiz 0.9.7 → 0.9.8
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/CHANGELOG.md +27 -0
- package/catalog/categories.json +2 -10
- package/catalog/overrides.json +0 -77
- package/dist/commands/doctor.js +32 -15
- package/package.json +1 -1
- package/src/commands/doctor.ts +38 -14
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.9.8] - 2026-10-15
|
|
9
|
+
|
|
10
|
+
### Removed
|
|
11
|
+
|
|
12
|
+
- **The 7 `eas-*` skills from the catalogue** - `test` and `devops` listed them
|
|
13
|
+
as `defaultSkills` (`eas-app-stores`, `eas-hosting`, `eas-observe`,
|
|
14
|
+
`eas-simulator`, `eas-update`, `eas-update-insights`, `eas-workflows`) while
|
|
15
|
+
the expo pack deliberately excludes them: `providers.json` says so in the
|
|
16
|
+
provider's own purpose. No provider could install a single one, so `doctor`
|
|
17
|
+
named them and `novahiz deps --install` returned `install: []`. 0.9.5 made
|
|
18
|
+
that row tell the truth instead of blaming the reader; the references
|
|
19
|
+
themselves stayed, and the row reports without blocking, which is why nothing
|
|
20
|
+
had failed since. `referencedSkills` now spans 51 ids and none of them is
|
|
21
|
+
undeliverable, so `doctor` reports `51 present` with no caveat. The seven
|
|
22
|
+
inert `overrides.json` entries went with them; the `devops` keywords `eas`,
|
|
23
|
+
`eas build` and `eas update` stay, since they route a deployment question to
|
|
24
|
+
a roadmap that still applies.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **A test holding the catalogue to that invariant** -
|
|
29
|
+
`undeliverableReferences(spec, packageRootDir)` is exported from
|
|
30
|
+
`doctor.ts`, and `tests/doctor-referenced-skills.test.ts` runs it against the
|
|
31
|
+
shipped catalogue: it must return `[]`, no `defaultSkills` may carry an
|
|
32
|
+
`eas-*`, and a reintroduced one must be named. Checked by injection: putting
|
|
33
|
+
`eas-simulator` back into `test.defaultSkills` turns both assertions red.
|
|
34
|
+
|
|
8
35
|
## [0.9.7] - 2026-10-15
|
|
9
36
|
|
|
10
37
|
### Added
|
package/catalog/categories.json
CHANGED
|
@@ -554,8 +554,7 @@
|
|
|
554
554
|
"defaultSkills": [
|
|
555
555
|
"flutter-add-widget-test",
|
|
556
556
|
"dart-add-unit-test",
|
|
557
|
-
"expo-skill-eval"
|
|
558
|
-
"eas-simulator"
|
|
557
|
+
"expo-skill-eval"
|
|
559
558
|
],
|
|
560
559
|
"roadmap": {
|
|
561
560
|
"id": "testing",
|
|
@@ -1329,14 +1328,7 @@
|
|
|
1329
1328
|
"tag a version",
|
|
1330
1329
|
"changelog"
|
|
1331
1330
|
],
|
|
1332
|
-
"defaultSkills": [
|
|
1333
|
-
"eas-workflows",
|
|
1334
|
-
"eas-app-stores",
|
|
1335
|
-
"eas-hosting",
|
|
1336
|
-
"eas-observe",
|
|
1337
|
-
"eas-update",
|
|
1338
|
-
"eas-update-insights"
|
|
1339
|
-
],
|
|
1331
|
+
"defaultSkills": [],
|
|
1340
1332
|
"roadmap": {
|
|
1341
1333
|
"id": "devops",
|
|
1342
1334
|
"steps": [
|
package/catalog/overrides.json
CHANGED
|
@@ -634,83 +634,6 @@
|
|
|
634
634
|
"docs-writing"
|
|
635
635
|
]
|
|
636
636
|
},
|
|
637
|
-
"eas-app-stores": {
|
|
638
|
-
"power": 4,
|
|
639
|
-
"stars": null,
|
|
640
|
-
"tags": [
|
|
641
|
-
"eas",
|
|
642
|
-
"expo"
|
|
643
|
-
],
|
|
644
|
-
"categories": [
|
|
645
|
-
"expo"
|
|
646
|
-
]
|
|
647
|
-
},
|
|
648
|
-
"eas-hosting": {
|
|
649
|
-
"power": 4,
|
|
650
|
-
"stars": null,
|
|
651
|
-
"tags": [
|
|
652
|
-
"eas",
|
|
653
|
-
"expo"
|
|
654
|
-
],
|
|
655
|
-
"categories": [
|
|
656
|
-
"expo"
|
|
657
|
-
]
|
|
658
|
-
},
|
|
659
|
-
"eas-observe": {
|
|
660
|
-
"power": 4,
|
|
661
|
-
"stars": null,
|
|
662
|
-
"tags": [
|
|
663
|
-
"eas",
|
|
664
|
-
"expo"
|
|
665
|
-
],
|
|
666
|
-
"categories": [
|
|
667
|
-
"expo"
|
|
668
|
-
]
|
|
669
|
-
},
|
|
670
|
-
"eas-simulator": {
|
|
671
|
-
"power": 4,
|
|
672
|
-
"stars": null,
|
|
673
|
-
"tags": [
|
|
674
|
-
"eas",
|
|
675
|
-
"expo"
|
|
676
|
-
],
|
|
677
|
-
"categories": [
|
|
678
|
-
"expo"
|
|
679
|
-
]
|
|
680
|
-
},
|
|
681
|
-
"eas-update": {
|
|
682
|
-
"power": 4,
|
|
683
|
-
"stars": null,
|
|
684
|
-
"tags": [
|
|
685
|
-
"eas",
|
|
686
|
-
"expo"
|
|
687
|
-
],
|
|
688
|
-
"categories": [
|
|
689
|
-
"expo"
|
|
690
|
-
]
|
|
691
|
-
},
|
|
692
|
-
"eas-update-insights": {
|
|
693
|
-
"power": 4,
|
|
694
|
-
"stars": null,
|
|
695
|
-
"tags": [
|
|
696
|
-
"eas",
|
|
697
|
-
"expo"
|
|
698
|
-
],
|
|
699
|
-
"categories": [
|
|
700
|
-
"expo"
|
|
701
|
-
]
|
|
702
|
-
},
|
|
703
|
-
"eas-workflows": {
|
|
704
|
-
"power": 4,
|
|
705
|
-
"stars": null,
|
|
706
|
-
"tags": [
|
|
707
|
-
"eas",
|
|
708
|
-
"expo"
|
|
709
|
-
],
|
|
710
|
-
"categories": [
|
|
711
|
-
"expo"
|
|
712
|
-
]
|
|
713
|
-
},
|
|
714
637
|
"expo-animation": {
|
|
715
638
|
"power": 4,
|
|
716
639
|
"stars": null,
|
package/dist/commands/doctor.js
CHANGED
|
@@ -443,22 +443,15 @@ function referencedSkills(spec) {
|
|
|
443
443
|
* `indexSkills` is null when the index is unreadable — the index check already
|
|
444
444
|
* reports that, so the row stays quiet instead of double-failing.
|
|
445
445
|
* Only skills the package ships (packageRoot/skills) can make a fresh install
|
|
446
|
-
* broken. The remaining references
|
|
447
|
-
* impeccable
|
|
446
|
+
* broken. The remaining references, the dart/expo/flutter packs and
|
|
447
|
+
* impeccable, are optional delivery downloaded on request and are simply not
|
|
448
448
|
* present on a machine that never asked for them; the gate already degrades
|
|
449
449
|
* them to "not enforced". Blocking on them turned every healthy fresh install
|
|
450
450
|
* red (`missing from index: dart-...` right after novahiz-install --yes). */
|
|
451
451
|
export function referencedSkillsCheck(spec, indexSkills, packageRootDir) {
|
|
452
452
|
const referenced = referencedSkills(spec);
|
|
453
453
|
const absent = indexSkills ? referenced.filter((id) => !indexSkills.has(id)) : [];
|
|
454
|
-
const shipped =
|
|
455
|
-
const shippedDir = join(packageRootDir, "skills");
|
|
456
|
-
if (existsSync(shippedDir)) {
|
|
457
|
-
for (const entry of readdirSync(shippedDir, { withFileTypes: true })) {
|
|
458
|
-
if (entry.isDirectory())
|
|
459
|
-
shipped.add(entry.name);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
454
|
+
const shipped = shippedSkills(packageRootDir);
|
|
462
455
|
const absentShipped = absent.filter((id) => shipped.has(id));
|
|
463
456
|
const absentPack = absent.filter((id) => !shipped.has(id));
|
|
464
457
|
// Only promise the update command when a pack can actually deliver what is
|
|
@@ -493,11 +486,14 @@ export function referencedSkillsCheck(spec, indexSkills, packageRootDir) {
|
|
|
493
486
|
* argv: an explicit `--skill a b c` names them, and `--skill *` delivers the
|
|
494
487
|
* whole repo, whose ids start with the repo's leading segment with any hyphen
|
|
495
488
|
* suffix dropped (`flutter/skills` -> `flutter-`, `dart-lang/skills` ->
|
|
496
|
-
* `dart-`). Measured 2026-10-15: the 7 skills doctor
|
|
497
|
-
* not installed"
|
|
498
|
-
* `devops`
|
|
499
|
-
* "run /novahiz-skills-update, or novahiz deps --install"
|
|
500
|
-
* installed a single one. Advice no command can honour is a
|
|
489
|
+
* `dart-`). Measured 2026-10-15 on the 0.9.5 install: the 7 skills doctor
|
|
490
|
+
* reported as "pack skills not installed" were `eas-*`, referenced as
|
|
491
|
+
* `defaultSkills` by `test` and `devops` while the expo pack deliberately
|
|
492
|
+
* excludes them, so "run /novahiz-skills-update, or novahiz deps --install"
|
|
493
|
+
* could not have installed a single one. Advice no command can honour is a
|
|
494
|
+
* defect. Those references are gone from the catalog; the guard stays, since
|
|
495
|
+
* the same situation reappears whenever a pack is disabled or its `--skill`
|
|
496
|
+
* list stops naming an id the catalog still asks for. */
|
|
501
497
|
function packDelivery(spec) {
|
|
502
498
|
const exact = new Set();
|
|
503
499
|
const prefixes = [];
|
|
@@ -526,6 +522,27 @@ function packDelivery(spec) {
|
|
|
526
522
|
}
|
|
527
523
|
return { exact, prefixes };
|
|
528
524
|
}
|
|
525
|
+
/** Skill ids the package itself carries in `packageRootDir/skills`. */
|
|
526
|
+
function shippedSkills(packageRootDir) {
|
|
527
|
+
const shipped = new Set();
|
|
528
|
+
const shippedDir = join(packageRootDir, "skills");
|
|
529
|
+
if (existsSync(shippedDir)) {
|
|
530
|
+
for (const entry of readdirSync(shippedDir, { withFileTypes: true })) {
|
|
531
|
+
if (entry.isDirectory())
|
|
532
|
+
shipped.add(entry.name);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return shipped;
|
|
536
|
+
}
|
|
537
|
+
/** Referenced skill ids nothing in the system can supply: the package ships
|
|
538
|
+
* none of them and no enabled pack can install them. Exported so the catalog
|
|
539
|
+
* is held to this invariant in tests, since the row above reports it without
|
|
540
|
+
* blocking and therefore never failed on it. */
|
|
541
|
+
export function undeliverableReferences(spec, packageRootDir) {
|
|
542
|
+
const shipped = shippedSkills(packageRootDir);
|
|
543
|
+
const { exact, prefixes } = packDelivery(spec);
|
|
544
|
+
return referencedSkills(spec).filter((id) => !shipped.has(id) && !exact.has(id) && !prefixes.some((prefix) => id.startsWith(prefix)));
|
|
545
|
+
}
|
|
529
546
|
/** Impeccable design-context checks: PRODUCT.md and DESIGN.md resolution
|
|
530
547
|
* (root -> .agents/context -> docs/). Rows appear only when the impeccable
|
|
531
548
|
* skill is installed (opt-in) and are never blocking: a missing record is a
|
package/package.json
CHANGED
package/src/commands/doctor.ts
CHANGED
|
@@ -439,8 +439,8 @@ function referencedSkills(spec: ReturnType<typeof loadSpec>): string[] {
|
|
|
439
439
|
* `indexSkills` is null when the index is unreadable — the index check already
|
|
440
440
|
* reports that, so the row stays quiet instead of double-failing.
|
|
441
441
|
* Only skills the package ships (packageRoot/skills) can make a fresh install
|
|
442
|
-
* broken. The remaining references
|
|
443
|
-
* impeccable
|
|
442
|
+
* broken. The remaining references, the dart/expo/flutter packs and
|
|
443
|
+
* impeccable, are optional delivery downloaded on request and are simply not
|
|
444
444
|
* present on a machine that never asked for them; the gate already degrades
|
|
445
445
|
* them to "not enforced". Blocking on them turned every healthy fresh install
|
|
446
446
|
* red (`missing from index: dart-...` right after novahiz-install --yes). */
|
|
@@ -451,13 +451,7 @@ export function referencedSkillsCheck(
|
|
|
451
451
|
): DoctorCheck {
|
|
452
452
|
const referenced = referencedSkills(spec);
|
|
453
453
|
const absent = indexSkills ? referenced.filter((id) => !indexSkills.has(id)) : [];
|
|
454
|
-
const shipped =
|
|
455
|
-
const shippedDir = join(packageRootDir, "skills");
|
|
456
|
-
if (existsSync(shippedDir)) {
|
|
457
|
-
for (const entry of readdirSync(shippedDir, { withFileTypes: true })) {
|
|
458
|
-
if (entry.isDirectory()) shipped.add(entry.name);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
454
|
+
const shipped = shippedSkills(packageRootDir);
|
|
461
455
|
const absentShipped = absent.filter((id) => shipped.has(id));
|
|
462
456
|
const absentPack = absent.filter((id) => !shipped.has(id));
|
|
463
457
|
// Only promise the update command when a pack can actually deliver what is
|
|
@@ -491,11 +485,14 @@ export function referencedSkillsCheck(
|
|
|
491
485
|
* argv: an explicit `--skill a b c` names them, and `--skill *` delivers the
|
|
492
486
|
* whole repo, whose ids start with the repo's leading segment with any hyphen
|
|
493
487
|
* suffix dropped (`flutter/skills` -> `flutter-`, `dart-lang/skills` ->
|
|
494
|
-
* `dart-`). Measured 2026-10-15: the 7 skills doctor
|
|
495
|
-
* not installed"
|
|
496
|
-
* `devops`
|
|
497
|
-
* "run /novahiz-skills-update, or novahiz deps --install"
|
|
498
|
-
* installed a single one. Advice no command can honour is a
|
|
488
|
+
* `dart-`). Measured 2026-10-15 on the 0.9.5 install: the 7 skills doctor
|
|
489
|
+
* reported as "pack skills not installed" were `eas-*`, referenced as
|
|
490
|
+
* `defaultSkills` by `test` and `devops` while the expo pack deliberately
|
|
491
|
+
* excludes them, so "run /novahiz-skills-update, or novahiz deps --install"
|
|
492
|
+
* could not have installed a single one. Advice no command can honour is a
|
|
493
|
+
* defect. Those references are gone from the catalog; the guard stays, since
|
|
494
|
+
* the same situation reappears whenever a pack is disabled or its `--skill`
|
|
495
|
+
* list stops naming an id the catalog still asks for. */
|
|
499
496
|
function packDelivery(spec: ReturnType<typeof loadSpec>): { exact: Set<string>; prefixes: string[] } {
|
|
500
497
|
const exact = new Set<string>();
|
|
501
498
|
const prefixes: string[] = [];
|
|
@@ -518,6 +515,33 @@ function packDelivery(spec: ReturnType<typeof loadSpec>): { exact: Set<string>;
|
|
|
518
515
|
return { exact, prefixes };
|
|
519
516
|
}
|
|
520
517
|
|
|
518
|
+
/** Skill ids the package itself carries in `packageRootDir/skills`. */
|
|
519
|
+
function shippedSkills(packageRootDir: string): Set<string> {
|
|
520
|
+
const shipped = new Set<string>();
|
|
521
|
+
const shippedDir = join(packageRootDir, "skills");
|
|
522
|
+
if (existsSync(shippedDir)) {
|
|
523
|
+
for (const entry of readdirSync(shippedDir, { withFileTypes: true })) {
|
|
524
|
+
if (entry.isDirectory()) shipped.add(entry.name);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return shipped;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/** Referenced skill ids nothing in the system can supply: the package ships
|
|
531
|
+
* none of them and no enabled pack can install them. Exported so the catalog
|
|
532
|
+
* is held to this invariant in tests, since the row above reports it without
|
|
533
|
+
* blocking and therefore never failed on it. */
|
|
534
|
+
export function undeliverableReferences(
|
|
535
|
+
spec: ReturnType<typeof loadSpec>,
|
|
536
|
+
packageRootDir: string
|
|
537
|
+
): string[] {
|
|
538
|
+
const shipped = shippedSkills(packageRootDir);
|
|
539
|
+
const { exact, prefixes } = packDelivery(spec);
|
|
540
|
+
return referencedSkills(spec).filter(
|
|
541
|
+
(id) => !shipped.has(id) && !exact.has(id) && !prefixes.some((prefix) => id.startsWith(prefix))
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
521
545
|
/** Impeccable design-context checks: PRODUCT.md and DESIGN.md resolution
|
|
522
546
|
* (root -> .agents/context -> docs/). Rows appear only when the impeccable
|
|
523
547
|
* skill is installed (opt-in) and are never blocking: a missing record is a
|