@skill-map/cli 0.20.1 → 0.21.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/tutorial/sm-tutorial.md +93 -14
- package/dist/cli.js +1332 -339
- package/dist/cli.js.map +1 -1
- package/dist/index.js +300 -238
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +91 -11
- package/dist/kernel/index.js +300 -238
- package/dist/kernel/index.js.map +1 -1
- package/dist/migrations/001_initial.sql +13 -0
- package/dist/ui/chunk-25AWRVIC.js +965 -0
- package/dist/ui/chunk-6FTVUS57.js +123 -0
- package/dist/ui/{chunk-4NLC7QD2.js → chunk-GXRWH2VL.js} +1 -1
- package/dist/ui/chunk-MF2M6GYF.js +1 -0
- package/dist/ui/{chunk-EZZF5RL5.js → chunk-MPMBTIUR.js} +2 -2
- package/dist/ui/chunk-N366HMME.js +1 -0
- package/dist/ui/{chunk-6GUHSAP5.js → chunk-OPPQMCMQ.js} +1 -1
- package/dist/ui/chunk-V3SZQETX.js +61 -0
- package/dist/ui/{chunk-E4ALROJS.js → chunk-VVOEPDQD.js} +1 -1
- package/dist/ui/{chunk-6BZZQV42.js → chunk-W2EFGI3J.js} +1 -1
- package/dist/ui/chunk-W62WVNU4.js +251 -0
- package/dist/ui/index.html +2 -10
- package/dist/ui/main-NIYE2VFS.js +2 -0
- package/dist/ui/media/fa-brands-400-AHOAZHCU.woff2 +0 -0
- package/dist/ui/media/fa-regular-400-VRZYIBIZ.woff2 +0 -0
- package/dist/ui/media/fa-solid-900-MDEYK55F.woff2 +0 -0
- package/dist/ui/media/fa-v4compatibility-ETEVP6IB.woff2 +0 -0
- package/dist/ui/styles-M2FETVAG.css +1 -0
- package/migrations/001_initial.sql +13 -0
- package/package.json +2 -2
- package/dist/ui/chunk-FWX4RRDF.js +0 -125
- package/dist/ui/chunk-GGMXMGRJ.js +0 -1
- package/dist/ui/chunk-K5PULFK7.js +0 -1
- package/dist/ui/chunk-OJ6W6OIB.js +0 -61
- package/dist/ui/chunk-PTCD42GB.js +0 -247
- package/dist/ui/chunk-ZSRIBCAW.js +0 -965
- package/dist/ui/main-5FJWWH5I.js +0 -1
- package/dist/ui/styles-VJ5Q6D2X.css +0 -1
package/dist/index.js
CHANGED
|
@@ -94,8 +94,8 @@ var Registry = class {
|
|
|
94
94
|
|
|
95
95
|
// kernel/orchestrator.ts
|
|
96
96
|
import { createHash } from "crypto";
|
|
97
|
-
import { existsSync as
|
|
98
|
-
import { isAbsolute as
|
|
97
|
+
import { existsSync as existsSync8, statSync as statSync2 } from "fs";
|
|
98
|
+
import { isAbsolute as isAbsolute3, resolve as resolvePath } from "path";
|
|
99
99
|
import { Tiktoken } from "js-tiktoken/lite";
|
|
100
100
|
import cl100k_base from "js-tiktoken/ranks/cl100k_base";
|
|
101
101
|
import yaml4 from "js-yaml";
|
|
@@ -103,7 +103,7 @@ import yaml4 from "js-yaml";
|
|
|
103
103
|
// package.json
|
|
104
104
|
var package_default = {
|
|
105
105
|
name: "@skill-map/cli",
|
|
106
|
-
version: "0.
|
|
106
|
+
version: "0.21.0",
|
|
107
107
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
108
108
|
license: "MIT",
|
|
109
109
|
type: "module",
|
|
@@ -169,7 +169,7 @@ var package_default = {
|
|
|
169
169
|
},
|
|
170
170
|
dependencies: {
|
|
171
171
|
"@hono/node-server": "2.0.1",
|
|
172
|
-
"@skill-map/spec": "0.
|
|
172
|
+
"@skill-map/spec": "0.21.0",
|
|
173
173
|
ajv: "8.18.0",
|
|
174
174
|
"ajv-formats": "3.0.1",
|
|
175
175
|
chokidar: "5.0.0",
|
|
@@ -368,175 +368,23 @@ function safeIsFile(path) {
|
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
// kernel/sidecar/store.ts
|
|
371
|
-
import { existsSync as
|
|
372
|
-
import { dirname as
|
|
373
|
-
import { createRequire as createRequire2 } from "module";
|
|
374
|
-
import { Ajv2020 as Ajv20202 } from "ajv/dist/2020.js";
|
|
375
|
-
import yaml2 from "js-yaml";
|
|
376
|
-
|
|
377
|
-
// kernel/adapters/in-memory-progress.ts
|
|
378
|
-
var InMemoryProgressEmitter = class {
|
|
379
|
-
#listeners = /* @__PURE__ */ new Set();
|
|
380
|
-
emit(event) {
|
|
381
|
-
for (const listener of this.#listeners) listener(event);
|
|
382
|
-
}
|
|
383
|
-
subscribe(listener) {
|
|
384
|
-
this.#listeners.add(listener);
|
|
385
|
-
return () => {
|
|
386
|
-
this.#listeners.delete(listener);
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
// kernel/adapters/silent-logger.ts
|
|
392
|
-
var SilentLogger = class {
|
|
393
|
-
trace() {
|
|
394
|
-
}
|
|
395
|
-
debug() {
|
|
396
|
-
}
|
|
397
|
-
info() {
|
|
398
|
-
}
|
|
399
|
-
warn() {
|
|
400
|
-
}
|
|
401
|
-
error() {
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
// kernel/util/logger.ts
|
|
406
|
-
var active = new SilentLogger();
|
|
407
|
-
var log = {
|
|
408
|
-
trace: (message, context) => active.trace(message, context),
|
|
409
|
-
debug: (message, context) => active.debug(message, context),
|
|
410
|
-
info: (message, context) => active.info(message, context),
|
|
411
|
-
warn: (message, context) => active.warn(message, context),
|
|
412
|
-
error: (message, context) => active.error(message, context)
|
|
413
|
-
};
|
|
414
|
-
function configureLogger(impl) {
|
|
415
|
-
active = impl;
|
|
416
|
-
}
|
|
417
|
-
function resetLogger() {
|
|
418
|
-
active = new SilentLogger();
|
|
419
|
-
}
|
|
420
|
-
function getActiveLogger() {
|
|
421
|
-
return active;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// kernel/adapters/plugin-loader.ts
|
|
371
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
372
|
+
import { dirname as dirname4, resolve as resolve5 } from "path";
|
|
425
373
|
import { createRequire as createRequire3 } from "module";
|
|
426
|
-
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
427
|
-
import { isAbsolute, join as join2, relative as relative2, resolve as resolve3 } from "path";
|
|
428
|
-
import { pathToFileURL } from "url";
|
|
429
374
|
import { Ajv2020 as Ajv20203 } from "ajv/dist/2020.js";
|
|
430
|
-
import
|
|
431
|
-
|
|
432
|
-
// kernel/i18n/plugin-store.texts.ts
|
|
433
|
-
var PLUGIN_STORE_TEXTS = {
|
|
434
|
-
kvValidationFailed: "plugin '{{pluginId}}' ctx.store.set('{{key}}', value): value violates declared schema ({{schemaPath}}) \u2014 {{errors}}",
|
|
435
|
-
dedicatedValidationFailed: "plugin '{{pluginId}}' ctx.store.write('{{table}}', row): row violates declared schema ({{schemaPath}}) \u2014 {{errors}}"
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
// kernel/adapters/plugin-store.ts
|
|
439
|
-
var KV_SCHEMA_KEY = "__kv__";
|
|
440
|
-
function makeKvStoreWrapper(opts) {
|
|
441
|
-
const { pluginId, schema, persist } = opts;
|
|
442
|
-
return {
|
|
443
|
-
async set(key, value) {
|
|
444
|
-
if (schema) {
|
|
445
|
-
if (!schema.validate(value)) {
|
|
446
|
-
throw new Error(
|
|
447
|
-
tx(PLUGIN_STORE_TEXTS.kvValidationFailed, {
|
|
448
|
-
pluginId,
|
|
449
|
-
schemaPath: schema.schemaPath,
|
|
450
|
-
key,
|
|
451
|
-
errors: formatAjvErrors(schema.validate.errors ?? null)
|
|
452
|
-
})
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
await persist(key, value);
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
function makeDedicatedStoreWrapper(opts) {
|
|
461
|
-
const { pluginId, schemas, persist } = opts;
|
|
462
|
-
return {
|
|
463
|
-
async write(table, row) {
|
|
464
|
-
const schema = schemas?.[table];
|
|
465
|
-
if (schema) {
|
|
466
|
-
if (!schema.validate(row)) {
|
|
467
|
-
throw new Error(
|
|
468
|
-
tx(PLUGIN_STORE_TEXTS.dedicatedValidationFailed, {
|
|
469
|
-
pluginId,
|
|
470
|
-
table,
|
|
471
|
-
schemaPath: schema.schemaPath,
|
|
472
|
-
errors: formatAjvErrors(schema.validate.errors ?? null)
|
|
473
|
-
})
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
await persist(table, row);
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
function makePluginStore(opts) {
|
|
482
|
-
const manifest = opts.plugin.manifest;
|
|
483
|
-
if (!manifest?.storage) return void 0;
|
|
484
|
-
const storageSchemas = opts.plugin.storageSchemas;
|
|
485
|
-
if (manifest.storage.mode === "kv") {
|
|
486
|
-
if (!opts.persistKv) return void 0;
|
|
487
|
-
const schema = storageSchemas?.[KV_SCHEMA_KEY];
|
|
488
|
-
return makeKvStoreWrapper({
|
|
489
|
-
pluginId: manifest.id,
|
|
490
|
-
schema,
|
|
491
|
-
persist: opts.persistKv
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
if (manifest.storage.mode === "dedicated") {
|
|
495
|
-
if (!opts.persistDedicated) return void 0;
|
|
496
|
-
return makeDedicatedStoreWrapper({
|
|
497
|
-
pluginId: manifest.id,
|
|
498
|
-
schemas: storageSchemas,
|
|
499
|
-
persist: opts.persistDedicated
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
return void 0;
|
|
503
|
-
}
|
|
504
|
-
function formatAjvErrors(errors) {
|
|
505
|
-
if (!errors || errors.length === 0) return "(no AJV details)";
|
|
506
|
-
return errors.map((e) => `${e.instancePath || "(root)"} ${e.message ?? e.keyword}`).join("; ");
|
|
507
|
-
}
|
|
375
|
+
import yaml2 from "js-yaml";
|
|
508
376
|
|
|
509
|
-
//
|
|
510
|
-
|
|
511
|
-
"boot",
|
|
512
|
-
"scan.started",
|
|
513
|
-
"scan.completed",
|
|
514
|
-
"extractor.completed",
|
|
515
|
-
"analyzer.completed",
|
|
516
|
-
"action.completed",
|
|
517
|
-
"job.spawning",
|
|
518
|
-
"job.completed",
|
|
519
|
-
"job.failed",
|
|
520
|
-
"shutdown"
|
|
521
|
-
]);
|
|
377
|
+
// core/config/helper.ts
|
|
378
|
+
import { isAbsolute, resolve as resolve4 } from "path";
|
|
522
379
|
|
|
523
|
-
// kernel/
|
|
524
|
-
|
|
525
|
-
var KNOWN_KINDS_LIST = [...KNOWN_KINDS].join(" / ");
|
|
526
|
-
var HOOKABLE_TRIGGERS_LIST = HOOK_TRIGGERS.join(", ");
|
|
527
|
-
function installedSpecVersion() {
|
|
528
|
-
const require2 = createRequire3(import.meta.url);
|
|
529
|
-
const indexPath = require2.resolve("@skill-map/spec/index.json");
|
|
530
|
-
const pkgPath = resolve3(indexPath, "..", "package.json");
|
|
531
|
-
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
532
|
-
return pkg.version;
|
|
533
|
-
}
|
|
380
|
+
// kernel/config/loader.ts
|
|
381
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
534
382
|
|
|
535
383
|
// kernel/adapters/schema-validators.ts
|
|
536
|
-
import { readFileSync as
|
|
537
|
-
import { dirname as
|
|
538
|
-
import { createRequire as
|
|
539
|
-
import { Ajv2020 as
|
|
384
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
385
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
386
|
+
import { createRequire as createRequire2 } from "module";
|
|
387
|
+
import { Ajv2020 as Ajv20202 } from "ajv/dist/2020.js";
|
|
540
388
|
var SCHEMA_FILES = {
|
|
541
389
|
node: "schemas/node.schema.json",
|
|
542
390
|
link: "schemas/link.schema.json",
|
|
@@ -572,22 +420,22 @@ function loadSchemaValidators() {
|
|
|
572
420
|
}
|
|
573
421
|
function buildSchemaValidators() {
|
|
574
422
|
const specRoot = resolveSpecRoot2();
|
|
575
|
-
const ajv = new
|
|
423
|
+
const ajv = new Ajv20202({
|
|
576
424
|
strict: false,
|
|
577
425
|
allErrors: true,
|
|
578
426
|
allowUnionTypes: true
|
|
579
427
|
});
|
|
580
428
|
applyAjvFormats(ajv);
|
|
581
429
|
for (const rel of SUPPORTING_SCHEMAS) {
|
|
582
|
-
const file =
|
|
430
|
+
const file = resolve2(specRoot, rel);
|
|
583
431
|
if (!existsSyncSafe(file)) continue;
|
|
584
|
-
const schema = JSON.parse(
|
|
432
|
+
const schema = JSON.parse(readFileSync2(file, "utf8"));
|
|
585
433
|
ajv.addSchema(schema);
|
|
586
434
|
}
|
|
587
435
|
const validators = /* @__PURE__ */ new Map();
|
|
588
436
|
for (const [name, rel] of Object.entries(SCHEMA_FILES)) {
|
|
589
|
-
const file =
|
|
590
|
-
const schema = JSON.parse(
|
|
437
|
+
const file = resolve2(specRoot, rel);
|
|
438
|
+
const schema = JSON.parse(readFileSync2(file, "utf8"));
|
|
591
439
|
const byId = typeof schema.$id === "string" ? ajv.getSchema(schema.$id) : void 0;
|
|
592
440
|
validators.set(name, byId ?? ajv.compile(schema));
|
|
593
441
|
}
|
|
@@ -607,7 +455,7 @@ function buildSchemaValidators() {
|
|
|
607
455
|
const KNOWN_SLOTS = /* @__PURE__ */ new Set([
|
|
608
456
|
"card.title.right",
|
|
609
457
|
"card.subtitle.left",
|
|
610
|
-
"card.footer.left
|
|
458
|
+
"card.footer.left",
|
|
611
459
|
"card.footer.right",
|
|
612
460
|
"graph.node.alert",
|
|
613
461
|
"inspector.header.badge.counter",
|
|
@@ -618,7 +466,7 @@ function buildSchemaValidators() {
|
|
|
618
466
|
"inspector.body.panel.key-values",
|
|
619
467
|
"inspector.body.panel.link-list",
|
|
620
468
|
"inspector.body.panel.markdown",
|
|
621
|
-
"topbar.
|
|
469
|
+
"topbar.nav.start"
|
|
622
470
|
]);
|
|
623
471
|
function getContributionValidator(slot) {
|
|
624
472
|
if (!KNOWN_SLOTS.has(slot)) return null;
|
|
@@ -668,14 +516,14 @@ function buildSchemaValidators() {
|
|
|
668
516
|
}
|
|
669
517
|
function buildProviderFrontmatterValidator(providers) {
|
|
670
518
|
const specRoot = resolveSpecRoot2();
|
|
671
|
-
const ajv = new
|
|
519
|
+
const ajv = new Ajv20202({
|
|
672
520
|
strict: false,
|
|
673
521
|
allErrors: true,
|
|
674
522
|
allowUnionTypes: true
|
|
675
523
|
});
|
|
676
524
|
applyAjvFormats(ajv);
|
|
677
|
-
const baseFile =
|
|
678
|
-
const baseSchema = JSON.parse(
|
|
525
|
+
const baseFile = resolve2(specRoot, "schemas/frontmatter/base.schema.json");
|
|
526
|
+
const baseSchema = JSON.parse(readFileSync2(baseFile, "utf8"));
|
|
679
527
|
ajv.addSchema(baseSchema);
|
|
680
528
|
registerProviderAuxiliarySchemas(ajv, providers);
|
|
681
529
|
const compiled = /* @__PURE__ */ new Map();
|
|
@@ -713,10 +561,10 @@ function registerProviderAuxiliarySchemas(ajv, providers) {
|
|
|
713
561
|
}
|
|
714
562
|
}
|
|
715
563
|
function resolveSpecRoot2() {
|
|
716
|
-
const require2 =
|
|
564
|
+
const require2 = createRequire2(import.meta.url);
|
|
717
565
|
try {
|
|
718
566
|
const indexPath = require2.resolve("@skill-map/spec/index.json");
|
|
719
|
-
return
|
|
567
|
+
return dirname2(indexPath);
|
|
720
568
|
} catch {
|
|
721
569
|
throw new Error(
|
|
722
570
|
"@skill-map/spec not resolvable \u2014 ensure the workspace is linked or the package is installed."
|
|
@@ -725,13 +573,201 @@ function resolveSpecRoot2() {
|
|
|
725
573
|
}
|
|
726
574
|
function existsSyncSafe(path) {
|
|
727
575
|
try {
|
|
728
|
-
|
|
576
|
+
readFileSync2(path, "utf8");
|
|
729
577
|
return true;
|
|
730
578
|
} catch {
|
|
731
579
|
return false;
|
|
732
580
|
}
|
|
733
581
|
}
|
|
734
582
|
|
|
583
|
+
// kernel/util/format-error.ts
|
|
584
|
+
function formatErrorMessage(err) {
|
|
585
|
+
return err instanceof Error ? err.message : String(err);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// kernel/util/skill-map-paths.ts
|
|
589
|
+
import { join as join3 } from "path";
|
|
590
|
+
|
|
591
|
+
// core/paths/db-path.ts
|
|
592
|
+
import { join as join2, resolve as resolve3 } from "path";
|
|
593
|
+
var SKILL_MAP_DIR = ".skill-map";
|
|
594
|
+
var DB_FILENAME = "skill-map.db";
|
|
595
|
+
var LOCAL_SETTINGS_FILENAME = "settings.local.json";
|
|
596
|
+
var DEFAULT_DB_REL = `${SKILL_MAP_DIR}/${DB_FILENAME}`;
|
|
597
|
+
var GITIGNORE_ENTRIES = [
|
|
598
|
+
`${SKILL_MAP_DIR}/${LOCAL_SETTINGS_FILENAME}`,
|
|
599
|
+
`${SKILL_MAP_DIR}/${DB_FILENAME}`
|
|
600
|
+
];
|
|
601
|
+
|
|
602
|
+
// core/config/atomic-write.ts
|
|
603
|
+
import {
|
|
604
|
+
existsSync as existsSync4,
|
|
605
|
+
mkdirSync,
|
|
606
|
+
readFileSync as readFileSync4,
|
|
607
|
+
renameSync,
|
|
608
|
+
unlinkSync,
|
|
609
|
+
writeFileSync
|
|
610
|
+
} from "fs";
|
|
611
|
+
import { dirname as dirname3 } from "path";
|
|
612
|
+
|
|
613
|
+
// kernel/adapters/in-memory-progress.ts
|
|
614
|
+
var InMemoryProgressEmitter = class {
|
|
615
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
616
|
+
emit(event) {
|
|
617
|
+
for (const listener of this.#listeners) listener(event);
|
|
618
|
+
}
|
|
619
|
+
subscribe(listener) {
|
|
620
|
+
this.#listeners.add(listener);
|
|
621
|
+
return () => {
|
|
622
|
+
this.#listeners.delete(listener);
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
// kernel/adapters/silent-logger.ts
|
|
628
|
+
var SilentLogger = class {
|
|
629
|
+
trace() {
|
|
630
|
+
}
|
|
631
|
+
debug() {
|
|
632
|
+
}
|
|
633
|
+
info() {
|
|
634
|
+
}
|
|
635
|
+
warn() {
|
|
636
|
+
}
|
|
637
|
+
error() {
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
// kernel/util/logger.ts
|
|
642
|
+
var active = new SilentLogger();
|
|
643
|
+
var log = {
|
|
644
|
+
trace: (message, context) => active.trace(message, context),
|
|
645
|
+
debug: (message, context) => active.debug(message, context),
|
|
646
|
+
info: (message, context) => active.info(message, context),
|
|
647
|
+
warn: (message, context) => active.warn(message, context),
|
|
648
|
+
error: (message, context) => active.error(message, context)
|
|
649
|
+
};
|
|
650
|
+
function configureLogger(impl) {
|
|
651
|
+
active = impl;
|
|
652
|
+
}
|
|
653
|
+
function resetLogger() {
|
|
654
|
+
active = new SilentLogger();
|
|
655
|
+
}
|
|
656
|
+
function getActiveLogger() {
|
|
657
|
+
return active;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// kernel/adapters/plugin-loader.ts
|
|
661
|
+
import { createRequire as createRequire4 } from "module";
|
|
662
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync2 } from "fs";
|
|
663
|
+
import { isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve6 } from "path";
|
|
664
|
+
import { pathToFileURL } from "url";
|
|
665
|
+
import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
|
|
666
|
+
import semver from "semver";
|
|
667
|
+
|
|
668
|
+
// kernel/i18n/plugin-store.texts.ts
|
|
669
|
+
var PLUGIN_STORE_TEXTS = {
|
|
670
|
+
kvValidationFailed: "plugin '{{pluginId}}' ctx.store.set('{{key}}', value): value violates declared schema ({{schemaPath}}) \u2014 {{errors}}",
|
|
671
|
+
dedicatedValidationFailed: "plugin '{{pluginId}}' ctx.store.write('{{table}}', row): row violates declared schema ({{schemaPath}}) \u2014 {{errors}}"
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
// kernel/adapters/plugin-store.ts
|
|
675
|
+
var KV_SCHEMA_KEY = "__kv__";
|
|
676
|
+
function makeKvStoreWrapper(opts) {
|
|
677
|
+
const { pluginId, schema, persist } = opts;
|
|
678
|
+
return {
|
|
679
|
+
async set(key, value) {
|
|
680
|
+
if (schema) {
|
|
681
|
+
if (!schema.validate(value)) {
|
|
682
|
+
throw new Error(
|
|
683
|
+
tx(PLUGIN_STORE_TEXTS.kvValidationFailed, {
|
|
684
|
+
pluginId,
|
|
685
|
+
schemaPath: schema.schemaPath,
|
|
686
|
+
key,
|
|
687
|
+
errors: formatAjvErrors(schema.validate.errors ?? null)
|
|
688
|
+
})
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
await persist(key, value);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function makeDedicatedStoreWrapper(opts) {
|
|
697
|
+
const { pluginId, schemas, persist } = opts;
|
|
698
|
+
return {
|
|
699
|
+
async write(table, row) {
|
|
700
|
+
const schema = schemas?.[table];
|
|
701
|
+
if (schema) {
|
|
702
|
+
if (!schema.validate(row)) {
|
|
703
|
+
throw new Error(
|
|
704
|
+
tx(PLUGIN_STORE_TEXTS.dedicatedValidationFailed, {
|
|
705
|
+
pluginId,
|
|
706
|
+
table,
|
|
707
|
+
schemaPath: schema.schemaPath,
|
|
708
|
+
errors: formatAjvErrors(schema.validate.errors ?? null)
|
|
709
|
+
})
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
await persist(table, row);
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function makePluginStore(opts) {
|
|
718
|
+
const manifest = opts.plugin.manifest;
|
|
719
|
+
if (!manifest?.storage) return void 0;
|
|
720
|
+
const storageSchemas = opts.plugin.storageSchemas;
|
|
721
|
+
if (manifest.storage.mode === "kv") {
|
|
722
|
+
if (!opts.persistKv) return void 0;
|
|
723
|
+
const schema = storageSchemas?.[KV_SCHEMA_KEY];
|
|
724
|
+
return makeKvStoreWrapper({
|
|
725
|
+
pluginId: manifest.id,
|
|
726
|
+
schema,
|
|
727
|
+
persist: opts.persistKv
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
if (manifest.storage.mode === "dedicated") {
|
|
731
|
+
if (!opts.persistDedicated) return void 0;
|
|
732
|
+
return makeDedicatedStoreWrapper({
|
|
733
|
+
pluginId: manifest.id,
|
|
734
|
+
schemas: storageSchemas,
|
|
735
|
+
persist: opts.persistDedicated
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
return void 0;
|
|
739
|
+
}
|
|
740
|
+
function formatAjvErrors(errors) {
|
|
741
|
+
if (!errors || errors.length === 0) return "(no AJV details)";
|
|
742
|
+
return errors.map((e) => `${e.instancePath || "(root)"} ${e.message ?? e.keyword}`).join("; ");
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// kernel/extensions/hook.ts
|
|
746
|
+
var HOOK_TRIGGERS = Object.freeze([
|
|
747
|
+
"boot",
|
|
748
|
+
"scan.started",
|
|
749
|
+
"scan.completed",
|
|
750
|
+
"extractor.completed",
|
|
751
|
+
"analyzer.completed",
|
|
752
|
+
"action.completed",
|
|
753
|
+
"job.spawning",
|
|
754
|
+
"job.completed",
|
|
755
|
+
"job.failed",
|
|
756
|
+
"shutdown"
|
|
757
|
+
]);
|
|
758
|
+
|
|
759
|
+
// kernel/adapters/plugin-loader.ts
|
|
760
|
+
var KNOWN_KINDS = /* @__PURE__ */ new Set(["provider", "extractor", "analyzer", "action", "formatter", "hook"]);
|
|
761
|
+
var KNOWN_KINDS_LIST = [...KNOWN_KINDS].join(" / ");
|
|
762
|
+
var HOOKABLE_TRIGGERS_LIST = HOOK_TRIGGERS.join(", ");
|
|
763
|
+
function installedSpecVersion() {
|
|
764
|
+
const require2 = createRequire4(import.meta.url);
|
|
765
|
+
const indexPath = require2.resolve("@skill-map/spec/index.json");
|
|
766
|
+
const pkgPath = resolve6(indexPath, "..", "package.json");
|
|
767
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
768
|
+
return pkg.version;
|
|
769
|
+
}
|
|
770
|
+
|
|
735
771
|
// kernel/i18n/orchestrator.texts.ts
|
|
736
772
|
var ORCHESTRATOR_TEXTS = {
|
|
737
773
|
frontmatterInvalid: "Frontmatter for {{path}} ({{kind}}) failed schema validation: {{errors}}",
|
|
@@ -746,18 +782,13 @@ var ORCHESTRATOR_TEXTS = {
|
|
|
746
782
|
runScanRootMissing: "runScan: root path '{{root}}' does not exist or is not a directory"
|
|
747
783
|
};
|
|
748
784
|
|
|
749
|
-
// kernel/util/format-error.ts
|
|
750
|
-
function formatErrorMessage(err) {
|
|
751
|
-
return err instanceof Error ? err.message : String(err);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
785
|
// kernel/scan/walk-content.ts
|
|
755
786
|
import { readFile, readdir, stat } from "fs/promises";
|
|
756
|
-
import { join as
|
|
787
|
+
import { join as join5, relative as relative3, sep as sep2 } from "path";
|
|
757
788
|
|
|
758
789
|
// kernel/scan/ignore.ts
|
|
759
|
-
import { existsSync as
|
|
760
|
-
import { dirname as
|
|
790
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
791
|
+
import { dirname as dirname5, resolve as resolve7 } from "path";
|
|
761
792
|
import { fileURLToPath } from "url";
|
|
762
793
|
import ignoreFactory from "ignore";
|
|
763
794
|
function buildIgnoreFilter(opts = {}) {
|
|
@@ -789,18 +820,18 @@ function loadDefaultsText() {
|
|
|
789
820
|
return cachedDefaults;
|
|
790
821
|
}
|
|
791
822
|
function readDefaultsFromDisk() {
|
|
792
|
-
const here =
|
|
823
|
+
const here = dirname5(fileURLToPath(import.meta.url));
|
|
793
824
|
const candidates = [
|
|
794
|
-
|
|
825
|
+
resolve7(here, "../../config/defaults/skillmapignore"),
|
|
795
826
|
// src/kernel/scan/ → src/config/defaults/
|
|
796
|
-
|
|
827
|
+
resolve7(here, "../config/defaults/skillmapignore"),
|
|
797
828
|
// dist/cli.js → dist/config/defaults/ (siblings)
|
|
798
|
-
|
|
829
|
+
resolve7(here, "config/defaults/skillmapignore")
|
|
799
830
|
];
|
|
800
831
|
for (const candidate of candidates) {
|
|
801
|
-
if (
|
|
832
|
+
if (existsSync7(candidate)) {
|
|
802
833
|
try {
|
|
803
|
-
return
|
|
834
|
+
return readFileSync7(candidate, "utf8");
|
|
804
835
|
} catch {
|
|
805
836
|
}
|
|
806
837
|
}
|
|
@@ -892,7 +923,7 @@ async function* walkRoot(root, current, filter, extensions) {
|
|
|
892
923
|
}
|
|
893
924
|
for (const entry of entries) {
|
|
894
925
|
const name = entry.name;
|
|
895
|
-
const full =
|
|
926
|
+
const full = join5(current, name);
|
|
896
927
|
const rel = relative3(root, full).split(sep2).join("/");
|
|
897
928
|
if (filter.ignores(rel)) continue;
|
|
898
929
|
if (entry.isSymbolicLink()) continue;
|
|
@@ -1095,7 +1126,7 @@ async function runScanInternal(_kernel, options) {
|
|
|
1095
1126
|
for (const analyzer of exts.analyzers ?? []) {
|
|
1096
1127
|
if (analyzer.viewContributions === void 0) continue;
|
|
1097
1128
|
for (const node of walked.nodes) {
|
|
1098
|
-
walked.freshlyRunTuples.add(`${analyzer.pluginId}
|
|
1129
|
+
walked.freshlyRunTuples.add(`${analyzer.pluginId}\0${analyzer.id}\0${node.path}`);
|
|
1099
1130
|
}
|
|
1100
1131
|
}
|
|
1101
1132
|
for (const issue of walked.frontmatterIssues) issues.push(issue);
|
|
@@ -1141,7 +1172,7 @@ function validateRoots(roots) {
|
|
|
1141
1172
|
throw new Error(ORCHESTRATOR_TEXTS.runScanRootEmptyArray);
|
|
1142
1173
|
}
|
|
1143
1174
|
for (const root of roots) {
|
|
1144
|
-
if (!
|
|
1175
|
+
if (!existsSync8(root) || !statSync2(root).isDirectory()) {
|
|
1145
1176
|
throw new Error(tx(ORCHESTRATOR_TEXTS.runScanRootMissing, { root }));
|
|
1146
1177
|
}
|
|
1147
1178
|
}
|
|
@@ -1311,8 +1342,10 @@ function computeCacheDecision(opts) {
|
|
|
1311
1342
|
const priorRunsForNode = opts.priorExtractorRuns.get(opts.nodePath) ?? /* @__PURE__ */ new Map();
|
|
1312
1343
|
for (const ex of applicableExtractors) {
|
|
1313
1344
|
const qualified = qualifiedExtensionId(ex.pluginId, ex.id);
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1345
|
+
const prior = priorRunsForNode.get(qualified);
|
|
1346
|
+
const bodyMatch = prior !== void 0 && prior.bodyHash === opts.bodyHash;
|
|
1347
|
+
const sidecarOk = prior !== void 0 && prior.sidecarAnnotationsHash === opts.sidecarAnnotationsHash;
|
|
1348
|
+
if (opts.nodeHashCacheEligible && bodyMatch && sidecarOk) {
|
|
1316
1349
|
cachedQualifiedIds.add(qualified);
|
|
1317
1350
|
} else {
|
|
1318
1351
|
missingExtractors.push(ex);
|
|
@@ -1357,7 +1390,8 @@ function reusePriorNode(opts) {
|
|
|
1357
1390
|
nodePath: opts.priorNode.path,
|
|
1358
1391
|
extractorId: qualified,
|
|
1359
1392
|
bodyHashAtRun: opts.bodyHash,
|
|
1360
|
-
ranAt
|
|
1393
|
+
ranAt,
|
|
1394
|
+
sidecarAnnotationsHashAtRun: opts.sidecarAnnotationsHash
|
|
1361
1395
|
});
|
|
1362
1396
|
}
|
|
1363
1397
|
return { ...base, extractorRuns };
|
|
@@ -1443,11 +1477,22 @@ async function walkAndExtract(opts) {
|
|
|
1443
1477
|
}
|
|
1444
1478
|
claimedPaths.add(raw.path);
|
|
1445
1479
|
index += 1;
|
|
1480
|
+
const sidecarResolution = resolveSidecarOverlay(
|
|
1481
|
+
raw.path,
|
|
1482
|
+
raw.path,
|
|
1483
|
+
roots,
|
|
1484
|
+
bodyHash,
|
|
1485
|
+
frontmatterHash
|
|
1486
|
+
);
|
|
1487
|
+
const sidecarAnnotationsHash = sha256(
|
|
1488
|
+
canonicalSidecarAnnotations(sidecarResolution.overlay.annotations)
|
|
1489
|
+
);
|
|
1446
1490
|
const cacheDecision = computeCacheDecision({
|
|
1447
1491
|
extractors,
|
|
1448
1492
|
kind,
|
|
1449
1493
|
nodePath: raw.path,
|
|
1450
1494
|
bodyHash,
|
|
1495
|
+
sidecarAnnotationsHash,
|
|
1451
1496
|
nodeHashCacheEligible,
|
|
1452
1497
|
priorExtractorRuns
|
|
1453
1498
|
});
|
|
@@ -1458,10 +1503,20 @@ async function walkAndExtract(opts) {
|
|
|
1458
1503
|
missingExtractors,
|
|
1459
1504
|
fullCacheHit
|
|
1460
1505
|
} = cacheDecision;
|
|
1506
|
+
const attachSidecar = (node2) => {
|
|
1507
|
+
node2.sidecar = sidecarResolution.overlay;
|
|
1508
|
+
if (sidecarResolution.parsedRoot !== null) {
|
|
1509
|
+
sidecarRoots.set(node2.path, sidecarResolution.parsedRoot);
|
|
1510
|
+
}
|
|
1511
|
+
return sidecarResolution.issues.map(
|
|
1512
|
+
(i) => i.nodeIds.length > 0 ? i : { ...i, nodeIds: [node2.path] }
|
|
1513
|
+
);
|
|
1514
|
+
};
|
|
1461
1515
|
if (fullCacheHit && priorNode) {
|
|
1462
1516
|
const reused = reusePriorNode({
|
|
1463
1517
|
priorNode,
|
|
1464
1518
|
bodyHash,
|
|
1519
|
+
sidecarAnnotationsHash,
|
|
1465
1520
|
strict,
|
|
1466
1521
|
cachedQualifiedIds,
|
|
1467
1522
|
applicableQualifiedIds,
|
|
@@ -1469,14 +1524,7 @@ async function walkAndExtract(opts) {
|
|
|
1469
1524
|
priorLinksByOriginating,
|
|
1470
1525
|
priorFrontmatterIssuesByNode
|
|
1471
1526
|
});
|
|
1472
|
-
const reusedSidecarIssues =
|
|
1473
|
-
reused.node,
|
|
1474
|
-
raw.path,
|
|
1475
|
-
roots,
|
|
1476
|
-
bodyHash,
|
|
1477
|
-
frontmatterHash,
|
|
1478
|
-
sidecarRoots
|
|
1479
|
-
);
|
|
1527
|
+
const reusedSidecarIssues = attachSidecar(reused.node);
|
|
1480
1528
|
nodes.push(reused.node);
|
|
1481
1529
|
cachedPaths.add(reused.node.path);
|
|
1482
1530
|
for (const link of reused.internalLinks) internalLinks.push(link);
|
|
@@ -1517,14 +1565,7 @@ async function walkAndExtract(opts) {
|
|
|
1517
1565
|
nodes.push(node);
|
|
1518
1566
|
for (const issue of fresh.frontmatterIssues) frontmatterIssues.push(issue);
|
|
1519
1567
|
}
|
|
1520
|
-
const sidecarIssues =
|
|
1521
|
-
node,
|
|
1522
|
-
raw.path,
|
|
1523
|
-
roots,
|
|
1524
|
-
bodyHash,
|
|
1525
|
-
frontmatterHash,
|
|
1526
|
-
sidecarRoots
|
|
1527
|
-
);
|
|
1568
|
+
const sidecarIssues = attachSidecar(node);
|
|
1528
1569
|
for (const issue of sidecarIssues) frontmatterIssues.push(issue);
|
|
1529
1570
|
emitter.emit(makeEvent("scan.progress", {
|
|
1530
1571
|
index,
|
|
@@ -1535,7 +1576,7 @@ async function walkAndExtract(opts) {
|
|
|
1535
1576
|
}));
|
|
1536
1577
|
const extractorsToRun = partialCacheHit ? missingExtractors : applicableExtractors;
|
|
1537
1578
|
for (const ex of extractorsToRun) {
|
|
1538
|
-
freshlyRunTuples.add(`${ex.pluginId}
|
|
1579
|
+
freshlyRunTuples.add(`${ex.pluginId}\0${ex.id}\0${node.path}`);
|
|
1539
1580
|
}
|
|
1540
1581
|
const extractResult = await runExtractorsForNode({
|
|
1541
1582
|
extractors: extractorsToRun,
|
|
@@ -1559,7 +1600,8 @@ async function walkAndExtract(opts) {
|
|
|
1559
1600
|
nodePath: node.path,
|
|
1560
1601
|
extractorId: qualified,
|
|
1561
1602
|
bodyHashAtRun: bodyHash,
|
|
1562
|
-
ranAt
|
|
1603
|
+
ranAt,
|
|
1604
|
+
sidecarAnnotationsHashAtRun: sidecarAnnotationsHash
|
|
1563
1605
|
});
|
|
1564
1606
|
}
|
|
1565
1607
|
}
|
|
@@ -1860,30 +1902,42 @@ function canonicalFrontmatter(parsed, raw) {
|
|
|
1860
1902
|
noCompatMode: true
|
|
1861
1903
|
});
|
|
1862
1904
|
}
|
|
1863
|
-
function
|
|
1905
|
+
function canonicalSidecarAnnotations(annotations) {
|
|
1906
|
+
if (!annotations || typeof annotations !== "object" || Array.isArray(annotations)) {
|
|
1907
|
+
return yaml4.dump({}, { sortKeys: true, lineWidth: -1, noRefs: true, noCompatMode: true });
|
|
1908
|
+
}
|
|
1909
|
+
return yaml4.dump(annotations, {
|
|
1910
|
+
sortKeys: true,
|
|
1911
|
+
lineWidth: -1,
|
|
1912
|
+
noRefs: true,
|
|
1913
|
+
noCompatMode: true
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
function resolveSidecarOverlay(relativePath, nodePathForIssue, roots, liveBodyHash, liveFrontmatterHash) {
|
|
1864
1917
|
const issues = [];
|
|
1865
1918
|
const mdAbs = resolveAbsoluteMdPath(relativePath, roots);
|
|
1866
1919
|
if (mdAbs === null) {
|
|
1867
|
-
|
|
1868
|
-
return issues;
|
|
1920
|
+
return { overlay: { present: false }, issues, parsedRoot: null };
|
|
1869
1921
|
}
|
|
1870
1922
|
const result = readSidecarFor(mdAbs);
|
|
1871
1923
|
if (!result.present) {
|
|
1872
|
-
|
|
1873
|
-
return issues;
|
|
1924
|
+
return { overlay: { present: false }, issues, parsedRoot: null };
|
|
1874
1925
|
}
|
|
1875
1926
|
if (result.parsed === null) {
|
|
1876
|
-
node.sidecar = { present: true, status: null, annotations: null, root: null };
|
|
1877
1927
|
for (const parseIssue of result.issues) {
|
|
1878
1928
|
issues.push({
|
|
1879
1929
|
analyzerId: "invalid-sidecar",
|
|
1880
1930
|
severity: "warn",
|
|
1881
|
-
nodeIds: [
|
|
1931
|
+
nodeIds: [nodePathForIssue],
|
|
1882
1932
|
message: parseIssue.message,
|
|
1883
1933
|
data: { sidecarPath: relativePathFromRoots(mdAbs, roots) }
|
|
1884
1934
|
});
|
|
1885
1935
|
}
|
|
1886
|
-
return
|
|
1936
|
+
return {
|
|
1937
|
+
overlay: { present: true, status: null, annotations: null, root: null },
|
|
1938
|
+
issues,
|
|
1939
|
+
parsedRoot: null
|
|
1940
|
+
};
|
|
1887
1941
|
}
|
|
1888
1942
|
const status = computeDriftStatus({
|
|
1889
1943
|
storedBodyHash: result.parsed.identityBodyHash,
|
|
@@ -1891,22 +1945,30 @@ function resolveAndApplySidecar(node, relativePath, roots, liveBodyHash, liveFro
|
|
|
1891
1945
|
liveBodyHash,
|
|
1892
1946
|
liveFrontmatterHash
|
|
1893
1947
|
});
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1948
|
+
return {
|
|
1949
|
+
// R15 closure (2026-05-07) — surface the full parsed root on the
|
|
1950
|
+
// overlay so BFF consumers (UI inspector audit / plugin-contributions
|
|
1951
|
+
// / debug panels) can read `for.*`, `audit.*`, `settings.*`, and
|
|
1952
|
+
// plugin-namespaced sub-keys without re-reading the file. The
|
|
1953
|
+
// `annotations` field above stays — it duplicates `root.annotations`
|
|
1954
|
+
// by design so existing consumers keep working unchanged.
|
|
1955
|
+
overlay: {
|
|
1956
|
+
present: true,
|
|
1957
|
+
status,
|
|
1958
|
+
annotations: result.parsed.annotations,
|
|
1959
|
+
root: result.parsed.raw
|
|
1960
|
+
},
|
|
1961
|
+
issues,
|
|
1962
|
+
parsedRoot: result.parsed.raw
|
|
1899
1963
|
};
|
|
1900
|
-
sidecarRoots.set(node.path, result.parsed.raw);
|
|
1901
|
-
return issues;
|
|
1902
1964
|
}
|
|
1903
1965
|
function resolveAbsoluteMdPath(relativePath, roots) {
|
|
1904
|
-
if (
|
|
1905
|
-
return
|
|
1966
|
+
if (isAbsolute3(relativePath)) {
|
|
1967
|
+
return existsSync8(relativePath) ? relativePath : null;
|
|
1906
1968
|
}
|
|
1907
1969
|
for (const root of roots) {
|
|
1908
1970
|
const candidate = resolvePath(root, relativePath);
|
|
1909
|
-
if (
|
|
1971
|
+
if (existsSync8(candidate)) return candidate;
|
|
1910
1972
|
}
|
|
1911
1973
|
return null;
|
|
1912
1974
|
}
|
|
@@ -2066,10 +2128,10 @@ function assignSafe(target, source) {
|
|
|
2066
2128
|
}
|
|
2067
2129
|
|
|
2068
2130
|
// kernel/scan/watcher.ts
|
|
2069
|
-
import { resolve as
|
|
2131
|
+
import { resolve as resolve8, relative as relative4, sep as sep3 } from "path";
|
|
2070
2132
|
import chokidar from "chokidar";
|
|
2071
2133
|
function createChokidarWatcher(opts) {
|
|
2072
|
-
const absRoots = opts.roots.map((r) =>
|
|
2134
|
+
const absRoots = opts.roots.map((r) => resolve8(opts.cwd, r));
|
|
2073
2135
|
const ignoreFilterOpt = opts.ignoreFilter;
|
|
2074
2136
|
const getFilter = ignoreFilterOpt === void 0 ? void 0 : typeof ignoreFilterOpt === "function" ? ignoreFilterOpt : () => ignoreFilterOpt;
|
|
2075
2137
|
const ignored = getFilter ? (path) => {
|