@kb-labs/cli-commands 2.89.0 → 2.94.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/{discover-Cz7X5bQp.d.ts → discover-CCE84_5E.d.ts} +16 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +157 -124
- package/dist/index.js.map +1 -1
- package/dist/registry/index.d.ts +5 -6
- package/dist/registry/index.js +106 -76
- package/dist/registry/index.js.map +1 -1
- package/package.json +22 -22
package/dist/registry/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as CommandManifest, A as AvailabilityCheck, R as RegisteredCommand, D as DiscoveryResult } from '../discover-
|
|
2
|
-
export { b as CacheFile, c as CommandLookupResult, e as CommandModule, f as CommandType, F as FlagDefinition, G as GlobalFlags, g as PackageCacheEntry, P as ProductGroup, _ as __test, h as discoverManifests, i as discoverManifestsByNamespace, j as findCommand, k as findCommandWithType, r as registry,
|
|
1
|
+
import { d as CommandManifest, A as AvailabilityCheck, R as RegisteredCommand, l as CommandRegistry, D as DiscoveryResult } from '../discover-CCE84_5E.js';
|
|
2
|
+
export { b as CacheFile, c as CommandLookupResult, e as CommandModule, f as CommandType, F as FlagDefinition, G as GlobalFlags, g as PackageCacheEntry, P as ProductGroup, _ as __test, h as discoverManifests, i as discoverManifestsByNamespace, j as findCommand, k as findCommandWithType, r as registry, m as resetInProcCache } from '../discover-CCE84_5E.js';
|
|
3
3
|
import { ILogger } from '@kb-labs/core-platform';
|
|
4
4
|
import '@kb-labs/plugin-contracts';
|
|
5
5
|
|
|
@@ -47,14 +47,13 @@ declare function preflightManifests(discoveryResults: DiscoveryResult[], logger?
|
|
|
47
47
|
/**
|
|
48
48
|
* Register manifests with shadowing and collision detection
|
|
49
49
|
*/
|
|
50
|
-
declare function registerManifests(discoveryResults: DiscoveryResult[], registry:
|
|
51
|
-
options?: RegisterManifestsOptions & {
|
|
50
|
+
declare function registerManifests(discoveryResults: DiscoveryResult[], registry: CommandRegistry, options?: RegisterManifestsOptions & {
|
|
52
51
|
logger?: ILogger;
|
|
53
52
|
}): Promise<ManifestRegistrationResult>;
|
|
54
53
|
/**
|
|
55
54
|
* Dispose all plugins by calling their dispose hooks
|
|
56
55
|
*/
|
|
57
|
-
declare function disposeAllPlugins(registry:
|
|
56
|
+
declare function disposeAllPlugins(registry: CommandRegistry, logger?: ILogger): Promise<void>;
|
|
58
57
|
|
|
59
58
|
/**
|
|
60
59
|
* Execute a registered command.
|
|
@@ -62,6 +61,6 @@ declare function disposeAllPlugins(registry: any, logger?: ILogger): Promise<voi
|
|
|
62
61
|
* - Unavailable commands return exit code 2.
|
|
63
62
|
* - Available commands are executed via manifest.loader().
|
|
64
63
|
*/
|
|
65
|
-
declare function runCommand(cmd: RegisteredCommand, ctx:
|
|
64
|
+
declare function runCommand(cmd: RegisteredCommand, ctx: Record<string, unknown>, argv: string[], flags: Record<string, unknown>): Promise<number>;
|
|
66
65
|
|
|
67
66
|
export { AvailabilityCheck, type CheckRequiresOptions, CommandManifest, DiscoveryResult, type ManifestRegistrationResult, type RegisterManifestsOptions, RegisteredCommand, type SkippedManifest, checkRequires, disposeAllPlugins, preflightManifests, registerManifests, runCommand };
|
package/dist/registry/index.js
CHANGED
|
@@ -68,7 +68,7 @@ function checkRequires(manifest, options = {}) {
|
|
|
68
68
|
if (isInMonorepo) {
|
|
69
69
|
continue;
|
|
70
70
|
}
|
|
71
|
-
const errorMessage = err.message || "";
|
|
71
|
+
const errorMessage = (err instanceof Error ? err.message : "") || "";
|
|
72
72
|
const hasExportsError = errorMessage.includes("exports") || errorMessage.includes("main");
|
|
73
73
|
if (hasExportsError || errorMessage.includes("Cannot resolve")) {
|
|
74
74
|
const parts = dep.startsWith("@") ? dep.slice(1).split("/") : [dep];
|
|
@@ -251,7 +251,7 @@ var __test = {
|
|
|
251
251
|
// resetInProcCache is exported directly (not via __test) since it's part of the public API
|
|
252
252
|
};
|
|
253
253
|
function createUnavailableManifest(pkgName, error) {
|
|
254
|
-
const rawMsg = (error
|
|
254
|
+
const rawMsg = (error instanceof Error ? error.message : String(error) || "").toString();
|
|
255
255
|
let missing = null;
|
|
256
256
|
const m1 = rawMsg.match(/Cannot find (?:module|package) '([^']+)'/);
|
|
257
257
|
const m2 = rawMsg.match(/from ['"]([^'"]+)['"]/);
|
|
@@ -272,9 +272,13 @@ function createUnavailableManifest(pkgName, error) {
|
|
|
272
272
|
requires,
|
|
273
273
|
loader: async () => {
|
|
274
274
|
throw new Error(`Cannot load ${pkgName} CLI manifest. ${rawMsg}`);
|
|
275
|
-
}
|
|
275
|
+
},
|
|
276
|
+
// Mark as synthetic so saveCache can skip it — synthetic manifests must never
|
|
277
|
+
// be persisted to disk because they represent transient load failures.
|
|
278
|
+
// Caching them would make the error "stick" until the TTL expires even after
|
|
279
|
+
// the underlying problem (missing build artifact, broken dep) is resolved.
|
|
280
|
+
_synthetic: true
|
|
276
281
|
};
|
|
277
|
-
manifest._synthetic = true;
|
|
278
282
|
return manifest;
|
|
279
283
|
}
|
|
280
284
|
var PACKAGE_JSON = "package.json";
|
|
@@ -365,7 +369,7 @@ async function detectNewWorkspacePackages(cwd, cachedPackages) {
|
|
|
365
369
|
}
|
|
366
370
|
}
|
|
367
371
|
} catch (error) {
|
|
368
|
-
log("debug", `[plugins][cache] Workspace scan skipped: ${error
|
|
372
|
+
log("debug", `[plugins][cache] Workspace scan skipped: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
369
373
|
}
|
|
370
374
|
return false;
|
|
371
375
|
}
|
|
@@ -376,7 +380,7 @@ async function loadManifestWithTimeout(manifestPath, pkgName, pkgRoot) {
|
|
|
376
380
|
try {
|
|
377
381
|
return await Promise.race([loadManifest(manifestPath, pkgName, pkgRoot), timeout]);
|
|
378
382
|
} catch (err) {
|
|
379
|
-
if (err.message === "Timeout") {
|
|
383
|
+
if (err instanceof Error && err.message === "Timeout") {
|
|
380
384
|
log("warn", `Timeout loading manifest from ${pkgName}`);
|
|
381
385
|
return [];
|
|
382
386
|
}
|
|
@@ -396,10 +400,12 @@ function getNamespaceFromManifest(manifestV2, packageName) {
|
|
|
396
400
|
async function loadManifest(manifestPath, pkgName, pkgRoot) {
|
|
397
401
|
const fileUrl = pathToFileURL(manifestPath).href;
|
|
398
402
|
const mod = await import(fileUrl);
|
|
399
|
-
const
|
|
400
|
-
|
|
403
|
+
const modTyped = mod;
|
|
404
|
+
const rawManifest = modTyped.manifest || modTyped.default;
|
|
405
|
+
if (!rawManifest || typeof rawManifest !== "object" || rawManifest.schema !== "kb.plugin/3") {
|
|
401
406
|
throw new Error(`Unsupported manifest format in ${pkgName}. Only kb.plugin/3 schema is supported.`);
|
|
402
407
|
}
|
|
408
|
+
const manifest = rawManifest;
|
|
403
409
|
const namespace = getNamespaceFromManifest(manifest, pkgName);
|
|
404
410
|
const manifestDir = path2.dirname(manifestPath);
|
|
405
411
|
const baseRoot = pkgRoot || manifestDir;
|
|
@@ -461,8 +467,9 @@ async function loadConfig(cwd) {
|
|
|
461
467
|
}
|
|
462
468
|
}
|
|
463
469
|
async function findManifestPath(pkgRoot, pkg) {
|
|
464
|
-
|
|
465
|
-
|
|
470
|
+
const kb = pkg.kb;
|
|
471
|
+
if (kb?.manifest) {
|
|
472
|
+
const manifestPath = path2.join(pkgRoot, kb.manifest);
|
|
466
473
|
try {
|
|
467
474
|
await promises.access(manifestPath);
|
|
468
475
|
return { path: manifestPath, deprecated: false };
|
|
@@ -470,8 +477,9 @@ async function findManifestPath(pkgRoot, pkg) {
|
|
|
470
477
|
return { path: null, deprecated: false };
|
|
471
478
|
}
|
|
472
479
|
}
|
|
473
|
-
|
|
474
|
-
|
|
480
|
+
const exports$1 = pkg.exports;
|
|
481
|
+
if (exports$1?.["./kb/commands"]) {
|
|
482
|
+
const exportPath = exports$1["./kb/commands"];
|
|
475
483
|
const manifestPath = typeof exportPath === "string" ? exportPath : exportPath.default || exportPath.import;
|
|
476
484
|
if (manifestPath) {
|
|
477
485
|
const resolved = path2.resolve(pkgRoot, manifestPath);
|
|
@@ -575,20 +583,21 @@ async function discoverProjectLocalPlugins(projectRoot) {
|
|
|
575
583
|
}
|
|
576
584
|
async function loadManifestsForPackages(packageInfos, source, scope) {
|
|
577
585
|
const loadPromises = packageInfos.map(async ({ pkgRoot, pkg, manifestPath }) => {
|
|
586
|
+
const pkgName = pkg.name;
|
|
578
587
|
const pkgStart = Date.now();
|
|
579
588
|
try {
|
|
580
|
-
const manifests = await loadManifestWithTimeout(manifestPath,
|
|
589
|
+
const manifests = await loadManifestWithTimeout(manifestPath, pkgName, pkgRoot);
|
|
581
590
|
const pkgTime = Date.now() - pkgStart;
|
|
582
591
|
if (pkgTime > 30) {
|
|
583
|
-
log("debug", `[plugins][perf] ${
|
|
592
|
+
log("debug", `[plugins][perf] ${pkgName} manifest parse: ${pkgTime}ms (budget: 30ms)`);
|
|
584
593
|
}
|
|
585
594
|
if (manifests.length > 0) {
|
|
586
|
-
validateUniqueIds(manifests,
|
|
595
|
+
validateUniqueIds(manifests, pkgName);
|
|
587
596
|
return {
|
|
588
597
|
manifests,
|
|
589
598
|
source,
|
|
590
599
|
scope,
|
|
591
|
-
packageName:
|
|
600
|
+
packageName: pkgName,
|
|
592
601
|
manifestPath: toPosixPath(manifestPath),
|
|
593
602
|
pkgRoot: toPosixPath(pkgRoot)
|
|
594
603
|
};
|
|
@@ -596,21 +605,23 @@ async function loadManifestsForPackages(packageInfos, source, scope) {
|
|
|
596
605
|
return null;
|
|
597
606
|
} catch (err) {
|
|
598
607
|
const pkgTime = Date.now() - pkgStart;
|
|
599
|
-
log("debug", `[plugins][perf] ${
|
|
608
|
+
log("debug", `[plugins][perf] ${pkgName} failed after ${pkgTime}ms`);
|
|
609
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
610
|
+
const errCode = err.code ?? "UNKNOWN";
|
|
600
611
|
log("warn", JSON.stringify({
|
|
601
612
|
code: "DISCOVERY_MANIFEST_LOAD_FAIL",
|
|
602
|
-
packageName:
|
|
613
|
+
packageName: pkgName,
|
|
603
614
|
manifestPath: toPosixPath(manifestPath),
|
|
604
|
-
errorCode:
|
|
605
|
-
errorMessage:
|
|
606
|
-
hint:
|
|
615
|
+
errorCode: errCode,
|
|
616
|
+
errorMessage: errMsg,
|
|
617
|
+
hint: errMsg.includes("Cannot find package") ? "Run: kb devlink apply && pnpm -w build" : "Check manifest syntax and dependencies"
|
|
607
618
|
}));
|
|
608
|
-
const synthetic = createUnavailableManifest(
|
|
619
|
+
const synthetic = createUnavailableManifest(pkgName, err);
|
|
609
620
|
return {
|
|
610
621
|
manifests: [synthetic],
|
|
611
622
|
source,
|
|
612
623
|
scope,
|
|
613
|
-
packageName:
|
|
624
|
+
packageName: pkgName,
|
|
614
625
|
manifestPath: toPosixPath(manifestPath),
|
|
615
626
|
pkgRoot: toPosixPath(pkgRoot)
|
|
616
627
|
};
|
|
@@ -631,29 +642,30 @@ async function discoverCurrentPackage(cwd) {
|
|
|
631
642
|
if (!pkg) {
|
|
632
643
|
return null;
|
|
633
644
|
}
|
|
645
|
+
const pkgName = pkg.name;
|
|
634
646
|
const manifestInfo = await findManifestPath(cwd, pkg);
|
|
635
647
|
if (manifestInfo.path) {
|
|
636
648
|
if (manifestInfo.deprecated) {
|
|
637
|
-
log("warn", `[DEPRECATED] ${
|
|
649
|
+
log("warn", `[DEPRECATED] ${pkgName} uses legacy manifest path: ${manifestInfo.path}`);
|
|
638
650
|
log("warn", ` \u2192 Migrate to exports["./kb/commands"] or set kb.commandsManifest in package.json`);
|
|
639
651
|
}
|
|
640
|
-
const manifests = await loadManifestWithTimeout(manifestInfo.path,
|
|
652
|
+
const manifests = await loadManifestWithTimeout(manifestInfo.path, pkgName, cwd);
|
|
641
653
|
if (manifests.length > 0) {
|
|
642
|
-
validateUniqueIds(manifests,
|
|
654
|
+
validateUniqueIds(manifests, pkgName);
|
|
643
655
|
return {
|
|
644
656
|
manifests,
|
|
645
657
|
source: "workspace",
|
|
646
658
|
// Current-package fallback fires in installed mode when the user's
|
|
647
659
|
// project itself exposes a manifest. That maps to the project scope.
|
|
648
660
|
scope: "project",
|
|
649
|
-
packageName:
|
|
661
|
+
packageName: pkgName,
|
|
650
662
|
manifestPath: toPosixPath(manifestInfo.path),
|
|
651
663
|
pkgRoot: toPosixPath(cwd)
|
|
652
664
|
};
|
|
653
665
|
}
|
|
654
666
|
}
|
|
655
667
|
} catch (err) {
|
|
656
|
-
log("debug", `No CLI manifest in current package: ${err.message}`);
|
|
668
|
+
log("debug", `No CLI manifest in current package: ${err instanceof Error ? err.message : String(err)}`);
|
|
657
669
|
}
|
|
658
670
|
return null;
|
|
659
671
|
}
|
|
@@ -670,7 +682,7 @@ async function discoverNodeModules(cwd) {
|
|
|
670
682
|
}
|
|
671
683
|
const scanEntry = async () => {
|
|
672
684
|
let pkgRoot;
|
|
673
|
-
let pkg;
|
|
685
|
+
let pkg = null;
|
|
674
686
|
if (entry.name.startsWith("@")) {
|
|
675
687
|
const scopeDir = path2.join(nmDir, entry.name);
|
|
676
688
|
try {
|
|
@@ -681,29 +693,30 @@ async function discoverNodeModules(cwd) {
|
|
|
681
693
|
if (!pkg) {
|
|
682
694
|
continue;
|
|
683
695
|
}
|
|
696
|
+
const scopedPkgName = pkg.name;
|
|
684
697
|
const isPlugin = isPluginPackage(pkg);
|
|
685
|
-
if (
|
|
698
|
+
if (scopedPkgName?.startsWith("@kb-labs/")) {
|
|
686
699
|
const manifestInfo = await findManifestPath(pkgRoot, pkg);
|
|
687
700
|
if (manifestInfo.path) {
|
|
688
701
|
packageInfos.push({ pkgRoot, pkg, manifestPath: manifestInfo.path });
|
|
689
702
|
}
|
|
690
703
|
} else if (isPlugin) {
|
|
691
|
-
if (config.block?.includes(
|
|
692
|
-
log("debug", `Plugin ${
|
|
704
|
+
if (config.block?.includes(scopedPkgName ?? "")) {
|
|
705
|
+
log("debug", `Plugin ${scopedPkgName} blocked by config`);
|
|
693
706
|
return;
|
|
694
707
|
}
|
|
695
|
-
const isAllowlisted = config.allow?.includes(
|
|
708
|
+
const isAllowlisted = config.allow?.includes(scopedPkgName ?? "") || config.linked?.includes(scopedPkgName ?? "");
|
|
696
709
|
if (!isAllowlisted) {
|
|
697
|
-
log("debug", `Plugin ${
|
|
710
|
+
log("debug", `Plugin ${scopedPkgName} skipped (not allowlisted). Add to kb-labs.config.json plugins.allow or enable via 'kb marketplace enable'`);
|
|
698
711
|
return;
|
|
699
712
|
}
|
|
700
713
|
const manifestInfo = await findManifestPath(pkgRoot, pkg);
|
|
701
714
|
if (manifestInfo.path) {
|
|
702
715
|
if (manifestInfo.deprecated) {
|
|
703
|
-
log("warn", `[DEPRECATED] ${
|
|
716
|
+
log("warn", `[DEPRECATED] ${scopedPkgName} uses legacy manifest path: ${manifestInfo.path}`);
|
|
704
717
|
log("warn", ` \u2192 Migrate to exports["./kb/commands"] or set kb.commandsManifest in package.json`);
|
|
705
718
|
}
|
|
706
|
-
const isLinked = config.linked?.includes(
|
|
719
|
+
const isLinked = config.linked?.includes(scopedPkgName ?? "");
|
|
707
720
|
packageInfos.push({ pkgRoot, pkg, manifestPath: manifestInfo.path, isLinked });
|
|
708
721
|
}
|
|
709
722
|
}
|
|
@@ -716,24 +729,25 @@ async function discoverNodeModules(cwd) {
|
|
|
716
729
|
if (!pkg) {
|
|
717
730
|
return;
|
|
718
731
|
}
|
|
732
|
+
const unscopedPkgName = pkg.name;
|
|
719
733
|
const isPlugin = isPluginPackage(pkg);
|
|
720
734
|
if (isPlugin) {
|
|
721
|
-
if (config.block?.includes(
|
|
722
|
-
log("debug", `Plugin ${
|
|
735
|
+
if (config.block?.includes(unscopedPkgName ?? "")) {
|
|
736
|
+
log("debug", `Plugin ${unscopedPkgName} blocked by config`);
|
|
723
737
|
return;
|
|
724
738
|
}
|
|
725
|
-
const isAllowlisted = config.allow?.includes(
|
|
739
|
+
const isAllowlisted = config.allow?.includes(unscopedPkgName ?? "") || config.linked?.includes(unscopedPkgName ?? "");
|
|
726
740
|
if (!isAllowlisted) {
|
|
727
|
-
log("debug", `Plugin ${
|
|
741
|
+
log("debug", `Plugin ${unscopedPkgName} skipped (not allowlisted). Add to kb-labs.config.json plugins.allow or enable via 'kb marketplace enable'`);
|
|
728
742
|
return;
|
|
729
743
|
}
|
|
730
744
|
const manifestInfo = await findManifestPath(pkgRoot, pkg);
|
|
731
745
|
if (manifestInfo.path) {
|
|
732
746
|
if (manifestInfo.deprecated) {
|
|
733
|
-
log("warn", `[DEPRECATED] ${
|
|
747
|
+
log("warn", `[DEPRECATED] ${unscopedPkgName} uses legacy manifest path: ${manifestInfo.path}`);
|
|
734
748
|
log("warn", ` \u2192 Migrate to exports["./kb/commands"] or set kb.commandsManifest in package.json`);
|
|
735
749
|
}
|
|
736
|
-
const isLinked = config.linked?.includes(
|
|
750
|
+
const isLinked = config.linked?.includes(unscopedPkgName ?? "");
|
|
737
751
|
packageInfos.push({ pkgRoot, pkg, manifestPath: manifestInfo.path, isLinked });
|
|
738
752
|
}
|
|
739
753
|
}
|
|
@@ -743,10 +757,11 @@ async function discoverNodeModules(cwd) {
|
|
|
743
757
|
}
|
|
744
758
|
await Promise.allSettled(scanPromises);
|
|
745
759
|
const loadPromises = packageInfos.map(async ({ pkgRoot, pkg, manifestPath, isLinked }) => {
|
|
760
|
+
const pkgName = pkg.name;
|
|
746
761
|
try {
|
|
747
|
-
const manifests = await loadManifestWithTimeout(manifestPath,
|
|
762
|
+
const manifests = await loadManifestWithTimeout(manifestPath, pkgName, pkgRoot);
|
|
748
763
|
if (manifests.length > 0) {
|
|
749
|
-
validateUniqueIds(manifests,
|
|
764
|
+
validateUniqueIds(manifests, pkgName);
|
|
750
765
|
return {
|
|
751
766
|
manifests,
|
|
752
767
|
source: isLinked ? "linked" : "node_modules",
|
|
@@ -754,27 +769,29 @@ async function discoverNodeModules(cwd) {
|
|
|
754
769
|
// platformRoot === projectRoot so either label is correct; we use
|
|
755
770
|
// platform to reflect where the manifest physically lives.
|
|
756
771
|
scope: "platform",
|
|
757
|
-
packageName:
|
|
772
|
+
packageName: pkgName,
|
|
758
773
|
manifestPath: toPosixPath(manifestPath),
|
|
759
774
|
pkgRoot: toPosixPath(pkgRoot)
|
|
760
775
|
};
|
|
761
776
|
}
|
|
762
777
|
return null;
|
|
763
778
|
} catch (err) {
|
|
779
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
780
|
+
const errCode = err.code ?? "UNKNOWN";
|
|
764
781
|
log("warn", JSON.stringify({
|
|
765
782
|
code: "DISCOVERY_MANIFEST_LOAD_FAIL",
|
|
766
|
-
packageName:
|
|
783
|
+
packageName: pkgName,
|
|
767
784
|
manifestPath: toPosixPath(manifestPath),
|
|
768
|
-
errorCode:
|
|
769
|
-
errorMessage:
|
|
770
|
-
hint:
|
|
785
|
+
errorCode: errCode,
|
|
786
|
+
errorMessage: errMsg,
|
|
787
|
+
hint: errMsg.includes("Cannot find package") ? "Run: kb devlink apply && pnpm -w build" : "Check manifest syntax and dependencies"
|
|
771
788
|
}));
|
|
772
|
-
const synthetic = createUnavailableManifest(
|
|
789
|
+
const synthetic = createUnavailableManifest(pkgName, err);
|
|
773
790
|
return {
|
|
774
791
|
manifests: [synthetic],
|
|
775
792
|
source: isLinked ? "linked" : "node_modules",
|
|
776
793
|
scope: "platform",
|
|
777
|
-
packageName:
|
|
794
|
+
packageName: pkgName,
|
|
778
795
|
manifestPath: toPosixPath(manifestPath),
|
|
779
796
|
pkgRoot: toPosixPath(pkgRoot)
|
|
780
797
|
};
|
|
@@ -789,7 +806,7 @@ async function discoverNodeModules(cwd) {
|
|
|
789
806
|
}
|
|
790
807
|
return results;
|
|
791
808
|
} catch (err) {
|
|
792
|
-
log("debug", `Could not scan node_modules: ${err.message}`);
|
|
809
|
+
log("debug", `Could not scan node_modules: ${err instanceof Error ? err.message : String(err)}`);
|
|
793
810
|
return [];
|
|
794
811
|
}
|
|
795
812
|
}
|
|
@@ -813,14 +830,14 @@ function deduplicateManifests(all) {
|
|
|
813
830
|
byPackageName.set(result.packageName, projectEntry);
|
|
814
831
|
continue;
|
|
815
832
|
}
|
|
816
|
-
const winner = existing.scope === "
|
|
817
|
-
const loser = existing.scope === "
|
|
818
|
-
log("
|
|
819
|
-
code: "
|
|
833
|
+
const winner = existing.scope === "project" ? existing : result;
|
|
834
|
+
const loser = existing.scope === "project" ? result : existing;
|
|
835
|
+
log("debug", JSON.stringify({
|
|
836
|
+
code: "DISCOVERY_SCOPE_OVERRIDE",
|
|
820
837
|
packageName: result.packageName,
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
message: "Package exists in both platform and project scopes \u2014
|
|
838
|
+
projectPath: winner.pkgRoot,
|
|
839
|
+
platformPath: loser.pkgRoot,
|
|
840
|
+
message: "Package exists in both platform and project scopes \u2014 project wins."
|
|
824
841
|
}));
|
|
825
842
|
byPackageName.set(result.packageName, winner);
|
|
826
843
|
continue;
|
|
@@ -913,7 +930,7 @@ async function isPackageCacheStale(entry, options) {
|
|
|
913
930
|
return true;
|
|
914
931
|
}
|
|
915
932
|
} catch (error) {
|
|
916
|
-
log("debug", `Package cache invalidated: missing package.json for ${entry.result.packageName} (${error
|
|
933
|
+
log("debug", `Package cache invalidated: missing package.json for ${entry.result.packageName} (${error instanceof Error ? error.message : "unknown"})`);
|
|
917
934
|
return true;
|
|
918
935
|
}
|
|
919
936
|
let manifestStat;
|
|
@@ -924,7 +941,7 @@ async function isPackageCacheStale(entry, options) {
|
|
|
924
941
|
return true;
|
|
925
942
|
}
|
|
926
943
|
} catch (error) {
|
|
927
|
-
log("debug", `Package cache invalidated: manifest deleted for ${entry.result.packageName} (${error
|
|
944
|
+
log("debug", `Package cache invalidated: manifest deleted for ${entry.result.packageName} (${error instanceof Error ? error.message : "unknown"})`);
|
|
928
945
|
return true;
|
|
929
946
|
}
|
|
930
947
|
if (options.validateHash) {
|
|
@@ -935,7 +952,7 @@ async function isPackageCacheStale(entry, options) {
|
|
|
935
952
|
return true;
|
|
936
953
|
}
|
|
937
954
|
} catch (error) {
|
|
938
|
-
log("debug", `Package cache hash validation failed for ${entry.result.packageName}: ${error
|
|
955
|
+
log("debug", `Package cache hash validation failed for ${entry.result.packageName}: ${error instanceof Error ? error.message : "unknown"}`);
|
|
939
956
|
return true;
|
|
940
957
|
}
|
|
941
958
|
}
|
|
@@ -981,7 +998,7 @@ async function saveCache(cwd, results, roots) {
|
|
|
981
998
|
stateHasher.update(result.packageName);
|
|
982
999
|
stateHasher.update(manifestHash);
|
|
983
1000
|
} catch (err) {
|
|
984
|
-
log("debug", `Failed to cache package ${result.packageName}: ${err.message}`);
|
|
1001
|
+
log("debug", `Failed to cache package ${result.packageName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
985
1002
|
}
|
|
986
1003
|
}
|
|
987
1004
|
const lockfileHash = await computeLockfileHash(cwd);
|
|
@@ -1024,7 +1041,7 @@ async function saveCache(cwd, results, roots) {
|
|
|
1024
1041
|
try {
|
|
1025
1042
|
await promises.writeFile(cachePath, JSON.stringify(cache), "utf8");
|
|
1026
1043
|
} catch (err) {
|
|
1027
|
-
log("debug", `Failed to save cache: ${err.message}`);
|
|
1044
|
+
log("debug", `Failed to save cache: ${err instanceof Error ? err.message : String(err)}`);
|
|
1028
1045
|
}
|
|
1029
1046
|
}
|
|
1030
1047
|
async function discoverManifests(cwd, noCache = false, options = {}) {
|
|
@@ -1117,8 +1134,21 @@ async function discoverManifests(cwd, noCache = false, options = {}) {
|
|
|
1117
1134
|
if (projectLocal.length > 0) {
|
|
1118
1135
|
log("info", `Discovered ${projectLocal.length} project-local plugins`);
|
|
1119
1136
|
}
|
|
1137
|
+
let projectWorkspace = [];
|
|
1138
|
+
if (roots.projectRoot !== roots.platformRoot) {
|
|
1139
|
+
try {
|
|
1140
|
+
const pwStart = Date.now();
|
|
1141
|
+
const raw = await discoverWorkspace(roots.projectRoot);
|
|
1142
|
+
projectWorkspace = raw.map((r) => ({ ...r, scope: "project" }));
|
|
1143
|
+
timings.projectWorkspace = Date.now() - pwStart;
|
|
1144
|
+
if (projectWorkspace.length > 0) {
|
|
1145
|
+
log("info", `Discovered ${projectWorkspace.length} project workspace packages with CLI manifests`);
|
|
1146
|
+
}
|
|
1147
|
+
} catch {
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1120
1150
|
const dedupStart = Date.now();
|
|
1121
|
-
const results = deduplicateManifests([...workspace, ...installed, ...projectLocal]);
|
|
1151
|
+
const results = deduplicateManifests([...workspace, ...installed, ...projectLocal, ...projectWorkspace]);
|
|
1122
1152
|
timings.deduplicate = Date.now() - dedupStart;
|
|
1123
1153
|
const saveStart = Date.now();
|
|
1124
1154
|
await saveCache(cwd, results, roots);
|
|
@@ -1293,7 +1323,7 @@ function preflightManifests(discoveryResults, logger) {
|
|
|
1293
1323
|
validateManifestStructure(manifest);
|
|
1294
1324
|
allowed.push(manifest);
|
|
1295
1325
|
} catch (error) {
|
|
1296
|
-
const reason = error
|
|
1326
|
+
const reason = error instanceof Error ? error.message : "Validation failed";
|
|
1297
1327
|
const manifestId = manifest?.id || manifest?.group || result.packageName || "unknown";
|
|
1298
1328
|
skipped.push({
|
|
1299
1329
|
id: manifestId,
|
|
@@ -1338,7 +1368,7 @@ async function registerManifests(discoveryResults, registry2, options = {}) {
|
|
|
1338
1368
|
try {
|
|
1339
1369
|
validateManifestStructure(manifest);
|
|
1340
1370
|
} catch (err) {
|
|
1341
|
-
throw new Error(`Validation failed: ${err.message}`);
|
|
1371
|
+
throw new Error(`Validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1342
1372
|
}
|
|
1343
1373
|
const normalizedId = normalizeCommandId(manifest.id, namespace);
|
|
1344
1374
|
if (normalizedId !== manifest.id) {
|
|
@@ -1385,7 +1415,8 @@ async function registerManifests(discoveryResults, registry2, options = {}) {
|
|
|
1385
1415
|
cmd._disposeHook = manifestModule.dispose;
|
|
1386
1416
|
}
|
|
1387
1417
|
} catch (hookError) {
|
|
1388
|
-
|
|
1418
|
+
const hookMsg = hookError instanceof Error ? hookError.message : String(hookError);
|
|
1419
|
+
log2.debug(`Lifecycle hooks unavailable for ${manifest.id}: ${hookMsg}`);
|
|
1389
1420
|
}
|
|
1390
1421
|
const canonicalKey = manifest.group ? `${manifest.group}:${manifest.id}` : manifest.id;
|
|
1391
1422
|
const existing = globalIds.get(canonicalKey);
|
|
@@ -1455,7 +1486,7 @@ async function registerManifests(discoveryResults, registry2, options = {}) {
|
|
|
1455
1486
|
registered.push(cmd);
|
|
1456
1487
|
} catch (error) {
|
|
1457
1488
|
errors++;
|
|
1458
|
-
const reason = error
|
|
1489
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1459
1490
|
skipped.push({
|
|
1460
1491
|
id: manifestId,
|
|
1461
1492
|
source: result.source,
|
|
@@ -1487,11 +1518,9 @@ async function disposeAllPlugins(registry2, logger) {
|
|
|
1487
1518
|
const disposeHook = cmd._disposeHook;
|
|
1488
1519
|
if (disposeHook && typeof disposeHook === "function") {
|
|
1489
1520
|
disposePromises.push(
|
|
1490
|
-
Promise.resolve(disposeHook({
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
})).catch((err) => {
|
|
1494
|
-
log2.warn(`Dispose hook failed for ${cmd.manifest.id}: ${err.message}`);
|
|
1521
|
+
Promise.resolve(disposeHook()).catch((err) => {
|
|
1522
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1523
|
+
log2.warn(`Dispose hook failed for ${cmd.manifest.id}: ${errMsg}`);
|
|
1495
1524
|
})
|
|
1496
1525
|
);
|
|
1497
1526
|
}
|
|
@@ -1502,8 +1531,9 @@ async function disposeAllPlugins(registry2, logger) {
|
|
|
1502
1531
|
// src/registry/run.ts
|
|
1503
1532
|
async function runCommand(cmd, ctx, argv, flags) {
|
|
1504
1533
|
if (!cmd.available) {
|
|
1505
|
-
|
|
1506
|
-
|
|
1534
|
+
const presenter = ctx.presenter;
|
|
1535
|
+
if (presenter?.json) {
|
|
1536
|
+
presenter.json({
|
|
1507
1537
|
ok: false,
|
|
1508
1538
|
available: false,
|
|
1509
1539
|
command: cmd.manifest.id,
|