@kb-labs/cli-commands 2.31.0 → 2.33.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.
@@ -1,5 +1,5 @@
1
- import { d as CommandManifest, A as AvailabilityCheck, R as RegisteredCommand, D as DiscoveryResult } from '../discover-DhqYgS-M.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, l as resetInProcCache } from '../discover-DhqYgS-M.js';
1
+ import { d as CommandManifest, A as AvailabilityCheck, R as RegisteredCommand, D as DiscoveryResult } from '../discover-Cz7X5bQp.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, l as resetInProcCache } from '../discover-Cz7X5bQp.js';
3
3
  import { ILogger } from '@kb-labs/core-platform';
4
4
  import '@kb-labs/plugin-contracts';
5
5
 
@@ -320,8 +320,8 @@ async function computePluginsStateHash(cwd) {
320
320
  return "";
321
321
  }
322
322
  }
323
- async function computeMarketplaceLockHash(cwd) {
324
- const lockPath = path2.join(cwd, ".kb", "marketplace.lock");
323
+ async function computeMarketplaceLockHashAt(root) {
324
+ const lockPath = path2.join(root, ".kb", "marketplace.lock");
325
325
  try {
326
326
  const content = await promises.readFile(lockPath, "utf8");
327
327
  return createHash("sha256").update(content).digest("hex");
@@ -550,22 +550,19 @@ async function discoverWorkspace(cwd) {
550
550
  }
551
551
  }
552
552
  }
553
- const localPluginPattern = path2.join(
554
- ".kb",
555
- "plugins",
556
- "*",
557
- "packages",
558
- "*-entry",
559
- PACKAGE_JSON
560
- );
561
- const localPluginFiles = await glob(localPluginPattern, {
562
- cwd,
553
+ return loadManifestsForPackages(packageInfos, "workspace", "platform");
554
+ }
555
+ async function discoverProjectLocalPlugins(projectRoot) {
556
+ const pattern = path2.join(".kb", "plugins", "*", "packages", "*-entry", PACKAGE_JSON);
557
+ const files = await glob(pattern, {
558
+ cwd: projectRoot,
563
559
  absolute: false,
564
560
  ignore: ["**/node_modules/**"]
565
561
  });
566
- for (const pkgFile of localPluginFiles) {
567
- const pkgRoot = path2.dirname(path2.join(cwd, pkgFile));
568
- const pkg = await readPackageJson(path2.join(cwd, pkgFile));
562
+ const packageInfos = [];
563
+ for (const pkgFile of files) {
564
+ const pkgRoot = path2.dirname(path2.join(projectRoot, pkgFile));
565
+ const pkg = await readPackageJson(path2.join(projectRoot, pkgFile));
569
566
  if (!pkg) {
570
567
  continue;
571
568
  }
@@ -574,6 +571,9 @@ async function discoverWorkspace(cwd) {
574
571
  packageInfos.push({ pkgRoot, pkg, manifestPath: manifestInfo.path });
575
572
  }
576
573
  }
574
+ return loadManifestsForPackages(packageInfos, "linked", "project");
575
+ }
576
+ async function loadManifestsForPackages(packageInfos, source, scope) {
577
577
  const loadPromises = packageInfos.map(async ({ pkgRoot, pkg, manifestPath }) => {
578
578
  const pkgStart = Date.now();
579
579
  try {
@@ -586,7 +586,8 @@ async function discoverWorkspace(cwd) {
586
586
  validateUniqueIds(manifests, pkg.name);
587
587
  return {
588
588
  manifests,
589
- source: "workspace",
589
+ source,
590
+ scope,
590
591
  packageName: pkg.name,
591
592
  manifestPath: toPosixPath(manifestPath),
592
593
  pkgRoot: toPosixPath(pkgRoot)
@@ -607,7 +608,8 @@ async function discoverWorkspace(cwd) {
607
608
  const synthetic = createUnavailableManifest(pkg.name, err);
608
609
  return {
609
610
  manifests: [synthetic],
610
- source: "workspace",
611
+ source,
612
+ scope,
611
613
  packageName: pkg.name,
612
614
  manifestPath: toPosixPath(manifestPath),
613
615
  pkgRoot: toPosixPath(pkgRoot)
@@ -641,6 +643,9 @@ async function discoverCurrentPackage(cwd) {
641
643
  return {
642
644
  manifests,
643
645
  source: "workspace",
646
+ // Current-package fallback fires in installed mode when the user's
647
+ // project itself exposes a manifest. That maps to the project scope.
648
+ scope: "project",
644
649
  packageName: pkg.name,
645
650
  manifestPath: toPosixPath(manifestInfo.path),
646
651
  pkgRoot: toPosixPath(cwd)
@@ -745,6 +750,10 @@ async function discoverNodeModules(cwd) {
745
750
  return {
746
751
  manifests,
747
752
  source: isLinked ? "linked" : "node_modules",
753
+ // node_modules discovery runs at the platform root. In dev mode
754
+ // platformRoot === projectRoot so either label is correct; we use
755
+ // platform to reflect where the manifest physically lives.
756
+ scope: "platform",
748
757
  packageName: pkg.name,
749
758
  manifestPath: toPosixPath(manifestPath),
750
759
  pkgRoot: toPosixPath(pkgRoot)
@@ -764,6 +773,7 @@ async function discoverNodeModules(cwd) {
764
773
  return {
765
774
  manifests: [synthetic],
766
775
  source: isLinked ? "linked" : "node_modules",
776
+ scope: "platform",
767
777
  packageName: pkg.name,
768
778
  manifestPath: toPosixPath(manifestPath),
769
779
  pkgRoot: toPosixPath(pkgRoot)
@@ -795,17 +805,35 @@ function deduplicateManifests(all) {
795
805
  const existing = byPackageName.get(result.packageName);
796
806
  if (!existing) {
797
807
  byPackageName.set(result.packageName, result);
798
- } else {
799
- const existingPriority = priority[existing.source] || 0;
800
- const newPriority = priority[result.source] || 0;
801
- if (newPriority > existingPriority) {
802
- byPackageName.set(result.packageName, result);
808
+ continue;
809
+ }
810
+ if (existing.scope !== result.scope) {
811
+ if (existing.pkgRoot === result.pkgRoot) {
812
+ const projectEntry = existing.scope === "project" ? existing : result;
813
+ byPackageName.set(result.packageName, projectEntry);
814
+ continue;
803
815
  }
816
+ const winner = existing.scope === "platform" ? existing : result;
817
+ const loser = existing.scope === "platform" ? result : existing;
818
+ log("warn", JSON.stringify({
819
+ code: "DISCOVERY_SCOPE_COLLISION",
820
+ packageName: result.packageName,
821
+ platformPath: winner.pkgRoot,
822
+ projectPath: loser.pkgRoot,
823
+ message: "Package exists in both platform and project scopes \u2014 platform wins."
824
+ }));
825
+ byPackageName.set(result.packageName, winner);
826
+ continue;
827
+ }
828
+ const existingPriority = priority[existing.source] ?? 0;
829
+ const newPriority = priority[result.source] ?? 0;
830
+ if (newPriority > existingPriority) {
831
+ byPackageName.set(result.packageName, result);
804
832
  }
805
833
  }
806
834
  return Array.from(byPackageName.values());
807
835
  }
808
- async function loadCache(cwd) {
836
+ async function loadCache(cwd, roots) {
809
837
  const cachePath = path2.join(cwd, ".kb", "cache", "cli-manifests.json");
810
838
  try {
811
839
  const content = await promises.readFile(cachePath, "utf8");
@@ -842,11 +870,26 @@ async function loadCache(cwd) {
842
870
  log("debug", "Cache invalidated: .kb/plugins.json changed");
843
871
  return null;
844
872
  }
845
- const currentMarketplaceLockHash = await computeMarketplaceLockHash(cwd);
846
- if (currentMarketplaceLockHash && cache.marketplaceLockHash && cache.marketplaceLockHash !== currentMarketplaceLockHash) {
847
- log("debug", "Cache invalidated: .kb/marketplace.lock changed");
873
+ if (cache.platformRoot && cache.platformRoot !== roots.platformRoot) {
874
+ log("debug", `Cache invalidated: platformRoot changed (${cache.platformRoot} \u2192 ${roots.platformRoot})`);
875
+ return null;
876
+ }
877
+ if (cache.projectRoot && cache.projectRoot !== roots.projectRoot) {
878
+ log("debug", `Cache invalidated: projectRoot changed (${cache.projectRoot} \u2192 ${roots.projectRoot})`);
879
+ return null;
880
+ }
881
+ const currentPlatformLockHash = await computeMarketplaceLockHashAt(roots.platformRoot);
882
+ if (currentPlatformLockHash && cache.platformMarketplaceLockHash && cache.platformMarketplaceLockHash !== currentPlatformLockHash) {
883
+ log("debug", `Cache invalidated: ${roots.platformRoot}/.kb/marketplace.lock changed`);
848
884
  return null;
849
885
  }
886
+ if (roots.projectRoot !== roots.platformRoot) {
887
+ const currentProjectLockHash = await computeMarketplaceLockHashAt(roots.projectRoot);
888
+ if (currentProjectLockHash && cache.projectMarketplaceLockHash && cache.projectMarketplaceLockHash !== currentProjectLockHash) {
889
+ log("debug", `Cache invalidated: ${roots.projectRoot}/.kb/marketplace.lock changed`);
890
+ return null;
891
+ }
892
+ }
850
893
  const parsedCache = cache;
851
894
  parsedCache.ttlMs = parsedCache.ttlMs ?? DISK_CACHE_TTL_MS;
852
895
  for (const entry of Object.values(parsedCache.packages)) {
@@ -898,7 +941,7 @@ async function isPackageCacheStale(entry, options) {
898
941
  }
899
942
  return false;
900
943
  }
901
- async function saveCache(cwd, results) {
944
+ async function saveCache(cwd, results, roots) {
902
945
  const cachePath = path2.join(cwd, ".kb", "cache", "cli-manifests.json");
903
946
  await promises.mkdir(path2.dirname(cachePath), { recursive: true });
904
947
  const packages = {};
@@ -944,7 +987,8 @@ async function saveCache(cwd, results) {
944
987
  const lockfileHash = await computeLockfileHash(cwd);
945
988
  const configHash = await computeConfigHash(cwd);
946
989
  const pluginsStateHash = await computePluginsStateHash(cwd);
947
- const marketplaceLockHash = await computeMarketplaceLockHash(cwd);
990
+ const platformMarketplaceLockHash = await computeMarketplaceLockHashAt(roots.platformRoot);
991
+ const projectMarketplaceLockHash = roots.projectRoot !== roots.platformRoot ? await computeMarketplaceLockHashAt(roots.projectRoot) : "";
948
992
  if (lockfileHash) {
949
993
  stateHasher.update(lockfileHash);
950
994
  }
@@ -954,9 +998,14 @@ async function saveCache(cwd, results) {
954
998
  if (pluginsStateHash) {
955
999
  stateHasher.update(pluginsStateHash);
956
1000
  }
957
- if (marketplaceLockHash) {
958
- stateHasher.update(marketplaceLockHash);
1001
+ if (platformMarketplaceLockHash) {
1002
+ stateHasher.update(platformMarketplaceLockHash);
1003
+ }
1004
+ if (projectMarketplaceLockHash) {
1005
+ stateHasher.update(projectMarketplaceLockHash);
959
1006
  }
1007
+ stateHasher.update(roots.platformRoot);
1008
+ stateHasher.update(roots.projectRoot);
960
1009
  const cache = {
961
1010
  version: process.version,
962
1011
  cliVersion: process.env.CLI_VERSION || "0.1.0",
@@ -966,7 +1015,10 @@ async function saveCache(cwd, results) {
966
1015
  lockfileHash: lockfileHash || void 0,
967
1016
  configHash: configHash || void 0,
968
1017
  pluginsStateHash: pluginsStateHash || void 0,
969
- marketplaceLockHash: marketplaceLockHash || void 0,
1018
+ platformMarketplaceLockHash: platformMarketplaceLockHash || void 0,
1019
+ projectMarketplaceLockHash: projectMarketplaceLockHash || void 0,
1020
+ platformRoot: roots.platformRoot,
1021
+ projectRoot: roots.projectRoot,
970
1022
  packages
971
1023
  };
972
1024
  try {
@@ -978,6 +1030,9 @@ async function saveCache(cwd, results) {
978
1030
  async function discoverManifests(cwd, noCache = false, options = {}) {
979
1031
  const startTime = Date.now();
980
1032
  const timings = {};
1033
+ const platformRoot = options.platformRoot ?? cwd;
1034
+ const projectRoot = options.projectRoot ?? cwd;
1035
+ const roots = { platformRoot, projectRoot };
981
1036
  if (noCache) {
982
1037
  inProcDiscoveryCache = null;
983
1038
  } else if (inProcDiscoveryCache) {
@@ -994,7 +1049,7 @@ async function discoverManifests(cwd, noCache = false, options = {}) {
994
1049
  }
995
1050
  if (!noCache) {
996
1051
  const cacheStart = Date.now();
997
- const cached = await loadCache(cwd);
1052
+ const cached = await loadCache(cwd, roots);
998
1053
  timings.cacheLoad = Date.now() - cacheStart;
999
1054
  if (cached) {
1000
1055
  log("debug", "Using cached manifests");
@@ -1037,7 +1092,7 @@ async function discoverManifests(cwd, noCache = false, options = {}) {
1037
1092
  let workspace = [];
1038
1093
  try {
1039
1094
  const wsStart = Date.now();
1040
- workspace = await discoverWorkspace(cwd);
1095
+ workspace = await discoverWorkspace(platformRoot);
1041
1096
  timings.workspace = Date.now() - wsStart;
1042
1097
  log("info", `Discovered ${workspace.length} workspace packages with CLI manifests`);
1043
1098
  } catch (_err) {
@@ -1051,17 +1106,22 @@ async function discoverManifests(cwd, noCache = false, options = {}) {
1051
1106
  }
1052
1107
  }
1053
1108
  const nmStart = Date.now();
1054
- const nodeModulesRoot = options.platformRoot ?? cwd;
1055
- const installed = await discoverNodeModules(nodeModulesRoot);
1109
+ const installed = await discoverNodeModules(platformRoot);
1056
1110
  timings.nodeModules = Date.now() - nmStart;
1057
1111
  if (installed.length > 0) {
1058
1112
  log("info", `Discovered ${installed.length} installed packages with CLI manifests`);
1059
1113
  }
1114
+ const plStart = Date.now();
1115
+ const projectLocal = await discoverProjectLocalPlugins(projectRoot);
1116
+ timings.projectLocal = Date.now() - plStart;
1117
+ if (projectLocal.length > 0) {
1118
+ log("info", `Discovered ${projectLocal.length} project-local plugins`);
1119
+ }
1060
1120
  const dedupStart = Date.now();
1061
- const results = deduplicateManifests([...workspace, ...installed]);
1121
+ const results = deduplicateManifests([...workspace, ...installed, ...projectLocal]);
1062
1122
  timings.deduplicate = Date.now() - dedupStart;
1063
1123
  const saveStart = Date.now();
1064
- await saveCache(cwd, results);
1124
+ await saveCache(cwd, results, roots);
1065
1125
  timings.cacheSave = Date.now() - saveStart;
1066
1126
  const totalTime = Date.now() - startTime;
1067
1127
  const sourceCounts = results.reduce((acc, r) => {