@skill-map/cli 0.21.0 → 0.22.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/cli.js +6974 -6661
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1588 -1471
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +217 -191
- package/dist/kernel/index.js +1588 -1471
- package/dist/kernel/index.js.map +1 -1
- package/dist/ui/chunk-GETTEQ3S.js +123 -0
- package/dist/ui/{chunk-W62WVNU4.js → chunk-HC6PNQMW.js} +7 -7
- package/dist/ui/chunk-HJHWJTFH.js +1 -0
- package/dist/ui/index.html +1 -1
- package/dist/ui/{main-NIYE2VFS.js → main-Q2WC254P.js} +2 -2
- package/package.json +6 -5
- package/dist/ui/chunk-6FTVUS57.js +0 -123
- package/dist/ui/chunk-N366HMME.js +0 -1
package/dist/kernel/index.d.ts
CHANGED
|
@@ -759,55 +759,6 @@ interface IExtensionBase {
|
|
|
759
759
|
viewContributions?: Record<string, IViewContribution>;
|
|
760
760
|
}
|
|
761
761
|
|
|
762
|
-
/**
|
|
763
|
-
* `.skillmapignore` parser + filter facade. Wraps `ignore` (kaelzhang)
|
|
764
|
-
* with the project-local layering: bundled defaults → `config.ignore`
|
|
765
|
-
* (from `.skill-map/settings.json`) → `.skillmapignore` file content.
|
|
766
|
-
*
|
|
767
|
-
* Why a wrapper instead of exposing `ignore` directly:
|
|
768
|
-
*
|
|
769
|
-
* 1. Single-source defaults — `src/config/defaults/skillmapignore` is
|
|
770
|
-
* the canonical default list, loaded once at module init (or at
|
|
771
|
-
* explicit build time, depending on bundling). The runtime never
|
|
772
|
-
* re-reads it per scan.
|
|
773
|
-
* 2. Stable interface — Providers and the orchestrator depend on a
|
|
774
|
-
* minimal `IIgnoreFilter` shape, so the underlying library can be
|
|
775
|
-
* swapped without touching every consumer.
|
|
776
|
-
* 3. Path normalization — every consumer passes the path RELATIVE to
|
|
777
|
-
* the scan root (POSIX separators); the wrapper guarantees that
|
|
778
|
-
* contract before delegating to `ignore`.
|
|
779
|
-
*/
|
|
780
|
-
interface IIgnoreFilter {
|
|
781
|
-
/**
|
|
782
|
-
* Returns `true` when `relativePath` should be skipped. The caller
|
|
783
|
-
* MUST pass paths relative to the scan root, with POSIX separators
|
|
784
|
-
* (forward slashes), no leading `/`. Directories MAY be passed with
|
|
785
|
-
* or without trailing `/`; the wrapper does not require it.
|
|
786
|
-
*/
|
|
787
|
-
ignores(relativePath: string): boolean;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* `ProgressEmitterPort` — emits progress events during long operations.
|
|
792
|
-
*
|
|
793
|
-
* Shape-only today. The full event catalog (`run.started`,
|
|
794
|
-
* `job.claimed`, `model.delta`, etc.) is normative in
|
|
795
|
-
* `spec/job-events.md`; this port carries an open `data` payload so
|
|
796
|
-
* adapters can emit any documented event without type churn.
|
|
797
|
-
*/
|
|
798
|
-
interface ProgressEvent {
|
|
799
|
-
type: string;
|
|
800
|
-
timestamp: string;
|
|
801
|
-
runId?: string;
|
|
802
|
-
jobId?: string;
|
|
803
|
-
data?: unknown;
|
|
804
|
-
}
|
|
805
|
-
type TProgressListener = (event: ProgressEvent) => void;
|
|
806
|
-
interface ProgressEmitterPort {
|
|
807
|
-
emit(event: ProgressEvent): void;
|
|
808
|
-
subscribe(listener: TProgressListener): () => void;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
762
|
/**
|
|
812
763
|
* Plugin-surface types, hand-written to mirror
|
|
813
764
|
* `spec/schemas/plugins-registry.schema.json#/$defs/PluginManifest` and the
|
|
@@ -913,9 +864,11 @@ interface IPluginManifest {
|
|
|
913
864
|
*
|
|
914
865
|
* - `incompatible-spec`: manifest parsed fine but `semver.satisfies` failed
|
|
915
866
|
* against the installed `@skill-map/spec` version.
|
|
916
|
-
* - `invalid-manifest`: `plugin.json` missing, unparseable,
|
|
917
|
-
*
|
|
918
|
-
*
|
|
867
|
+
* - `invalid-manifest`: `plugin.json` missing, unparseable, failing AJV on
|
|
868
|
+
* the base manifest schema, OR the exported extension shape failed its
|
|
869
|
+
* kind-specific schema (per spec/architecture.md §Plugin discovery —
|
|
870
|
+
* "AJV rejects unknown `slot` names with `invalid-manifest`").
|
|
871
|
+
* - `load-error`: manifest parsed but an extension module failed to import.
|
|
919
872
|
*/
|
|
920
873
|
/**
|
|
921
874
|
* Possible outcomes after the loader sees a plugin.json. Mirrors the
|
|
@@ -1252,6 +1205,34 @@ interface IPriorExtractorRun {
|
|
|
1252
1205
|
sidecarAnnotationsHash: string;
|
|
1253
1206
|
}
|
|
1254
1207
|
|
|
1208
|
+
/**
|
|
1209
|
+
* `.skillmapignore` parser + filter facade. Wraps `ignore` (kaelzhang)
|
|
1210
|
+
* with the project-local layering: bundled defaults → `config.ignore`
|
|
1211
|
+
* (from `.skill-map/settings.json`) → `.skillmapignore` file content.
|
|
1212
|
+
*
|
|
1213
|
+
* Why a wrapper instead of exposing `ignore` directly:
|
|
1214
|
+
*
|
|
1215
|
+
* 1. Single-source defaults — `src/config/defaults/skillmapignore` is
|
|
1216
|
+
* the canonical default list, loaded once at module init (or at
|
|
1217
|
+
* explicit build time, depending on bundling). The runtime never
|
|
1218
|
+
* re-reads it per scan.
|
|
1219
|
+
* 2. Stable interface — Providers and the orchestrator depend on a
|
|
1220
|
+
* minimal `IIgnoreFilter` shape, so the underlying library can be
|
|
1221
|
+
* swapped without touching every consumer.
|
|
1222
|
+
* 3. Path normalization — every consumer passes the path RELATIVE to
|
|
1223
|
+
* the scan root (POSIX separators); the wrapper guarantees that
|
|
1224
|
+
* contract before delegating to `ignore`.
|
|
1225
|
+
*/
|
|
1226
|
+
interface IIgnoreFilter {
|
|
1227
|
+
/**
|
|
1228
|
+
* Returns `true` when `relativePath` should be skipped. The caller
|
|
1229
|
+
* MUST pass paths relative to the scan root, with POSIX separators
|
|
1230
|
+
* (forward slashes), no leading `/`. Directories MAY be passed with
|
|
1231
|
+
* or without trailing `/`; the wrapper does not require it.
|
|
1232
|
+
*/
|
|
1233
|
+
ignores(relativePath: string): boolean;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1255
1236
|
/**
|
|
1256
1237
|
* Provider runtime contract. Walks filesystem roots and emits raw node
|
|
1257
1238
|
* records; classification maps path conventions to a node kind.
|
|
@@ -1395,15 +1376,6 @@ type TProviderKindIcon = {
|
|
|
1395
1376
|
};
|
|
1396
1377
|
interface IProvider extends IExtensionBase {
|
|
1397
1378
|
kind: 'provider';
|
|
1398
|
-
/**
|
|
1399
|
-
* Filesystem directory (relative to user home or project root) where this
|
|
1400
|
-
* Provider's content lives. Required. Examples: `'~/.claude'` for the
|
|
1401
|
-
* Claude Provider, `'~/.cursor'` for a hypothetical Cursor Provider.
|
|
1402
|
-
* The kernel walks this directory during boot/scan to discover nodes;
|
|
1403
|
-
* `sm doctor` validates the directory exists and emits a non-blocking
|
|
1404
|
-
* warning when it does not.
|
|
1405
|
-
*/
|
|
1406
|
-
explorationDir: string;
|
|
1407
1379
|
/**
|
|
1408
1380
|
* Catalog of node kinds this Provider emits. Keyed by kind name. Every
|
|
1409
1381
|
* kind the Provider can `classify()` MUST have an entry; an entry is
|
|
@@ -2153,6 +2125,182 @@ interface IHook extends IExtensionBase {
|
|
|
2153
2125
|
on(ctx: IHookContext): void | Promise<void>;
|
|
2154
2126
|
}
|
|
2155
2127
|
|
|
2128
|
+
/**
|
|
2129
|
+
* `ProgressEmitterPort` — emits progress events during long operations.
|
|
2130
|
+
*
|
|
2131
|
+
* Shape-only today. The full event catalog (`run.started`,
|
|
2132
|
+
* `job.claimed`, `model.delta`, etc.) is normative in
|
|
2133
|
+
* `spec/job-events.md`; this port carries an open `data` payload so
|
|
2134
|
+
* adapters can emit any documented event without type churn.
|
|
2135
|
+
*/
|
|
2136
|
+
interface ProgressEvent {
|
|
2137
|
+
type: string;
|
|
2138
|
+
timestamp: string;
|
|
2139
|
+
runId?: string;
|
|
2140
|
+
jobId?: string;
|
|
2141
|
+
data?: unknown;
|
|
2142
|
+
}
|
|
2143
|
+
type TProgressListener = (event: ProgressEvent) => void;
|
|
2144
|
+
interface ProgressEmitterPort {
|
|
2145
|
+
emit(event: ProgressEvent): void;
|
|
2146
|
+
subscribe(listener: TProgressListener): () => void;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
/**
|
|
2150
|
+
* Per-node extractor invocation: build a fresh `IExtractorContext` for
|
|
2151
|
+
* each extractor, validate every emitted link / contribution against
|
|
2152
|
+
* the declared catalog, fold enrichment partials into per-`(node,
|
|
2153
|
+
* extractor)` records, and surface emit-time drops as
|
|
2154
|
+
* `extension.error` events.
|
|
2155
|
+
*
|
|
2156
|
+
* Also hosts the post-walk recompute helpers that re-derive
|
|
2157
|
+
* `linksOutCount` / `linksInCount` / `externalRefsCount` on every node
|
|
2158
|
+
* from the final merged link buffer, plus the `IExtractorRunRecord`
|
|
2159
|
+
* and `IEnrichmentRecord` types those records eventually persist as.
|
|
2160
|
+
*/
|
|
2161
|
+
|
|
2162
|
+
/**
|
|
2163
|
+
* Spec § A.9 — runs to persist into `scan_extractor_runs`. One entry
|
|
2164
|
+
* per `(nodePath, qualifiedExtractorId)` pair the orchestrator decided
|
|
2165
|
+
* "this extractor is current for this body". Includes both freshly-run
|
|
2166
|
+
* pairs (extractor invoked this scan) and reused pairs (cached node, the
|
|
2167
|
+
* extractor's prior run still applies to the same body hash). Excludes
|
|
2168
|
+
* obsolete pairs — extractors that ran in the prior but are no longer
|
|
2169
|
+
* registered — so a replace-all persist drops them automatically.
|
|
2170
|
+
*/
|
|
2171
|
+
interface IExtractorRunRecord {
|
|
2172
|
+
nodePath: string;
|
|
2173
|
+
extractorId: string;
|
|
2174
|
+
bodyHashAtRun: string;
|
|
2175
|
+
ranAt: number;
|
|
2176
|
+
/**
|
|
2177
|
+
* sha256 of the canonical-form sidecar annotations the Extractor saw
|
|
2178
|
+
* at run time. Always populated (an absent sidecar canonicalises to
|
|
2179
|
+
* `{}` so the hash is stable). Used unconditionally by the cache
|
|
2180
|
+
* decision alongside `bodyHashAtRun`: a sidecar-only edit invalidates
|
|
2181
|
+
* the cached run for every applicable Extractor on that node.
|
|
2182
|
+
*/
|
|
2183
|
+
sidecarAnnotationsHashAtRun: string;
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Spec § A.8 — universal enrichment layer.
|
|
2187
|
+
*
|
|
2188
|
+
* One entry per `(nodePath, qualifiedExtractorId)` pair an Extractor
|
|
2189
|
+
* produced via `ctx.enrichNode(...)` during the walk. Attribution is
|
|
2190
|
+
* preserved per-Extractor (rather than merged client-side as B.1 did)
|
|
2191
|
+
* so the persistence layer can:
|
|
2192
|
+
*
|
|
2193
|
+
* - upsert a single row per pair (stable PRIMARY KEY conflict on
|
|
2194
|
+
* re-extract);
|
|
2195
|
+
* - feed `mergeNodeWithEnrichments` with `enrichedAt`-sorted partials
|
|
2196
|
+
* for last-write-wins per field at read time.
|
|
2197
|
+
*
|
|
2198
|
+
* `value` is the cumulative merge across every `enrichNode` call that
|
|
2199
|
+
* Extractor made for this node within this scan — multiple
|
|
2200
|
+
* `ctx.enrichNode({...})` calls inside one `extract(ctx)` invocation
|
|
2201
|
+
* fold into a single row, but two different Extractors hitting the
|
|
2202
|
+
* same node yield two distinct rows.
|
|
2203
|
+
*
|
|
2204
|
+
* `isProbabilistic` is reserved: Extractors are deterministic-only, so
|
|
2205
|
+
* every record produced by the orchestrator sets it to `false`. The
|
|
2206
|
+
* field is kept on the record (and the row in `node_enrichments`) so a
|
|
2207
|
+
* future Action-issued enrichment can populate it without reshaping
|
|
2208
|
+
* the persistence contract — see spec `architecture.md`
|
|
2209
|
+
* §Extractor · enrichment layer.
|
|
2210
|
+
*/
|
|
2211
|
+
interface IEnrichmentRecord {
|
|
2212
|
+
nodePath: string;
|
|
2213
|
+
extractorId: string;
|
|
2214
|
+
bodyHashAtEnrichment: string;
|
|
2215
|
+
value: Partial<Node>;
|
|
2216
|
+
enrichedAt: number;
|
|
2217
|
+
isProbabilistic: boolean;
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Run a set of extractors against a single node, collecting their link
|
|
2221
|
+
* emissions and node-enrichment partials. Each extractor is invoked
|
|
2222
|
+
* exactly once with a fresh `IExtractorContext`. Caller decides what
|
|
2223
|
+
* to do with the returned arrays (push into per-scan buffers, write to
|
|
2224
|
+
* a focused refresh result, etc.).
|
|
2225
|
+
*
|
|
2226
|
+
* Exported so `cli/commands/refresh.ts` can reuse the same wiring it
|
|
2227
|
+
* needs for re-running a single extractor against a single node — the
|
|
2228
|
+
* pre-extraction code in `refresh.ts` was hand-duplicating this loop
|
|
2229
|
+
* (audit item V4).
|
|
2230
|
+
*
|
|
2231
|
+
* Within this call, multiple `enrichNode(partial)` calls from the same
|
|
2232
|
+
* extractor against the same node fold into one record (last-write-wins
|
|
2233
|
+
* per field) — same contract as the in-scan path.
|
|
2234
|
+
*/
|
|
2235
|
+
declare function runExtractorsForNode(opts: {
|
|
2236
|
+
extractors: IExtractor[];
|
|
2237
|
+
node: Node;
|
|
2238
|
+
body: string;
|
|
2239
|
+
frontmatter: Record<string, unknown>;
|
|
2240
|
+
bodyHash: string;
|
|
2241
|
+
emitter: ProgressEmitterPort;
|
|
2242
|
+
/**
|
|
2243
|
+
* Spec § A.12 — per-plugin `ctx.store` wrappers keyed by `pluginId`.
|
|
2244
|
+
* The map's lookup is per-extractor inside the loop, so callers that
|
|
2245
|
+
* don't track plugin storage can omit it; the resulting `ctx.store`
|
|
2246
|
+
* stays `undefined` (the existing contract).
|
|
2247
|
+
*/
|
|
2248
|
+
pluginStores?: ReadonlyMap<string, IPluginStore>;
|
|
2249
|
+
}): Promise<{
|
|
2250
|
+
internalLinks: Link[];
|
|
2251
|
+
externalLinks: Link[];
|
|
2252
|
+
enrichments: IEnrichmentRecord[];
|
|
2253
|
+
contributions: IContributionRecord[];
|
|
2254
|
+
}>;
|
|
2255
|
+
|
|
2256
|
+
/**
|
|
2257
|
+
* Rename + orphan classification per `spec/db-schema.md` §Rename
|
|
2258
|
+
* detection. Pure: takes the prior `ScanResult` and the current node
|
|
2259
|
+
* set, mutates the supplied `issues` array in place, and returns the
|
|
2260
|
+
* `RenameOp[]` the persistence layer must apply inside the same tx as
|
|
2261
|
+
* the scan zone replace-all.
|
|
2262
|
+
*/
|
|
2263
|
+
|
|
2264
|
+
/**
|
|
2265
|
+
* Confidence-tagged plan to repoint `state_*` references from one node
|
|
2266
|
+
* path to another. Emitted by the rename heuristic during `runScan` and
|
|
2267
|
+
* consumed by `persistScanResult` so the FK migration runs inside the
|
|
2268
|
+
* same transaction as the scan zone replace-all.
|
|
2269
|
+
*/
|
|
2270
|
+
interface RenameOp {
|
|
2271
|
+
from: string;
|
|
2272
|
+
to: string;
|
|
2273
|
+
confidence: 'high' | 'medium';
|
|
2274
|
+
}
|
|
2275
|
+
/**
|
|
2276
|
+
* Pure rename / orphan classification per `spec/db-schema.md` §Rename
|
|
2277
|
+
* detection. Mutates `issues` in place — caller passes the in-progress
|
|
2278
|
+
* issue list; returns the `RenameOp[]` for the persistence layer to
|
|
2279
|
+
* apply inside its tx.
|
|
2280
|
+
*
|
|
2281
|
+
* Pipeline (1-to-1: a `newPath` claimed by one stage cannot be reused
|
|
2282
|
+
* by another):
|
|
2283
|
+
*
|
|
2284
|
+
* 1. **High-confidence**: pair each `deletedPath` with a `newPath`
|
|
2285
|
+
* that has the same `bodyHash`. No issue, no prompt.
|
|
2286
|
+
* 2. **Medium-confidence (1:1)**: of the remaining deletions, pair
|
|
2287
|
+
* each with the *unique* unclaimed `newPath` that shares its
|
|
2288
|
+
* `frontmatterHash`. Emits `auto-rename-medium` (severity warn)
|
|
2289
|
+
* with `data: { from, to, confidence: 'medium' }`.
|
|
2290
|
+
* 3. **Ambiguous (N:1)**: when a single `newPath` has more than one
|
|
2291
|
+
* remaining frontmatter-matching candidate, emit ONE
|
|
2292
|
+
* `auto-rename-ambiguous` issue per `newPath`, listing all
|
|
2293
|
+
* candidates in `data.candidates`. NO migration.
|
|
2294
|
+
* 4. **Orphan**: every `deletedPath` left after steps 1-3 yields one
|
|
2295
|
+
* `orphan` issue (severity info) with `data: { path: <deletedPath> }`.
|
|
2296
|
+
*
|
|
2297
|
+
* Determinism: `deletedPaths` and `newPaths` are iterated in lex-asc
|
|
2298
|
+
* order so the same input always produces the same matches —
|
|
2299
|
+
* required for reproducible tests and conformance fixtures (the spec
|
|
2300
|
+
* does not prescribe an order, but stability is the obvious contract).
|
|
2301
|
+
*/
|
|
2302
|
+
declare function detectRenamesAndOrphans(prior: ScanResult, current: Node[], issues: Issue[]): RenameOp[];
|
|
2303
|
+
|
|
2156
2304
|
/**
|
|
2157
2305
|
* Scan orchestrator — runs the Provider → extractor → analyzer pipeline across
|
|
2158
2306
|
* every registered extension and emits `ProgressEmitterPort` events in
|
|
@@ -2219,17 +2367,6 @@ interface IScanExtensions {
|
|
|
2219
2367
|
*/
|
|
2220
2368
|
hooks?: IHook[];
|
|
2221
2369
|
}
|
|
2222
|
-
/**
|
|
2223
|
-
* Confidence-tagged plan to repoint `state_*` references from one node
|
|
2224
|
-
* path to another. Emitted by the rename heuristic during `runScan` and
|
|
2225
|
-
* consumed by `persistScanResult` so the FK migration runs inside the
|
|
2226
|
-
* same transaction as the scan zone replace-all.
|
|
2227
|
-
*/
|
|
2228
|
-
interface RenameOp {
|
|
2229
|
-
from: string;
|
|
2230
|
-
to: string;
|
|
2231
|
-
confidence: 'high' | 'medium';
|
|
2232
|
-
}
|
|
2233
2370
|
interface RunScanOptions {
|
|
2234
2371
|
/**
|
|
2235
2372
|
* Filesystem roots to walk. Spec requires `minItems: 1`; passing an
|
|
@@ -2393,63 +2530,6 @@ interface RunScanOptions {
|
|
|
2393
2530
|
*/
|
|
2394
2531
|
cwd?: string;
|
|
2395
2532
|
}
|
|
2396
|
-
/**
|
|
2397
|
-
* Spec § A.9 — runs to persist into `scan_extractor_runs`. One entry
|
|
2398
|
-
* per `(nodePath, qualifiedExtractorId)` pair the orchestrator decided
|
|
2399
|
-
* "this extractor is current for this body". Includes both freshly-run
|
|
2400
|
-
* pairs (extractor invoked this scan) and reused pairs (cached node, the
|
|
2401
|
-
* extractor's prior run still applies to the same body hash). Excludes
|
|
2402
|
-
* obsolete pairs — extractors that ran in the prior but are no longer
|
|
2403
|
-
* registered — so a replace-all persist drops them automatically.
|
|
2404
|
-
*/
|
|
2405
|
-
interface IExtractorRunRecord {
|
|
2406
|
-
nodePath: string;
|
|
2407
|
-
extractorId: string;
|
|
2408
|
-
bodyHashAtRun: string;
|
|
2409
|
-
ranAt: number;
|
|
2410
|
-
/**
|
|
2411
|
-
* sha256 of the canonical-form sidecar annotations the Extractor saw
|
|
2412
|
-
* at run time. Always populated (an absent sidecar canonicalises to
|
|
2413
|
-
* `{}` so the hash is stable). Used unconditionally by the cache
|
|
2414
|
-
* decision alongside `bodyHashAtRun`: a sidecar-only edit invalidates
|
|
2415
|
-
* the cached run for every applicable Extractor on that node.
|
|
2416
|
-
*/
|
|
2417
|
-
sidecarAnnotationsHashAtRun: string;
|
|
2418
|
-
}
|
|
2419
|
-
/**
|
|
2420
|
-
* Spec § A.8 — universal enrichment layer.
|
|
2421
|
-
*
|
|
2422
|
-
* One entry per `(nodePath, qualifiedExtractorId)` pair an Extractor
|
|
2423
|
-
* produced via `ctx.enrichNode(...)` during the walk. Attribution is
|
|
2424
|
-
* preserved per-Extractor (rather than merged client-side as B.1 did)
|
|
2425
|
-
* so the persistence layer can:
|
|
2426
|
-
*
|
|
2427
|
-
* - upsert a single row per pair (stable PRIMARY KEY conflict on
|
|
2428
|
-
* re-extract);
|
|
2429
|
-
* - feed `mergeNodeWithEnrichments` with `enrichedAt`-sorted partials
|
|
2430
|
-
* for last-write-wins per field at read time.
|
|
2431
|
-
*
|
|
2432
|
-
* `value` is the cumulative merge across every `enrichNode` call that
|
|
2433
|
-
* Extractor made for this node within this scan — multiple
|
|
2434
|
-
* `ctx.enrichNode({...})` calls inside one `extract(ctx)` invocation
|
|
2435
|
-
* fold into a single row, but two different Extractors hitting the
|
|
2436
|
-
* same node yield two distinct rows.
|
|
2437
|
-
*
|
|
2438
|
-
* `isProbabilistic` is reserved: Extractors are deterministic-only, so
|
|
2439
|
-
* every record produced by the orchestrator sets it to `false`. The
|
|
2440
|
-
* field is kept on the record (and the row in `node_enrichments`) so a
|
|
2441
|
-
* future Action-issued enrichment can populate it without reshaping
|
|
2442
|
-
* the persistence contract — see spec `architecture.md`
|
|
2443
|
-
* §Extractor · enrichment layer.
|
|
2444
|
-
*/
|
|
2445
|
-
interface IEnrichmentRecord {
|
|
2446
|
-
nodePath: string;
|
|
2447
|
-
extractorId: string;
|
|
2448
|
-
bodyHashAtEnrichment: string;
|
|
2449
|
-
value: Partial<Node>;
|
|
2450
|
-
enrichedAt: number;
|
|
2451
|
-
isProbabilistic: boolean;
|
|
2452
|
-
}
|
|
2453
2533
|
/**
|
|
2454
2534
|
* Same as `runScan` but also returns the rename heuristic's `RenameOp[]`
|
|
2455
2535
|
* — the high- and medium-confidence renames the persistence layer must
|
|
@@ -2472,70 +2552,16 @@ declare function runScanWithRenames(_kernel: Kernel, options: RunScanOptions): P
|
|
|
2472
2552
|
freshlyRunTuples: ReadonlySet<string>;
|
|
2473
2553
|
}>;
|
|
2474
2554
|
declare function runScan(_kernel: Kernel, options: RunScanOptions): Promise<ScanResult>;
|
|
2555
|
+
|
|
2475
2556
|
/**
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
2479
|
-
*
|
|
2480
|
-
*
|
|
2481
|
-
*
|
|
2482
|
-
* Exported so `cli/commands/refresh.ts` can reuse the same wiring it
|
|
2483
|
-
* needs for re-running a single extractor against a single node — the
|
|
2484
|
-
* pre-extraction code in `refresh.ts` was hand-duplicating this loop
|
|
2485
|
-
* (audit item V4).
|
|
2486
|
-
*
|
|
2487
|
-
* Within this call, multiple `enrichNode(partial)` calls from the same
|
|
2488
|
-
* extractor against the same node fold into one record (last-write-wins
|
|
2489
|
-
* per field) — same contract as the in-scan path.
|
|
2490
|
-
*/
|
|
2491
|
-
declare function runExtractorsForNode(opts: {
|
|
2492
|
-
extractors: IExtractor[];
|
|
2493
|
-
node: Node;
|
|
2494
|
-
body: string;
|
|
2495
|
-
frontmatter: Record<string, unknown>;
|
|
2496
|
-
bodyHash: string;
|
|
2497
|
-
emitter: ProgressEmitterPort;
|
|
2498
|
-
/**
|
|
2499
|
-
* Spec § A.12 — per-plugin `ctx.store` wrappers keyed by `pluginId`.
|
|
2500
|
-
* The map's lookup is per-extractor inside the loop, so callers that
|
|
2501
|
-
* don't track plugin storage can omit it; the resulting `ctx.store`
|
|
2502
|
-
* stays `undefined` (the existing contract).
|
|
2503
|
-
*/
|
|
2504
|
-
pluginStores?: ReadonlyMap<string, IPluginStore>;
|
|
2505
|
-
}): Promise<{
|
|
2506
|
-
internalLinks: Link[];
|
|
2507
|
-
externalLinks: Link[];
|
|
2508
|
-
enrichments: IEnrichmentRecord[];
|
|
2509
|
-
contributions: IContributionRecord[];
|
|
2510
|
-
}>;
|
|
2511
|
-
/**
|
|
2512
|
-
* Pure rename / orphan classification per `spec/db-schema.md` §Rename
|
|
2513
|
-
* detection. Mutates `issues` in place — caller passes the in-progress
|
|
2514
|
-
* issue list; returns the `RenameOp[]` for the persistence layer to
|
|
2515
|
-
* apply inside its tx.
|
|
2516
|
-
*
|
|
2517
|
-
* Pipeline (1-to-1: a `newPath` claimed by one stage cannot be reused
|
|
2518
|
-
* by another):
|
|
2519
|
-
*
|
|
2520
|
-
* 1. **High-confidence**: pair each `deletedPath` with a `newPath`
|
|
2521
|
-
* that has the same `bodyHash`. No issue, no prompt.
|
|
2522
|
-
* 2. **Medium-confidence (1:1)**: of the remaining deletions, pair
|
|
2523
|
-
* each with the *unique* unclaimed `newPath` that shares its
|
|
2524
|
-
* `frontmatterHash`. Emits `auto-rename-medium` (severity warn)
|
|
2525
|
-
* with `data: { from, to, confidence: 'medium' }`.
|
|
2526
|
-
* 3. **Ambiguous (N:1)**: when a single `newPath` has more than one
|
|
2527
|
-
* remaining frontmatter-matching candidate, emit ONE
|
|
2528
|
-
* `auto-rename-ambiguous` issue per `newPath`, listing all
|
|
2529
|
-
* candidates in `data.candidates`. NO migration.
|
|
2530
|
-
* 4. **Orphan**: every `deletedPath` left after steps 1-3 yields one
|
|
2531
|
-
* `orphan` issue (severity info) with `data: { path: <deletedPath> }`.
|
|
2532
|
-
*
|
|
2533
|
-
* Determinism: `deletedPaths` and `newPaths` are iterated in lex-asc
|
|
2534
|
-
* order so the same input always produces the same matches —
|
|
2535
|
-
* required for reproducible tests and conformance fixtures (the spec
|
|
2536
|
-
* does not prescribe an order, but stability is the obvious contract).
|
|
2557
|
+
* Node-construction helpers: hash a body, canonicalise frontmatter /
|
|
2558
|
+
* sidecar annotations, resolve the sidecar overlay for a given relative
|
|
2559
|
+
* path, and produce a fresh `Node` (validating its frontmatter on the
|
|
2560
|
+
* way out). Also hosts `mergeNodeWithEnrichments` + `IPersistedEnrichment`
|
|
2561
|
+
* — the read-time merge of author frontmatter with the A.8 enrichment
|
|
2562
|
+
* layer.
|
|
2537
2563
|
*/
|
|
2538
|
-
|
|
2564
|
+
|
|
2539
2565
|
/**
|
|
2540
2566
|
* Spec § A.8 — produce the merged read-time view of a Node.
|
|
2541
2567
|
*
|