@skill-map/cli 0.41.0 → 0.42.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.
@@ -1975,9 +1975,80 @@ type TProviderKindIcon = {
1975
1975
  kind: 'svg';
1976
1976
  path: string;
1977
1977
  };
1978
+ /**
1979
+ * Presentation contract for the Provider's OWN identity, distinct from
1980
+ * its per-kind visuals (`IProviderKindUi`). Drives the active-lens
1981
+ * dropdown label, the topbar lens chip, and the per-node provider chip
1982
+ * on cards. Reaches the UI via the `providerRegistry` field embedded in
1983
+ * REST envelopes (sibling of `kindRegistry`). Unlike kind colors
1984
+ * (normalised across Providers so every `agent` paints the same),
1985
+ * Provider colors are deliberately distinct so the chip tells the user
1986
+ * at a glance which platform a node came from. Mirrors
1987
+ * `spec/schemas/extensions/provider.schema.json#/properties/ui`.
1988
+ */
1989
+ interface IProviderUi {
1990
+ /**
1991
+ * Human-readable Provider name shown in the lens dropdown, the topbar
1992
+ * lens chip, and the per-node provider chip (e.g. `'Claude'`,
1993
+ * `'OpenAI Codex'`, `'Antigravity'`, `'Open Skills'`, `'Markdown'`).
1994
+ */
1995
+ label: string;
1996
+ /** Base hex color (`#RRGGBB`) for the light-theme provider chip. */
1997
+ color: string;
1998
+ /** Optional dark-theme variant of `color`. Falls back to `color`. */
1999
+ colorDark?: string;
2000
+ /** Optional decorative emoji fallback when `icon` is absent. */
2001
+ emoji?: string;
2002
+ /** Optional discriminated icon descriptor (preferred over `emoji`). */
2003
+ icon?: TProviderKindIcon;
2004
+ /**
2005
+ * When `true`, the UI does NOT paint this Provider's chip on node
2006
+ * cards. Reserved for the universal `markdown` fallback (carried by
2007
+ * the majority of nodes, so badging every generic `.md` would be
2008
+ * noise). The Provider still appears in the lens dropdown and the
2009
+ * topbar lens chip; only the per-card badge is suppressed.
2010
+ */
2011
+ hideChip?: boolean;
2012
+ }
2013
+ /**
2014
+ * Auto-detection markers for the active-provider lens. The lens resolver
2015
+ * checks each marker path (relative to the scope root) and, when present,
2016
+ * suggests this Provider as a candidate lens. Replaces the former
2017
+ * hardcoded detection table: the detectable set now derives from the
2018
+ * registered Providers. Mirrors
2019
+ * `spec/schemas/extensions/provider.schema.json#/properties/detect`.
2020
+ */
2021
+ interface IProviderDetect {
2022
+ /**
2023
+ * Paths relative to the scope root whose existence signals this
2024
+ * Provider's presence (e.g. `['.claude']`, `['.codex', 'AGENTS.md']`).
2025
+ * A directory or a file both count; existence is the only test.
2026
+ */
2027
+ markers: string[];
2028
+ }
1978
2029
  interface IProvider extends IExtensionBase {
1979
2030
  /** Discriminant injected by the loader from the folder structure. */
1980
2031
  kind: 'provider';
2032
+ /**
2033
+ * Presentation metadata for the Provider's own identity (lens dropdown
2034
+ * label, topbar lens chip, per-node provider chip). Required so the UI
2035
+ * never hardcodes a closed provider list: it reads every registered
2036
+ * Provider's identity from the `providerRegistry` envelope field.
2037
+ * Distinct from `kinds[*].ui` (per-kind node visuals).
2038
+ *
2039
+ * Named `presentation`, NOT `ui`: the base `IExtensionBase.ui` field is
2040
+ * the view-contributions map (`Record<string, IViewContribution>`,
2041
+ * declared only by `extractor` / `analyzer` kinds). Providers leave that
2042
+ * inherited field undefined and carry their identity here instead.
2043
+ */
2044
+ presentation: IProviderUi;
2045
+ /**
2046
+ * Optional auto-detection markers for the active-provider lens. When
2047
+ * present, the lens resolver auto-suggests this Provider if any marker
2048
+ * path exists under the scope root. Absent means the Provider is never
2049
+ * auto-suggested (it can still be selected manually).
2050
+ */
2051
+ detect?: IProviderDetect;
1981
2052
  /**
1982
2053
  * Catalog of node kinds this Provider emits. Populated by the loader
1983
2054
  * from the `<plugin>/kinds/<kindName>/` directory layout: each subfolder
@@ -101,7 +101,7 @@ import cl100k_base from "js-tiktoken/ranks/cl100k_base";
101
101
  // package.json
102
102
  var package_default = {
103
103
  name: "@skill-map/cli",
104
- version: "0.41.0",
104
+ version: "0.42.0",
105
105
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
106
106
  license: "MIT",
107
107
  type: "module",
@@ -1050,21 +1050,8 @@ function loadConfigForScope(opts) {
1050
1050
  }
1051
1051
 
1052
1052
  // core/config/active-provider.ts
1053
- var DETECTION_RULES = [
1054
- { providerId: "claude", marker: ".claude" },
1055
- // `gemini` retired 2026-05-22: Google replaced the Gemini CLI with the
1056
- // Antigravity CLI (released 2026-05-19; Gemini CLI sunsets 2026-06-18).
1057
- // Antigravity adopted the open-standard `.agents/` instead of a
1058
- // vendor-specific directory, so detection of a Google CLI project
1059
- // falls through to the universal `agent-skills` lens (`.agents/`
1060
- // already classifies via that neutral provider). The lens can still
1061
- // be set manually via `sm config set activeProvider antigravity`.
1062
- { providerId: "openai", marker: ".codex" },
1063
- { providerId: "openai", marker: "AGENTS.md" },
1064
- { providerId: "cursor", marker: ".cursor" }
1065
- ];
1066
- function resolveActiveProvider(cwd) {
1067
- const detected = detectProvidersFromFilesystem(cwd);
1053
+ function resolveActiveProvider(cwd, providers = []) {
1054
+ const detected = detectProvidersFromFilesystem(cwd, providers);
1068
1055
  const fromConfig = readConfigValue("activeProvider", { cwd });
1069
1056
  if (typeof fromConfig === "string" && fromConfig.length > 0) {
1070
1057
  return { resolved: fromConfig, source: "config", detected };
@@ -1074,14 +1061,16 @@ function resolveActiveProvider(cwd) {
1074
1061
  }
1075
1062
  return { resolved: null, source: "none", detected };
1076
1063
  }
1077
- function detectProvidersFromFilesystem(cwd) {
1064
+ function detectProvidersFromFilesystem(cwd, providers) {
1078
1065
  const seen = /* @__PURE__ */ new Set();
1079
1066
  const out = [];
1080
- for (const rule of DETECTION_RULES) {
1081
- if (seen.has(rule.providerId)) continue;
1082
- if (!existsSync5(join6(cwd, rule.marker))) continue;
1083
- seen.add(rule.providerId);
1084
- out.push(rule.providerId);
1067
+ for (const provider of providers) {
1068
+ if (seen.has(provider.id)) continue;
1069
+ const markers = provider.detect?.markers;
1070
+ if (!markers || markers.length === 0) continue;
1071
+ if (!markers.some((marker) => existsSync5(join6(cwd, marker)))) continue;
1072
+ seen.add(provider.id);
1073
+ out.push(provider.id);
1085
1074
  }
1086
1075
  return out;
1087
1076
  }
@@ -3152,7 +3141,11 @@ async function runScanInternal(_kernel, options) {
3152
3141
  const scanStartedEvent = makeEvent("scan.started", { roots: options.roots });
3153
3142
  emitter.emit(scanStartedEvent);
3154
3143
  await hookDispatcher.dispatch("scan.started", scanStartedEvent);
3155
- const activeProviderId = resolveActiveProviderOption(options.activeProvider, options.roots);
3144
+ const activeProviderId = resolveActiveProviderOption(
3145
+ options.activeProvider,
3146
+ options.roots,
3147
+ exts.providers
3148
+ );
3156
3149
  const walked = await walkAndExtract({
3157
3150
  providers: exts.providers,
3158
3151
  extractors: exts.extractors,
@@ -3361,12 +3354,12 @@ function validateRoots(roots) {
3361
3354
  }
3362
3355
  }
3363
3356
  }
3364
- function resolveActiveProviderOption(optionValue, roots) {
3357
+ function resolveActiveProviderOption(optionValue, roots, providers) {
3365
3358
  if (optionValue !== void 0) return optionValue;
3366
3359
  for (const root of roots) {
3367
3360
  const absRoot = isAbsolute4(root) ? root : resolve11(root);
3368
3361
  if (!existsSync11(absRoot)) continue;
3369
- const detected = resolveActiveProvider(absRoot).resolved;
3362
+ const detected = resolveActiveProvider(absRoot, providers).resolved;
3370
3363
  if (detected !== null) return detected;
3371
3364
  }
3372
3365
  return null;