@skill-map/cli 0.32.0 → 0.34.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.
@@ -501,7 +501,26 @@ interface IExtensionBase {
501
501
  */
502
502
  type NodeKind = 'skill' | 'agent' | 'command' | 'markdown';
503
503
  type LinkKind = 'invokes' | 'references' | 'mentions' | 'supersedes';
504
- type Confidence = 'high' | 'medium' | 'low';
504
+ /**
505
+ * Extractor's self-assessed confidence, normalized to `[0..1]`. Drives
506
+ * UI edge opacity in the graph view (more confident = more opaque edge).
507
+ * Migrated from the legacy `'high' | 'medium' | 'low'` string union to
508
+ * a numeric range so callers can express finer granularity than three
509
+ * buckets. The named tiers below (`ConfidenceTier`) preserve the
510
+ * legacy buckets as constants for callers that prefer bucket-thinking.
511
+ *
512
+ * Reference scoring (guideline, not contract):
513
+ *
514
+ * `1.0` structured input (sidecar `supersedes`)
515
+ * `0.95` unambiguous syntax (`[text](file.md)`, `https://…`)
516
+ * `0.85` strong signal with one inference (`@file.md`)
517
+ * `0.5` genuine ambiguity (`@bare-handle`)
518
+ *
519
+ * Validation: the orchestrator's `validateLink` rejects values outside
520
+ * `[0..1]` with an `extension.error` event, mirroring the LinkKind
521
+ * enum check. Missing confidence defaults to `ConfidenceTier.MEDIUM`.
522
+ */
523
+ type Confidence = number;
505
524
  type Severity = 'error' | 'warn' | 'info';
506
525
  type Stability = 'experimental' | 'stable' | 'deprecated';
507
526
  /**
@@ -569,6 +588,25 @@ interface Node {
569
588
  * truthy `isFavorite` only ever lands when the BFF set it.
570
589
  */
571
590
  isFavorite?: boolean;
591
+ /**
592
+ * When `true`, the node is synthetic / derived: it does not correspond
593
+ * to a single file on disk. Reconstructed on every scan from the
594
+ * file(s) listed in `derivedFrom`. Synthetic nodes use a non-filesystem
595
+ * path scheme (e.g. `mcp://github`) so the identifier is stable and
596
+ * visibly non-physical. See
597
+ * [`node.schema.json`](../../spec/schemas/node.schema.json) for the
598
+ * normative contract. Absent / `false` for ordinary filesystem-backed
599
+ * entities. Stability: experimental.
600
+ */
601
+ virtual?: boolean;
602
+ /**
603
+ * Paths of the source files this node was derived from. Required (and
604
+ * only meaningful) when `virtual === true`. Drives invalidation: any
605
+ * change to a listed source between scans propagates into the virtual
606
+ * node's hashes. Empty / absent when the node is a regular filesystem
607
+ * entity (the `path` itself is the source).
608
+ */
609
+ derivedFrom?: string[];
572
610
  }
573
611
  /**
574
612
  * Drift status of a co-located `.sm` sidecar relative to the live
@@ -621,6 +659,83 @@ interface Link {
621
659
  location?: LinkLocation | null;
622
660
  raw?: string | null;
623
661
  }
662
+ /**
663
+ * Scope of a `Signal` within its originating node. Mirrors
664
+ * `signal.schema.json#/properties/scope`.
665
+ *
666
+ * - `body` = markdown body or equivalent prose payload.
667
+ * - `frontmatter` = parsed metadata block at the top of the file.
668
+ * - `sidecar` = co-located `.sm` overlay.
669
+ */
670
+ type SignalScope = 'body' | 'frontmatter' | 'sidecar';
671
+ /**
672
+ * Surface context for a body-scope `Signal`. Mirrors
673
+ * `signal.schema.json#/properties/context/enum`. Null when the signal is in
674
+ * normal prose or when the context concept does not apply (frontmatter /
675
+ * sidecar scopes).
676
+ */
677
+ type SignalContext = 'code-block' | 'inline-code' | 'escaped';
678
+ /**
679
+ * Byte-range location for a body-scope `Signal`. `start` is inclusive,
680
+ * `end` is exclusive (one past the last char).
681
+ */
682
+ interface SignalRange {
683
+ start: number;
684
+ end: number;
685
+ }
686
+ /**
687
+ * One alternative interpretation of a `Signal`. The resolver picks the
688
+ * winning candidate per Signal and materialises it as a `Link`; the
689
+ * rejected candidates remain on `IAnalyzerContext.signals` for
690
+ * collision-detection and conflict-visualisation analyzers.
691
+ *
692
+ * `confidence` is numeric `[0..1]`, identical shape to the `Link`'s
693
+ * `Confidence` type after the Phase 4 migration. No conversion needed
694
+ * when the resolver materialises a winning candidate.
695
+ */
696
+ interface SignalCandidate {
697
+ extractorId: string;
698
+ kind: LinkKind;
699
+ target: string;
700
+ /** `[0..1]`. Reference scoring guideline lives in `signal.schema.json`. */
701
+ confidence: number;
702
+ rationale?: string;
703
+ trigger?: LinkTrigger | null;
704
+ }
705
+ /**
706
+ * Intermediate Representation (IR) emitted by extractors via
707
+ * `ctx.emitSignal(signal)`. The kernel's resolver phase consumes
708
+ * `Signal[]` and produces final `Link[]` per the active Provider's
709
+ * `resolverRules`. Opt-in: extractors with unambiguous detections keep
710
+ * using `ctx.emitLink(link)` directly. See
711
+ * [`signal.schema.json`](../../spec/schemas/signal.schema.json) for the
712
+ * normative contract.
713
+ */
714
+ interface Signal {
715
+ /** `node.path` of the originating node. */
716
+ source: string;
717
+ scope: SignalScope;
718
+ /**
719
+ * Byte-range location within the source. Required for `scope: 'body'`,
720
+ * optional otherwise. Powers collision detection between extractors
721
+ * (overlapping ranges) and code-block awareness (the orchestrator can
722
+ * mark ranges that fall inside code spans).
723
+ */
724
+ range?: SignalRange | null;
725
+ /**
726
+ * Structured-data location for `frontmatter` / `sidecar` scopes. Each
727
+ * entry is a step of the path: object keys are strings, array indices
728
+ * are integers serialised as strings. Example: `['tools', '0']`. Null
729
+ * for body scope or when the extractor does not track field locations.
730
+ */
731
+ fieldPath?: string[] | null;
732
+ /** Verbatim matched text (body) or stringified value (frontmatter / sidecar). */
733
+ raw: string;
734
+ /** Surface context. Null when in normal prose or when not applicable. */
735
+ context?: SignalContext | null;
736
+ /** One or more alternative interpretations. At least one. */
737
+ candidates: SignalCandidate[];
738
+ }
624
739
  interface IssueFix {
625
740
  summary?: string;
626
741
  autofixable?: boolean;
@@ -1828,6 +1943,36 @@ interface IProviderReadConfig {
1828
1943
  * Confidence is per-emit (no manifest-level default).
1829
1944
  */
1830
1945
 
1946
+ /**
1947
+ * Payload accepted by `IExtractorCallbacks.emitNode`. A loose subset of
1948
+ * `Node` because the kernel fills the rest from the emission context:
1949
+ *
1950
+ * - `bodyHash`, `frontmatterHash` are computed from `derivedFrom` (the
1951
+ * hash of the sources concatenated in declared order, so the
1952
+ * virtual node's hashes drift when any source changes).
1953
+ * - `bytes`, `linksOutCount`, `linksInCount`, `externalRefsCount`
1954
+ * default to zero counts on emission; the orchestrator's
1955
+ * post-extraction recompute pass fills them in once links resolve.
1956
+ *
1957
+ * The emitter MUST supply `path` (canonical id), `kind` (registered in
1958
+ * a Provider's catalog), `derivedFrom` (one or more existing-node paths
1959
+ * the virtual node is derived from), and SHOULD supply `frontmatter`
1960
+ * with the metadata the UI / analyzers will surface.
1961
+ */
1962
+ interface IEmittedNode {
1963
+ /** Synthetic identifier. Use a non-filesystem scheme (`mcp://`, etc). */
1964
+ path: string;
1965
+ /** Kind declared in some Provider's `kinds` catalog. */
1966
+ kind: string;
1967
+ /** Required for virtual nodes: paths of the source(s). */
1968
+ derivedFrom: string[];
1969
+ /** Always true on this surface; the kernel mirrors it to `Node.virtual`. */
1970
+ virtual: true;
1971
+ /** Provider id the node is attributed to (e.g. `'claude'`). */
1972
+ provider: string;
1973
+ /** Optional structured metadata the UI / analyzers read. */
1974
+ frontmatter?: Record<string, unknown>;
1975
+ }
1831
1976
  /**
1832
1977
  * Output callbacks supplied by the kernel on the extractor context.
1833
1978
  */
@@ -1839,6 +1984,35 @@ interface IExtractorCallbacks {
1839
1984
  * `extension.error` event.
1840
1985
  */
1841
1986
  emitLink(link: Link): void;
1987
+ /**
1988
+ * Emit a multi-candidate `Signal` for the kernel's resolver phase to
1989
+ * collapse into a single Link (or reject). Use this instead of
1990
+ * `emitLink` when the detection carries genuine ambiguity (multiple
1991
+ * plausible kinds / targets), needs byte-range awareness for
1992
+ * collision detection, or needs numeric confidence with
1993
+ * sub-tier granularity. Unambiguous detectors should keep using
1994
+ * `emitLink` directly. See
1995
+ * [`signal.schema.json`](../../../spec/schemas/signal.schema.json) for the
1996
+ * normative contract. Validated against the same closed kind enum;
1997
+ * off-spec Signals (no candidates, off-enum kind, confidence outside
1998
+ * `[0..1]`) drop silently with an `extension.error` event.
1999
+ */
2000
+ emitSignal(signal: Signal): void;
2001
+ /**
2002
+ * Phase 5, emit a synthetic / virtual `Node` derived from the
2003
+ * scanning context (frontmatter, sidecar, config). Used by the
2004
+ * `core/mcp-tools` extractor to materialise an `mcp://<name>` node
2005
+ * out of a `tools: [mcp__<name>__*]` frontmatter entry, and by the
2006
+ * future Cursor / Codex MCP-config extractors that walk
2007
+ * `.cursor/mcp.json` / `~/.codex/config.toml`. The kernel
2008
+ * deduplicates by `node.path` against the walker's nodes AND across
2009
+ * extractor emissions: the FIRST emission of a given path wins,
2010
+ * subsequent emissions are silently ignored (idempotent semantics so
2011
+ * N skills referencing the same MCP collapse into one node). Emitted
2012
+ * nodes carry `virtual: true` and `derivedFrom: [...]` per
2013
+ * [`node.schema.json`](../../../spec/schemas/node.schema.json).
2014
+ */
2015
+ emitNode(node: IEmittedNode): void;
1842
2016
  /**
1843
2017
  * Merge canonical, kernel-curated properties onto the current node's
1844
2018
  * enrichment layer. The author-supplied frontmatter stays untouched
@@ -2004,6 +2178,18 @@ interface IAnalyzerContext {
2004
2178
  * absolute path when present.
2005
2179
  */
2006
2180
  cwd?: string;
2181
+ /**
2182
+ * Signals emitted by extractors during the scan, before the resolver
2183
+ * collapsed them into `links`. Populated when at least one extractor
2184
+ * opted into the Signal IR path (`ctx.emitSignal` in
2185
+ * `IExtractorCallbacks`). Empty / absent when every extractor used
2186
+ * `emitLink` directly (legacy and unambiguous paths). Treat as
2187
+ * read-only. Analyzers consume this for collision detection
2188
+ * (overlapping `range` from different extractors), fragmentation
2189
+ * detection, and conflict-visualisation; the resolved `links` remain
2190
+ * the source of truth for graph-level analyses.
2191
+ */
2192
+ signals?: readonly Signal[];
2007
2193
  /**
2008
2194
  * Emit a per-node view contribution declared in this analyzer's
2009
2195
  * manifest `viewContributions` map. Sync, void return; the
@@ -2489,6 +2675,8 @@ declare function runExtractorsForNode(opts: {
2489
2675
  externalLinks: Link[];
2490
2676
  enrichments: IEnrichmentRecord[];
2491
2677
  contributions: IContributionRecord[];
2678
+ signals: Signal[];
2679
+ virtualNodes: Node[];
2492
2680
  }>;
2493
2681
 
2494
2682
  /**
@@ -2508,7 +2696,14 @@ declare function runExtractorsForNode(opts: {
2508
2696
  interface RenameOp {
2509
2697
  from: string;
2510
2698
  to: string;
2511
- confidence: 'high' | 'medium';
2699
+ /**
2700
+ * Rename-heuristic confidence as a numeric tier. Body-hash matches
2701
+ * use `ConfidenceTier.HIGH` (`0.9`); frontmatter-hash matches use
2702
+ * `ConfidenceTier.MEDIUM` (`0.6`). Consumers that surface the tier
2703
+ * as a string (e.g. issue analyzerId `auto-rename-<tier>`) call
2704
+ * `renameTierLabel(confidence)` to recover the legacy label.
2705
+ */
2706
+ confidence: number;
2512
2707
  }
2513
2708
  /**
2514
2709
  * Pure rename / orphan classification per `spec/db-schema.md` §Rename
@@ -2524,7 +2719,7 @@ interface RenameOp {
2524
2719
  * 2. **Medium-confidence (1:1)**: of the remaining deletions, pair
2525
2720
  * each with the *unique* unclaimed `newPath` that shares its
2526
2721
  * `frontmatterHash`. Emits `auto-rename-medium` (severity warn)
2527
- * with `data: { from, to, confidence: 'medium' }`.
2722
+ * with `data: { from, to, confidence: ConfidenceTier.MEDIUM }`.
2528
2723
  * 3. **Ambiguous (N:1)**: when a single `newPath` has more than one
2529
2724
  * remaining frontmatter-matching candidate, emit ONE
2530
2725
  * `auto-rename-ambiguous` issue per `newPath`, listing all
@@ -2774,6 +2969,25 @@ interface RunScanOptions {
2774
2969
  * concept (out-of-band tests, embedders).
2775
2970
  */
2776
2971
  cwd?: string;
2972
+ /**
2973
+ * Active provider lens for this scan, gating provider-specific
2974
+ * extractors against both the node's provider AND the lens (per
2975
+ * `spec/architecture.md` §Universal extractors and per-provider
2976
+ * extractors). Three interpretations:
2977
+ *
2978
+ * - `string`: explicit lens. Provider-specific extractors run only
2979
+ * when their declared `precondition.provider` includes BOTH this
2980
+ * value AND the node's provider.
2981
+ * - `null`: explicit "no lens". Provider-specific extractors are
2982
+ * unconditionally skipped (spec-strict).
2983
+ * - `undefined`: kernel auto-detects from `options.roots[0]` using
2984
+ * filesystem markers (`.claude/`, `.gemini/`, `.codex/`,
2985
+ * `AGENTS.md`). Convenient default for out-of-band callers
2986
+ * (integration tests, embedders) that don't thread a settings
2987
+ * reader. Production callers (scan-runner) resolve upstream and
2988
+ * pass `string | null` explicitly, never `undefined`.
2989
+ */
2990
+ activeProvider?: string | null;
2777
2991
  }
2778
2992
  /**
2779
2993
  * Same as `runScan` but also returns the rename heuristic's `RenameOp[]`