@skill-map/cli 0.34.1 → 0.36.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/README.md +1 -1
- package/dist/cli/tutorial/sm-master/SKILL.md +12 -14
- package/dist/cli/tutorial/sm-master/references/fixture-templates.md +10 -9
- package/dist/cli/tutorial/sm-master/references/tour-plugins.md +3 -3
- package/dist/cli/tutorial/sm-tutorial/SKILL.md +47 -41
- package/dist/cli.js +457 -243
- package/dist/cli.js.map +1 -1
- package/dist/index.js +178 -48
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +120 -3
- package/dist/kernel/index.js +178 -48
- package/dist/kernel/index.js.map +1 -1
- package/dist/ui/{chunk-K3VXQ5PI.js → chunk-GQ5YNA5Q.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/ui/{main-OQDTVVQA.js → main-MGFSWAOX.js} +1 -1
- package/package.json +2 -2
package/dist/kernel/index.d.ts
CHANGED
|
@@ -1742,7 +1742,42 @@ interface IProviderKind {
|
|
|
1742
1742
|
* invent visuals for a Provider-declared kind.
|
|
1743
1743
|
*/
|
|
1744
1744
|
ui: IProviderKindUi;
|
|
1745
|
+
/**
|
|
1746
|
+
* Priority-ordered list of identifier sources the post-walk resolver
|
|
1747
|
+
* uses to derive this kind's canonical name(s). Each entry contributes
|
|
1748
|
+
* one normalized name to the name index built by
|
|
1749
|
+
* `liftResolvedLinkConfidence`; multiple sources accumulate (e.g. a
|
|
1750
|
+
* skill with `name: foo` AND dirname `foo` yields one entry, a skill
|
|
1751
|
+
* with `name: bar` and dirname `foo` yields two).
|
|
1752
|
+
*
|
|
1753
|
+
* Defaults to `[]` (no name-resolvable). Source semantics:
|
|
1754
|
+
*
|
|
1755
|
+
* - `'frontmatter.name'`, read `node.frontmatter.name`. Required-name
|
|
1756
|
+
* kinds (`agent`, `command`, `skill` per their schemas) typically
|
|
1757
|
+
* declare this first.
|
|
1758
|
+
* - `'filename-basename'`, `basename(path)` without the extension.
|
|
1759
|
+
* For Claude/OpenAI agents and commands the filename IS the
|
|
1760
|
+
* invocation handle when `name:` is absent.
|
|
1761
|
+
* - `'dirname'`, `basename(dirname(path))`. Anthropic skills +
|
|
1762
|
+
* agent-skills (open standard, also adopted by Antigravity)
|
|
1763
|
+
* resolve to the directory between the skills root and the
|
|
1764
|
+
* SKILL.md (e.g. `.claude/skills/foo/SKILL.md` → `foo`).
|
|
1765
|
+
*
|
|
1766
|
+
* Compare with `IProvider.resolution` (which declares which target
|
|
1767
|
+
* kinds resolve which link.kind): `identifiers` is a per-kind detail
|
|
1768
|
+
* about WHERE the name lives; `resolution` is a per-provider strict
|
|
1769
|
+
* matrix about WHICH kinds count as resolution for a given link.kind.
|
|
1770
|
+
*/
|
|
1771
|
+
identifiers?: TIdentifierSource[];
|
|
1745
1772
|
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Sources the post-walk confidence-lift transform consults to derive a
|
|
1775
|
+
* node's canonical name. Closed set: extending it is a spec + kernel
|
|
1776
|
+
* change. Order is meaningful inside `IProviderKind.identifiers`, the
|
|
1777
|
+
* resolver visits sources in declaration order, but the resulting index
|
|
1778
|
+
* is presence-based so multiple matches collapse.
|
|
1779
|
+
*/
|
|
1780
|
+
type TIdentifierSource = 'frontmatter.name' | 'filename-basename' | 'dirname';
|
|
1746
1781
|
/**
|
|
1747
1782
|
* Presentation contract for one Provider kind. The Provider declares
|
|
1748
1783
|
* intent (label + base color, optional dark variant + emoji + icon);
|
|
@@ -1895,13 +1930,80 @@ interface IProvider extends IExtensionBase {
|
|
|
1895
1930
|
* orchestrator drops the duplicate.
|
|
1896
1931
|
*
|
|
1897
1932
|
* Convention: a Provider's classify returns one of its own `kinds`
|
|
1898
|
-
* map keys for paths in its territory (`.claude/`, `.
|
|
1933
|
+
* map keys for paths in its territory (`.claude/`, `.codex/`,
|
|
1899
1934
|
* `.agents/skills/`, etc.) and `null` elsewhere. External Providers
|
|
1900
1935
|
* (Cursor, Obsidian, …) follow the same rule: claim what's yours,
|
|
1901
1936
|
* disclaim everything else. The orchestrator does not validate the
|
|
1902
1937
|
* kind against `NodeKind`.
|
|
1903
1938
|
*/
|
|
1904
1939
|
classify(path: string, frontmatter: Record<string, unknown>): string | null;
|
|
1940
|
+
/**
|
|
1941
|
+
* Strict resolution matrix consumed by the post-walk confidence-lift
|
|
1942
|
+
* transform: maps a `link.kind` (emitted by an Extractor in this
|
|
1943
|
+
* Provider's bundle, e.g. `'mentions'`, `'invokes'`) to the set of
|
|
1944
|
+
* target `node.kind` values that count as a valid resolution.
|
|
1945
|
+
*
|
|
1946
|
+
* Used to decide whether to bump a link's confidence to 1.0 when its
|
|
1947
|
+
* normalized trigger matches some node's identifier (see
|
|
1948
|
+
* `IProviderKind.identifiers`). A link whose name resolves to a node
|
|
1949
|
+
* whose kind is NOT in `resolution[link.kind]` stays at its
|
|
1950
|
+
* extractor-emitted confidence, the name exists but does not resolve
|
|
1951
|
+
* AS THIS link.kind. Example: in `claude`, `invokes` resolves to
|
|
1952
|
+
* `['command', 'skill']`, so a `/foo` slash matching an `agent` named
|
|
1953
|
+
* `foo` does not bump (agents are mentioned with `@`, not invoked
|
|
1954
|
+
* with `/`).
|
|
1955
|
+
*
|
|
1956
|
+
* The lookup uses the Provider id attached to the link's SOURCE node
|
|
1957
|
+
* (i.e. who wrote the trigger). A link sourced from a markdown body
|
|
1958
|
+
* outside any Provider's territory falls under `core/markdown`'s
|
|
1959
|
+
* empty rules, no bump applies via the name path (the path-match rule
|
|
1960
|
+
* still does).
|
|
1961
|
+
*
|
|
1962
|
+
* Default `undefined` ≡ empty map ≡ no link.kind bumps under this
|
|
1963
|
+
* Provider's name index. Path matches (`link.target === node.path`)
|
|
1964
|
+
* are unaffected, those always bump regardless of `resolution`.
|
|
1965
|
+
*
|
|
1966
|
+
* Distinct from the spec's `IProvider.resolverRules` (referenced in
|
|
1967
|
+
* §Resolver phase): `resolverRules` rank candidates inside the Signal
|
|
1968
|
+
* IR (Phase 3+, not wired today); `resolution` is the post-walk
|
|
1969
|
+
* confidence-lift contract, which runs against the merged Link graph.
|
|
1970
|
+
*/
|
|
1971
|
+
resolution?: Record<string, string[]>;
|
|
1972
|
+
/**
|
|
1973
|
+
* Reserved invocation names this Provider's runtime owns for each
|
|
1974
|
+
* kind. Maps a `node.kind` to the set of normalised names the runtime
|
|
1975
|
+
* uses for its built-in invocables (e.g. `claude` reserves
|
|
1976
|
+
* `['help', 'clear', 'init', …]` under `command` because typing
|
|
1977
|
+
* `/help` in the Claude CLI runs the built-in help screen, not a
|
|
1978
|
+
* user-authored `.claude/commands/help.md`).
|
|
1979
|
+
*
|
|
1980
|
+
* Two consumers share the catalog:
|
|
1981
|
+
*
|
|
1982
|
+
* 1. The `core/reserved-name` analyzer scans every user node and
|
|
1983
|
+
* emits a `warn` issue when the node's normalised identifiers
|
|
1984
|
+
* (per `IProviderKind.identifiers`) intersect the reserved list
|
|
1985
|
+
* for its provider + kind. The user file is silently shadowed
|
|
1986
|
+
* by the runtime, the analyzer surfaces it so the operator can
|
|
1987
|
+
* rename.
|
|
1988
|
+
* 2. The post-walk confidence-lift transform downgrades any link
|
|
1989
|
+
* that resolves to a reserved node (by path OR by name) to a
|
|
1990
|
+
* very low confidence floor (today `0.1`) instead of bumping
|
|
1991
|
+
* to `1.0`. The graph then reflects "this edge exists in disk
|
|
1992
|
+
* but the runtime ignores the target".
|
|
1993
|
+
*
|
|
1994
|
+
* Default `undefined` ≡ empty map ≡ no reserved names. Reserved
|
|
1995
|
+
* lookup normalises both sides via the §Extractor · trigger
|
|
1996
|
+
* normalization pipeline (lowercase, NFD, separator unification),
|
|
1997
|
+
* so a literal `Init-Project` in the manifest still matches a user
|
|
1998
|
+
* `name: init project` or filename `Init-Project.md`.
|
|
1999
|
+
*
|
|
2000
|
+
* The set is intentionally per-kind, not global: a name reserved for
|
|
2001
|
+
* commands (`/help`) may legitimately appear as a skill (a "help"
|
|
2002
|
+
* skill that triggers via something other than the command channel).
|
|
2003
|
+
* Providers MUST scope each entry to the kind the runtime actually
|
|
2004
|
+
* consumes.
|
|
2005
|
+
*/
|
|
2006
|
+
reservedNames?: Record<string, readonly string[]>;
|
|
1905
2007
|
}
|
|
1906
2008
|
/**
|
|
1907
2009
|
* Declarative read config a Provider declares via `IProvider.read`.
|
|
@@ -2167,6 +2269,21 @@ interface IAnalyzerContext {
|
|
|
2167
2269
|
* adapter does not maintain the side index. Treat as read-only.
|
|
2168
2270
|
*/
|
|
2169
2271
|
referenceablePaths?: ReadonlySet<string>;
|
|
2272
|
+
/**
|
|
2273
|
+
* Paths of nodes whose normalised identifier(s) intersect their
|
|
2274
|
+
* Provider's `reservedNames[kind]` catalog (e.g. a user-authored
|
|
2275
|
+
* `.claude/commands/help.md` whose name normalises to `help`,
|
|
2276
|
+
* shadowed by Claude's built-in `/help` command). The set is
|
|
2277
|
+
* computed once per scan by the orchestrator (mirroring the same
|
|
2278
|
+
* set threaded to the post-walk confidence-lift transform), so
|
|
2279
|
+
* analyzers consume it without re-deriving every node's
|
|
2280
|
+
* identifiers. The single consumer today is `core/reserved-name`,
|
|
2281
|
+
* which projects one warn issue per entry; future analyzers MAY
|
|
2282
|
+
* read the set for cross-rule cohesion (e.g. an action that
|
|
2283
|
+
* suggests rename targets). Absent for legacy callers (older
|
|
2284
|
+
* `runScan` sites that never wired the field through).
|
|
2285
|
+
*/
|
|
2286
|
+
reservedNodePaths?: ReadonlySet<string>;
|
|
2170
2287
|
/**
|
|
2171
2288
|
* Absolute path of the scan's project root (cwd of the invocation).
|
|
2172
2289
|
* Threaded into the analyzer pass so an analyzer that needs to
|
|
@@ -2981,8 +3098,8 @@ interface RunScanOptions {
|
|
|
2981
3098
|
* - `null`: explicit "no lens". Provider-specific extractors are
|
|
2982
3099
|
* unconditionally skipped (spec-strict).
|
|
2983
3100
|
* - `undefined`: kernel auto-detects from `options.roots[0]` using
|
|
2984
|
-
* filesystem markers (`.claude/`, `.
|
|
2985
|
-
*
|
|
3101
|
+
* filesystem markers (`.claude/`, `.codex/`, `AGENTS.md`).
|
|
3102
|
+
* Convenient default for out-of-band callers
|
|
2986
3103
|
* (integration tests, embedders) that don't thread a settings
|
|
2987
3104
|
* reader. Production callers (scan-runner) resolve upstream and
|
|
2988
3105
|
* pass `string | null` explicitly, never `undefined`.
|
package/dist/kernel/index.js
CHANGED
|
@@ -94,14 +94,14 @@ var Registry = class {
|
|
|
94
94
|
|
|
95
95
|
// kernel/orchestrator/index.ts
|
|
96
96
|
import { existsSync as existsSync11, statSync as statSync4 } from "fs";
|
|
97
|
-
import { isAbsolute as isAbsolute4, resolve as
|
|
97
|
+
import { isAbsolute as isAbsolute4, resolve as resolve11 } from "path";
|
|
98
98
|
import { Tiktoken as Tiktoken2 } from "js-tiktoken/lite";
|
|
99
99
|
import cl100k_base from "js-tiktoken/ranks/cl100k_base";
|
|
100
100
|
|
|
101
101
|
// package.json
|
|
102
102
|
var package_default = {
|
|
103
103
|
name: "@skill-map/cli",
|
|
104
|
-
version: "0.
|
|
104
|
+
version: "0.36.0",
|
|
105
105
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
106
106
|
license: "MIT",
|
|
107
107
|
type: "module",
|
|
@@ -1051,7 +1051,13 @@ function loadConfigForScope(opts) {
|
|
|
1051
1051
|
// core/config/active-provider.ts
|
|
1052
1052
|
var DETECTION_RULES = [
|
|
1053
1053
|
{ providerId: "claude", marker: ".claude" },
|
|
1054
|
-
|
|
1054
|
+
// `gemini` retired 2026-05-22: Google replaced the Gemini CLI with the
|
|
1055
|
+
// Antigravity CLI (released 2026-05-19; Gemini CLI sunsets 2026-06-18).
|
|
1056
|
+
// Antigravity adopted the open-standard `.agents/` instead of a
|
|
1057
|
+
// vendor-specific directory, so detection of a Google CLI project
|
|
1058
|
+
// falls through to the universal `agent-skills` lens (`.agents/`
|
|
1059
|
+
// already classifies via that neutral provider). The lens can still
|
|
1060
|
+
// be set manually via `sm config set activeProvider antigravity`.
|
|
1055
1061
|
{ providerId: "openai", marker: ".codex" },
|
|
1056
1062
|
{ providerId: "openai", marker: "AGENTS.md" },
|
|
1057
1063
|
{ providerId: "cursor", marker: ".cursor" }
|
|
@@ -1429,7 +1435,7 @@ function isExternalUrlLink(link) {
|
|
|
1429
1435
|
}
|
|
1430
1436
|
|
|
1431
1437
|
// kernel/orchestrator/analyzers.ts
|
|
1432
|
-
async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher) {
|
|
1438
|
+
async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths) {
|
|
1433
1439
|
const issues = [];
|
|
1434
1440
|
const contributions = [];
|
|
1435
1441
|
const validators = loadSchemaValidators();
|
|
@@ -1493,6 +1499,7 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1493
1499
|
orphanJobFiles,
|
|
1494
1500
|
...referenceablePaths ? { referenceablePaths } : {},
|
|
1495
1501
|
...cwd ? { cwd } : {},
|
|
1502
|
+
...reservedNodePaths ? { reservedNodePaths } : {},
|
|
1496
1503
|
emitContribution
|
|
1497
1504
|
});
|
|
1498
1505
|
for (const issue of emitted) {
|
|
@@ -1713,6 +1720,9 @@ function classifyLinkSource(source, shortIdToQualified, cachedQualifiedIds, appl
|
|
|
1713
1720
|
return "obsolete";
|
|
1714
1721
|
}
|
|
1715
1722
|
|
|
1723
|
+
// kernel/orchestrator/node-identifiers.ts
|
|
1724
|
+
import { posix as pathPosix } from "path";
|
|
1725
|
+
|
|
1716
1726
|
// kernel/trigger-normalize.ts
|
|
1717
1727
|
function normalizeTrigger(source) {
|
|
1718
1728
|
let out = source.normalize("NFD");
|
|
@@ -1723,37 +1733,105 @@ function normalizeTrigger(source) {
|
|
|
1723
1733
|
return out.trim();
|
|
1724
1734
|
}
|
|
1725
1735
|
|
|
1726
|
-
// kernel/orchestrator/
|
|
1727
|
-
function
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
const
|
|
1732
|
-
|
|
1733
|
-
if (
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
}
|
|
1736
|
+
// kernel/orchestrator/node-identifiers.ts
|
|
1737
|
+
function deriveNodeIdentifiers(node, kindDescriptor) {
|
|
1738
|
+
const sources = kindDescriptor?.identifiers;
|
|
1739
|
+
if (!sources || sources.length === 0) return [];
|
|
1740
|
+
const out = [];
|
|
1741
|
+
for (const source of sources) {
|
|
1742
|
+
const raw = readIdentifier(source, node);
|
|
1743
|
+
if (!raw) continue;
|
|
1744
|
+
const normalised = normalizeTrigger(raw);
|
|
1745
|
+
if (normalised) out.push(normalised);
|
|
1737
1746
|
}
|
|
1747
|
+
return out;
|
|
1738
1748
|
}
|
|
1739
|
-
function
|
|
1740
|
-
|
|
1741
|
-
if (
|
|
1742
|
-
|
|
1743
|
-
|
|
1749
|
+
function readIdentifier(source, node) {
|
|
1750
|
+
if (source === "frontmatter.name") return readFrontmatterName(node);
|
|
1751
|
+
if (source === "filename-basename") return readFilenameBasename(node);
|
|
1752
|
+
return readDirname(node);
|
|
1753
|
+
}
|
|
1754
|
+
function readFrontmatterName(node) {
|
|
1755
|
+
const raw = node.frontmatter?.["name"];
|
|
1756
|
+
if (typeof raw !== "string") return null;
|
|
1757
|
+
return raw.length > 0 ? raw : null;
|
|
1758
|
+
}
|
|
1759
|
+
function readFilenameBasename(node) {
|
|
1760
|
+
const base = pathPosix.basename(node.path);
|
|
1761
|
+
if (!base) return null;
|
|
1762
|
+
const ext = pathPosix.extname(base);
|
|
1763
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
1764
|
+
return stem.length > 0 ? stem : null;
|
|
1765
|
+
}
|
|
1766
|
+
function readDirname(node) {
|
|
1767
|
+
const dir = pathPosix.dirname(node.path);
|
|
1768
|
+
if (!dir || dir === "." || dir === "/") return null;
|
|
1769
|
+
const base = pathPosix.basename(dir);
|
|
1770
|
+
return base.length > 0 ? base : null;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// kernel/orchestrator/lift-resolved-link-confidence.ts
|
|
1774
|
+
var RESERVED_TARGET_CONFIDENCE = 0.1;
|
|
1775
|
+
function liftResolvedLinkConfidence(links, nodes, ctx) {
|
|
1776
|
+
if (!links.some((l) => l.confidence < 1)) return;
|
|
1777
|
+
const indexes = buildIndexes(nodes, ctx);
|
|
1778
|
+
for (const link of links) {
|
|
1779
|
+
if (link.confidence >= 1) continue;
|
|
1780
|
+
const resolution = resolve7(link, indexes, ctx);
|
|
1781
|
+
if (resolution === "none") continue;
|
|
1782
|
+
link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
|
|
1744
1783
|
}
|
|
1745
|
-
if (byPath2.has(link.target)) return true;
|
|
1746
|
-
return false;
|
|
1747
1784
|
}
|
|
1748
|
-
function
|
|
1749
|
-
const
|
|
1785
|
+
function buildIndexes(nodes, ctx) {
|
|
1786
|
+
const byPath2 = /* @__PURE__ */ new Set();
|
|
1787
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1788
|
+
const nodeByPath = /* @__PURE__ */ new Map();
|
|
1750
1789
|
for (const node of nodes) {
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1790
|
+
byPath2.add(node.path);
|
|
1791
|
+
nodeByPath.set(node.path, node);
|
|
1792
|
+
indexNode(node, ctx, byName);
|
|
1793
|
+
}
|
|
1794
|
+
return { byPath: byPath2, byName, nodeByPath };
|
|
1795
|
+
}
|
|
1796
|
+
function resolve7(link, indexes, ctx) {
|
|
1797
|
+
if (indexes.byPath.has(link.target)) return link.target;
|
|
1798
|
+
return resolveByName(link, indexes, ctx);
|
|
1799
|
+
}
|
|
1800
|
+
function resolveByName(link, indexes, ctx) {
|
|
1801
|
+
const stripped = stripTriggerSigil(link.trigger?.normalizedTrigger);
|
|
1802
|
+
if (stripped === null) return "none";
|
|
1803
|
+
const candidates = indexes.byName.get(stripped);
|
|
1804
|
+
if (!candidates?.length) return "none";
|
|
1805
|
+
const allowedKinds = lookupAllowedKinds(link, indexes, ctx);
|
|
1806
|
+
if (!allowedKinds?.length) return "none";
|
|
1807
|
+
const winner = candidates.find((c) => allowedKinds.includes(c.kind));
|
|
1808
|
+
return winner ? winner.path : "none";
|
|
1809
|
+
}
|
|
1810
|
+
function lookupAllowedKinds(link, indexes, ctx) {
|
|
1811
|
+
const sourceNode = indexes.nodeByPath.get(link.source);
|
|
1812
|
+
if (!sourceNode) return void 0;
|
|
1813
|
+
return ctx.providerResolution.get(sourceNode.provider)?.[link.kind];
|
|
1814
|
+
}
|
|
1815
|
+
function stripTriggerSigil(normalized) {
|
|
1816
|
+
if (!normalized) return null;
|
|
1817
|
+
const trimmed = normalized.replace(/^[/@]/, "").trim();
|
|
1818
|
+
return trimmed.length === 0 ? null : trimmed;
|
|
1819
|
+
}
|
|
1820
|
+
function indexNode(node, ctx, byName) {
|
|
1821
|
+
const kindDescriptor = ctx.kindRegistry.get(kindKey(node));
|
|
1822
|
+
const normalised = deriveNodeIdentifiers(node, kindDescriptor);
|
|
1823
|
+
for (const name of normalised) {
|
|
1824
|
+
const entry = { kind: node.kind, path: node.path };
|
|
1825
|
+
const bucket = byName.get(name);
|
|
1826
|
+
if (bucket) {
|
|
1827
|
+
bucket.push(entry);
|
|
1828
|
+
} else {
|
|
1829
|
+
byName.set(name, [entry]);
|
|
1830
|
+
}
|
|
1755
1831
|
}
|
|
1756
|
-
|
|
1832
|
+
}
|
|
1833
|
+
function kindKey(node) {
|
|
1834
|
+
return `${node.provider}/${node.kind}`;
|
|
1757
1835
|
}
|
|
1758
1836
|
|
|
1759
1837
|
// kernel/orchestrator/post-walk-transforms.ts
|
|
@@ -1766,17 +1844,17 @@ var POST_WALK_TRANSFORMS = [
|
|
|
1766
1844
|
}
|
|
1767
1845
|
},
|
|
1768
1846
|
{
|
|
1769
|
-
id: "lift-
|
|
1770
|
-
description: "Bump
|
|
1771
|
-
run(links, nodes) {
|
|
1772
|
-
|
|
1847
|
+
id: "lift-resolved-link-confidence",
|
|
1848
|
+
description: "Bump invocation links to confidence 1.0 when target / trigger resolves against the full node graph per the source Provider rules.",
|
|
1849
|
+
run(links, nodes, ctx) {
|
|
1850
|
+
liftResolvedLinkConfidence(links, nodes, ctx);
|
|
1773
1851
|
}
|
|
1774
1852
|
}
|
|
1775
1853
|
];
|
|
1776
|
-
function applyPostWalkTransforms(links, nodes, transforms = POST_WALK_TRANSFORMS) {
|
|
1854
|
+
function applyPostWalkTransforms(links, nodes, ctx, transforms = POST_WALK_TRANSFORMS) {
|
|
1777
1855
|
let current = links;
|
|
1778
1856
|
for (const transform of transforms) {
|
|
1779
|
-
const next = transform.run(current, nodes);
|
|
1857
|
+
const next = transform.run(current, nodes, ctx);
|
|
1780
1858
|
if (next) current = next;
|
|
1781
1859
|
}
|
|
1782
1860
|
return current;
|
|
@@ -1920,7 +1998,7 @@ import { join as join7, relative as relative2, sep } from "path";
|
|
|
1920
1998
|
|
|
1921
1999
|
// kernel/scan/ignore.ts
|
|
1922
2000
|
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
1923
|
-
import { dirname as dirname4, resolve as
|
|
2001
|
+
import { dirname as dirname4, resolve as resolve8 } from "path";
|
|
1924
2002
|
import { fileURLToPath } from "url";
|
|
1925
2003
|
import ignoreFactory from "ignore";
|
|
1926
2004
|
function buildIgnoreFilter(opts = {}) {
|
|
@@ -1954,11 +2032,11 @@ function loadDefaultsText() {
|
|
|
1954
2032
|
function readDefaultsFromDisk() {
|
|
1955
2033
|
const here = dirname4(fileURLToPath(import.meta.url));
|
|
1956
2034
|
const candidates = [
|
|
1957
|
-
|
|
2035
|
+
resolve8(here, "../../config/defaults/skillmapignore"),
|
|
1958
2036
|
// src/kernel/scan/ → src/config/defaults/
|
|
1959
|
-
|
|
2037
|
+
resolve8(here, "../config/defaults/skillmapignore"),
|
|
1960
2038
|
// dist/cli.js → dist/config/defaults/ (siblings)
|
|
1961
|
-
|
|
2039
|
+
resolve8(here, "config/defaults/skillmapignore")
|
|
1962
2040
|
];
|
|
1963
2041
|
for (const candidate of candidates) {
|
|
1964
2042
|
if (existsSync6(candidate)) {
|
|
@@ -2149,7 +2227,7 @@ function resolveProviderWalk(provider) {
|
|
|
2149
2227
|
|
|
2150
2228
|
// kernel/sidecar/parse.ts
|
|
2151
2229
|
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
2152
|
-
import { dirname as dirname5, resolve as
|
|
2230
|
+
import { dirname as dirname5, resolve as resolve9 } from "path";
|
|
2153
2231
|
import { createRequire as createRequire3 } from "module";
|
|
2154
2232
|
import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
|
|
2155
2233
|
import yaml2 from "js-yaml";
|
|
@@ -2228,10 +2306,10 @@ function getSidecarValidator() {
|
|
|
2228
2306
|
applyAjvFormats(ajv);
|
|
2229
2307
|
const specRoot = resolveSpecRoot2();
|
|
2230
2308
|
const annotationsSchema = JSON.parse(
|
|
2231
|
-
readFileSync8(
|
|
2309
|
+
readFileSync8(resolve9(specRoot, "schemas/annotations.schema.json"), "utf8")
|
|
2232
2310
|
);
|
|
2233
2311
|
const sidecarSchema = JSON.parse(
|
|
2234
|
-
readFileSync8(
|
|
2312
|
+
readFileSync8(resolve9(specRoot, "schemas/sidecar.schema.json"), "utf8")
|
|
2235
2313
|
);
|
|
2236
2314
|
ajv.addSchema(annotationsSchema);
|
|
2237
2315
|
cachedSidecarValidator = ajv.compile(sidecarSchema);
|
|
@@ -2302,7 +2380,7 @@ function safeIsFile(path) {
|
|
|
2302
2380
|
|
|
2303
2381
|
// kernel/sidecar/store.ts
|
|
2304
2382
|
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
2305
|
-
import { dirname as dirname6, resolve as
|
|
2383
|
+
import { dirname as dirname6, resolve as resolve10 } from "path";
|
|
2306
2384
|
import { createRequire as createRequire4 } from "module";
|
|
2307
2385
|
import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
|
|
2308
2386
|
import yaml3 from "js-yaml";
|
|
@@ -2846,7 +2924,8 @@ async function runScanInternal(_kernel, options) {
|
|
|
2846
2924
|
pluginStores: options.pluginStores,
|
|
2847
2925
|
activeProvider: resolveActiveProviderOption(options.activeProvider, options.roots)
|
|
2848
2926
|
});
|
|
2849
|
-
|
|
2927
|
+
const postWalkCtx = buildPostWalkTransformCtx(_kernel, walked.nodes);
|
|
2928
|
+
walked.internalLinks = applyPostWalkTransforms(walked.internalLinks, walked.nodes, postWalkCtx);
|
|
2850
2929
|
recomputeLinkCounts(walked.nodes, walked.internalLinks);
|
|
2851
2930
|
recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
|
|
2852
2931
|
await dispatchExtractorCompleted(exts.extractors, emitter, hookDispatcher);
|
|
@@ -2866,7 +2945,8 @@ async function runScanInternal(_kernel, options) {
|
|
|
2866
2945
|
options.cwd,
|
|
2867
2946
|
registeredActionIds,
|
|
2868
2947
|
emitter,
|
|
2869
|
-
hookDispatcher
|
|
2948
|
+
hookDispatcher,
|
|
2949
|
+
postWalkCtx.reservedNodePaths
|
|
2870
2950
|
);
|
|
2871
2951
|
mergeAnalyzerEmissions(walked, analyzerResult, exts.analyzers);
|
|
2872
2952
|
const issues = analyzerResult.issues;
|
|
@@ -2879,6 +2959,56 @@ async function runScanInternal(_kernel, options) {
|
|
|
2879
2959
|
await hookDispatcher.dispatch("scan.completed", scanCompletedEvent);
|
|
2880
2960
|
return buildScanReturn(walked, issues, renameOps, stats, options, setup);
|
|
2881
2961
|
}
|
|
2962
|
+
function buildPostWalkTransformCtx(kernel, nodes) {
|
|
2963
|
+
const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(kernel);
|
|
2964
|
+
const reservedNodePaths = buildReservedNodePaths(
|
|
2965
|
+
nodes,
|
|
2966
|
+
kindRegistry,
|
|
2967
|
+
reservedNamesByProviderKind
|
|
2968
|
+
);
|
|
2969
|
+
return { kindRegistry, providerResolution, reservedNodePaths };
|
|
2970
|
+
}
|
|
2971
|
+
function buildProviderIndexes(kernel) {
|
|
2972
|
+
const kindRegistry = /* @__PURE__ */ new Map();
|
|
2973
|
+
const providerResolution = /* @__PURE__ */ new Map();
|
|
2974
|
+
const reservedNamesByProviderKind = /* @__PURE__ */ new Map();
|
|
2975
|
+
const providers = kernel.registry.all("provider");
|
|
2976
|
+
for (const provider of providers) {
|
|
2977
|
+
if (provider.kinds) {
|
|
2978
|
+
for (const [kindName, descriptor] of Object.entries(provider.kinds)) {
|
|
2979
|
+
kindRegistry.set(`${provider.id}/${kindName}`, descriptor);
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
if (provider.resolution) {
|
|
2983
|
+
providerResolution.set(provider.id, provider.resolution);
|
|
2984
|
+
}
|
|
2985
|
+
if (provider.reservedNames) {
|
|
2986
|
+
indexReservedNames(provider, reservedNamesByProviderKind);
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
return { kindRegistry, providerResolution, reservedNamesByProviderKind };
|
|
2990
|
+
}
|
|
2991
|
+
function indexReservedNames(provider, out) {
|
|
2992
|
+
for (const [kindName, list] of Object.entries(provider.reservedNames ?? {})) {
|
|
2993
|
+
const normalised = new Set(list.map((raw) => normalizeTrigger(raw)).filter(Boolean));
|
|
2994
|
+
if (normalised.size > 0) {
|
|
2995
|
+
out.set(`${provider.id}/${kindName}`, normalised);
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
function buildReservedNodePaths(nodes, kindRegistry, reservedNamesByProviderKind) {
|
|
3000
|
+
const out = /* @__PURE__ */ new Set();
|
|
3001
|
+
for (const node of nodes) {
|
|
3002
|
+
const key = `${node.provider}/${node.kind}`;
|
|
3003
|
+
const reservedSet = reservedNamesByProviderKind.get(key);
|
|
3004
|
+
if (!reservedSet || reservedSet.size === 0) continue;
|
|
3005
|
+
const ids = deriveNodeIdentifiers(node, kindRegistry.get(key));
|
|
3006
|
+
if (ids.some((id) => reservedSet.has(id))) {
|
|
3007
|
+
out.add(node.path);
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
return out;
|
|
3011
|
+
}
|
|
2882
3012
|
function buildScanSetup(options) {
|
|
2883
3013
|
const start = Date.now();
|
|
2884
3014
|
const emitter = options.emitter ?? new InMemoryProgressEmitter();
|
|
@@ -2970,7 +3100,7 @@ function validateRoots(roots) {
|
|
|
2970
3100
|
function resolveActiveProviderOption(optionValue, roots) {
|
|
2971
3101
|
if (optionValue !== void 0) return optionValue;
|
|
2972
3102
|
for (const root of roots) {
|
|
2973
|
-
const absRoot = isAbsolute4(root) ? root :
|
|
3103
|
+
const absRoot = isAbsolute4(root) ? root : resolve11(root);
|
|
2974
3104
|
if (!existsSync11(absRoot)) continue;
|
|
2975
3105
|
const detected = resolveActiveProvider(absRoot).resolved;
|
|
2976
3106
|
if (detected !== null) return detected;
|
|
@@ -2979,10 +3109,10 @@ function resolveActiveProviderOption(optionValue, roots) {
|
|
|
2979
3109
|
}
|
|
2980
3110
|
|
|
2981
3111
|
// kernel/scan/watcher.ts
|
|
2982
|
-
import { resolve as
|
|
3112
|
+
import { resolve as resolve12, relative as relative4, sep as sep3 } from "path";
|
|
2983
3113
|
import chokidar from "chokidar";
|
|
2984
3114
|
function createChokidarWatcher(opts) {
|
|
2985
|
-
const absRoots = opts.roots.map((r) =>
|
|
3115
|
+
const absRoots = opts.roots.map((r) => resolve12(opts.cwd, r));
|
|
2986
3116
|
const ignoreFilterOpt = opts.ignoreFilter;
|
|
2987
3117
|
const getFilter = ignoreFilterOpt === void 0 ? void 0 : typeof ignoreFilterOpt === "function" ? ignoreFilterOpt : () => ignoreFilterOpt;
|
|
2988
3118
|
const ignored = getFilter ? (path) => {
|