@skill-map/spec 0.55.1 → 0.56.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/CHANGELOG.md +24 -0
- package/architecture.md +1 -1
- package/cli-contract.md +6 -1
- package/db-schema.md +3 -0
- package/index.json +8 -8
- package/package.json +1 -1
- package/plugin-author-guide.md +1 -1
- package/schemas/project-config.schema.json +6 -1
- package/schemas/scan-result.schema.json +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
+
## 0.56.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Splits the scan cap into two knobs: `scan.maxScan` (corpus ceiling, default 50000) bounds what the walk parses and reference-validates, while `scan.maxNodes` (default 256) now caps only the graph render. References resolve across the whole corpus, so large repos no longer flag links to unrendered files as broken. Adds the `--max-scan` flag and the `/api/folders`, `/api/branch`, and `/api/scan?meta=1` endpoints that back the lazy folders tree and branch-scoped map.
|
|
8
|
+
|
|
9
|
+
## User-facing
|
|
10
|
+
|
|
11
|
+
Large repos now scan and validate references across the whole tree; check folders (with per-folder issue counts) to choose what the map shows. Map palettes count what is shown; a Reset filters button clears it all; the refresh button spins while any scan runs.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Restores the files rail's per-row stale-clock icon, dropped when the rail switched to building from the lightweight `GET /api/folders` payload (which carried the error / warn counts but not the sidecar drift status). The endpoint now emits a `sidecarStatus` field (the persisted `scan_nodes.sidecar_status`, `null` when there is no parseable sidecar), threaded from the kernel loader through the BFF into the rail so staleness flags corpus-wide in demo and `sm serve` mode.
|
|
16
|
+
|
|
17
|
+
## User-facing
|
|
18
|
+
|
|
19
|
+
The files rail again flags out-of-date nodes with the clock icon, so you can see at a glance which files have drifted since their last review.
|
|
20
|
+
|
|
21
|
+
- Body extractors now strip raw HTML (comments and tag tokens) before matching, alongside the existing code-region strip. A markdown link commented out as `<!-- [x](old.md) -->` or hidden in an attribute value (`<img alt="[x](y.md)">`) no longer produces a phantom edge. The strip is bounded to comments and tag tokens, so markdown nested inside a `<div>` block still resolves; `core/backtick-path` is unaffected (HTML is not a code region).
|
|
22
|
+
|
|
23
|
+
## User-facing
|
|
24
|
+
|
|
25
|
+
Scanning `.md` files that contain HTML no longer creates phantom links or false broken-reference warnings from links that were commented out or tucked inside HTML attributes.
|
|
26
|
+
|
|
3
27
|
## 0.55.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/architecture.md
CHANGED
|
@@ -424,7 +424,7 @@ The Signal's `range` field (byte offsets in the source) powers two cross-extract
|
|
|
424
424
|
|
|
425
425
|
### Extractor · code-region file references (`core/backtick-path`)
|
|
426
426
|
|
|
427
|
-
Every body extractor strips fenced code blocks
|
|
427
|
+
Every body extractor strips fenced code blocks, inline code spans, and raw HTML (comments and tag tokens) before matching (the strip policy): invocation tokens (`@handle`, `/command`, URLs) inside backticks, and any reference inside HTML, are literal payload the runtime never follows. The HTML half closes two authoring papercuts: a markdown link commented out as `<!-- [x](old.md) -->` no longer emits a phantom edge, and a `[x](y.md)`-shaped token hiding in an attribute value (`<img alt="[see](ref.md)">`) no longer false-matches. No supported runtime renders raw HTML in a `.md` body to follow `<a href>` or load `<img src>`; the file reaches the LLM as text, so an HTML reference is at most LLM-interpreted, the same tier as a backticked `@handle`. The HTML strip is deliberately bounded to comments and tag tokens, never the content between an open and close tag, so markdown nested inside a `<div>` block survives; replicating CommonMark's full HTML-block algorithm is out of scope. **Relative file paths are the documented exception.** The Agent Skills open standard mandates that a skill references its bundled resources by relative path and that "agents load these on demand"; prose like ``Read `references/rules.md` `` is an instruction the consuming LLM runtime follows. The `core/backtick-path` extractor surfaces exactly that class of references, ONLY inside code regions, the precise complement of the code-strip policy, so it can never collide with the prose-side extractors. The HTML strip is a separate, prose-side transform and never feeds the code-region inverse mask: HTML is not a code region, so a path inside an HTML tag is not a `points` target.
|
|
428
428
|
|
|
429
429
|
The contract:
|
|
430
430
|
|
package/cli-contract.md
CHANGED
|
@@ -312,7 +312,9 @@ The three privacy-sensitive keys above PLUS `allowEditSmFiles` are members of `P
|
|
|
312
312
|
|
|
313
313
|
The watcher subscribes to the same roots `sm scan` walks and respects `.skillmapignore` plus `config.ignore` exactly as the one-shot scan does. Filesystem events are grouped using `scan.watch.debounceMs` (default 300ms) before the watcher re-runs the incremental scan and persists. `SIGINT` / `SIGTERM` close the watcher cleanly. Exit code on clean shutdown is 0.
|
|
314
314
|
|
|
315
|
-
**
|
|
315
|
+
**Scan ceiling** (`--max-scan <N>`): on `sm scan`, `sm watch` (alias `sm scan --watch`), and `sm serve`, a hard ceiling on the number of files the walker accepts after `.skillmapignore` filtering, before extractors run. Default from `scan.maxScan` (default 50000). The scan walks, parses, analyzes, and reference-validates every file up to this ceiling, so link resolution sees the whole corpus (a large monorepo) and references resolve across it regardless of how many nodes the map renders. The flag fully overrides the setting and is **bidirectional** (raise or lower). At the ceiling, additional files are dropped in stable provider-walker order and `scan_meta.scan_truncated` is set; the `ScanResult` envelope carries `scanCeiling` and `scanTruncated` so the UI raises a persistent banner pointing at the `.skillmapignore` editor in Settings → Project. The CLI prints a human-mode notice naming both escapes: edit `.skillmapignore` (preferred, trims permanently) or re-run with `--max-scan <N>` (force). `sm refresh` operates on a single already-classified node, so the ceiling does not apply there. Validation: integer ≥ 1, else exits `2` operational.
|
|
316
|
+
|
|
317
|
+
**Map render cap** (`--max-nodes <N>`): the maximum number of nodes the graph map renders onto the canvas at once. Default from `scan.maxNodes` (default 256). This does NOT bound the scan: the full corpus up to `scan.maxScan` is walked and reference-validated, and the folders tree shows all of it; the cap only bounds the Foblex graph projection so a large project stays readable. The effective value is recorded in `scan_meta.max_render_nodes` and carried on `ScanResult.maxRenderNodes`; the UI projects the selected folder branch capped at this number and raises an in-view banner (distinct from the scan-ceiling banner) when a branch exceeds it. The flag fully overrides the setting (bidirectional) and is honoured on `sm scan` / `sm watch` / `sm serve`; on headless `sm scan` it only records the value (nothing renders). Validation: integer ≥ 1, else exits `2` operational.
|
|
316
318
|
|
|
317
319
|
**File-size skip** (`scan.maxFileSizeBytes`, default 1 MiB): the walker checks each candidate file's on-disk size before reading and skips any larger than the limit. The skip happens at the source (never read, parsed, or indexed), so an accidental binary or generated artefact cannot poison the graph. Every skipped file is reported in the `ScanResult` envelope as `oversizedFiles` (each entry the root-relative, forward-slash path plus byte size) and counted in `stats.filesOversized`. When at least one file is skipped, `sm scan`, `sm watch` (per batch), and `sm serve` (initial scan and every batch) print a **WARN** terminal notice listing the skipped files with a human-readable size, plus a hint pointing at `scan.maxFileSizeBytes` and `.skillmapignore`; the UI raises a matching banner. Unlike the node cap, the limit is config-only (no per-invocation flag).
|
|
318
320
|
|
|
@@ -593,12 +595,15 @@ The reference implementation ships a Hono BFF rooted at `src/server/`. One Node
|
|
|
593
595
|
|---|---|---|
|
|
594
596
|
| `GET /api/health` | implemented | `{ ok: true, schemaVersion, specVersion, implVersion, db: 'present'\|'missing', cwd: string, dbPath: string }`. `cwd` is the absolute project root the BFF resolves against (`runtimeContext.cwd`); `dbPath` is the absolute project DB path (`IServerOptions.dbPath`). Both surfaced so the SPA's About panel can show "you are looking at <project>" + the DB location without a second endpoint. |
|
|
595
597
|
| `GET /api/scan` | implemented | latest persisted `ScanResult` (1:1 with `scan-result.schema.json`; byte-equal to `sm scan --json` modulo whitespace). DB absent → empty `ScanResult` shape (zero `nodes` / `links` / `issues`). |
|
|
598
|
+
| `GET /api/scan?meta=1` | implemented | metadata-only `ScanResult`: every scalar field plus `stats` (real `COUNT(*)`-derived counts) and `scanCeiling` / `scanTruncated` / `maxRenderNodes` / `tokenizer` / `oversizedFiles`, but `nodes` / `links` / `issues` are empty arrays. Reads only `scan_meta` + counts (never selects the node/link/issue rows), so the SPA hydrates its header and banners at boot without the full-corpus payload (paired with `/api/folders` for the tree and `/api/branch` for the map). DB absent → empty `ScanResult` shape. |
|
|
596
599
|
| `GET /api/scan?fresh=1` | implemented | runs an in-memory scan and returns the produced `ScanResult` without persistence. Rejects with `bad-query` (400) when the server was started with `--no-built-ins` or `--no-plugins` (would yield empty / partial results). |
|
|
597
600
|
| `POST /api/scan` | implemented | Run a fresh scan **and persist it** through the same `runScanWithRenames` + `persistScanResult` pipeline the watcher uses. Body empty (`{}` or none). Response: the persisted `ScanResult` inline (same shape as `GET /api/scan`). Side effects: broadcasts `scan.started` then `scan.completed` over `/ws` so other clients refresh; the per-batch sequence is identical to a watcher-driven batch. **Concurrency**: only one scan may run at a time across the whole BFF process. A POST arriving while a watcher batch (or another POST) is in flight is rejected with `409 scan-busy` so the caller can retry. **Pipeline gate**: rejected with `400 bad-query` when the server started with `--no-built-ins` or `--no-plugins` (a partial pipeline would persist a misleading DB the next watcher boot must reconcile). **DB gate**: rejected with `500 db-missing` when the project DB is absent; the read-side `/api/scan` degrades to the empty shape, but a write path cannot, so it fails fast. |
|
|
598
601
|
| `GET /api/nodes?kind=&hasIssues=&path=&limit=&offset=` | implemented | `RestEnvelope` (`kind: 'nodes'`), paginated, filtered list. Filters share the `kind=` / `has=issues` / `path=<glob>` grammar with `sm export`. `hasIssues=false` is a server-side post-filter (not representable in the kernel grammar). Pagination defaults `offset=0`, `limit=100`; max `limit=1000`. |
|
|
599
602
|
| `GET /api/nodes/:pathB64[?include=body]` | implemented | Single-node detail envelope: `{ schemaVersion, kind: 'node', item: Node, links: { incoming: Link[], outgoing: Link[] }, issues: Issue[] }`. `:pathB64` is base64url (RFC 4648 §5, no padding) of `node.path`. Missing node or malformed `pathB64` → 404 `not-found`. **`?include=body`** (Step 14.5.a), opt-in flag adding `item.body: string \| null` to the response. The body is read from disk on demand at request time (the kernel persists `bodyHash` only). `null` means the source file was missing / unreadable when the request landed (the watcher re-emits `scan.completed` on catch-up). Without the flag, `item.body` is `undefined` and the handler does not touch the filesystem. |
|
|
600
603
|
| `GET /api/links?kind=&from=&to=` | implemented | `RestEnvelope` (`kind: 'links'`), list of links. Filters: `kind` (CSV whitelist of `link.kind`), `from` (exact match on `link.source`), `to` (exact match on `link.target`). No pagination at v14.2. |
|
|
601
604
|
| `GET /api/issues?severity=&analyzerId=&node=` | implemented | `RestEnvelope` (`kind: 'issues'`), list of issues. Filters: `severity` (CSV from `error\|warn\|info`), `analyzerId` (CSV; qualified or short suffix per `sm check --analyzers`), `node` (filter to issues whose `nodeIds` includes the path). No pagination at v14.2. |
|
|
605
|
+
| `GET /api/folders` | implemented | `RestEnvelope` (`kind: 'folders'`), lightweight full-corpus projection: one entry per scanned node `{ path, kind, linksInCount, linksOutCount, tokensTotal, modifiedAtMs, errorCount, warnCount, sidecarStatus }`. Only cheap scalar columns of `scan_nodes` (no frontmatter, body, links, signals, or contributions), so the SPA folders tree renders the whole corpus (up to `scan.maxScan`) with per-node data columns + per-folder issue badges without hydrating the full `ScanResult`. `tokensTotal` / `modifiedAtMs` are nullable (tokenization disabled / unknown mtime). `errorCount` / `warnCount` are the count of error / warn issues whose `nodeIds` include that path (the same incidence the tree rolls up across descendants). `sidecarStatus` is the node's sidecar drift status (`scan_nodes.sidecar_status`), `null` when there is no parseable sidecar, so the folders tree can flag per-row staleness without hydrating the branch payload. No pagination (the complete tree is the point; the corpus is already bounded by `scan.maxScan`). DB absent → zero items. |
|
|
606
|
+
| `GET /api/branch?path=<prefix>&path=<prefix>&limit=<n>` | implemented | Branch projection for the map. `path` is **repeatable**: the response is the UNION of the subtrees under every given prefix (forward-slash; a node matches a prefix when its path equals it or starts with `<prefix>/`). No `path` (or a single empty one) = the whole corpus. The union is capped at `limit` nodes (default and effective max = the scan's `maxRenderNodes`), so the response stays bounded regardless of how many prefixes are sent. Direct shape (no envelope wrap, like `/api/scan`): `{ schemaVersion, kind: 'branch', branch: { paths, total, rendered, truncated, cap }, nodes: Node[], links: Link[], issues: Issue[] }`, where `paths` echoes the requested prefixes. `nodes` is the first `rendered` nodes of the union in stable path order; `links` carries only edges whose source AND target are in `nodes`; `issues` carries those touching `nodes`. `truncated` is `total > cap`. Lets the SPA render a multi-folder selection without hydrating the full `ScanResult`. DB absent → empty branch (zero nodes). Validation: `limit` integer ≥ 1 else 400 `bad-query`. |
|
|
602
607
|
| `GET /api/graph?format=ascii\|json\|md` | implemented | formatter-rendered graph. `Content-Type` per format: `text/plain` (ascii), `application/json` (json), `text/markdown` (md / mermaid). Default `format=ascii`. Unknown format → 400 `bad-query`. |
|
|
603
608
|
| `GET /api/config` | implemented | `RestEnvelope` (`kind: 'config'`), merged effective config (defaults → user → user-local → project → project-local → override). |
|
|
604
609
|
| `GET /api/plugins` | implemented | `RestEnvelope` (`kind: 'plugins'`), list of installed plugins (built-in + drop-in) with status. Item shape: `{ id, version, kinds, status, reason, source: 'built-in'\|'project', description?: string, locked?: boolean, startsAsDisabled?: boolean, extensions?: Array<{ id, kind, version, enabled, description?: string, stability?: 'experimental'\|'beta'\|'stable'\|'deprecated', locked?: boolean }> }`. The plugin row has no granular toggle axis; its `status` aggregates the children (`'enabled'` when at least one extension is enabled, else `'disabled'`). The `description` carries the manifest-declared description (built-ins: hardcoded on `IBuiltInPlugin`; drop-ins: `plugin.json#/description`); each `extensions[]` entry carries its manifest's `description` per `IExtensionBase` (`extensions/base.schema.json#/properties/description`), plus the optional `stability` lifecycle label per `extensions/base.schema.json#/properties/stability` (omitted when undeclared; missing means `stable`. The SPA badges only non-default values, `experimental` / `beta` / `deprecated`, next to the extension row; `stable` renders nothing. Presentation-only EXCEPT `experimental` and `deprecated`, which each flip the extension's installed default to disabled). The SPA's Settings list renders descriptions as muted secondary text and indexes them for substring search alongside the ids. The `extensions` array is present whenever the plugin declares any extension AND loaded successfully. Each entry's `enabled` reflects the per-extension override resolution (DB > settings.json > installed default, where the default is `false` for `experimental` and `deprecated` extensions and `true` otherwise). The optional `locked: true` flag is stamped when the plugin id (or qualified extension id) appears in the host's lock-list (`src/server/locked-plugins.ts`); locked items render the toggle disabled in the SPA and any `PATCH` returns `403 locked`. Omitted when false. The optional `startsAsDisabled: true` flag is stamped on drop-in plugins (never built-ins) whose discovery-time `status` was `'disabled'`, i.e. every extension was disabled in `config_plugins` / `settings.json` at `sm serve` boot, so the handlers were never bucketed into the runtime. The SPA renders a per-row hint when this flag is set AND the user re-enables at least one of the plugin's extensions in the buffered state, since re-enabling requires `sm serve` restart (the rest of the toggle pipeline applies live). Omitted when false. |
|
package/db-schema.md
CHANGED
|
@@ -153,6 +153,9 @@ Single-row table holding the last persisted scan's metadata. Lets `loadScanResul
|
|
|
153
153
|
| `stats_files_walked` | INTEGER | NOT NULL |
|
|
154
154
|
| `stats_files_skipped` | INTEGER | NOT NULL |
|
|
155
155
|
| `stats_duration_ms` | INTEGER | NOT NULL |
|
|
156
|
+
| `scan_ceiling` | INTEGER | NOT NULL | Effective walk ceiling for this scan (`--max-scan` override, else `scan.maxScan`, default 50000). The scan walks + reference-validates the full corpus up to this number. Carried on `ScanResult.scanCeiling`. |
|
|
157
|
+
| `scan_truncated` | INTEGER | NOT NULL | 1 when the walker reached `scan_ceiling` and dropped files in stable provider-walker order, 0 otherwise. Drives the UI "scan truncated" banner pointing at the `.skillmapignore` editor. Carried on `ScanResult.scanTruncated`. |
|
|
158
|
+
| `max_render_nodes` | INTEGER | NOT NULL | Effective map render cap (`--max-nodes` override, else `scan.maxNodes`, default 256). The full corpus is persisted regardless; this bounds only the graph projection (the folders tree shows everything). Carried on `ScanResult.maxRenderNodes`. |
|
|
156
159
|
| `tokenizer` | TEXT | NULL | Resolved offline encoder that produced this scan's per-node token counts (closed enum `cl100k_base` / `o200k_base`, see `project-config.md` / `project-config.schema.json` §tokenizer). Carried on the `ScanResult.tokenizer` wire field. NULL on a pre-feature DB or a scan with tokenization disabled. On `sm scan --changed` the orchestrator compares this against the freshly-resolved encoder and, when they differ (or the stored value is NULL), bypasses cached per-node token reuse so `buildNode` recomputes counts with the current encoder; changing the tokenizer thus invalidates prior counts. |
|
|
157
160
|
| `schema_fingerprint` | TEXT | NULL | sha256 (hex) of the migration DDL the schema was built from, written at persist time. NULL on a DB created by a pre-fingerprint CLI; a NULL (or mismatching) value is read as schema drift (see §Schema drift). Internal DB metadata, NOT carried on the `ScanResult` wire shape. |
|
|
158
161
|
|
package/index.json
CHANGED
|
@@ -174,14 +174,14 @@
|
|
|
174
174
|
}
|
|
175
175
|
]
|
|
176
176
|
},
|
|
177
|
-
"specPackageVersion": "0.
|
|
177
|
+
"specPackageVersion": "0.56.0",
|
|
178
178
|
"integrity": {
|
|
179
179
|
"algorithm": "sha256",
|
|
180
180
|
"files": {
|
|
181
|
-
"CHANGELOG.md": "
|
|
181
|
+
"CHANGELOG.md": "49c8267a556ee260ce198a53abacf22a5eca6798417ae5ee4776d39785d83899",
|
|
182
182
|
"README.md": "a790cd010b46d47883d1f37e3893cea9d7aa69ec4750c0202e6a0c99991e7980",
|
|
183
|
-
"architecture.md": "
|
|
184
|
-
"cli-contract.md": "
|
|
183
|
+
"architecture.md": "5eb1b54e66b3db3d28091830a9a990e94dc72b4488f94ab9506cd509aa884e8b",
|
|
184
|
+
"cli-contract.md": "3733b1277c92d2af9e0728b0bcdd0579dd13bf0c3adfd7f272a18efd3a8c8257",
|
|
185
185
|
"conformance/README.md": "dcbef7249f161acf597552a05dcadc813cd0ced430dcd3f813fcf5e1c876335d",
|
|
186
186
|
"conformance/cases/backtick-path-extraction.json": "4620e7f8bc161fc57cb44001e9d99879c7e22b4865a0c27a20dc28969cd936d9",
|
|
187
187
|
"conformance/cases/extractor-collision-detection.json": "179a02c61892f0d26492de0c4e2c327fa6b4986d1265a8f119e871df6afe4658",
|
|
@@ -229,11 +229,11 @@
|
|
|
229
229
|
"conformance/fixtures/view-contribution-payloads/notes/example.md": "312b1919cd7fd0f233648b053acfb2975662ede3c65dd391cc508204b67ad6fb",
|
|
230
230
|
"conformance/fixtures/view-slots-all/.skill-map/plugins/all-slots/analyzers/everything/index.js": "ea0022fec7f0fd5a26ba12db1310335f434f2f820682206a3a9542d98db0d346",
|
|
231
231
|
"conformance/fixtures/view-slots-all/.skill-map/plugins/all-slots/plugin.json": "c48e8a0574947ade0b4eb189d6bc27a48e24f92f616aacdc177f2d22d472a599",
|
|
232
|
-
"db-schema.md": "
|
|
232
|
+
"db-schema.md": "b27e57da2e6b10cf0aa15d841703654ce4e2b91cb3ed9ddbbe6c158205dbef7b",
|
|
233
233
|
"interfaces/security-scanner.md": "0996dd782e2d39d4791f2e290da4bb1a68a5b30c1f79187977188ec8e3fe6ef2",
|
|
234
234
|
"job-events.md": "2c7017f5f0003b19653424111a07043487173cbe88b51e961598bb1693987059",
|
|
235
235
|
"job-lifecycle.md": "ce33bc8bb5090ea183f860e495bfccc2a4a0ac2e23f6ebad83b9c28aad59124e",
|
|
236
|
-
"plugin-author-guide.md": "
|
|
236
|
+
"plugin-author-guide.md": "45c7da2293372c9781117f0ed1a2c1e1eb9a0da89f32fa7ed64e70d6379ed20a",
|
|
237
237
|
"plugin-kv-api.md": "5e095581020043af73ff028e272f56d42ca9eb6e506dd777d45703f9db796a5b",
|
|
238
238
|
"plugin-quickstart.md": "19092b278d80df357ea623dc3bd9f833d059582ee1356f317621913d91e50512",
|
|
239
239
|
"prompt-preamble.md": "5d0f836688aa23eafc32104c3174132340b268361f6060326eec84da17c6ad6d",
|
|
@@ -260,11 +260,11 @@
|
|
|
260
260
|
"schemas/node.schema.json": "1ebba38e0c0ae022fccbc0cdf7c298da1720a68d4cb375f0baf9f0847998a0d8",
|
|
261
261
|
"schemas/plugins-doctor.schema.json": "03e2dc51c052a09bf0198c80e2c26e6129734ada4a748e483245de3dd8576c42",
|
|
262
262
|
"schemas/plugins-registry.schema.json": "211d081691fc83526e1593c79ed9741ad8a5dbd4db1a756f72141b0cced2ea15",
|
|
263
|
-
"schemas/project-config.schema.json": "
|
|
263
|
+
"schemas/project-config.schema.json": "3724ed08ff06a8debe1f8f8a07f0d5f42e7f78ba7806a5c44844d4416f1b34df",
|
|
264
264
|
"schemas/refresh-report.schema.json": "47184d4f6b15e9b7671dc178b3b3886a64422da198898508ecdb2cb27876db04",
|
|
265
265
|
"schemas/report-base-deterministic.schema.json": "59785fe6f3ceb34814bbbd03d10fa7336a32835ce598946f2923d469b32aa32a",
|
|
266
266
|
"schemas/report-base.schema.json": "e4d25f055e24f18ae0f77c24661c1bddc87ff2e43b001b6a827fcb14f9753f44",
|
|
267
|
-
"schemas/scan-result.schema.json": "
|
|
267
|
+
"schemas/scan-result.schema.json": "236c7022fbbe19ffc1d8ad9bfab1159c427adba435da22ffda884b6c29420156",
|
|
268
268
|
"schemas/sidecar.schema.json": "f9d914e61b2d04495b84dc90e55240aca959e6f16137e5bfa4c0e10ada33ecbe",
|
|
269
269
|
"schemas/signal.schema.json": "c677f04964dcc15e00368c5cc4b0569fb4cf21889d34fa3c29dc21a5cb6b919c",
|
|
270
270
|
"schemas/summaries/agent.schema.json": "5b26b95fb082b73d302c8aa6489ab09488a155ccfbb8943dfc47079509d35122",
|
package/package.json
CHANGED
package/plugin-author-guide.md
CHANGED
|
@@ -227,7 +227,7 @@ Pure single-node analysis. **Never** read another node, the graph, or the databa
|
|
|
227
227
|
|
|
228
228
|
You can read `ctx.node.sidecar.*` freely: the per-`(node, extractor)` cache hashes the sidecar `annotations` block alongside the body, so a `.sm`-only edit invalidates the cached run automatically.
|
|
229
229
|
|
|
230
|
-
> **Pick a syntax that doesn't collide with built-ins.** `core/at-directive` claims `@`, `core/slash-command` claims `/`, both with LLM-aligned semantics (and both strip fenced code blocks
|
|
230
|
+
> **Pick a syntax that doesn't collide with built-ins.** `core/at-directive` claims `@`, `core/slash-command` claims `/`, both with LLM-aligned semantics (and both strip fenced code blocks, inline backticks, and raw HTML before matching). `core/backtick-path` is the deliberate inverse: it matches relative `.md` paths ONLY inside those stripped code regions, so it cannot overlap the prose-side extractors. A new extractor matching one of those prefixes fires on the same input and emits a competing link; when both resolve to the same node that surfaces as `reference-redundant` (`name-collision` is reserved for two nodes declaring the same resolvable `name`, not for overlapping invocation forms). The example below uses a wikilink-style `[[ref:<name>]]` pattern to side-step the overlap. See [`architecture.md` §Extractor · trigger normalization](./architecture.md#extractor--trigger-normalization) for the normalization pipeline.
|
|
231
231
|
|
|
232
232
|
```javascript
|
|
233
233
|
export default {
|
|
@@ -46,10 +46,15 @@
|
|
|
46
46
|
"minimum": 1,
|
|
47
47
|
"description": "Files larger than this are skipped before they are read and surfaced at WARN level. Default 1048576 (1 MiB). Protects against scanning accidental binary drops or generated artefacts. Every skipped file is reported in `ScanResult.oversizedFiles` (root-relative path + byte size), counted in `ScanResult.stats.filesOversized`, printed as a terminal warning on `sm scan` / `sm watch` / `sm serve`, and raised as a UI banner. Trim the offending paths via `.skillmapignore` or raise this limit to include them."
|
|
48
48
|
},
|
|
49
|
+
"maxScan": {
|
|
50
|
+
"type": "integer",
|
|
51
|
+
"minimum": 1,
|
|
52
|
+
"description": "Scan corpus ceiling: hard cap on the number of files the scan accepts after `.skillmapignore` filtering, before extractors run. Default 50000. The scan walks, parses, analyzes, and reference-validates every file up to this ceiling; that full corpus is what link resolution checks against, so references resolve across the whole project (a large monorepo) regardless of how many nodes the map renders. When the walker reaches the ceiling, additional files are dropped in stable provider-walker order and the scan is marked truncated in `scan_meta` (the UI raises a persistent banner pointing at the `.skillmapignore` editor in Settings → Project). Override per invocation with `--max-scan N` on `sm scan` / `sm watch` / `sm serve`, bidirectional (raises OR lowers the ceiling, the flag is a full override of this setting). Distinct from `maxNodes`, which bounds only the graph render, not the scan."
|
|
53
|
+
},
|
|
49
54
|
"maxNodes": {
|
|
50
55
|
"type": "integer",
|
|
51
56
|
"minimum": 1,
|
|
52
|
-
"description": "
|
|
57
|
+
"description": "Map render cap: the maximum number of nodes the graph view projects onto the canvas at once. Default 256. This does NOT bound the scan; the full corpus is walked and reference-validated up to `maxScan`, and the folders tree shows all of it. `maxNodes` only limits the Foblex graph projection so a large project stays readable. When a selected folder branch exceeds this cap, the map renders the branch's first N nodes (stable order) and raises an in-view banner inviting the user to pick a narrower sub-folder. Override per invocation with `--max-nodes N` on `sm scan` / `sm watch` / `sm serve`; the value persists in `scan_meta` and is read by the UI when the map renders. Headless `sm scan` records but does not act on it (it renders nothing)."
|
|
53
58
|
},
|
|
54
59
|
"watch": {
|
|
55
60
|
"type": "object",
|
|
@@ -41,15 +41,19 @@
|
|
|
41
41
|
"type": "string",
|
|
42
42
|
"description": "Resolved offline tokenizer (encoder) that produced the per-node token counts in this scan, one of the closed allow-list in `project-config.schema.json#/properties/tokenizer` (`cl100k_base` default, `o200k_base`). Mirrors `scan_meta.tokenizer`. Reported so consumers know which encoder the counts came from; the incremental scan compares the persisted value against the resolved one and force-recomputes counts when they differ. Absent on synthetic fixtures and when tokenization was disabled."
|
|
43
43
|
},
|
|
44
|
-
"
|
|
44
|
+
"scanCeiling": {
|
|
45
45
|
"type": "integer",
|
|
46
46
|
"minimum": 1,
|
|
47
|
-
"description": "Effective
|
|
47
|
+
"description": "Effective walk ceiling for this scan (`--max-scan <N>` override on `sm scan` / `sm watch` / `sm serve`, else `scan.maxScan` from settings, default 50000). The scan walks, parses, analyzes, and reference-validates the full corpus up to this number, so references resolve across the whole project regardless of how many nodes the map renders. Mirrors `scan_meta.scan_ceiling`. Absent on synthetic fixtures."
|
|
48
48
|
},
|
|
49
|
-
"
|
|
50
|
-
"type":
|
|
49
|
+
"scanTruncated": {
|
|
50
|
+
"type": "boolean",
|
|
51
|
+
"description": "True when the walker reached `scanCeiling` and dropped files in stable provider-walker order, false otherwise. Reported so the UI raises the persistent 'scan truncated' banner pointing at the `.skillmapignore` editor. Mirrors `scan_meta.scan_truncated`. Absent on synthetic fixtures."
|
|
52
|
+
},
|
|
53
|
+
"maxRenderNodes": {
|
|
54
|
+
"type": "integer",
|
|
51
55
|
"minimum": 1,
|
|
52
|
-
"description": "
|
|
56
|
+
"description": "Effective map render cap for this scan (`--max-nodes <N>` override, else `scan.maxNodes` from settings, default 256). Does NOT bound the scan (the full corpus up to `scanCeiling` is persisted and the folders tree shows all of it); it only bounds the graph projection. The UI projects the selected folder branch capped at this number and raises an in-view banner when a branch exceeds it. Mirrors `scan_meta.max_render_nodes`. Absent on synthetic fixtures."
|
|
53
57
|
},
|
|
54
58
|
"oversizedFiles": {
|
|
55
59
|
"type": "array",
|