@skill-map/cli 0.45.1 → 0.46.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.
Files changed (43) hide show
  1. package/dist/cli/tutorial/sm-master/SKILL.md +29 -29
  2. package/dist/cli/tutorial/sm-master/references/fixture-templates.md +18 -13
  3. package/dist/cli/tutorial/sm-master/references/tour-authoring.md +35 -40
  4. package/dist/cli/tutorial/sm-master/references/tour-plugins.md +32 -32
  5. package/dist/cli/tutorial/sm-master/references/tour-settings.md +156 -75
  6. package/dist/cli/tutorial/sm-tutorial/SKILL.md +3 -3
  7. package/dist/cli.js +606 -301
  8. package/dist/conformance/index.js +4 -1
  9. package/dist/index.js +44 -17
  10. package/dist/kernel/index.d.ts +64 -9
  11. package/dist/kernel/index.js +44 -17
  12. package/dist/migrations/001_initial.sql +7 -0
  13. package/dist/ui/chunk-22CKFAEU.js +1 -0
  14. package/dist/ui/{chunk-I5AX4U2N.js → chunk-3YSNJXGB.js} +1 -1
  15. package/dist/ui/{chunk-MS6B7344.js → chunk-6AP364TB.js} +7 -7
  16. package/dist/ui/{chunk-VGPYYAVI.js → chunk-EPBUSS3I.js} +1 -1
  17. package/dist/ui/{chunk-IYM26L3O.js → chunk-ERUALZOV.js} +1 -1
  18. package/dist/ui/{chunk-5AD5ZV4I.js → chunk-EYBKZOMF.js} +1 -1
  19. package/dist/ui/{chunk-2RAE3FAN.js → chunk-F4RIBZ4P.js} +1 -1
  20. package/dist/ui/chunk-HAWX5WNM.js +4 -0
  21. package/dist/ui/{chunk-QDUSFOBE.js → chunk-K365TVPA.js} +1 -1
  22. package/dist/ui/{chunk-ZIGUUDUX.js → chunk-L3JYFPSZ.js} +2 -2
  23. package/dist/ui/chunk-N3RUQDAR.js +1 -0
  24. package/dist/ui/{chunk-A7PRWMQD.js → chunk-P4E74ZOS.js} +1 -1
  25. package/dist/ui/{chunk-X227ITGS.js → chunk-RT7E4S5B.js} +1 -1
  26. package/dist/ui/{chunk-QNTAOR2L.js → chunk-RXQYLVSJ.js} +1 -1
  27. package/dist/ui/{chunk-MFLFIA7C.js → chunk-S32E6ZCZ.js} +1 -1
  28. package/dist/ui/{chunk-T3IVIRRJ.js → chunk-SF4FUT4U.js} +1 -1
  29. package/dist/ui/chunk-VNA3TMIO.js +1 -0
  30. package/dist/ui/{chunk-F7I6KMHX.js → chunk-VW2A6WZ3.js} +1 -1
  31. package/dist/ui/chunk-ZZJ7XWDX.js +1 -0
  32. package/dist/ui/index.html +1 -1
  33. package/dist/ui/main-NF5GO3JR.js +4 -0
  34. package/migrations/001_initial.sql +7 -0
  35. package/package.json +2 -2
  36. package/dist/cli.js.map +0 -1
  37. package/dist/conformance/index.js.map +0 -1
  38. package/dist/index.js.map +0 -1
  39. package/dist/kernel/index.js.map +0 -1
  40. package/dist/ui/chunk-27WQPOXP.js +0 -1
  41. package/dist/ui/chunk-555ST76V.js +0 -1
  42. package/dist/ui/chunk-PZQHB7GS.js +0 -4
  43. package/dist/ui/main-KMSUFJ6Y.js +0 -3
@@ -1,4 +1,6 @@
1
1
  // conformance/index.ts
2
+
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e3097683-993f-599d-92ef-d1e724637586")}catch(e){}}();
2
4
  import { spawnSync } from "child_process";
3
5
  import { cpSync, existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from "fs";
4
6
  import { tmpdir } from "os";
@@ -422,4 +424,5 @@ export {
422
424
  assertSpecRoot,
423
425
  runConformanceCase
424
426
  };
425
- //# sourceMappingURL=index.js.map
427
+ //# sourceMappingURL=index.js.map
428
+ //# debugId=e3097683-993f-599d-92ef-d1e724637586
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  // kernel/i18n/registry.texts.ts
2
+
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="06565fad-66f0-5ec4-b01b-746d84e4893d")}catch(e){}}();
2
4
  var REGISTRY_TEXTS = {
3
5
  duplicateExtension: "Extension already registered: {{kind}}:{{qualifiedId}}",
4
6
  unknownKind: "Unknown extension kind: {{kind}}",
@@ -101,7 +103,7 @@ import cl100k_base from "js-tiktoken/ranks/cl100k_base";
101
103
  // package.json
102
104
  var package_default = {
103
105
  name: "@skill-map/cli",
104
- version: "0.45.1",
106
+ version: "0.46.0",
105
107
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
106
108
  license: "MIT",
107
109
  type: "module",
@@ -765,16 +767,13 @@ function strip(value) {
765
767
  // config/defaults.json
766
768
  var defaults_default = {
767
769
  schemaVersion: 1,
768
- autoMigrate: true,
769
770
  allowEditSmFiles: false,
770
771
  tokenizer: "cl100k_base",
771
- providers: [],
772
772
  roots: [],
773
773
  ignore: [],
774
774
  scan: {
775
775
  tokenize: true,
776
776
  strict: false,
777
- followSymlinks: false,
778
777
  maxFileSizeBytes: 1048576,
779
778
  maxNodes: 256,
780
779
  watch: {
@@ -783,9 +782,6 @@ var defaults_default = {
783
782
  referencePaths: []
784
783
  },
785
784
  plugins: {},
786
- history: {
787
- share: false
788
- },
789
785
  jobs: {
790
786
  ttlSeconds: 3600,
791
787
  graceMultiplier: 3,
@@ -796,9 +792,6 @@ var defaults_default = {
796
792
  completed: 2592e3,
797
793
  failed: null
798
794
  }
799
- },
800
- i18n: {
801
- locale: "en"
802
795
  }
803
796
  };
804
797
 
@@ -2363,8 +2356,9 @@ async function* walkContent(roots, options) {
2363
2356
  if (!parser) throw new UnknownParserError(options.parser);
2364
2357
  const filter = options.ignoreFilter ?? buildIgnoreFilter();
2365
2358
  const extensions = options.extensions;
2359
+ const sizeLimit = buildSizeLimit(options);
2366
2360
  for (const root of roots) {
2367
- for await (const file of walkRoot(root, root, filter, extensions)) {
2361
+ for await (const file of walkRoot(root, root, filter, extensions, sizeLimit)) {
2368
2362
  const relPath = relative2(root, file).split(sep2).join("/");
2369
2363
  let raw;
2370
2364
  try {
@@ -2387,7 +2381,15 @@ async function* walkContent(roots, options) {
2387
2381
  }
2388
2382
  }
2389
2383
  }
2390
- async function* walkRoot(root, current, filter, extensions) {
2384
+ function buildSizeLimit(options) {
2385
+ const sizeLimit = {};
2386
+ if (options.maxFileSizeBytes !== void 0) {
2387
+ sizeLimit.maxFileSizeBytes = options.maxFileSizeBytes;
2388
+ }
2389
+ if (options.onOversizedFile) sizeLimit.onOversizedFile = options.onOversizedFile;
2390
+ return sizeLimit;
2391
+ }
2392
+ async function* walkRoot(root, current, filter, extensions, sizeLimit) {
2391
2393
  let entries;
2392
2394
  try {
2393
2395
  entries = await readdir(current, { withFileTypes: true, encoding: "utf8" });
@@ -2401,11 +2403,16 @@ async function* walkRoot(root, current, filter, extensions) {
2401
2403
  if (filter.ignores(rel)) continue;
2402
2404
  if (entry.isSymbolicLink()) continue;
2403
2405
  if (entry.isDirectory()) {
2404
- yield* walkRoot(root, full, filter, extensions);
2406
+ yield* walkRoot(root, full, filter, extensions, sizeLimit);
2405
2407
  } else if (entry.isFile() && hasMatchingExtension(name, extensions)) {
2406
2408
  try {
2407
2409
  const s = await lstat(full);
2408
- if (s.isFile()) yield full;
2410
+ if (!s.isFile()) continue;
2411
+ if (sizeLimit.maxFileSizeBytes !== void 0 && s.size > sizeLimit.maxFileSizeBytes) {
2412
+ sizeLimit.onOversizedFile?.({ path: rel, bytes: s.size });
2413
+ continue;
2414
+ }
2415
+ yield full;
2409
2416
  } catch {
2410
2417
  }
2411
2418
  }
@@ -2435,6 +2442,10 @@ function resolveProviderWalk(provider) {
2435
2442
  parser: read.parser
2436
2443
  };
2437
2444
  if (options?.ignoreFilter) walkOptions.ignoreFilter = options.ignoreFilter;
2445
+ if (options?.maxFileSizeBytes !== void 0) {
2446
+ walkOptions.maxFileSizeBytes = options.maxFileSizeBytes;
2447
+ }
2448
+ if (options?.onOversizedFile) walkOptions.onOversizedFile = options.onOversizedFile;
2438
2449
  return walkContent(roots, walkOptions);
2439
2450
  };
2440
2451
  }
@@ -2843,7 +2854,18 @@ async function walkAndExtract(opts) {
2843
2854
  const accum = createWalkAccumulators();
2844
2855
  const wctx = buildWalkContext(opts);
2845
2856
  const claimedPaths = /* @__PURE__ */ new Set();
2846
- const walkOptions = opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {};
2857
+ const oversizedFiles = [];
2858
+ const oversizedSeen = /* @__PURE__ */ new Set();
2859
+ const onOversizedFile = (info) => {
2860
+ if (oversizedSeen.has(info.path)) return;
2861
+ oversizedSeen.add(info.path);
2862
+ oversizedFiles.push(info);
2863
+ };
2864
+ const walkOptions = {
2865
+ ...opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {},
2866
+ onOversizedFile,
2867
+ ...opts.maxFileSizeBytes !== void 0 ? { maxFileSizeBytes: opts.maxFileSizeBytes } : {}
2868
+ };
2847
2869
  let filesWalked = 0;
2848
2870
  let index = 0;
2849
2871
  const effectiveMaxNodes = opts.overrideMaxNodes ?? opts.recommendedNodeLimit;
@@ -2876,6 +2898,7 @@ async function walkAndExtract(opts) {
2876
2898
  cachedPaths: accum.cachedPaths,
2877
2899
  frontmatterIssues: accum.frontmatterIssues,
2878
2900
  filesWalked,
2901
+ oversizedFiles,
2879
2902
  recommendedNodeLimit: opts.recommendedNodeLimit,
2880
2903
  overrideMaxNodes: opts.overrideMaxNodes,
2881
2904
  capReached,
@@ -3163,7 +3186,8 @@ async function runScanInternal(_kernel, options) {
3163
3186
  pluginStores: options.pluginStores,
3164
3187
  activeProvider: activeProviderId,
3165
3188
  recommendedNodeLimit: options.recommendedNodeLimit ?? 256,
3166
- overrideMaxNodes: options.overrideMaxNodes ?? null
3189
+ overrideMaxNodes: options.overrideMaxNodes ?? null,
3190
+ ...options.maxFileSizeBytes !== void 0 ? { maxFileSizeBytes: options.maxFileSizeBytes } : {}
3167
3191
  });
3168
3192
  const activeProvider = activeProviderId ? exts.providers.find((p) => p.id === activeProviderId) ?? null : null;
3169
3193
  const resolved = resolveSignals({
@@ -3322,6 +3346,7 @@ function buildScanStats(walked, issues, start) {
3322
3346
  // Providers compete.
3323
3347
  filesWalked: walked.filesWalked,
3324
3348
  filesSkipped: 0,
3349
+ filesOversized: walked.oversizedFiles.length,
3325
3350
  nodesCount: walked.nodes.length,
3326
3351
  linksCount: walked.internalLinks.length,
3327
3352
  issuesCount: issues.length,
@@ -3338,6 +3363,7 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
3338
3363
  scannedBy: SCANNED_BY,
3339
3364
  recommendedNodeLimit: walked.recommendedNodeLimit,
3340
3365
  overrideMaxNodes: walked.overrideMaxNodes,
3366
+ oversizedFiles: walked.oversizedFiles,
3341
3367
  nodes: walked.nodes,
3342
3368
  links: walked.internalLinks,
3343
3369
  issues,
@@ -3775,4 +3801,5 @@ export {
3775
3801
  runScan,
3776
3802
  runScanWithRenames
3777
3803
  };
3778
- //# sourceMappingURL=index.js.map
3804
+ //# sourceMappingURL=index.js.map
3805
+ //# debugId=06565fad-66f0-5ec4-b01b-746d84e4893d
@@ -442,7 +442,7 @@ interface IExtensionBase {
442
442
  * 4. **Internal interfaces**, option bags, result records, config
443
443
  * slices, anything declared as `interface` and passed across
444
444
  * function boundaries inside the kernel / CLI but not part of the
445
- * spec: `IPluginRuntimeBundle`, `IPruneResult`, `IMigrationFile`,
445
+ * spec: `IPluginRuntime`, `IPruneResult`, `IMigrationFile`,
446
446
  * `IDbLocationOptions`. **`I` prefix.** The prefix matches
447
447
  * category 3 because both are "shapes that live in TypeScript
448
448
  * only, never in JSON".
@@ -912,6 +912,13 @@ interface ScanStats {
912
912
  * multiple Providers can claim the same file.
913
913
  */
914
914
  filesSkipped: number;
915
+ /**
916
+ * Files skipped by the walker BEFORE reading because their on-disk
917
+ * size exceeded `scan.maxFileSizeBytes`. Equals
918
+ * `ScanResult.oversizedFiles.length`. Absent on synthetic fixtures /
919
+ * loaders that predate the field; defaults to 0 when omitted.
920
+ */
921
+ filesOversized?: number;
915
922
  nodesCount: number;
916
923
  linksCount: number;
917
924
  issuesCount: number;
@@ -1035,11 +1042,30 @@ interface ScanResult {
1035
1042
  * setting). Bidirectional: can raise OR lower the recommended limit.
1036
1043
  */
1037
1044
  overrideMaxNodes?: number | null;
1045
+ /**
1046
+ * Files the walker skipped because their on-disk size exceeded
1047
+ * `scan.maxFileSizeBytes` (default 1 MiB). Each entry is the
1048
+ * root-relative, forward-slash path (same form as `node.path`) plus
1049
+ * the byte size. Drives the CLI / serve terminal WARN and the UI
1050
+ * banner. Defaults to `[]`; absent on synthetic fixtures that bypass
1051
+ * the walker.
1052
+ */
1053
+ oversizedFiles?: OversizedFile[];
1038
1054
  nodes: Node[];
1039
1055
  links: Link[];
1040
1056
  issues: Issue[];
1041
1057
  stats: ScanStats;
1042
1058
  }
1059
+ /**
1060
+ * One file the walker skipped for exceeding `scan.maxFileSizeBytes`.
1061
+ * Mirrors `scan-result.schema.json#/properties/oversizedFiles/items`.
1062
+ */
1063
+ interface OversizedFile {
1064
+ /** Root-relative, forward-slash path (same form as `node.path`). */
1065
+ path: string;
1066
+ /** On-disk size of the skipped file, in bytes. */
1067
+ bytes: number;
1068
+ }
1043
1069
 
1044
1070
  /**
1045
1071
  * Plugin-surface types, hand-written to mirror
@@ -1396,7 +1422,7 @@ interface IPersistOptions {
1396
1422
  * `<pluginId>/<extensionId>/<contributionId>`. Passed to the
1397
1423
  * `scan_contributions` upsert so the catalog sweep can drop rows
1398
1424
  * belonging to plugins / extensions that are no longer in the
1399
- * catalog (uninstalled plugins, disabled bundles, removed
1425
+ * catalog (uninstalled plugins, disabled plugins, removed
1400
1426
  * contributions). Empty / absent set = no catalog sweep (legacy
1401
1427
  * behaviour, leaves disabled-plugin rows stale per design F24
1402
1428
  * pre-fix).
@@ -1713,8 +1739,9 @@ interface IContributionRecord {
1713
1739
  *
1714
1740
  * Meta envelope: the `scan_meta` table persists `roots` /
1715
1741
  * `scannedAt` / `scannedBy` / `providers` / `stats.filesWalked` /
1716
- * `stats.filesSkipped` / `stats.durationMs`. When the row exists,
1717
- * those fields come back authoritatively. When it does not (DB
1742
+ * `stats.filesSkipped` / `stats.filesOversized` / `stats.durationMs` /
1743
+ * `oversizedFiles`. When the row exists, those fields come back
1744
+ * authoritatively. When it does not (DB
1718
1745
  * freshly migrated but never scanned, or a legacy DB never
1719
1746
  * re-persisted), the loader degrades to a synthetic envelope:
1720
1747
  *
@@ -2163,9 +2190,7 @@ interface IProvider extends IExtensionBase {
2163
2190
  * directly, it goes through `resolveProviderWalk(provider)` which
2164
2191
  * picks `walk` over `read`.
2165
2192
  */
2166
- walk?(roots: string[], options?: {
2167
- ignoreFilter?: IIgnoreFilter;
2168
- }): AsyncIterable<IRawNode>;
2193
+ walk?(roots: string[], options?: IProviderWalkOptions): AsyncIterable<IRawNode>;
2169
2194
  /**
2170
2195
  * Given a path and its parsed frontmatter, decide the node kind, or
2171
2196
  * `null` to disclaim the file. The classifier is called after walk()
@@ -2186,7 +2211,7 @@ interface IProvider extends IExtensionBase {
2186
2211
  /**
2187
2212
  * Strict resolution matrix consumed by the post-walk confidence-lift
2188
2213
  * transform: maps a `link.kind` (emitted by an Extractor in this
2189
- * Provider's bundle, e.g. `'mentions'`, `'invokes'`) to the set of
2214
+ * Provider's plugin, e.g. `'mentions'`, `'invokes'`) to the set of
2190
2215
  * target `node.kind` values that count as a valid resolution.
2191
2216
  *
2192
2217
  * Used to decide whether to bump a link's confidence to 1.0 when its
@@ -2317,6 +2342,28 @@ interface IResolverRules {
2317
2342
  */
2318
2343
  kindPriority?: readonly LinkKind[];
2319
2344
  }
2345
+ /**
2346
+ * Per-invocation options the orchestrator threads into a Provider walk
2347
+ * (and through `resolveProviderWalk` into the kernel walker). All
2348
+ * optional, so a bare `provider.walk(roots)` keeps working.
2349
+ *
2350
+ * - `ignoreFilter`, the composed `.skillmapignore` + config.ignore +
2351
+ * bundled-defaults filter.
2352
+ * - `maxFileSizeBytes` / `onOversizedFile`, mirror of
2353
+ * `scan.maxFileSizeBytes` and the collector that records skipped
2354
+ * files into `ScanResult.oversizedFiles`. A Provider that ships its
2355
+ * own `walk()` SHOULD forward both into `walkContent` (or apply the
2356
+ * same size guard) so oversized files stay skipped + reported
2357
+ * regardless of which discovery path runs.
2358
+ */
2359
+ interface IProviderWalkOptions {
2360
+ ignoreFilter?: IIgnoreFilter;
2361
+ maxFileSizeBytes?: number;
2362
+ onOversizedFile?: (info: {
2363
+ path: string;
2364
+ bytes: number;
2365
+ }) => void;
2366
+ }
2320
2367
  /**
2321
2368
  * Declarative read config a Provider declares via `IProvider.read`.
2322
2369
  * Mirrors `extensions/provider.schema.json#/properties/read` at the
@@ -3468,6 +3515,14 @@ interface RunScanOptions {
3468
3515
  * replaces the recommended limit for the duration of this scan.
3469
3516
  */
3470
3517
  overrideMaxNodes?: number | null;
3518
+ /**
3519
+ * Mirror of `scan.maxFileSizeBytes` (default 1 MiB). Threaded into
3520
+ * `walkAndExtract` so the walker skips any file larger than this
3521
+ * BEFORE reading it; skipped files surface in
3522
+ * `ScanResult.oversizedFiles` and `stats.filesOversized`. Absent → no
3523
+ * size limit (out-of-band callers and synthetic fixtures stay safe).
3524
+ */
3525
+ maxFileSizeBytes?: number;
3471
3526
  }
3472
3527
  /**
3473
3528
  * Same as `runScan` but also returns the rename heuristic's `RenameOp[]`
@@ -4015,7 +4070,7 @@ interface StoragePort {
4015
4070
  lookup(pluginId: string, contributionId: string, nodePath: string, extensionId?: string): Promise<IPersistedContribution[]>;
4016
4071
  /**
4017
4072
  * Drop rows for a plugin (optionally narrowed to a single
4018
- * extension within the bundle). Returns the number of deleted
4073
+ * extension within the plugin). Returns the number of deleted
4019
4074
  * rows. Called by `sm plugins disable` so the UI stops rendering
4020
4075
  * the disabled plugin's chips before the next scan.
4021
4076
  */
@@ -1,4 +1,6 @@
1
1
  // kernel/i18n/registry.texts.ts
2
+
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="06771c65-929f-52b4-a0eb-581d6c7216ff")}catch(e){}}();
2
4
  var REGISTRY_TEXTS = {
3
5
  duplicateExtension: "Extension already registered: {{kind}}:{{qualifiedId}}",
4
6
  unknownKind: "Unknown extension kind: {{kind}}",
@@ -101,7 +103,7 @@ import cl100k_base from "js-tiktoken/ranks/cl100k_base";
101
103
  // package.json
102
104
  var package_default = {
103
105
  name: "@skill-map/cli",
104
- version: "0.45.1",
106
+ version: "0.46.0",
105
107
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
106
108
  license: "MIT",
107
109
  type: "module",
@@ -765,16 +767,13 @@ function strip(value) {
765
767
  // config/defaults.json
766
768
  var defaults_default = {
767
769
  schemaVersion: 1,
768
- autoMigrate: true,
769
770
  allowEditSmFiles: false,
770
771
  tokenizer: "cl100k_base",
771
- providers: [],
772
772
  roots: [],
773
773
  ignore: [],
774
774
  scan: {
775
775
  tokenize: true,
776
776
  strict: false,
777
- followSymlinks: false,
778
777
  maxFileSizeBytes: 1048576,
779
778
  maxNodes: 256,
780
779
  watch: {
@@ -783,9 +782,6 @@ var defaults_default = {
783
782
  referencePaths: []
784
783
  },
785
784
  plugins: {},
786
- history: {
787
- share: false
788
- },
789
785
  jobs: {
790
786
  ttlSeconds: 3600,
791
787
  graceMultiplier: 3,
@@ -796,9 +792,6 @@ var defaults_default = {
796
792
  completed: 2592e3,
797
793
  failed: null
798
794
  }
799
- },
800
- i18n: {
801
- locale: "en"
802
795
  }
803
796
  };
804
797
 
@@ -2363,8 +2356,9 @@ async function* walkContent(roots, options) {
2363
2356
  if (!parser) throw new UnknownParserError(options.parser);
2364
2357
  const filter = options.ignoreFilter ?? buildIgnoreFilter();
2365
2358
  const extensions = options.extensions;
2359
+ const sizeLimit = buildSizeLimit(options);
2366
2360
  for (const root of roots) {
2367
- for await (const file of walkRoot(root, root, filter, extensions)) {
2361
+ for await (const file of walkRoot(root, root, filter, extensions, sizeLimit)) {
2368
2362
  const relPath = relative2(root, file).split(sep2).join("/");
2369
2363
  let raw;
2370
2364
  try {
@@ -2387,7 +2381,15 @@ async function* walkContent(roots, options) {
2387
2381
  }
2388
2382
  }
2389
2383
  }
2390
- async function* walkRoot(root, current, filter, extensions) {
2384
+ function buildSizeLimit(options) {
2385
+ const sizeLimit = {};
2386
+ if (options.maxFileSizeBytes !== void 0) {
2387
+ sizeLimit.maxFileSizeBytes = options.maxFileSizeBytes;
2388
+ }
2389
+ if (options.onOversizedFile) sizeLimit.onOversizedFile = options.onOversizedFile;
2390
+ return sizeLimit;
2391
+ }
2392
+ async function* walkRoot(root, current, filter, extensions, sizeLimit) {
2391
2393
  let entries;
2392
2394
  try {
2393
2395
  entries = await readdir(current, { withFileTypes: true, encoding: "utf8" });
@@ -2401,11 +2403,16 @@ async function* walkRoot(root, current, filter, extensions) {
2401
2403
  if (filter.ignores(rel)) continue;
2402
2404
  if (entry.isSymbolicLink()) continue;
2403
2405
  if (entry.isDirectory()) {
2404
- yield* walkRoot(root, full, filter, extensions);
2406
+ yield* walkRoot(root, full, filter, extensions, sizeLimit);
2405
2407
  } else if (entry.isFile() && hasMatchingExtension(name, extensions)) {
2406
2408
  try {
2407
2409
  const s = await lstat(full);
2408
- if (s.isFile()) yield full;
2410
+ if (!s.isFile()) continue;
2411
+ if (sizeLimit.maxFileSizeBytes !== void 0 && s.size > sizeLimit.maxFileSizeBytes) {
2412
+ sizeLimit.onOversizedFile?.({ path: rel, bytes: s.size });
2413
+ continue;
2414
+ }
2415
+ yield full;
2409
2416
  } catch {
2410
2417
  }
2411
2418
  }
@@ -2435,6 +2442,10 @@ function resolveProviderWalk(provider) {
2435
2442
  parser: read.parser
2436
2443
  };
2437
2444
  if (options?.ignoreFilter) walkOptions.ignoreFilter = options.ignoreFilter;
2445
+ if (options?.maxFileSizeBytes !== void 0) {
2446
+ walkOptions.maxFileSizeBytes = options.maxFileSizeBytes;
2447
+ }
2448
+ if (options?.onOversizedFile) walkOptions.onOversizedFile = options.onOversizedFile;
2438
2449
  return walkContent(roots, walkOptions);
2439
2450
  };
2440
2451
  }
@@ -2843,7 +2854,18 @@ async function walkAndExtract(opts) {
2843
2854
  const accum = createWalkAccumulators();
2844
2855
  const wctx = buildWalkContext(opts);
2845
2856
  const claimedPaths = /* @__PURE__ */ new Set();
2846
- const walkOptions = opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {};
2857
+ const oversizedFiles = [];
2858
+ const oversizedSeen = /* @__PURE__ */ new Set();
2859
+ const onOversizedFile = (info) => {
2860
+ if (oversizedSeen.has(info.path)) return;
2861
+ oversizedSeen.add(info.path);
2862
+ oversizedFiles.push(info);
2863
+ };
2864
+ const walkOptions = {
2865
+ ...opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {},
2866
+ onOversizedFile,
2867
+ ...opts.maxFileSizeBytes !== void 0 ? { maxFileSizeBytes: opts.maxFileSizeBytes } : {}
2868
+ };
2847
2869
  let filesWalked = 0;
2848
2870
  let index = 0;
2849
2871
  const effectiveMaxNodes = opts.overrideMaxNodes ?? opts.recommendedNodeLimit;
@@ -2876,6 +2898,7 @@ async function walkAndExtract(opts) {
2876
2898
  cachedPaths: accum.cachedPaths,
2877
2899
  frontmatterIssues: accum.frontmatterIssues,
2878
2900
  filesWalked,
2901
+ oversizedFiles,
2879
2902
  recommendedNodeLimit: opts.recommendedNodeLimit,
2880
2903
  overrideMaxNodes: opts.overrideMaxNodes,
2881
2904
  capReached,
@@ -3163,7 +3186,8 @@ async function runScanInternal(_kernel, options) {
3163
3186
  pluginStores: options.pluginStores,
3164
3187
  activeProvider: activeProviderId,
3165
3188
  recommendedNodeLimit: options.recommendedNodeLimit ?? 256,
3166
- overrideMaxNodes: options.overrideMaxNodes ?? null
3189
+ overrideMaxNodes: options.overrideMaxNodes ?? null,
3190
+ ...options.maxFileSizeBytes !== void 0 ? { maxFileSizeBytes: options.maxFileSizeBytes } : {}
3167
3191
  });
3168
3192
  const activeProvider = activeProviderId ? exts.providers.find((p) => p.id === activeProviderId) ?? null : null;
3169
3193
  const resolved = resolveSignals({
@@ -3322,6 +3346,7 @@ function buildScanStats(walked, issues, start) {
3322
3346
  // Providers compete.
3323
3347
  filesWalked: walked.filesWalked,
3324
3348
  filesSkipped: 0,
3349
+ filesOversized: walked.oversizedFiles.length,
3325
3350
  nodesCount: walked.nodes.length,
3326
3351
  linksCount: walked.internalLinks.length,
3327
3352
  issuesCount: issues.length,
@@ -3338,6 +3363,7 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
3338
3363
  scannedBy: SCANNED_BY,
3339
3364
  recommendedNodeLimit: walked.recommendedNodeLimit,
3340
3365
  overrideMaxNodes: walked.overrideMaxNodes,
3366
+ oversizedFiles: walked.oversizedFiles,
3341
3367
  nodes: walked.nodes,
3342
3368
  links: walked.internalLinks,
3343
3369
  issues,
@@ -3775,4 +3801,5 @@ export {
3775
3801
  runScan,
3776
3802
  runScanWithRenames
3777
3803
  };
3778
- //# sourceMappingURL=index.js.map
3804
+ //# sourceMappingURL=index.js.map
3805
+ //# debugId=06771c65-929f-52b4-a0eb-581d6c7216ff
@@ -292,6 +292,13 @@ CREATE TABLE scan_meta (
292
292
  -- was passed) or NULL when the value above came from the setting.
293
293
  recommended_node_limit INTEGER NOT NULL,
294
294
  override_max_nodes INTEGER,
295
+ -- File-size skip envelope (see spec/cli-contract.md §Scan, `scan.maxFileSizeBytes`
296
+ -- setting, default 1 MiB). `files_oversized` is the count of files the walker
297
+ -- skipped before reading because they exceeded the limit (= `stats.filesOversized`);
298
+ -- `oversized_files_json` is the JSON array of `{ path, bytes }` entries the CLI /
299
+ -- serve terminal warns on and the UI banner lists. NULL when no file was skipped.
300
+ files_oversized INTEGER NOT NULL DEFAULT 0,
301
+ oversized_files_json TEXT,
295
302
  CONSTRAINT ck_scan_meta_singleton CHECK (id = 1)
296
303
  );
297
304
 
@@ -0,0 +1 @@
1
+ import{Ka as i,Za as r,Zb as s,_b as l,yb as o,zb as a}from"./chunk-HAWX5WNM.js";import"./chunk-WCABR6TI.js";var n={triggering:"Triggering an intentional uncaught error to exercise UI Sentry error reporting...",errorMessage:"skill-map UI intentional failure (Sentry self-test)"};var d=(()=>{class e{texts=n;ngOnInit(){console.warn(n.triggering),setTimeout(()=>{throw new Error(n.errorMessage)},0)}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=r({type:e,selectors:[["sm-intentional-fail"]],decls:2,vars:1,consts:[["data-testid","intentional-fail",1,"sm-intentional-fail"]],template:function(t,c){t&1&&(o(0,"p",0),s(1),a()),t&2&&(i(),l(c.texts.triggering))},encapsulation:2,changeDetection:0})}return e})();export{d as IntentionalFail};
@@ -1,4 +1,4 @@
1
- import{a as Ht,b as Nt,c as Ui,d as qt,e as Yt,f as mn,g as Wt,h as hn,i as _n,j as Zt,k as hi,l as fn,m as gn,o as bn,p as yn,q as xn}from"./chunk-T3IVIRRJ.js";import{a as Qe,b as Qt}from"./chunk-MFLFIA7C.js";import{a as tn,b as ln,c as cn,e as dn,f as pn,g as un}from"./chunk-5AD5ZV4I.js";import{a as ct,b as qi,d as $t,e as mt,f as an,g as on}from"./chunk-IYM26L3O.js";import{c as Wi,e as Zi,h as Ji,i as Xi,k as en,m as Ut,n as rn,p as sn}from"./chunk-QDUSFOBE.js";import{A as G,B as mi,C as Kt,D as Xe,E as dt,F as j,G as Qi,H as pt,I as Gt,J as Yi,R as jt,S as Ae,T as nn,U as ut,V as et,W as tt,X as $e,a as re,d as Hi,e as pi,f as zt,g as st,h as Ni,i as Ki,j as pe,k as Z,l as _e,m as ye,p as xe,q as Ke,r as $,s as $i,t as At,u as ui,v as qe,w as q,x as Ee,y as Gi,z as ji}from"./chunk-A7PRWMQD.js";import{A as Oi,D as Vi,F as Bi,J as Ri,O as It,R as Pi,T as Ne,U as Ze,V as Je,W as Li,X as St,a as Oe,aa as zi,b as li,ba as Mt,ca as Ai,k as si,l as ci,m as Di,n as Ei,p as di,t as ze,u as oe,v as We,w as Tt,x as Fi,z as kt}from"./chunk-4SG4352Z.js";import{$b as vt,Bb as A,Bc as C,Cb as ce,Cc as W,Db as I,Fb as s,Gb as Rt,Hb as lt,Ia as c,Ib as Me,Jb as De,K as Re,Kb as y,L as de,Lb as x,Lc as Le,M as fe,Nc as je,O as ue,Oc as we,Pb as Pe,Pc as Ue,Q as N,Qa as Se,Qb as ve,Qc as Ce,Rb as gt,Rc as he,Sb as ke,Tb as b,Ua as E,Ub as T,Va as ge,Vb as K,Vc as Ct,W as _,Wb as le,X as f,Xa as be,Xb as bt,Y as k,Ya as R,Za as p,Zb as yt,_ as Vt,_b as xt,ca as D,d as rt,da as Ye,dc as me,ec as oi,fc as Y,gb as w,gc as Ie,ha as Te,hb as Ii,hc as Pt,ib as Si,ic as ri,ja as Bt,jb as te,jc as Lt,kb as ie,kc as wt,la as F,lc as Mi,mc as ae,pb as r,pc as ne,qb as u,rb as m,sb as S,tb as X,tc as se,ub as ee,vb as H,wb as O,xb as V,yb as P}from"./chunk-PZQHB7GS.js";import{a as Be,b as ot}from"./chunk-WCABR6TI.js";var vn=`
1
+ import{a as Ht,b as Nt,c as Ui,d as qt,e as Yt,f as mn,g as Wt,h as hn,i as _n,j as Zt,k as hi,l as fn,m as gn,o as bn,p as yn,q as xn}from"./chunk-SF4FUT4U.js";import{a as Qe,b as Qt}from"./chunk-S32E6ZCZ.js";import{a as tn,b as ln,c as cn,e as dn,f as pn,g as un}from"./chunk-EYBKZOMF.js";import{a as ct,b as qi,d as $t,e as mt,f as an,g as on}from"./chunk-ERUALZOV.js";import{c as Wi,e as Zi,h as Ji,i as Xi,k as en,m as Ut,n as rn,p as sn}from"./chunk-K365TVPA.js";import{A as G,B as mi,C as Kt,D as Xe,E as dt,F as j,G as Qi,H as pt,I as Gt,J as Yi,R as jt,S as Ae,T as nn,U as ut,V as et,W as tt,X as $e,a as re,d as Hi,e as pi,f as zt,g as st,h as Ni,i as Ki,j as pe,k as Z,l as _e,m as ye,p as xe,q as Ke,r as $,s as $i,t as At,u as ui,v as qe,w as q,x as Ee,y as Gi,z as ji}from"./chunk-P4E74ZOS.js";import{A as Oi,D as Vi,F as Bi,J as Ri,O as It,R as Pi,T as Ne,U as Ze,V as Je,W as Li,X as St,a as Oe,aa as zi,b as li,ba as Mt,ca as Ai,k as si,l as ci,m as Di,n as Ei,p as di,t as ze,u as oe,v as We,w as Tt,x as Fi,z as kt}from"./chunk-4SG4352Z.js";import{g as Le,i as je,j as we,k as Ue,l as Ce,m as he,q as Ct}from"./chunk-VNA3TMIO.js";import{$b as le,Ab as H,Bb as O,Cb as V,Db as P,Gb as A,Hb as ce,Ib as I,Ic as C,Jc as W,K as Re,Ka as c,Kb as s,L as de,Lb as Rt,M as fe,Mb as lt,Nb as Me,O as ue,Ob as De,Pb as y,Q as N,Qb as x,Ta as Se,Ub as Pe,Vb as ve,W as _,Wb as gt,X as f,Xb as ke,Y as k,Yb as b,Za as E,Zb as T,_ as Vt,_a as ge,_b as K,ab as be,ac as bt,bb as R,ca as D,cb as p,cc as yt,d as rt,da as Ye,dc as xt,ec as vt,ha as Te,ic as me,ja as Bt,jc as oi,kc as Y,la as F,lb as w,lc as Ie,mb as Ii,mc as Pt,nb as Si,nc as ri,ob as te,oc as Lt,pb as ie,pc as wt,qc as Mi,rc as ae,ub as r,uc as ne,vb as u,wb as m,xb as S,yb as X,yc as se,zb as ee}from"./chunk-HAWX5WNM.js";import{a as Be,b as ot}from"./chunk-WCABR6TI.js";var vn=`
2
2
  .p-datatable {
3
3
  position: relative;
4
4
  display: block;