@skill-map/cli 0.32.0 → 0.33.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/SKILL.md +27 -7
- package/dist/cli.js +851 -318
- package/dist/cli.js.map +1 -1
- package/dist/index.js +206 -15
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +198 -3
- package/dist/kernel/index.js +206 -15
- package/dist/kernel/index.js.map +1 -1
- package/dist/migrations/001_initial.sql +2 -2
- package/dist/ui/chunk-2QZDJSJN.js +1 -0
- package/dist/ui/chunk-5CFY2K3Y.js +135 -0
- package/dist/ui/{chunk-YQIWQVJ6.js → chunk-L3OLNVKI.js} +9 -9
- package/dist/ui/chunk-OKFHCQNJ.js +123 -0
- package/dist/ui/{chunk-47OZB7LR.js → chunk-TKV6TXTI.js} +1 -1
- package/dist/ui/{chunk-WJLIYGWJ.js → chunk-UK5YFHL3.js} +1 -1
- package/dist/ui/{chunk-FEPH4VNB.js → chunk-UMCC32EJ.js} +3 -3
- package/dist/ui/{chunk-VDQLDTTR.js → chunk-YZ7KCL3G.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-H7FURBYT.js +2 -0
- package/migrations/001_initial.sql +2 -2
- package/package.json +3 -2
- package/dist/ui/chunk-BCQZKYOD.js +0 -1
- package/dist/ui/chunk-LS2NXZQZ.js +0 -135
- package/dist/ui/chunk-WCE7MTK5.js +0 -123
- package/dist/ui/main-LJIHL73M.js +0 -2
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// cli/entry.ts
|
|
2
|
-
import { existsSync as
|
|
2
|
+
import { existsSync as existsSync33 } from "fs";
|
|
3
3
|
import { Builtins, Cli as Cli2 } from "clipanion";
|
|
4
4
|
|
|
5
5
|
// kernel/adapters/in-memory-progress.ts
|
|
@@ -494,6 +494,31 @@ var claudeProvider = {
|
|
|
494
494
|
colorDark: "#34d399",
|
|
495
495
|
icon: { kind: "pi", id: "pi-bolt" }
|
|
496
496
|
}
|
|
497
|
+
},
|
|
498
|
+
/**
|
|
499
|
+
* Phase 5 of the active-lens migration: MCP servers surface as
|
|
500
|
+
* synthetic / virtual nodes (no filesystem path; identifier is
|
|
501
|
+
* `mcp://<name>`) derived from a config file (`settings.json`
|
|
502
|
+
* for Claude). Per-skill / per-agent references appear as
|
|
503
|
+
* `tools: [mcp__<server>__<tool>, ...]` entries in frontmatter;
|
|
504
|
+
* the `core/mcp-tools` extractor turns each match into one
|
|
505
|
+
* MCP node (idempotent dedup by path) plus a `references` link
|
|
506
|
+
* from the source skill / agent to that node.
|
|
507
|
+
*
|
|
508
|
+
* `schema` is provider-agnostic enough that we reuse the skill
|
|
509
|
+
* schema for now (mcp nodes have `name` + `description` at most,
|
|
510
|
+
* which the base skill schema accepts). A dedicated schema lands
|
|
511
|
+
* if MCP nodes grow Claude-specific metadata.
|
|
512
|
+
*/
|
|
513
|
+
mcp: {
|
|
514
|
+
schema: "./schemas/skill.schema.json",
|
|
515
|
+
schemaJson: skill_schema_default,
|
|
516
|
+
ui: {
|
|
517
|
+
label: "MCP servers",
|
|
518
|
+
color: "#8b5cf6",
|
|
519
|
+
colorDark: "#a78bfa",
|
|
520
|
+
icon: { kind: "pi", id: "pi-server" }
|
|
521
|
+
}
|
|
497
522
|
}
|
|
498
523
|
},
|
|
499
524
|
// Auxiliary schemas the per-kind schemas $ref by $id. AJV needs them
|
|
@@ -511,6 +536,166 @@ var claudeProvider = {
|
|
|
511
536
|
}
|
|
512
537
|
};
|
|
513
538
|
|
|
539
|
+
// kernel/util/strip-code-blocks.ts
|
|
540
|
+
var FENCE_RE = /^(?<indent> {0,3})(?<fence>`{3,}|~{3,})/;
|
|
541
|
+
function stripCodeBlocks(input) {
|
|
542
|
+
if (!input) return input;
|
|
543
|
+
const fenceless = stripFences(input);
|
|
544
|
+
return stripInline(fenceless);
|
|
545
|
+
}
|
|
546
|
+
function stripFences(input) {
|
|
547
|
+
const out = [];
|
|
548
|
+
const lines = input.split("\n");
|
|
549
|
+
let openFence = null;
|
|
550
|
+
for (const line of lines) {
|
|
551
|
+
if (openFence) {
|
|
552
|
+
const closer = matchClosingFence(line, openFence);
|
|
553
|
+
if (closer) {
|
|
554
|
+
out.push(blank(line));
|
|
555
|
+
openFence = null;
|
|
556
|
+
} else {
|
|
557
|
+
out.push(blank(line));
|
|
558
|
+
}
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
const open = FENCE_RE.exec(line);
|
|
562
|
+
if (open?.groups) {
|
|
563
|
+
openFence = open.groups["fence"];
|
|
564
|
+
out.push(blank(line));
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
out.push(line);
|
|
568
|
+
}
|
|
569
|
+
return out.join("\n");
|
|
570
|
+
}
|
|
571
|
+
function matchClosingFence(line, openFence) {
|
|
572
|
+
const m = FENCE_RE.exec(line);
|
|
573
|
+
if (!m?.groups) return false;
|
|
574
|
+
const fence = m.groups["fence"];
|
|
575
|
+
return fence[0] === openFence[0] && fence.length >= openFence.length;
|
|
576
|
+
}
|
|
577
|
+
function stripInline(input) {
|
|
578
|
+
return input.replace(/(`+)([\s\S]*?)\1/g, (_full, ticks, body) => {
|
|
579
|
+
return ticks.replace(/`/g, " ") + blank(body) + ticks.replace(/`/g, " ");
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
function blank(s) {
|
|
583
|
+
return s.replace(/[^\s]/g, " ");
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// kernel/trigger-normalize.ts
|
|
587
|
+
function normalizeTrigger(source) {
|
|
588
|
+
let out = source.normalize("NFD");
|
|
589
|
+
out = out.replace(new RegExp("\\p{Mn}+", "gu"), "");
|
|
590
|
+
out = out.toLowerCase();
|
|
591
|
+
out = out.replace(/[-_\s]+/g, " ");
|
|
592
|
+
out = out.replace(/ +/g, " ");
|
|
593
|
+
return out.trim();
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// plugins/claude/extractors/at-directive/index.ts
|
|
597
|
+
var ID = "at-directive";
|
|
598
|
+
var AT_RE = /(?:^|[^A-Za-z0-9_@])(@(?:\.{1,2}\/|\/)?[a-z0-9](?:[a-z0-9_\-./]*[a-z0-9_])?(?::[a-z0-9][a-z0-9_-]*)?)/gi;
|
|
599
|
+
var FILE_EXT_RE = /\.(md|mdx|js|jsx|ts|tsx|json|yml|yaml|toml|txt|html|css|scss|less|py|rb|go|rs|java|c|cpp|h|hpp|sh|sql|svg|png|jpg|jpeg|gif|webp|pdf)$/i;
|
|
600
|
+
var atDirectiveExtractor = {
|
|
601
|
+
id: ID,
|
|
602
|
+
pluginId: "claude",
|
|
603
|
+
kind: "extractor",
|
|
604
|
+
version: "1.0.0",
|
|
605
|
+
description: "Detects `@<token>` directives in a node's body using Claude Code interpretation rules. A bare handle (e.g. `@team`) becomes a `mentions` link; a file-flavoured token (e.g. `@docs/api.md`, `@./readme.md`) becomes a `references` link. Gated by `precondition.provider: ['claude']` so Gemini / Cursor / Codex apply their own at-directive flavours via their own extractors.",
|
|
606
|
+
scope: "body",
|
|
607
|
+
precondition: { provider: ["claude"] },
|
|
608
|
+
extract(ctx) {
|
|
609
|
+
const seenMentions = /* @__PURE__ */ new Set();
|
|
610
|
+
const seenReferences = /* @__PURE__ */ new Set();
|
|
611
|
+
const body = stripCodeBlocks(ctx.body);
|
|
612
|
+
for (const match of body.matchAll(AT_RE)) {
|
|
613
|
+
const original = match[1];
|
|
614
|
+
const bare = original.slice(1);
|
|
615
|
+
const isReference = bare.startsWith("./") || bare.startsWith("../") || bare.startsWith("/") || FILE_EXT_RE.test(bare);
|
|
616
|
+
if (isReference) {
|
|
617
|
+
const target = bare.replace(/^\.\//, "");
|
|
618
|
+
if (seenReferences.has(target)) continue;
|
|
619
|
+
seenReferences.add(target);
|
|
620
|
+
ctx.emitLink({
|
|
621
|
+
source: ctx.node.path,
|
|
622
|
+
target,
|
|
623
|
+
kind: "references",
|
|
624
|
+
// 0.85: strong file signal (path prefix `./` / `../` / `/` OR
|
|
625
|
+
// a known file extension on the tail). One degree of inference
|
|
626
|
+
// (the runtime still resolves the path).
|
|
627
|
+
confidence: 0.85,
|
|
628
|
+
sources: [ID],
|
|
629
|
+
trigger: {
|
|
630
|
+
originalTrigger: original,
|
|
631
|
+
normalizedTrigger: target.toLowerCase()
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
const normalized = normalizeTrigger(original);
|
|
637
|
+
if (seenMentions.has(normalized)) continue;
|
|
638
|
+
seenMentions.add(normalized);
|
|
639
|
+
ctx.emitLink({
|
|
640
|
+
source: ctx.node.path,
|
|
641
|
+
target: original,
|
|
642
|
+
kind: "mentions",
|
|
643
|
+
// 0.5: genuine ambiguity. A bare `@handle` (no extension, no
|
|
644
|
+
// path prefix) could be an agent, a handle, or generic prose.
|
|
645
|
+
// The runtime decides at invocation time; the extractor leaves
|
|
646
|
+
// the question open.
|
|
647
|
+
confidence: 0.5,
|
|
648
|
+
sources: [ID],
|
|
649
|
+
trigger: {
|
|
650
|
+
originalTrigger: original,
|
|
651
|
+
normalizedTrigger: normalized
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
// plugins/claude/extractors/slash/index.ts
|
|
659
|
+
var ID2 = "slash";
|
|
660
|
+
var SLASH_RE = /(?<![A-Za-z0-9_/.:?#])(\/[a-z0-9][a-z0-9_-]*(?::[a-z0-9][a-z0-9_-]*)?)/gi;
|
|
661
|
+
var slashExtractor = {
|
|
662
|
+
id: ID2,
|
|
663
|
+
pluginId: "claude",
|
|
664
|
+
kind: "extractor",
|
|
665
|
+
version: "1.0.0",
|
|
666
|
+
description: "Detects `/command` invocations in a node's body using Claude Code routing rules and turns each one into an arrow between nodes in the graph. Gated by `precondition.provider: ['claude']` so Gemini / Cursor / Codex apply their own slash flavours (Gemini has 4 routing separators, Codex deprecated user slash commands, etc.) via their own extractors.",
|
|
667
|
+
scope: "body",
|
|
668
|
+
precondition: { provider: ["claude"] },
|
|
669
|
+
extract(ctx) {
|
|
670
|
+
const seen = /* @__PURE__ */ new Set();
|
|
671
|
+
const body = stripCodeBlocks(ctx.body);
|
|
672
|
+
for (const match of body.matchAll(SLASH_RE)) {
|
|
673
|
+
const original = match[1];
|
|
674
|
+
const endIdx = (match.index ?? 0) + match[0].length;
|
|
675
|
+
const nextChar = body[endIdx];
|
|
676
|
+
if (nextChar && /[A-Za-z0-9_/-]/.test(nextChar)) continue;
|
|
677
|
+
const normalized = normalizeTrigger(original);
|
|
678
|
+
if (seen.has(normalized)) continue;
|
|
679
|
+
seen.add(normalized);
|
|
680
|
+
ctx.emitLink({
|
|
681
|
+
source: ctx.node.path,
|
|
682
|
+
target: original,
|
|
683
|
+
kind: "invokes",
|
|
684
|
+
// 0.8: clean `/command` match after code-block strip. The
|
|
685
|
+
// post-match path guard above filters URL / file-path noise,
|
|
686
|
+
// so a hit is unambiguous syntax. Resolution against the live
|
|
687
|
+
// skill / command catalog happens downstream.
|
|
688
|
+
confidence: 0.8,
|
|
689
|
+
sources: [ID2],
|
|
690
|
+
trigger: {
|
|
691
|
+
originalTrigger: original,
|
|
692
|
+
normalizedTrigger: normalized
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
|
|
514
699
|
// plugins/gemini/providers/gemini/schemas/agent.schema.json
|
|
515
700
|
var agent_schema_default2 = {
|
|
516
701
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -629,6 +814,86 @@ var geminiProvider = {
|
|
|
629
814
|
}
|
|
630
815
|
};
|
|
631
816
|
|
|
817
|
+
// plugins/openai/providers/openai/schemas/agent.schema.json
|
|
818
|
+
var agent_schema_default3 = {
|
|
819
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
820
|
+
$id: "https://skill-map.dev/providers/openai/v1/frontmatter/agent.schema.json",
|
|
821
|
+
title: "FrontmatterCodexAgent",
|
|
822
|
+
description: "Frontmatter shape for nodes classified as `agent` by the OpenAI Codex Provider. Codex sub-agents live as TOML files under `.codex/agents/<name>.toml`; the entire file IS the agent definition (no markdown body). The TOML parser feeds the parsed root object into `frontmatter`, so this schema validates the same shape skill-map's other providers carry on per-kind frontmatter. Mirrors Codex's documented sub-agent fields (https://github.com/openai/codex) with `additionalProperties: true` so future additions flow through unchanged.",
|
|
823
|
+
allOf: [
|
|
824
|
+
{ $ref: "https://skill-map.dev/spec/v0/frontmatter/base.schema.json" }
|
|
825
|
+
],
|
|
826
|
+
type: "object",
|
|
827
|
+
additionalProperties: true,
|
|
828
|
+
properties: {
|
|
829
|
+
name: {
|
|
830
|
+
type: "string",
|
|
831
|
+
minLength: 1,
|
|
832
|
+
description: "Sub-agent identifier. Conventionally matches the filename stem."
|
|
833
|
+
},
|
|
834
|
+
description: {
|
|
835
|
+
type: "string",
|
|
836
|
+
description: "Short description of when this sub-agent applies. Codex surfaces this in the agent picker; skill-map mirrors it in the card."
|
|
837
|
+
},
|
|
838
|
+
model: {
|
|
839
|
+
type: "string",
|
|
840
|
+
description: "Model identifier (`gpt-4o`, `o3-mini`, etc.) the sub-agent runs against."
|
|
841
|
+
},
|
|
842
|
+
instructions: {
|
|
843
|
+
type: "string",
|
|
844
|
+
description: "Multi-line prompt body (TOML triple-quoted string)."
|
|
845
|
+
},
|
|
846
|
+
tools: {
|
|
847
|
+
type: "array",
|
|
848
|
+
items: { type: "string" },
|
|
849
|
+
description: "Tool ids this sub-agent is allowed to call."
|
|
850
|
+
},
|
|
851
|
+
mcp_servers: {
|
|
852
|
+
type: "array",
|
|
853
|
+
items: { type: "string" },
|
|
854
|
+
description: "MCP server ids attached to this sub-agent (`tools: [mcp__<server>__*]` follows the same pattern as Claude)."
|
|
855
|
+
},
|
|
856
|
+
approval_policy: {
|
|
857
|
+
type: "string",
|
|
858
|
+
enum: ["never", "on-request", "untrusted"],
|
|
859
|
+
description: "Codex approval policy for this sub-agent's destructive operations."
|
|
860
|
+
},
|
|
861
|
+
sandbox_mode: {
|
|
862
|
+
type: "string",
|
|
863
|
+
enum: ["read-only", "workspace-write", "danger-full-access"],
|
|
864
|
+
description: "Codex sandbox mode the sub-agent runs under."
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
// plugins/openai/providers/openai/index.ts
|
|
870
|
+
var openaiProvider = {
|
|
871
|
+
id: "openai",
|
|
872
|
+
pluginId: "openai",
|
|
873
|
+
kind: "provider",
|
|
874
|
+
version: "1.0.0",
|
|
875
|
+
description: "Walks OpenAI Codex CLI scope conventions (.codex/agents/*.toml).",
|
|
876
|
+
read: { extensions: [".toml"], parser: "toml" },
|
|
877
|
+
kinds: {
|
|
878
|
+
agent: {
|
|
879
|
+
schema: "./schemas/agent.schema.json",
|
|
880
|
+
schemaJson: agent_schema_default3,
|
|
881
|
+
ui: {
|
|
882
|
+
label: "Codex agents",
|
|
883
|
+
// Codex green; distinct from claude / gemini palettes.
|
|
884
|
+
color: "#22c55e",
|
|
885
|
+
colorDark: "#4ade80",
|
|
886
|
+
icon: { kind: "pi", id: "pi-bolt" }
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
classify(path) {
|
|
891
|
+
const lower = path.toLowerCase();
|
|
892
|
+
if (lower.startsWith(".codex/agents/") && lower.endsWith(".toml")) return "agent";
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
|
|
632
897
|
// plugins/agent-skills/providers/agent-skills/schemas/skill.schema.json
|
|
633
898
|
var skill_schema_default3 = {
|
|
634
899
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -722,9 +987,9 @@ var coreMarkdownProvider = {
|
|
|
722
987
|
};
|
|
723
988
|
|
|
724
989
|
// plugins/core/extractors/annotations/index.ts
|
|
725
|
-
var
|
|
990
|
+
var ID3 = "annotations";
|
|
726
991
|
var annotationsExtractor = {
|
|
727
|
-
id:
|
|
992
|
+
id: ID3,
|
|
728
993
|
pluginId: "core",
|
|
729
994
|
kind: "extractor",
|
|
730
995
|
version: "1.0.0",
|
|
@@ -770,128 +1035,17 @@ function link(source, target) {
|
|
|
770
1035
|
source,
|
|
771
1036
|
target,
|
|
772
1037
|
kind: "supersedes",
|
|
773
|
-
confidence:
|
|
774
|
-
sources: [
|
|
1038
|
+
confidence: 1,
|
|
1039
|
+
sources: [ID3]
|
|
775
1040
|
};
|
|
776
1041
|
}
|
|
777
1042
|
|
|
778
|
-
// kernel/util/strip-code-blocks.ts
|
|
779
|
-
var FENCE_RE = /^(?<indent> {0,3})(?<fence>`{3,}|~{3,})/;
|
|
780
|
-
function stripCodeBlocks(input) {
|
|
781
|
-
if (!input) return input;
|
|
782
|
-
const fenceless = stripFences(input);
|
|
783
|
-
return stripInline(fenceless);
|
|
784
|
-
}
|
|
785
|
-
function stripFences(input) {
|
|
786
|
-
const out = [];
|
|
787
|
-
const lines = input.split("\n");
|
|
788
|
-
let openFence = null;
|
|
789
|
-
for (const line of lines) {
|
|
790
|
-
if (openFence) {
|
|
791
|
-
const closer = matchClosingFence(line, openFence);
|
|
792
|
-
if (closer) {
|
|
793
|
-
out.push(blank(line));
|
|
794
|
-
openFence = null;
|
|
795
|
-
} else {
|
|
796
|
-
out.push(blank(line));
|
|
797
|
-
}
|
|
798
|
-
continue;
|
|
799
|
-
}
|
|
800
|
-
const open = FENCE_RE.exec(line);
|
|
801
|
-
if (open?.groups) {
|
|
802
|
-
openFence = open.groups["fence"];
|
|
803
|
-
out.push(blank(line));
|
|
804
|
-
continue;
|
|
805
|
-
}
|
|
806
|
-
out.push(line);
|
|
807
|
-
}
|
|
808
|
-
return out.join("\n");
|
|
809
|
-
}
|
|
810
|
-
function matchClosingFence(line, openFence) {
|
|
811
|
-
const m = FENCE_RE.exec(line);
|
|
812
|
-
if (!m?.groups) return false;
|
|
813
|
-
const fence = m.groups["fence"];
|
|
814
|
-
return fence[0] === openFence[0] && fence.length >= openFence.length;
|
|
815
|
-
}
|
|
816
|
-
function stripInline(input) {
|
|
817
|
-
return input.replace(/(`+)([\s\S]*?)\1/g, (_full, ticks, body) => {
|
|
818
|
-
return ticks.replace(/`/g, " ") + blank(body) + ticks.replace(/`/g, " ");
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
function blank(s) {
|
|
822
|
-
return s.replace(/[^\s]/g, " ");
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// kernel/trigger-normalize.ts
|
|
826
|
-
function normalizeTrigger(source) {
|
|
827
|
-
let out = source.normalize("NFD");
|
|
828
|
-
out = out.replace(new RegExp("\\p{Mn}+", "gu"), "");
|
|
829
|
-
out = out.toLowerCase();
|
|
830
|
-
out = out.replace(/[-_\s]+/g, " ");
|
|
831
|
-
out = out.replace(/ +/g, " ");
|
|
832
|
-
return out.trim();
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// plugins/core/extractors/at-directive/index.ts
|
|
836
|
-
var ID2 = "at-directive";
|
|
837
|
-
var AT_RE = /(?:^|[^A-Za-z0-9_@])(@(?:\.{1,2}\/|\/)?[a-z0-9](?:[a-z0-9_\-./]*[a-z0-9_])?(?::[a-z0-9][a-z0-9_-]*)?)/gi;
|
|
838
|
-
var FILE_EXT_RE = /\.(md|mdx|js|jsx|ts|tsx|json|yml|yaml|toml|txt|html|css|scss|less|py|rb|go|rs|java|c|cpp|h|hpp|sh|sql|svg|png|jpg|jpeg|gif|webp|pdf)$/i;
|
|
839
|
-
var atDirectiveExtractor = {
|
|
840
|
-
id: ID2,
|
|
841
|
-
pluginId: "core",
|
|
842
|
-
kind: "extractor",
|
|
843
|
-
version: "1.0.0",
|
|
844
|
-
description: "Detects `@<token>` directives in a node's body. A bare handle (e.g. `@team`) becomes a `mentions` link; a file-flavoured token (e.g. `@docs/api.md`, `@./readme.md`) becomes a `references` link, matching how Claude Code / Gemini CLI / Cursor read the same syntax.",
|
|
845
|
-
scope: "body",
|
|
846
|
-
extract(ctx) {
|
|
847
|
-
const seenMentions = /* @__PURE__ */ new Set();
|
|
848
|
-
const seenReferences = /* @__PURE__ */ new Set();
|
|
849
|
-
const body = stripCodeBlocks(ctx.body);
|
|
850
|
-
for (const match of body.matchAll(AT_RE)) {
|
|
851
|
-
const original = match[1];
|
|
852
|
-
const bare = original.slice(1);
|
|
853
|
-
const isReference = bare.startsWith("./") || bare.startsWith("../") || bare.startsWith("/") || FILE_EXT_RE.test(bare);
|
|
854
|
-
if (isReference) {
|
|
855
|
-
const target = bare.replace(/^\.\//, "");
|
|
856
|
-
if (seenReferences.has(target)) continue;
|
|
857
|
-
seenReferences.add(target);
|
|
858
|
-
ctx.emitLink({
|
|
859
|
-
source: ctx.node.path,
|
|
860
|
-
target,
|
|
861
|
-
kind: "references",
|
|
862
|
-
confidence: "medium",
|
|
863
|
-
sources: [ID2],
|
|
864
|
-
trigger: {
|
|
865
|
-
originalTrigger: original,
|
|
866
|
-
normalizedTrigger: target.toLowerCase()
|
|
867
|
-
}
|
|
868
|
-
});
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
871
|
-
const normalized = normalizeTrigger(original);
|
|
872
|
-
if (seenMentions.has(normalized)) continue;
|
|
873
|
-
seenMentions.add(normalized);
|
|
874
|
-
ctx.emitLink({
|
|
875
|
-
source: ctx.node.path,
|
|
876
|
-
target: original,
|
|
877
|
-
kind: "mentions",
|
|
878
|
-
confidence: "medium",
|
|
879
|
-
sources: [ID2],
|
|
880
|
-
trigger: {
|
|
881
|
-
originalTrigger: original,
|
|
882
|
-
normalizedTrigger: normalized
|
|
883
|
-
}
|
|
884
|
-
});
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
};
|
|
888
|
-
|
|
889
1043
|
// plugins/core/extractors/external-url-counter/index.ts
|
|
890
|
-
var
|
|
1044
|
+
var ID4 = "external-url-counter";
|
|
891
1045
|
var URL_RE = /https?:\/\/[^\s<>"'`)\]]+/g;
|
|
892
1046
|
var TRAILING_PUNCT = /[.,;:!?]+$/;
|
|
893
1047
|
var externalUrlCounterExtractor = {
|
|
894
|
-
id:
|
|
1048
|
+
id: ID4,
|
|
895
1049
|
pluginId: "core",
|
|
896
1050
|
kind: "extractor",
|
|
897
1051
|
version: "1.0.0",
|
|
@@ -937,8 +1091,8 @@ var externalUrlCounterExtractor = {
|
|
|
937
1091
|
source: ctx.node.path,
|
|
938
1092
|
target: normalized,
|
|
939
1093
|
kind: "references",
|
|
940
|
-
confidence:
|
|
941
|
-
sources: [
|
|
1094
|
+
confidence: 0.3,
|
|
1095
|
+
sources: [ID4],
|
|
942
1096
|
trigger: {
|
|
943
1097
|
originalTrigger: original,
|
|
944
1098
|
normalizedTrigger: normalized
|
|
@@ -985,11 +1139,11 @@ function lineFor(lineStarts, offset) {
|
|
|
985
1139
|
|
|
986
1140
|
// plugins/core/extractors/markdown-link/index.ts
|
|
987
1141
|
import { posix as pathPosix } from "path";
|
|
988
|
-
var
|
|
1142
|
+
var ID5 = "markdown-link";
|
|
989
1143
|
var LINK_RE = /(?<!!)\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
|
|
990
1144
|
var URL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
991
1145
|
var markdownLinkExtractor = {
|
|
992
|
-
id:
|
|
1146
|
+
id: ID5,
|
|
993
1147
|
pluginId: "core",
|
|
994
1148
|
kind: "extractor",
|
|
995
1149
|
version: "1.0.0",
|
|
@@ -1010,8 +1164,8 @@ var markdownLinkExtractor = {
|
|
|
1010
1164
|
source: ctx.node.path,
|
|
1011
1165
|
target: resolved,
|
|
1012
1166
|
kind: "references",
|
|
1013
|
-
confidence:
|
|
1014
|
-
sources: [
|
|
1167
|
+
confidence: 0.95,
|
|
1168
|
+
sources: [ID5],
|
|
1015
1169
|
trigger: {
|
|
1016
1170
|
originalTrigger: original,
|
|
1017
1171
|
normalizedTrigger: resolved
|
|
@@ -1050,47 +1204,61 @@ function lineFor2(lineStarts, offset) {
|
|
|
1050
1204
|
return lo + 1;
|
|
1051
1205
|
}
|
|
1052
1206
|
|
|
1053
|
-
// plugins/core/extractors/
|
|
1054
|
-
var
|
|
1055
|
-
var
|
|
1056
|
-
var
|
|
1057
|
-
id:
|
|
1207
|
+
// plugins/core/extractors/mcp-tools/index.ts
|
|
1208
|
+
var ID6 = "mcp-tools";
|
|
1209
|
+
var MCP_PATTERN = /^mcp__([a-z0-9][a-z0-9_-]*)__[a-z0-9_-]+$/i;
|
|
1210
|
+
var mcpToolsExtractor = {
|
|
1211
|
+
id: ID6,
|
|
1058
1212
|
pluginId: "core",
|
|
1059
1213
|
kind: "extractor",
|
|
1060
1214
|
version: "1.0.0",
|
|
1061
|
-
description: "Detects
|
|
1062
|
-
scope: "
|
|
1215
|
+
description: "Detects `tools: [mcp__<server>__<tool>]` entries in a node's frontmatter and turns each unique server into an MCP node + a reference edge from the source.",
|
|
1216
|
+
scope: "frontmatter",
|
|
1063
1217
|
extract(ctx) {
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1218
|
+
const raw = ctx.frontmatter["tools"];
|
|
1219
|
+
if (!Array.isArray(raw)) return;
|
|
1220
|
+
const servers = collectMcpServers(raw);
|
|
1221
|
+
if (servers.size === 0) return;
|
|
1222
|
+
for (const server of servers) {
|
|
1223
|
+
const mcpPath = `mcp://${server}`;
|
|
1224
|
+
ctx.emitNode({
|
|
1225
|
+
path: mcpPath,
|
|
1226
|
+
kind: "mcp",
|
|
1227
|
+
virtual: true,
|
|
1228
|
+
provider: ctx.node.provider,
|
|
1229
|
+
derivedFrom: [ctx.node.path],
|
|
1230
|
+
frontmatter: { name: server }
|
|
1231
|
+
});
|
|
1074
1232
|
ctx.emitLink({
|
|
1075
1233
|
source: ctx.node.path,
|
|
1076
|
-
target:
|
|
1077
|
-
kind: "
|
|
1078
|
-
confidence:
|
|
1079
|
-
sources: [
|
|
1234
|
+
target: mcpPath,
|
|
1235
|
+
kind: "references",
|
|
1236
|
+
confidence: 0.85,
|
|
1237
|
+
sources: [ID6],
|
|
1080
1238
|
trigger: {
|
|
1081
|
-
originalTrigger:
|
|
1082
|
-
normalizedTrigger:
|
|
1239
|
+
originalTrigger: `mcp__${server}__*`,
|
|
1240
|
+
normalizedTrigger: mcpPath
|
|
1083
1241
|
}
|
|
1084
1242
|
});
|
|
1085
1243
|
}
|
|
1086
1244
|
}
|
|
1087
1245
|
};
|
|
1246
|
+
function collectMcpServers(tools) {
|
|
1247
|
+
const out = /* @__PURE__ */ new Set();
|
|
1248
|
+
for (const t of tools) {
|
|
1249
|
+
if (typeof t !== "string" || t.length === 0) continue;
|
|
1250
|
+
const match = MCP_PATTERN.exec(t);
|
|
1251
|
+
if (!match) continue;
|
|
1252
|
+
out.add(match[1].toLowerCase());
|
|
1253
|
+
}
|
|
1254
|
+
return out;
|
|
1255
|
+
}
|
|
1088
1256
|
|
|
1089
1257
|
// plugins/core/extractors/tools-count/index.ts
|
|
1090
|
-
var
|
|
1258
|
+
var ID7 = "tools-count";
|
|
1091
1259
|
var TOOLTIP_MAX = 255;
|
|
1092
1260
|
var toolsCountExtractor = {
|
|
1093
|
-
id:
|
|
1261
|
+
id: ID7,
|
|
1094
1262
|
pluginId: "core",
|
|
1095
1263
|
kind: "extractor",
|
|
1096
1264
|
version: "1.0.0",
|
|
@@ -1133,9 +1301,9 @@ var ANNOTATION_ORPHAN_TEXTS = {
|
|
|
1133
1301
|
};
|
|
1134
1302
|
|
|
1135
1303
|
// plugins/core/analyzers/annotation-orphan/index.ts
|
|
1136
|
-
var
|
|
1304
|
+
var ID8 = "annotation-orphan";
|
|
1137
1305
|
var annotationOrphanAnalyzer = {
|
|
1138
|
-
id:
|
|
1306
|
+
id: ID8,
|
|
1139
1307
|
pluginId: "core",
|
|
1140
1308
|
kind: "analyzer",
|
|
1141
1309
|
version: "1.0.0",
|
|
@@ -1148,7 +1316,7 @@ var annotationOrphanAnalyzer = {
|
|
|
1148
1316
|
for (const orphan of orphans) {
|
|
1149
1317
|
const expectedMdRelative = orphan.relativePath.endsWith(".sm") ? `${orphan.relativePath.slice(0, -".sm".length)}.md` : `${orphan.relativePath}.md`;
|
|
1150
1318
|
issues.push({
|
|
1151
|
-
analyzerId:
|
|
1319
|
+
analyzerId: ID8,
|
|
1152
1320
|
severity: "warn",
|
|
1153
1321
|
nodeIds: [expectedMdRelative],
|
|
1154
1322
|
message: tx(ANNOTATION_ORPHAN_TEXTS.message, {
|
|
@@ -1185,9 +1353,9 @@ var ANNOTATION_STALE_TEXTS = {
|
|
|
1185
1353
|
};
|
|
1186
1354
|
|
|
1187
1355
|
// plugins/core/analyzers/annotation-stale/index.ts
|
|
1188
|
-
var
|
|
1356
|
+
var ID9 = "annotation-stale";
|
|
1189
1357
|
var annotationStaleAnalyzer = {
|
|
1190
|
-
id:
|
|
1358
|
+
id: ID9,
|
|
1191
1359
|
pluginId: "core",
|
|
1192
1360
|
kind: "analyzer",
|
|
1193
1361
|
version: "1.0.0",
|
|
@@ -1222,7 +1390,7 @@ var annotationStaleAnalyzer = {
|
|
|
1222
1390
|
if (status === "fresh") continue;
|
|
1223
1391
|
const message = status === "stale-body" ? tx(ANNOTATION_STALE_TEXTS.bodyDrift, { path: node.path }) : status === "stale-frontmatter" ? tx(ANNOTATION_STALE_TEXTS.frontmatterDrift, { path: node.path }) : tx(ANNOTATION_STALE_TEXTS.bothDrift, { path: node.path });
|
|
1224
1392
|
issues.push({
|
|
1225
|
-
analyzerId:
|
|
1393
|
+
analyzerId: ID9,
|
|
1226
1394
|
severity: "warn",
|
|
1227
1395
|
nodeIds: [node.path],
|
|
1228
1396
|
message,
|
|
@@ -1268,9 +1436,9 @@ var BROKEN_REF_TEXTS = {
|
|
|
1268
1436
|
};
|
|
1269
1437
|
|
|
1270
1438
|
// plugins/core/analyzers/broken-ref/index.ts
|
|
1271
|
-
var
|
|
1439
|
+
var ID10 = "broken-ref";
|
|
1272
1440
|
var brokenRefAnalyzer = {
|
|
1273
|
-
id:
|
|
1441
|
+
id: ID10,
|
|
1274
1442
|
pluginId: "core",
|
|
1275
1443
|
kind: "analyzer",
|
|
1276
1444
|
version: "1.0.0",
|
|
@@ -1339,7 +1507,7 @@ function buildIssue(link2, hintCandidates = []) {
|
|
|
1339
1507
|
trigger: link2.trigger?.normalizedTrigger ?? null
|
|
1340
1508
|
};
|
|
1341
1509
|
const issue = {
|
|
1342
|
-
analyzerId:
|
|
1510
|
+
analyzerId: ID10,
|
|
1343
1511
|
severity: "warn",
|
|
1344
1512
|
nodeIds: [link2.source],
|
|
1345
1513
|
message: tx(BROKEN_REF_TEXTS.message, {
|
|
@@ -1433,9 +1601,9 @@ function isPathStyleLink(link2) {
|
|
|
1433
1601
|
}
|
|
1434
1602
|
|
|
1435
1603
|
// plugins/core/analyzers/contribution-orphan/index.ts
|
|
1436
|
-
var
|
|
1604
|
+
var ID11 = "contribution-orphan";
|
|
1437
1605
|
var contributionOrphanAnalyzer = {
|
|
1438
|
-
id:
|
|
1606
|
+
id: ID11,
|
|
1439
1607
|
pluginId: "core",
|
|
1440
1608
|
kind: "analyzer",
|
|
1441
1609
|
version: "0.0.0",
|
|
@@ -1456,9 +1624,9 @@ var JOB_ORPHAN_FILE_TEXTS = {
|
|
|
1456
1624
|
};
|
|
1457
1625
|
|
|
1458
1626
|
// plugins/core/analyzers/job-orphan-file/index.ts
|
|
1459
|
-
var
|
|
1627
|
+
var ID12 = "job-orphan-file";
|
|
1460
1628
|
var jobOrphanFileAnalyzer = {
|
|
1461
|
-
id:
|
|
1629
|
+
id: ID12,
|
|
1462
1630
|
pluginId: "core",
|
|
1463
1631
|
kind: "analyzer",
|
|
1464
1632
|
version: "1.0.0",
|
|
@@ -1470,7 +1638,7 @@ var jobOrphanFileAnalyzer = {
|
|
|
1470
1638
|
const issues = [];
|
|
1471
1639
|
for (const filePath of orphans) {
|
|
1472
1640
|
issues.push({
|
|
1473
|
-
analyzerId:
|
|
1641
|
+
analyzerId: ID12,
|
|
1474
1642
|
severity: "warn",
|
|
1475
1643
|
nodeIds: [filePath],
|
|
1476
1644
|
message: tx(JOB_ORPHAN_FILE_TEXTS.message, { filePath }),
|
|
@@ -1488,9 +1656,9 @@ var LINK_CONFLICT_TEXTS = {
|
|
|
1488
1656
|
};
|
|
1489
1657
|
|
|
1490
1658
|
// plugins/core/analyzers/link-conflict/index.ts
|
|
1491
|
-
var
|
|
1659
|
+
var ID13 = "link-conflict";
|
|
1492
1660
|
var linkConflictAnalyzer = {
|
|
1493
|
-
id:
|
|
1661
|
+
id: ID13,
|
|
1494
1662
|
pluginId: "core",
|
|
1495
1663
|
kind: "analyzer",
|
|
1496
1664
|
version: "1.0.0",
|
|
@@ -1538,7 +1706,7 @@ var linkConflictAnalyzer = {
|
|
|
1538
1706
|
const [source, target] = key.split("\0");
|
|
1539
1707
|
const kindList = variants.map((v) => v.kind).join(" / ");
|
|
1540
1708
|
issues.push({
|
|
1541
|
-
analyzerId:
|
|
1709
|
+
analyzerId: ID13,
|
|
1542
1710
|
severity: "warn",
|
|
1543
1711
|
nodeIds: [source, target],
|
|
1544
1712
|
message: tx(LINK_CONFLICT_TEXTS.message, {
|
|
@@ -1553,14 +1721,7 @@ var linkConflictAnalyzer = {
|
|
|
1553
1721
|
}
|
|
1554
1722
|
};
|
|
1555
1723
|
function rankConfidence(c) {
|
|
1556
|
-
|
|
1557
|
-
case "high":
|
|
1558
|
-
return 2;
|
|
1559
|
-
case "medium":
|
|
1560
|
-
return 1;
|
|
1561
|
-
case "low":
|
|
1562
|
-
return 0;
|
|
1563
|
-
}
|
|
1724
|
+
return c;
|
|
1564
1725
|
}
|
|
1565
1726
|
|
|
1566
1727
|
// kernel/util/trigger-resolve.ts
|
|
@@ -1612,9 +1773,9 @@ function resolveLinkTargetToPath(link2, nameIndex) {
|
|
|
1612
1773
|
}
|
|
1613
1774
|
|
|
1614
1775
|
// plugins/core/analyzers/link-counts/index.ts
|
|
1615
|
-
var
|
|
1776
|
+
var ID14 = "link-counts";
|
|
1616
1777
|
var linkCountsAnalyzer = {
|
|
1617
|
-
id:
|
|
1778
|
+
id: ID14,
|
|
1618
1779
|
pluginId: "core",
|
|
1619
1780
|
kind: "analyzer",
|
|
1620
1781
|
version: "1.0.0",
|
|
@@ -1678,11 +1839,11 @@ function formatBreakdown(byKind, direction) {
|
|
|
1678
1839
|
}
|
|
1679
1840
|
|
|
1680
1841
|
// plugins/core/analyzers/stability/index.ts
|
|
1681
|
-
var
|
|
1842
|
+
var ID15 = "stability";
|
|
1682
1843
|
var EXPERIMENTAL_TOOLTIP = "Experimental: API may change";
|
|
1683
1844
|
var DEPRECATED_TOOLTIP = "Deprecated: avoid in new code";
|
|
1684
1845
|
var stabilityAnalyzer = {
|
|
1685
|
-
id:
|
|
1846
|
+
id: ID15,
|
|
1686
1847
|
pluginId: "core",
|
|
1687
1848
|
kind: "analyzer",
|
|
1688
1849
|
version: "1.0.0",
|
|
@@ -1714,7 +1875,7 @@ var stabilityAnalyzer = {
|
|
|
1714
1875
|
tooltip: EXPERIMENTAL_TOOLTIP
|
|
1715
1876
|
});
|
|
1716
1877
|
issues.push({
|
|
1717
|
-
analyzerId:
|
|
1878
|
+
analyzerId: ID15,
|
|
1718
1879
|
severity: "info",
|
|
1719
1880
|
nodeIds: [node.path],
|
|
1720
1881
|
message: `Node '${node.path}' is marked experimental: API may change.`,
|
|
@@ -1727,7 +1888,7 @@ var stabilityAnalyzer = {
|
|
|
1727
1888
|
severity: "warn"
|
|
1728
1889
|
});
|
|
1729
1890
|
issues.push({
|
|
1730
|
-
analyzerId:
|
|
1891
|
+
analyzerId: ID15,
|
|
1731
1892
|
severity: "warn",
|
|
1732
1893
|
nodeIds: [node.path],
|
|
1733
1894
|
message: `Node '${node.path}' is marked deprecated: avoid in new code.`,
|
|
@@ -1761,9 +1922,9 @@ var SUPERSEDED_TEXTS = {
|
|
|
1761
1922
|
};
|
|
1762
1923
|
|
|
1763
1924
|
// plugins/core/analyzers/superseded/index.ts
|
|
1764
|
-
var
|
|
1925
|
+
var ID16 = "superseded";
|
|
1765
1926
|
var supersededAnalyzer = {
|
|
1766
|
-
id:
|
|
1927
|
+
id: ID16,
|
|
1767
1928
|
pluginId: "core",
|
|
1768
1929
|
kind: "analyzer",
|
|
1769
1930
|
version: "1.0.0",
|
|
@@ -1775,7 +1936,7 @@ var supersededAnalyzer = {
|
|
|
1775
1936
|
const supersededBy = pickSupersededBy(node);
|
|
1776
1937
|
if (supersededBy === null) continue;
|
|
1777
1938
|
issues.push({
|
|
1778
|
-
analyzerId:
|
|
1939
|
+
analyzerId: ID16,
|
|
1779
1940
|
severity: "info",
|
|
1780
1941
|
nodeIds: [node.path],
|
|
1781
1942
|
message: tx(SUPERSEDED_TEXTS.message, {
|
|
@@ -1824,14 +1985,14 @@ var TRIGGER_COLLISION_TEXTS = {
|
|
|
1824
1985
|
};
|
|
1825
1986
|
|
|
1826
1987
|
// plugins/core/analyzers/trigger-collision/index.ts
|
|
1827
|
-
var
|
|
1988
|
+
var ID17 = "trigger-collision";
|
|
1828
1989
|
var ADVERTISING_KINDS = /* @__PURE__ */ new Set([
|
|
1829
1990
|
"command",
|
|
1830
1991
|
"skill",
|
|
1831
1992
|
"agent"
|
|
1832
1993
|
]);
|
|
1833
1994
|
var triggerCollisionAnalyzer = {
|
|
1834
|
-
id:
|
|
1995
|
+
id: ID17,
|
|
1835
1996
|
pluginId: "core",
|
|
1836
1997
|
kind: "analyzer",
|
|
1837
1998
|
mode: "deterministic",
|
|
@@ -1930,7 +2091,7 @@ function analyzeTriggerBucket(normalized, claims) {
|
|
|
1930
2091
|
part: parts[0]
|
|
1931
2092
|
});
|
|
1932
2093
|
return {
|
|
1933
|
-
analyzerId:
|
|
2094
|
+
analyzerId: ID17,
|
|
1934
2095
|
severity: "error",
|
|
1935
2096
|
nodeIds,
|
|
1936
2097
|
message,
|
|
@@ -1970,10 +2131,10 @@ var UNKNOWN_FIELD_TEXTS = {
|
|
|
1970
2131
|
};
|
|
1971
2132
|
|
|
1972
2133
|
// plugins/core/analyzers/unknown-field/index.ts
|
|
1973
|
-
var
|
|
2134
|
+
var ID18 = "unknown-field";
|
|
1974
2135
|
var RESERVED_ROOT_BLOCKS = /* @__PURE__ */ new Set(["identity", "annotations", "settings", "audit"]);
|
|
1975
2136
|
var unknownFieldAnalyzer = {
|
|
1976
|
-
id:
|
|
2137
|
+
id: ID18,
|
|
1977
2138
|
pluginId: "core",
|
|
1978
2139
|
kind: "analyzer",
|
|
1979
2140
|
version: "1.0.0",
|
|
@@ -2031,7 +2192,7 @@ var unknownFieldAnalyzer = {
|
|
|
2031
2192
|
for (const key of Object.keys(annotations)) {
|
|
2032
2193
|
if (!knownAnnotationKeys.has(key)) {
|
|
2033
2194
|
issues.push({
|
|
2034
|
-
analyzerId:
|
|
2195
|
+
analyzerId: ID18,
|
|
2035
2196
|
severity: "warn",
|
|
2036
2197
|
nodeIds: [node.path],
|
|
2037
2198
|
message: tx(UNKNOWN_FIELD_TEXTS.unknownAnnotationKey, {
|
|
@@ -2058,7 +2219,7 @@ var unknownFieldAnalyzer = {
|
|
|
2058
2219
|
if (validator(value)) continue;
|
|
2059
2220
|
const errors = (validator.errors ?? []).map((e) => `${e.instancePath || "(root)"} ${e.message ?? e.keyword}`).join("; ");
|
|
2060
2221
|
issues.push({
|
|
2061
|
-
analyzerId:
|
|
2222
|
+
analyzerId: ID18,
|
|
2062
2223
|
severity: "warn",
|
|
2063
2224
|
nodeIds: [node.path],
|
|
2064
2225
|
message: tx(UNKNOWN_FIELD_TEXTS.pluginNamespaceInvalid, {
|
|
@@ -2074,7 +2235,7 @@ var unknownFieldAnalyzer = {
|
|
|
2074
2235
|
continue;
|
|
2075
2236
|
}
|
|
2076
2237
|
issues.push({
|
|
2077
|
-
analyzerId:
|
|
2238
|
+
analyzerId: ID18,
|
|
2078
2239
|
severity: "warn",
|
|
2079
2240
|
nodeIds: [node.path],
|
|
2080
2241
|
message: tx(UNKNOWN_FIELD_TEXTS.unknownRootKey, {
|
|
@@ -2367,9 +2528,9 @@ var VALIDATE_ALL_TEXTS = {
|
|
|
2367
2528
|
};
|
|
2368
2529
|
|
|
2369
2530
|
// plugins/core/analyzers/validate-all/index.ts
|
|
2370
|
-
var
|
|
2531
|
+
var ID19 = "validate-all";
|
|
2371
2532
|
var validateAllAnalyzer = {
|
|
2372
|
-
id:
|
|
2533
|
+
id: ID19,
|
|
2373
2534
|
pluginId: "core",
|
|
2374
2535
|
kind: "analyzer",
|
|
2375
2536
|
version: "1.0.0",
|
|
@@ -2432,7 +2593,7 @@ function collectNodeFindings(v, node, out) {
|
|
|
2432
2593
|
const result = v.validate("node", toNodeForSchema(node));
|
|
2433
2594
|
if (result.ok) return;
|
|
2434
2595
|
out.push({
|
|
2435
|
-
analyzerId:
|
|
2596
|
+
analyzerId: ID19,
|
|
2436
2597
|
severity: "error",
|
|
2437
2598
|
nodeIds: [node.path],
|
|
2438
2599
|
message: tx(VALIDATE_ALL_TEXTS.nodeFailure, {
|
|
@@ -2451,7 +2612,7 @@ function collectFrontmatterBaseFindings(node, out) {
|
|
|
2451
2612
|
if (isMissingStringField(fm, "description")) missing.push("description");
|
|
2452
2613
|
if (missing.length === 0) return;
|
|
2453
2614
|
out.push({
|
|
2454
|
-
analyzerId:
|
|
2615
|
+
analyzerId: ID19,
|
|
2455
2616
|
// `warn` (not `error`) so the default `sm scan` exit code stays
|
|
2456
2617
|
// 0 even when nodes are missing frontmatter base fields. Strict
|
|
2457
2618
|
// mode (`sm scan --strict`) still escalates to exit 1. Matches
|
|
@@ -2473,7 +2634,7 @@ function collectLinkFindings(v, link2, out) {
|
|
|
2473
2634
|
const result = v.validate("link", toLinkForSchema(link2));
|
|
2474
2635
|
if (result.ok) return;
|
|
2475
2636
|
out.push({
|
|
2476
|
-
analyzerId:
|
|
2637
|
+
analyzerId: ID19,
|
|
2477
2638
|
severity: "error",
|
|
2478
2639
|
nodeIds: [link2.source],
|
|
2479
2640
|
message: tx(VALIDATE_ALL_TEXTS.linkFailure, {
|
|
@@ -2541,13 +2702,13 @@ var ASCII_FORMATTER_TEXTS = {
|
|
|
2541
2702
|
};
|
|
2542
2703
|
|
|
2543
2704
|
// plugins/core/formatters/ascii/index.ts
|
|
2544
|
-
var
|
|
2705
|
+
var ID20 = "ascii";
|
|
2545
2706
|
var KIND_ORDER = ["agent", "command", "skill", "markdown"];
|
|
2546
2707
|
var asciiFormatter = {
|
|
2547
|
-
id:
|
|
2708
|
+
id: ID20,
|
|
2548
2709
|
pluginId: "core",
|
|
2549
2710
|
kind: "formatter",
|
|
2550
|
-
formatId:
|
|
2711
|
+
formatId: ID20,
|
|
2551
2712
|
version: "1.0.0",
|
|
2552
2713
|
description: "Renders the scan as plain text, grouped by kind, arrows, and issues. Used by `sm scan --format=ascii`.",
|
|
2553
2714
|
// ASCII tree formatter, header + per-kind sections + per-issue
|
|
@@ -2642,14 +2803,14 @@ function renderSection(out, kind, group) {
|
|
|
2642
2803
|
}
|
|
2643
2804
|
|
|
2644
2805
|
// plugins/core/formatters/json/index.ts
|
|
2645
|
-
var
|
|
2806
|
+
var ID21 = "json";
|
|
2646
2807
|
var jsonFormatter = {
|
|
2647
|
-
id:
|
|
2808
|
+
id: ID21,
|
|
2648
2809
|
pluginId: "core",
|
|
2649
2810
|
kind: "formatter",
|
|
2650
2811
|
version: "1.0.0",
|
|
2651
2812
|
description: "Renders the persisted scan as JSON (conforms to `scan-result.schema.json` when the full ScanResult is available). Used by `sm graph --format json` and `GET /api/graph?format=json`.",
|
|
2652
|
-
formatId:
|
|
2813
|
+
formatId: ID21,
|
|
2653
2814
|
format(ctx) {
|
|
2654
2815
|
if (ctx.scanResult !== void 0) {
|
|
2655
2816
|
return JSON.stringify(ctx.scanResult);
|
|
@@ -2788,10 +2949,10 @@ function resolveSpecRoot2() {
|
|
|
2788
2949
|
}
|
|
2789
2950
|
|
|
2790
2951
|
// plugins/core/actions/bump/index.ts
|
|
2791
|
-
var
|
|
2952
|
+
var ID22 = "bump";
|
|
2792
2953
|
var PLUGIN_ID = "core";
|
|
2793
2954
|
var bumpAction = {
|
|
2794
|
-
id:
|
|
2955
|
+
id: ID22,
|
|
2795
2956
|
pluginId: PLUGIN_ID,
|
|
2796
2957
|
kind: "action",
|
|
2797
2958
|
version: "1.0.0",
|
|
@@ -2850,10 +3011,10 @@ function pickCurrentVersion(overlay) {
|
|
|
2850
3011
|
}
|
|
2851
3012
|
|
|
2852
3013
|
// plugins/core/actions/mark-superseded/index.ts
|
|
2853
|
-
var
|
|
3014
|
+
var ID23 = "mark-superseded";
|
|
2854
3015
|
var PLUGIN_ID2 = "core";
|
|
2855
3016
|
var markSupersededAction = {
|
|
2856
|
-
id:
|
|
3017
|
+
id: ID23,
|
|
2857
3018
|
pluginId: PLUGIN_ID2,
|
|
2858
3019
|
kind: "action",
|
|
2859
3020
|
version: "0.0.0",
|
|
@@ -2963,7 +3124,7 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
2963
3124
|
// package.json
|
|
2964
3125
|
var package_default = {
|
|
2965
3126
|
name: "@skill-map/cli",
|
|
2966
|
-
version: "0.
|
|
3127
|
+
version: "0.33.0",
|
|
2967
3128
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
2968
3129
|
license: "MIT",
|
|
2969
3130
|
type: "module",
|
|
@@ -3044,6 +3205,7 @@ var package_default = {
|
|
|
3044
3205
|
"js-yaml": "4.1.1",
|
|
3045
3206
|
kysely: "0.28.17",
|
|
3046
3207
|
semver: "7.7.4",
|
|
3208
|
+
"smol-toml": "1.6.1",
|
|
3047
3209
|
typanion: "3.14.0",
|
|
3048
3210
|
ws: "8.20.0"
|
|
3049
3211
|
},
|
|
@@ -3339,14 +3501,16 @@ var updateCheckHook = {
|
|
|
3339
3501
|
|
|
3340
3502
|
// plugins/built-ins.ts
|
|
3341
3503
|
var claudeProvider2 = { ...claudeProvider, pluginId: "claude" };
|
|
3504
|
+
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude" };
|
|
3505
|
+
var slashExtractor2 = { ...slashExtractor, pluginId: "claude" };
|
|
3342
3506
|
var geminiProvider2 = { ...geminiProvider, pluginId: "gemini" };
|
|
3507
|
+
var openaiProvider2 = { ...openaiProvider, pluginId: "openai" };
|
|
3343
3508
|
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills" };
|
|
3344
3509
|
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core" };
|
|
3345
3510
|
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core" };
|
|
3346
|
-
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "core" };
|
|
3347
3511
|
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core" };
|
|
3348
3512
|
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core" };
|
|
3349
|
-
var
|
|
3513
|
+
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core" };
|
|
3350
3514
|
var toolsCountExtractor2 = { ...toolsCountExtractor, pluginId: "core" };
|
|
3351
3515
|
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core" };
|
|
3352
3516
|
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core" };
|
|
@@ -3371,7 +3535,9 @@ var builtInBundles = [
|
|
|
3371
3535
|
granularity: "bundle",
|
|
3372
3536
|
description: "Claude Code platform integration. Classifies files under `.claude/{agents,commands,skills}` and parses Claude-flavored frontmatter.",
|
|
3373
3537
|
extensions: [
|
|
3374
|
-
claudeProvider2
|
|
3538
|
+
claudeProvider2,
|
|
3539
|
+
atDirectiveExtractor2,
|
|
3540
|
+
slashExtractor2
|
|
3375
3541
|
]
|
|
3376
3542
|
},
|
|
3377
3543
|
{
|
|
@@ -3382,6 +3548,14 @@ var builtInBundles = [
|
|
|
3382
3548
|
geminiProvider2
|
|
3383
3549
|
]
|
|
3384
3550
|
},
|
|
3551
|
+
{
|
|
3552
|
+
id: "openai",
|
|
3553
|
+
granularity: "bundle",
|
|
3554
|
+
description: "OpenAI Codex CLI platform integration. Classifies TOML sub-agent definitions under `.codex/agents/*.toml` and (future) walks the hierarchical AGENTS.md cascade. Provider for the active-lens `openai` runtime.",
|
|
3555
|
+
extensions: [
|
|
3556
|
+
openaiProvider2
|
|
3557
|
+
]
|
|
3558
|
+
},
|
|
3385
3559
|
{
|
|
3386
3560
|
id: "agent-skills",
|
|
3387
3561
|
granularity: "bundle",
|
|
@@ -3397,10 +3571,9 @@ var builtInBundles = [
|
|
|
3397
3571
|
extensions: [
|
|
3398
3572
|
coreMarkdownProvider2,
|
|
3399
3573
|
annotationsExtractor2,
|
|
3400
|
-
atDirectiveExtractor2,
|
|
3401
3574
|
externalUrlCounterExtractor2,
|
|
3402
3575
|
markdownLinkExtractor2,
|
|
3403
|
-
|
|
3576
|
+
mcpToolsExtractor2,
|
|
3404
3577
|
toolsCountExtractor2,
|
|
3405
3578
|
annotationOrphanAnalyzer2,
|
|
3406
3579
|
annotationStaleAnalyzer2,
|
|
@@ -5945,11 +6118,6 @@ var LINK_KIND_VALUES = Object.freeze([
|
|
|
5945
6118
|
"mentions",
|
|
5946
6119
|
"supersedes"
|
|
5947
6120
|
]);
|
|
5948
|
-
var CONFIDENCE_VALUES = Object.freeze([
|
|
5949
|
-
"high",
|
|
5950
|
-
"medium",
|
|
5951
|
-
"low"
|
|
5952
|
-
]);
|
|
5953
6121
|
var SEVERITY_VALUES = Object.freeze([
|
|
5954
6122
|
"error",
|
|
5955
6123
|
"warn",
|
|
@@ -5981,7 +6149,7 @@ function isLinkKind(s) {
|
|
|
5981
6149
|
return typeof s === "string" && LINK_KIND_VALUES.includes(s);
|
|
5982
6150
|
}
|
|
5983
6151
|
function isConfidence(s) {
|
|
5984
|
-
return typeof s === "
|
|
6152
|
+
return typeof s === "number" && Number.isFinite(s) && s >= 0 && s <= 1;
|
|
5985
6153
|
}
|
|
5986
6154
|
function isSeverity(s) {
|
|
5987
6155
|
return typeof s === "string" && SEVERITY_VALUES.includes(s);
|
|
@@ -5995,7 +6163,7 @@ function parseLinkKind(s, ctx) {
|
|
|
5995
6163
|
function parseConfidence(s, ctx) {
|
|
5996
6164
|
if (isConfidence(s)) return s;
|
|
5997
6165
|
throw new Error(
|
|
5998
|
-
`Invalid Confidence value ${formatValue(s)} at ${ctx}.
|
|
6166
|
+
`Invalid Confidence value ${formatValue(s)} at ${ctx}. Expected a finite number in [0..1].`
|
|
5999
6167
|
);
|
|
6000
6168
|
}
|
|
6001
6169
|
function parseSeverity(s, ctx) {
|
|
@@ -8794,10 +8962,45 @@ var plainParser = {
|
|
|
8794
8962
|
}
|
|
8795
8963
|
};
|
|
8796
8964
|
|
|
8965
|
+
// plugins/core/parsers/toml/index.ts
|
|
8966
|
+
import { parse as parseToml } from "smol-toml";
|
|
8967
|
+
var tomlParser = {
|
|
8968
|
+
id: "toml",
|
|
8969
|
+
parse(raw, _path) {
|
|
8970
|
+
let parsed = {};
|
|
8971
|
+
const issues = [];
|
|
8972
|
+
try {
|
|
8973
|
+
const doc = parseToml(raw);
|
|
8974
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc)) {
|
|
8975
|
+
parsed = stripPrototypePollution(doc);
|
|
8976
|
+
}
|
|
8977
|
+
} catch (err) {
|
|
8978
|
+
issues.push({
|
|
8979
|
+
code: "frontmatter-parse-error",
|
|
8980
|
+
message: sanitiseParseErrorMessage2(err)
|
|
8981
|
+
});
|
|
8982
|
+
}
|
|
8983
|
+
const out = {
|
|
8984
|
+
frontmatterRaw: raw,
|
|
8985
|
+
frontmatter: parsed,
|
|
8986
|
+
body: ""
|
|
8987
|
+
};
|
|
8988
|
+
if (issues.length > 0) {
|
|
8989
|
+
return { ...out, issues };
|
|
8990
|
+
}
|
|
8991
|
+
return out;
|
|
8992
|
+
}
|
|
8993
|
+
};
|
|
8994
|
+
function sanitiseParseErrorMessage2(err) {
|
|
8995
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
8996
|
+
return raw.replace(/[-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
8997
|
+
}
|
|
8998
|
+
|
|
8797
8999
|
// kernel/scan/parsers/index.ts
|
|
8798
9000
|
var REGISTRY = /* @__PURE__ */ new Map([
|
|
8799
9001
|
[frontmatterYamlParser.id, frontmatterYamlParser],
|
|
8800
|
-
[plainParser.id, plainParser]
|
|
9002
|
+
[plainParser.id, plainParser],
|
|
9003
|
+
[tomlParser.id, tomlParser]
|
|
8801
9004
|
]);
|
|
8802
9005
|
var FROZEN_IDS = new Set(REGISTRY.keys());
|
|
8803
9006
|
function getParser(id) {
|
|
@@ -9469,6 +9672,42 @@ function relativeIfBelow(path, cwd) {
|
|
|
9469
9672
|
return rel;
|
|
9470
9673
|
}
|
|
9471
9674
|
|
|
9675
|
+
// cli/util/scan-zone-drop.ts
|
|
9676
|
+
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
9677
|
+
|
|
9678
|
+
// cli/commands/db/shared.ts
|
|
9679
|
+
var SAFE_SQL_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
9680
|
+
function assertSafeIdentifier(name) {
|
|
9681
|
+
if (!SAFE_SQL_IDENTIFIER_RE.test(name)) {
|
|
9682
|
+
throw new Error(`refusing to operate on non-identifier table name: ${JSON.stringify(name)}`);
|
|
9683
|
+
}
|
|
9684
|
+
}
|
|
9685
|
+
|
|
9686
|
+
// cli/util/scan-zone-drop.ts
|
|
9687
|
+
function dropScanZone(dbPath) {
|
|
9688
|
+
const db = new DatabaseSync4(dbPath);
|
|
9689
|
+
try {
|
|
9690
|
+
const rows = db.prepare(
|
|
9691
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'scan\\_%' ESCAPE '\\'"
|
|
9692
|
+
).all();
|
|
9693
|
+
for (const r of rows) assertSafeIdentifier(r.name);
|
|
9694
|
+
if (rows.length === 0) {
|
|
9695
|
+
return { tableCount: 0, droppedTables: [] };
|
|
9696
|
+
}
|
|
9697
|
+
db.exec("BEGIN");
|
|
9698
|
+
for (const { name } of rows) {
|
|
9699
|
+
db.exec(`DELETE FROM "${name}"`);
|
|
9700
|
+
}
|
|
9701
|
+
db.exec("COMMIT");
|
|
9702
|
+
return {
|
|
9703
|
+
tableCount: rows.length,
|
|
9704
|
+
droppedTables: rows.map((r) => r.name)
|
|
9705
|
+
};
|
|
9706
|
+
} finally {
|
|
9707
|
+
db.close();
|
|
9708
|
+
}
|
|
9709
|
+
}
|
|
9710
|
+
|
|
9472
9711
|
// cli/i18n/config.texts.ts
|
|
9473
9712
|
var CONFIG_TEXTS = {
|
|
9474
9713
|
unknownKey: "{{glyph}} Unknown config key: {{key}}\n",
|
|
@@ -9511,6 +9750,20 @@ var CONFIG_TEXTS = {
|
|
|
9511
9750
|
* screen what they just opted into.
|
|
9512
9751
|
*/
|
|
9513
9752
|
privacyGateConfirmed: '{{glyph}} Opening disk access for "{{key}}":\n{{paths}}\n',
|
|
9753
|
+
/**
|
|
9754
|
+
* Confirmation printed after `sm config set activeProvider <id>`
|
|
9755
|
+
* succeeds. The lens change atomically drops the scan_* zone (per
|
|
9756
|
+
* `architecture.md` §Active Provider Lens) so the persisted graph
|
|
9757
|
+
* never carries stale node / link rows from the previous lens. We
|
|
9758
|
+
* surface what was cleared so the operator knows their state was
|
|
9759
|
+
* touched and what to do next.
|
|
9760
|
+
*/
|
|
9761
|
+
lensSwitchedCleared: "{{glyph}} Lens switched. Cleared {{tableCount}} scan table(s): {{tableNames}}.\n {{hint}}\n",
|
|
9762
|
+
lensSwitchedClearedHint: "Run `sm scan` to repopulate the graph under the new lens.",
|
|
9763
|
+
/** Same lens-switch announcement when the DB was empty (no rows to clear). */
|
|
9764
|
+
lensSwitchedEmpty: "{{glyph}} Lens switched. Scan zone was already empty.\n {{hint}}\n",
|
|
9765
|
+
/** Lens switch happened before any `sm scan` ran (no DB file on disk yet). */
|
|
9766
|
+
lensSwitchedNoDb: "{{glyph}} Lens switched. Run `sm scan` to populate the graph under the new lens.\n",
|
|
9514
9767
|
// --- list verb (sectioned human renderer) ----------------------------
|
|
9515
9768
|
/** Section heading: ` General`, ` Scan`, … rendered before its rows. */
|
|
9516
9769
|
listSectionHeader: " {{title}}\n",
|
|
@@ -9962,8 +10215,44 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
9962
10215
|
)
|
|
9963
10216
|
})
|
|
9964
10217
|
);
|
|
10218
|
+
if (this.key === "activeProvider") {
|
|
10219
|
+
this.announceLensSwitch(ctx.cwd, ansi);
|
|
10220
|
+
}
|
|
9965
10221
|
return ExitCode.Ok;
|
|
9966
10222
|
}
|
|
10223
|
+
/**
|
|
10224
|
+
* Side effect of `sm config set activeProvider <id>`, atomically
|
|
10225
|
+
* drops the `scan_*` zone so the persisted graph never reflects the
|
|
10226
|
+
* wrong lens (see `architecture.md` §Active Provider Lens). The drop
|
|
10227
|
+
* is non-destructive of `state_*` / `config_*` rows; the operator
|
|
10228
|
+
* runs `sm scan` next to repopulate.
|
|
10229
|
+
*
|
|
10230
|
+
* Silent when no DB file exists on disk yet (fresh project that has
|
|
10231
|
+
* never run `sm scan`), the lens just gets set and the next scan
|
|
10232
|
+
* uses it.
|
|
10233
|
+
*/
|
|
10234
|
+
announceLensSwitch(cwd, ansi) {
|
|
10235
|
+
const dbPath = resolveDbPath({ db: void 0, cwd });
|
|
10236
|
+
const okGlyph = ansi.green("\u2713");
|
|
10237
|
+
if (!existsSync14(dbPath)) {
|
|
10238
|
+
this.printer.info(tx(CONFIG_TEXTS.lensSwitchedNoDb, { glyph: okGlyph }));
|
|
10239
|
+
return;
|
|
10240
|
+
}
|
|
10241
|
+
const result = dropScanZone(dbPath);
|
|
10242
|
+
const hint = ansi.dim(CONFIG_TEXTS.lensSwitchedClearedHint);
|
|
10243
|
+
if (result.tableCount === 0) {
|
|
10244
|
+
this.printer.info(tx(CONFIG_TEXTS.lensSwitchedEmpty, { glyph: okGlyph, hint }));
|
|
10245
|
+
return;
|
|
10246
|
+
}
|
|
10247
|
+
this.printer.info(
|
|
10248
|
+
tx(CONFIG_TEXTS.lensSwitchedCleared, {
|
|
10249
|
+
glyph: okGlyph,
|
|
10250
|
+
tableCount: result.tableCount,
|
|
10251
|
+
tableNames: result.droppedTables.join(", "),
|
|
10252
|
+
hint
|
|
10253
|
+
})
|
|
10254
|
+
);
|
|
10255
|
+
}
|
|
9967
10256
|
};
|
|
9968
10257
|
var ConfigResetCommand = class extends SmCommand {
|
|
9969
10258
|
static paths = [["config", "reset"]];
|
|
@@ -11001,18 +11290,8 @@ var DbRestoreCommand = class extends SmCommand {
|
|
|
11001
11290
|
|
|
11002
11291
|
// cli/commands/db/reset.ts
|
|
11003
11292
|
import { rm as rm2 } from "fs/promises";
|
|
11004
|
-
import { DatabaseSync as
|
|
11293
|
+
import { DatabaseSync as DatabaseSync5 } from "node:sqlite";
|
|
11005
11294
|
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
11006
|
-
|
|
11007
|
-
// cli/commands/db/shared.ts
|
|
11008
|
-
var SAFE_SQL_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
11009
|
-
function assertSafeIdentifier(name) {
|
|
11010
|
-
if (!SAFE_SQL_IDENTIFIER_RE.test(name)) {
|
|
11011
|
-
throw new Error(`refusing to operate on non-identifier table name: ${JSON.stringify(name)}`);
|
|
11012
|
-
}
|
|
11013
|
-
}
|
|
11014
|
-
|
|
11015
|
-
// cli/commands/db/reset.ts
|
|
11016
11295
|
var DbResetCommand = class extends SmCommand {
|
|
11017
11296
|
static paths = [["db", "reset"]];
|
|
11018
11297
|
static usage = Command8.Usage({
|
|
@@ -11094,7 +11373,7 @@ var DbResetCommand = class extends SmCommand {
|
|
|
11094
11373
|
return ExitCode.Error;
|
|
11095
11374
|
}
|
|
11096
11375
|
}
|
|
11097
|
-
const db = new
|
|
11376
|
+
const db = new DatabaseSync5(path);
|
|
11098
11377
|
try {
|
|
11099
11378
|
const rows = db.prepare(
|
|
11100
11379
|
"SELECT name FROM sqlite_master WHERE type='table' AND (name LIKE 'scan\\_%' ESCAPE '\\'" + (this.state ? " OR name LIKE 'state\\_%' ESCAPE '\\'" : "") + ")"
|
|
@@ -11237,7 +11516,7 @@ var DbBrowserCommand = class extends SmCommand {
|
|
|
11237
11516
|
};
|
|
11238
11517
|
|
|
11239
11518
|
// cli/commands/db/dump.ts
|
|
11240
|
-
import { DatabaseSync as
|
|
11519
|
+
import { DatabaseSync as DatabaseSync6 } from "node:sqlite";
|
|
11241
11520
|
import { Command as Command11, Option as Option10 } from "clipanion";
|
|
11242
11521
|
var DbDumpCommand = class extends SmCommand {
|
|
11243
11522
|
static paths = [["db", "dump"]];
|
|
@@ -11279,7 +11558,7 @@ var DbDumpCommand = class extends SmCommand {
|
|
|
11279
11558
|
}
|
|
11280
11559
|
};
|
|
11281
11560
|
function dumpDatabaseToStream(dbPath, out, tables) {
|
|
11282
|
-
const db = new
|
|
11561
|
+
const db = new DatabaseSync6(dbPath, { readOnly: true });
|
|
11283
11562
|
try {
|
|
11284
11563
|
out.write("PRAGMA foreign_keys=OFF;\n");
|
|
11285
11564
|
out.write("BEGIN TRANSACTION;\n");
|
|
@@ -12745,12 +13024,22 @@ var ORCHESTRATOR_TEXTS = {
|
|
|
12745
13024
|
runScanRootMissing: "runScan: root path '{{root}}' does not exist or is not a directory"
|
|
12746
13025
|
};
|
|
12747
13026
|
|
|
13027
|
+
// kernel/types.ts
|
|
13028
|
+
var ConfidenceTier = Object.freeze({
|
|
13029
|
+
HIGH: 0.9,
|
|
13030
|
+
MEDIUM: 0.6,
|
|
13031
|
+
LOW: 0.3
|
|
13032
|
+
});
|
|
13033
|
+
|
|
12748
13034
|
// kernel/orchestrator/extractors.ts
|
|
12749
13035
|
async function runExtractorsForNode(opts) {
|
|
12750
13036
|
const internalLinks = [];
|
|
12751
13037
|
const externalLinks = [];
|
|
12752
13038
|
const enrichmentBuffer = /* @__PURE__ */ new Map();
|
|
12753
13039
|
const contributions = [];
|
|
13040
|
+
const signals = [];
|
|
13041
|
+
const virtualNodes = [];
|
|
13042
|
+
const virtualNodePaths = /* @__PURE__ */ new Set();
|
|
12754
13043
|
const validators = loadSchemaValidators();
|
|
12755
13044
|
for (const extractor of opts.extractors) {
|
|
12756
13045
|
const qualifiedId2 = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
@@ -12822,6 +13111,18 @@ async function runExtractorsForNode(opts) {
|
|
|
12822
13111
|
emittedAt: Date.now()
|
|
12823
13112
|
});
|
|
12824
13113
|
};
|
|
13114
|
+
const emitSignal = (signal) => {
|
|
13115
|
+
const validated = validateSignal(extractor, signal, opts.emitter);
|
|
13116
|
+
if (!validated) return;
|
|
13117
|
+
signals.push(validated);
|
|
13118
|
+
};
|
|
13119
|
+
const emitNode = (emitted) => {
|
|
13120
|
+
if (virtualNodePaths.has(emitted.path)) return;
|
|
13121
|
+
const node = buildVirtualNode(extractor, emitted, opts.emitter);
|
|
13122
|
+
if (!node) return;
|
|
13123
|
+
virtualNodePaths.add(node.path);
|
|
13124
|
+
virtualNodes.push(node);
|
|
13125
|
+
};
|
|
12825
13126
|
const store = opts.pluginStores?.get(extractor.pluginId);
|
|
12826
13127
|
const ctx = buildExtractorContext(
|
|
12827
13128
|
extractor,
|
|
@@ -12831,6 +13132,8 @@ async function runExtractorsForNode(opts) {
|
|
|
12831
13132
|
emitLink,
|
|
12832
13133
|
enrichNode,
|
|
12833
13134
|
emitContribution,
|
|
13135
|
+
emitSignal,
|
|
13136
|
+
emitNode,
|
|
12834
13137
|
store
|
|
12835
13138
|
);
|
|
12836
13139
|
await extractor.extract(ctx);
|
|
@@ -12839,7 +13142,9 @@ async function runExtractorsForNode(opts) {
|
|
|
12839
13142
|
internalLinks,
|
|
12840
13143
|
externalLinks,
|
|
12841
13144
|
enrichments: Array.from(enrichmentBuffer.values()),
|
|
12842
|
-
contributions
|
|
13145
|
+
contributions,
|
|
13146
|
+
signals,
|
|
13147
|
+
virtualNodes
|
|
12843
13148
|
};
|
|
12844
13149
|
}
|
|
12845
13150
|
function readDeclaredContributions(extension) {
|
|
@@ -12864,7 +13169,7 @@ function emitExtensionError(emitter, qualifiedId2, nodePath, data) {
|
|
|
12864
13169
|
})
|
|
12865
13170
|
);
|
|
12866
13171
|
}
|
|
12867
|
-
function buildExtractorContext(extractor, node, body, frontmatter, emitLink, enrichNode, emitContribution, store) {
|
|
13172
|
+
function buildExtractorContext(extractor, node, body, frontmatter, emitLink, enrichNode, emitContribution, emitSignal, emitNode, store) {
|
|
12868
13173
|
const scope = extractor.scope ?? "both";
|
|
12869
13174
|
const settings = extractor.resolvedSettings ?? {};
|
|
12870
13175
|
return {
|
|
@@ -12875,9 +13180,62 @@ function buildExtractorContext(extractor, node, body, frontmatter, emitLink, enr
|
|
|
12875
13180
|
emitLink,
|
|
12876
13181
|
enrichNode,
|
|
12877
13182
|
emitContribution,
|
|
13183
|
+
emitSignal,
|
|
13184
|
+
emitNode,
|
|
12878
13185
|
...store !== void 0 ? { store } : {}
|
|
12879
13186
|
};
|
|
12880
13187
|
}
|
|
13188
|
+
var VIRTUAL_NODE_PLACEHOLDER_HASH = "0".repeat(64);
|
|
13189
|
+
function buildVirtualNode(extractor, emitted, emitter) {
|
|
13190
|
+
const qualifiedId2 = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
13191
|
+
if (typeof emitted.path !== "string" || emitted.path.length === 0) {
|
|
13192
|
+
emitter.emit(
|
|
13193
|
+
makeEvent("extension.error", {
|
|
13194
|
+
kind: "virtual-node-missing-path",
|
|
13195
|
+
extensionId: qualifiedId2,
|
|
13196
|
+
message: `Extractor ${qualifiedId2} emitted a virtual node with no path; dropped.`
|
|
13197
|
+
})
|
|
13198
|
+
);
|
|
13199
|
+
return null;
|
|
13200
|
+
}
|
|
13201
|
+
if (typeof emitted.kind !== "string" || emitted.kind.length === 0) {
|
|
13202
|
+
emitter.emit(
|
|
13203
|
+
makeEvent("extension.error", {
|
|
13204
|
+
kind: "virtual-node-missing-kind",
|
|
13205
|
+
extensionId: qualifiedId2,
|
|
13206
|
+
virtualPath: emitted.path,
|
|
13207
|
+
message: `Extractor ${qualifiedId2} emitted a virtual node at '${emitted.path}' with no kind; dropped.`
|
|
13208
|
+
})
|
|
13209
|
+
);
|
|
13210
|
+
return null;
|
|
13211
|
+
}
|
|
13212
|
+
if (!Array.isArray(emitted.derivedFrom) || emitted.derivedFrom.length === 0) {
|
|
13213
|
+
emitter.emit(
|
|
13214
|
+
makeEvent("extension.error", {
|
|
13215
|
+
kind: "virtual-node-missing-derived-from",
|
|
13216
|
+
extensionId: qualifiedId2,
|
|
13217
|
+
virtualPath: emitted.path,
|
|
13218
|
+
message: `Extractor ${qualifiedId2} emitted a virtual node at '${emitted.path}' with empty derivedFrom; dropped.`
|
|
13219
|
+
})
|
|
13220
|
+
);
|
|
13221
|
+
return null;
|
|
13222
|
+
}
|
|
13223
|
+
const node = {
|
|
13224
|
+
path: emitted.path,
|
|
13225
|
+
kind: emitted.kind,
|
|
13226
|
+
provider: emitted.provider,
|
|
13227
|
+
bodyHash: VIRTUAL_NODE_PLACEHOLDER_HASH,
|
|
13228
|
+
frontmatterHash: VIRTUAL_NODE_PLACEHOLDER_HASH,
|
|
13229
|
+
bytes: { frontmatter: 0, body: 0, total: 0 },
|
|
13230
|
+
linksOutCount: 0,
|
|
13231
|
+
linksInCount: 0,
|
|
13232
|
+
externalRefsCount: 0,
|
|
13233
|
+
virtual: true,
|
|
13234
|
+
derivedFrom: [...emitted.derivedFrom]
|
|
13235
|
+
};
|
|
13236
|
+
if (emitted.frontmatter) node.frontmatter = emitted.frontmatter;
|
|
13237
|
+
return node;
|
|
13238
|
+
}
|
|
12881
13239
|
function validateLink(extractor, link2, emitter) {
|
|
12882
13240
|
const knownKinds = ["invokes", "references", "mentions", "supersedes"];
|
|
12883
13241
|
if (!knownKinds.includes(link2.kind)) {
|
|
@@ -12898,9 +13256,68 @@ function validateLink(extractor, link2, emitter) {
|
|
|
12898
13256
|
);
|
|
12899
13257
|
return null;
|
|
12900
13258
|
}
|
|
12901
|
-
const
|
|
13259
|
+
const c = link2.confidence;
|
|
13260
|
+
if (c !== void 0 && (typeof c !== "number" || !Number.isFinite(c) || c < 0 || c > 1)) {
|
|
13261
|
+
const qualifiedId2 = `${extractor.pluginId}/${extractor.id}`;
|
|
13262
|
+
emitter.emit(
|
|
13263
|
+
makeEvent("extension.error", {
|
|
13264
|
+
kind: "link-confidence-out-of-range",
|
|
13265
|
+
extensionId: qualifiedId2,
|
|
13266
|
+
confidence: c,
|
|
13267
|
+
message: `Extractor ${qualifiedId2} emitted a Link with confidence ${String(c)} outside [0..1]; dropped.`
|
|
13268
|
+
})
|
|
13269
|
+
);
|
|
13270
|
+
return null;
|
|
13271
|
+
}
|
|
13272
|
+
const confidence = c ?? ConfidenceTier.MEDIUM;
|
|
12902
13273
|
return { ...link2, confidence };
|
|
12903
13274
|
}
|
|
13275
|
+
var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes"];
|
|
13276
|
+
function validateSignal(extractor, signal, emitter) {
|
|
13277
|
+
const qualifiedId2 = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
13278
|
+
if (!Array.isArray(signal.candidates) || signal.candidates.length === 0) {
|
|
13279
|
+
emitter.emit(
|
|
13280
|
+
makeEvent("extension.error", {
|
|
13281
|
+
kind: "signal-no-candidates",
|
|
13282
|
+
extensionId: qualifiedId2,
|
|
13283
|
+
signal: { source: signal.source, scope: signal.scope },
|
|
13284
|
+
message: `Extractor ${qualifiedId2} emitted a Signal with no candidates; dropped.`
|
|
13285
|
+
})
|
|
13286
|
+
);
|
|
13287
|
+
return null;
|
|
13288
|
+
}
|
|
13289
|
+
for (const candidate of signal.candidates) {
|
|
13290
|
+
if (!isValidSignalCandidate(qualifiedId2, candidate, emitter)) return null;
|
|
13291
|
+
}
|
|
13292
|
+
return signal;
|
|
13293
|
+
}
|
|
13294
|
+
function isValidSignalCandidate(qualifiedId2, candidate, emitter) {
|
|
13295
|
+
if (!KNOWN_LINK_KINDS.includes(candidate.kind)) {
|
|
13296
|
+
emitter.emit(
|
|
13297
|
+
makeEvent("extension.error", {
|
|
13298
|
+
kind: "signal-candidate-kind-not-declared",
|
|
13299
|
+
extensionId: qualifiedId2,
|
|
13300
|
+
candidateKind: candidate.kind,
|
|
13301
|
+
declaredKinds: KNOWN_LINK_KINDS,
|
|
13302
|
+
message: `Extractor ${qualifiedId2} emitted a Signal candidate with off-enum kind '${String(candidate.kind)}'; dropped.`
|
|
13303
|
+
})
|
|
13304
|
+
);
|
|
13305
|
+
return false;
|
|
13306
|
+
}
|
|
13307
|
+
const c = candidate.confidence;
|
|
13308
|
+
if (typeof c !== "number" || !Number.isFinite(c) || c < 0 || c > 1) {
|
|
13309
|
+
emitter.emit(
|
|
13310
|
+
makeEvent("extension.error", {
|
|
13311
|
+
kind: "signal-candidate-confidence-out-of-range",
|
|
13312
|
+
extensionId: qualifiedId2,
|
|
13313
|
+
confidence: candidate.confidence,
|
|
13314
|
+
message: `Extractor ${qualifiedId2} emitted a Signal candidate with confidence ${String(c)} outside [0..1]; dropped.`
|
|
13315
|
+
})
|
|
13316
|
+
);
|
|
13317
|
+
return false;
|
|
13318
|
+
}
|
|
13319
|
+
return true;
|
|
13320
|
+
}
|
|
12904
13321
|
function dedupeLinks(links) {
|
|
12905
13322
|
const out = /* @__PURE__ */ new Map();
|
|
12906
13323
|
for (const link2 of links) {
|
|
@@ -12947,7 +13364,9 @@ function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
|
|
|
12947
13364
|
}
|
|
12948
13365
|
}
|
|
12949
13366
|
var EXTERNAL_URL_SCHEME_RE = /^[a-z][a-z0-9+\-.]+:/i;
|
|
13367
|
+
var VIRTUAL_NODE_SCHEME_RE = /^mcp:\/\//i;
|
|
12950
13368
|
function isExternalUrlLink(link2) {
|
|
13369
|
+
if (VIRTUAL_NODE_SCHEME_RE.test(link2.target)) return false;
|
|
12951
13370
|
return EXTERNAL_URL_SCHEME_RE.test(link2.target);
|
|
12952
13371
|
}
|
|
12953
13372
|
|
|
@@ -13106,13 +13525,9 @@ function originatingNodeOf(link2, priorNodePaths) {
|
|
|
13106
13525
|
}
|
|
13107
13526
|
function computeCacheDecision(opts) {
|
|
13108
13527
|
const applicableExtractors = opts.extractors.filter((ex) => {
|
|
13109
|
-
|
|
13110
|
-
if (!
|
|
13111
|
-
return
|
|
13112
|
-
const slashIdx = qualified.indexOf("/");
|
|
13113
|
-
const kindOnly = slashIdx === -1 ? qualified : qualified.slice(slashIdx + 1);
|
|
13114
|
-
return kindOnly === opts.kind;
|
|
13115
|
-
});
|
|
13528
|
+
if (!matchesKindPrecondition(ex, opts.kind)) return false;
|
|
13529
|
+
if (!matchesProviderPrecondition(ex, opts.provider)) return false;
|
|
13530
|
+
return true;
|
|
13116
13531
|
});
|
|
13117
13532
|
const applicableQualifiedIds = new Set(
|
|
13118
13533
|
applicableExtractors.map((ex) => qualifiedExtensionId(ex.pluginId, ex.id))
|
|
@@ -13126,6 +13541,20 @@ function computeCacheDecision(opts) {
|
|
|
13126
13541
|
fullCacheHit: opts.nodeHashCacheEligible && split.missingExtractors.length === 0
|
|
13127
13542
|
};
|
|
13128
13543
|
}
|
|
13544
|
+
function matchesKindPrecondition(ex, kind) {
|
|
13545
|
+
const kinds = ex.precondition?.kind;
|
|
13546
|
+
if (!kinds || kinds.length === 0) return true;
|
|
13547
|
+
return kinds.some((qualified) => {
|
|
13548
|
+
const slashIdx = qualified.indexOf("/");
|
|
13549
|
+
const kindOnly = slashIdx === -1 ? qualified : qualified.slice(slashIdx + 1);
|
|
13550
|
+
return kindOnly === kind;
|
|
13551
|
+
});
|
|
13552
|
+
}
|
|
13553
|
+
function matchesProviderPrecondition(ex, provider) {
|
|
13554
|
+
const providers = ex.precondition?.provider;
|
|
13555
|
+
if (!providers || providers.length === 0) return true;
|
|
13556
|
+
return providers.includes(provider);
|
|
13557
|
+
}
|
|
13129
13558
|
function splitLegacy(applicableExtractors, applicableQualifiedIds, nodeHashCacheEligible) {
|
|
13130
13559
|
const cachedQualifiedIds = /* @__PURE__ */ new Set();
|
|
13131
13560
|
const missingExtractors = [];
|
|
@@ -13235,7 +13664,7 @@ function findHighConfidenceRenames(opts) {
|
|
|
13235
13664
|
if (opts.claimedNew.has(toPath)) continue;
|
|
13236
13665
|
const toNode = opts.currentByPath.get(toPath);
|
|
13237
13666
|
if (toNode.bodyHash === fromNode.bodyHash) {
|
|
13238
|
-
ops.push({ from: fromPath, to: toPath, confidence:
|
|
13667
|
+
ops.push({ from: fromPath, to: toPath, confidence: ConfidenceTier.HIGH });
|
|
13239
13668
|
opts.claimedDeleted.add(fromPath);
|
|
13240
13669
|
opts.claimedNew.add(toPath);
|
|
13241
13670
|
break;
|
|
@@ -13270,13 +13699,13 @@ function claimSingletonRenames(opts) {
|
|
|
13270
13699
|
const remaining = candidates.filter((p) => !opts.claimedDeleted.has(p));
|
|
13271
13700
|
if (remaining.length === 1) {
|
|
13272
13701
|
const fromPath = remaining[0];
|
|
13273
|
-
ops.push({ from: fromPath, to: toPath, confidence:
|
|
13702
|
+
ops.push({ from: fromPath, to: toPath, confidence: ConfidenceTier.MEDIUM });
|
|
13274
13703
|
opts.issues.push({
|
|
13275
13704
|
analyzerId: "auto-rename-medium",
|
|
13276
13705
|
severity: "warn",
|
|
13277
13706
|
nodeIds: [toPath],
|
|
13278
13707
|
message: `Auto-rename (medium confidence): ${fromPath} \u2192 ${toPath}`,
|
|
13279
|
-
data: { from: fromPath, to: toPath, confidence:
|
|
13708
|
+
data: { from: fromPath, to: toPath, confidence: ConfidenceTier.MEDIUM }
|
|
13280
13709
|
});
|
|
13281
13710
|
opts.claimedDeleted.add(fromPath);
|
|
13282
13711
|
opts.claimedNew.add(toPath);
|
|
@@ -13714,6 +14143,7 @@ async function processRawNode(raw, provider, wctx, accum, claimedPaths, nextInde
|
|
|
13714
14143
|
const cacheDecision = computeCacheDecision({
|
|
13715
14144
|
extractors: wctx.opts.extractors,
|
|
13716
14145
|
kind,
|
|
14146
|
+
provider: provider.id,
|
|
13717
14147
|
nodePath: raw.path,
|
|
13718
14148
|
bodyHash,
|
|
13719
14149
|
sidecarAnnotationsHash,
|
|
@@ -13816,6 +14246,10 @@ function mergeExtractResult(extractResult, accum) {
|
|
|
13816
14246
|
accum.enrichmentBuffer.set(`${enr.nodePath}\0${enr.extractorId}`, enr);
|
|
13817
14247
|
}
|
|
13818
14248
|
for (const c of extractResult.contributions) accum.contributionsBuffer.push(c);
|
|
14249
|
+
for (const vn of extractResult.virtualNodes) {
|
|
14250
|
+
if (accum.nodes.some((n) => n.path === vn.path)) continue;
|
|
14251
|
+
accum.nodes.push(vn);
|
|
14252
|
+
}
|
|
13819
14253
|
}
|
|
13820
14254
|
function isPartialCacheHit(ctx) {
|
|
13821
14255
|
return ctx.nodeHashCacheEligible && ctx.cacheDecision.cachedQualifiedIds.size > 0 && ctx.priorNode !== void 0;
|
|
@@ -19389,7 +19823,7 @@ function renderDeltaIssues(issues) {
|
|
|
19389
19823
|
|
|
19390
19824
|
// cli/commands/serve.ts
|
|
19391
19825
|
import { spawn as spawn2 } from "child_process";
|
|
19392
|
-
import { existsSync as
|
|
19826
|
+
import { existsSync as existsSync30 } from "fs";
|
|
19393
19827
|
import { Command as Command33, Option as Option31 } from "clipanion";
|
|
19394
19828
|
|
|
19395
19829
|
// cli/util/browser-launch.ts
|
|
@@ -19411,7 +19845,7 @@ import { WebSocketServer } from "ws";
|
|
|
19411
19845
|
// server/app.ts
|
|
19412
19846
|
import { Hono } from "hono";
|
|
19413
19847
|
import { bodyLimit } from "hono/body-limit";
|
|
19414
|
-
import { HTTPException as
|
|
19848
|
+
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
19415
19849
|
|
|
19416
19850
|
// core/config/service.ts
|
|
19417
19851
|
var ConfigService = class {
|
|
@@ -19719,7 +20153,20 @@ var SERVER_TEXTS = {
|
|
|
19719
20153
|
// is a synthetic `emitter.error` event; v14.4.a does not yet route
|
|
19720
20154
|
// it through the broadcaster (would re-enter the same stringify
|
|
19721
20155
|
// path), so we degrade to a logged warning.
|
|
19722
|
-
wsBroadcastSerializeFailed: "skill-map server: ws broadcast dropped, failed to serialize event: {{message}}.\n"
|
|
20156
|
+
wsBroadcastSerializeFailed: "skill-map server: ws broadcast dropped, failed to serialize event: {{message}}.\n",
|
|
20157
|
+
// ---- active-provider route (routes/active-provider.ts) -----------
|
|
20158
|
+
//
|
|
20159
|
+
// GET / PUT /api/active-provider. The active provider lens selects
|
|
20160
|
+
// which provider's extractors / classifiers / resolution rules apply
|
|
20161
|
+
// to the whole project (see `architecture.md` §Active Provider Lens).
|
|
20162
|
+
// Changing the lens drops the `scan_*` zone atomically and prompts
|
|
20163
|
+
// the user to re-scan; `state_*` and `config_*` survive.
|
|
20164
|
+
activeProviderBodyNotJson: "Request body must be valid JSON.",
|
|
20165
|
+
activeProviderBodyNotObject: "Request body must be a JSON object.",
|
|
20166
|
+
activeProviderBodyMissing: "Request body must include `activeProvider` (a non-empty string).",
|
|
20167
|
+
activeProviderValueNotString: "`activeProvider` must be a string.",
|
|
20168
|
+
activeProviderValueEmpty: "`activeProvider` cannot be the empty string. Send the id of an enabled provider.",
|
|
20169
|
+
activeProviderPersistFailed: "Could not persist activeProvider: {{message}}"
|
|
19723
20170
|
};
|
|
19724
20171
|
|
|
19725
20172
|
// server/loopback-gate.ts
|
|
@@ -20606,11 +21053,6 @@ function registerPluginsRoute(app, deps) {
|
|
|
20606
21053
|
message: tx(SERVER_TEXTS.pluginsUnknown, { id: bundleId })
|
|
20607
21054
|
});
|
|
20608
21055
|
}
|
|
20609
|
-
if (granularityOf(handle) !== "extension") {
|
|
20610
|
-
throw new HTTPException8(400, {
|
|
20611
|
-
message: tx(SERVER_TEXTS.pluginsGranularityBundleExpected, { id: bundleId })
|
|
20612
|
-
});
|
|
20613
|
-
}
|
|
20614
21056
|
if (!hasExtension(handle, extensionId)) {
|
|
20615
21057
|
throw new HTTPException8(404, {
|
|
20616
21058
|
message: tx(SERVER_TEXTS.pluginsExtensionUnknown, { bundleId, extensionId })
|
|
@@ -20651,7 +21093,7 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
20651
21093
|
return builtInBundles.map((bundle) => {
|
|
20652
21094
|
const bundleEnabled = resolveEnabled(bundle.id);
|
|
20653
21095
|
const bundleLocked = isPluginLocked(bundle.id);
|
|
20654
|
-
const extensions = bundle.
|
|
21096
|
+
const extensions = bundle.extensions.map((ext) => {
|
|
20655
21097
|
const qualified = qualifiedExtensionId(bundle.id, ext.id);
|
|
20656
21098
|
const extLocked = bundleLocked || isPluginLocked(qualified);
|
|
20657
21099
|
return {
|
|
@@ -20662,7 +21104,7 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
20662
21104
|
...ext.description ? { description: ext.description } : {},
|
|
20663
21105
|
...extLocked ? { locked: true } : {}
|
|
20664
21106
|
};
|
|
20665
|
-
})
|
|
21107
|
+
});
|
|
20666
21108
|
return {
|
|
20667
21109
|
id: bundle.id,
|
|
20668
21110
|
version: firstVersion(bundle.extensions),
|
|
@@ -20672,7 +21114,7 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
20672
21114
|
source: "built-in",
|
|
20673
21115
|
granularity: bundle.granularity,
|
|
20674
21116
|
description: bundle.description,
|
|
20675
|
-
...extensions ? { extensions } : {},
|
|
21117
|
+
...extensions.length > 0 ? { extensions } : {},
|
|
20676
21118
|
...bundleLocked ? { locked: true } : {}
|
|
20677
21119
|
};
|
|
20678
21120
|
});
|
|
@@ -20705,8 +21147,8 @@ function optionalDiscoveredFields(plugin, extensions) {
|
|
|
20705
21147
|
if (extensions) out.extensions = extensions;
|
|
20706
21148
|
return out;
|
|
20707
21149
|
}
|
|
20708
|
-
function projectExtensionRows(plugin,
|
|
20709
|
-
if (
|
|
21150
|
+
function projectExtensionRows(plugin, _granularity, resolveEnabled, bundleLocked) {
|
|
21151
|
+
if (!plugin.extensions || plugin.extensions.length === 0) return void 0;
|
|
20710
21152
|
return plugin.extensions.map((ext) => {
|
|
20711
21153
|
const description = readInstanceDescription(ext.instance);
|
|
20712
21154
|
const qualified = qualifiedExtensionId(plugin.id, ext.id);
|
|
@@ -20823,13 +21265,6 @@ function validateBulkChange(change, deps) {
|
|
|
20823
21265
|
message: tx(SERVER_TEXTS.pluginsUnknown, { id: bundleId })
|
|
20824
21266
|
};
|
|
20825
21267
|
}
|
|
20826
|
-
if (granularityOf(handle) !== "extension") {
|
|
20827
|
-
return {
|
|
20828
|
-
status: 400,
|
|
20829
|
-
code: "bad-query",
|
|
20830
|
-
message: tx(SERVER_TEXTS.pluginsGranularityBundleExpected, { id: bundleId })
|
|
20831
|
-
};
|
|
20832
|
-
}
|
|
20833
21268
|
if (!hasExtension(handle, extensionId)) {
|
|
20834
21269
|
return {
|
|
20835
21270
|
status: 404,
|
|
@@ -21309,9 +21744,106 @@ var parsePatchBody4 = makeBodyValidator(PATCH_BODY_SCHEMA3, {
|
|
|
21309
21744
|
}
|
|
21310
21745
|
});
|
|
21311
21746
|
|
|
21312
|
-
// server/routes/
|
|
21747
|
+
// server/routes/active-provider.ts
|
|
21748
|
+
import { existsSync as existsSync27 } from "fs";
|
|
21313
21749
|
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
21314
21750
|
|
|
21751
|
+
// core/config/active-provider.ts
|
|
21752
|
+
import { existsSync as existsSync26 } from "fs";
|
|
21753
|
+
import { join as join17 } from "path";
|
|
21754
|
+
var DETECTION_RULES = [
|
|
21755
|
+
{ providerId: "claude", marker: ".claude" },
|
|
21756
|
+
{ providerId: "gemini", marker: ".gemini" },
|
|
21757
|
+
{ providerId: "openai", marker: ".codex" },
|
|
21758
|
+
{ providerId: "openai", marker: "AGENTS.md" },
|
|
21759
|
+
{ providerId: "cursor", marker: ".cursor" }
|
|
21760
|
+
];
|
|
21761
|
+
function resolveActiveProvider(cwd) {
|
|
21762
|
+
const detected = detectProvidersFromFilesystem(cwd);
|
|
21763
|
+
const fromConfig = readConfigValue("activeProvider", { cwd });
|
|
21764
|
+
if (typeof fromConfig === "string" && fromConfig.length > 0) {
|
|
21765
|
+
return { resolved: fromConfig, source: "config", detected };
|
|
21766
|
+
}
|
|
21767
|
+
if (detected.length > 0) {
|
|
21768
|
+
return { resolved: detected[0], source: "autodetect", detected };
|
|
21769
|
+
}
|
|
21770
|
+
return { resolved: null, source: "none", detected };
|
|
21771
|
+
}
|
|
21772
|
+
function detectProvidersFromFilesystem(cwd) {
|
|
21773
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21774
|
+
const out = [];
|
|
21775
|
+
for (const rule of DETECTION_RULES) {
|
|
21776
|
+
if (seen.has(rule.providerId)) continue;
|
|
21777
|
+
if (!existsSync26(join17(cwd, rule.marker))) continue;
|
|
21778
|
+
seen.add(rule.providerId);
|
|
21779
|
+
out.push(rule.providerId);
|
|
21780
|
+
}
|
|
21781
|
+
return out;
|
|
21782
|
+
}
|
|
21783
|
+
|
|
21784
|
+
// server/routes/active-provider.ts
|
|
21785
|
+
function registerActiveProviderRoute(app, deps) {
|
|
21786
|
+
app.get("/api/active-provider", (c) => {
|
|
21787
|
+
return c.json(buildEnvelope4(deps));
|
|
21788
|
+
});
|
|
21789
|
+
app.patch("/api/active-provider", async (c) => {
|
|
21790
|
+
const body = await parsePatchBody5(c.req.raw);
|
|
21791
|
+
const result = applyLensSwitch(deps, body.activeProvider);
|
|
21792
|
+
deps.configService.reload();
|
|
21793
|
+
return c.json({ ...buildEnvelope4(deps), switch: result });
|
|
21794
|
+
});
|
|
21795
|
+
}
|
|
21796
|
+
function buildEnvelope4(deps) {
|
|
21797
|
+
const r = resolveActiveProvider(deps.runtimeContext.cwd);
|
|
21798
|
+
return {
|
|
21799
|
+
activeProvider: r.resolved,
|
|
21800
|
+
detected: r.detected,
|
|
21801
|
+
source: r.source
|
|
21802
|
+
};
|
|
21803
|
+
}
|
|
21804
|
+
function applyLensSwitch(deps, newValue) {
|
|
21805
|
+
const cwd = deps.runtimeContext.cwd;
|
|
21806
|
+
try {
|
|
21807
|
+
writeConfigValue("activeProvider", newValue, { target: "project", cwd });
|
|
21808
|
+
} catch (err) {
|
|
21809
|
+
throw new HTTPException12(400, {
|
|
21810
|
+
message: tx(SERVER_TEXTS.activeProviderPersistFailed, {
|
|
21811
|
+
message: formatErrorMessage(err)
|
|
21812
|
+
})
|
|
21813
|
+
});
|
|
21814
|
+
}
|
|
21815
|
+
const dbPath = resolveDbPath({ db: void 0, cwd });
|
|
21816
|
+
if (!existsSync27(dbPath)) return { dropped: null };
|
|
21817
|
+
const dropResult = dropScanZone(dbPath);
|
|
21818
|
+
return {
|
|
21819
|
+
dropped: {
|
|
21820
|
+
tableCount: dropResult.tableCount,
|
|
21821
|
+
tableNames: dropResult.droppedTables
|
|
21822
|
+
}
|
|
21823
|
+
};
|
|
21824
|
+
}
|
|
21825
|
+
var PATCH_BODY_SCHEMA4 = {
|
|
21826
|
+
type: "object",
|
|
21827
|
+
additionalProperties: false,
|
|
21828
|
+
required: ["activeProvider"],
|
|
21829
|
+
properties: {
|
|
21830
|
+
activeProvider: { type: "string", minLength: 1 }
|
|
21831
|
+
}
|
|
21832
|
+
};
|
|
21833
|
+
var parsePatchBody5 = makeBodyValidator(PATCH_BODY_SCHEMA4, {
|
|
21834
|
+
notJson: SERVER_TEXTS.activeProviderBodyNotJson,
|
|
21835
|
+
notObject: SERVER_TEXTS.activeProviderBodyNotObject,
|
|
21836
|
+
invalid: SERVER_TEXTS.activeProviderBodyMissing,
|
|
21837
|
+
mapping: {
|
|
21838
|
+
":required": SERVER_TEXTS.activeProviderBodyMissing,
|
|
21839
|
+
"/activeProvider:type:string": SERVER_TEXTS.activeProviderValueNotString,
|
|
21840
|
+
"/activeProvider:minLength": SERVER_TEXTS.activeProviderValueEmpty
|
|
21841
|
+
}
|
|
21842
|
+
});
|
|
21843
|
+
|
|
21844
|
+
// server/routes/scan.ts
|
|
21845
|
+
import { HTTPException as HTTPException13 } from "hono/http-exception";
|
|
21846
|
+
|
|
21315
21847
|
// server/scan-mutex.ts
|
|
21316
21848
|
var inFlight = null;
|
|
21317
21849
|
async function withScanMutex(fn) {
|
|
@@ -21465,7 +21997,7 @@ function registerScanRoute(app, deps) {
|
|
|
21465
21997
|
}
|
|
21466
21998
|
async function runPersistedScan(c, deps) {
|
|
21467
21999
|
if (deps.options.noBuiltIns || deps.options.noPlugins) {
|
|
21468
|
-
throw new
|
|
22000
|
+
throw new HTTPException13(400, { message: SERVER_TEXTS.scanPostRequiresFullPipeline });
|
|
21469
22001
|
}
|
|
21470
22002
|
const dbExists = await tryWithSqlite(
|
|
21471
22003
|
{ databasePath: deps.options.dbPath, autoBackup: false },
|
|
@@ -21494,7 +22026,7 @@ async function runPersistedScan(c, deps) {
|
|
|
21494
22026
|
emitterFactory: () => buildBroadcasterEmitter(deps.broadcaster)
|
|
21495
22027
|
});
|
|
21496
22028
|
if (outcome.kind !== "ok") {
|
|
21497
|
-
throw new
|
|
22029
|
+
throw new HTTPException13(500, {
|
|
21498
22030
|
message: outcome.kind === "guard-trip" ? tx(SERVER_TEXTS.scanGuardTrip, { existing: outcome.existing }) : outcome.message
|
|
21499
22031
|
});
|
|
21500
22032
|
}
|
|
@@ -21502,7 +22034,7 @@ async function runPersistedScan(c, deps) {
|
|
|
21502
22034
|
});
|
|
21503
22035
|
} catch (err) {
|
|
21504
22036
|
if (err instanceof ScanBusyError) {
|
|
21505
|
-
throw new
|
|
22037
|
+
throw new HTTPException13(409, { message: SERVER_TEXTS.scanPostBusy });
|
|
21506
22038
|
}
|
|
21507
22039
|
throw err;
|
|
21508
22040
|
}
|
|
@@ -21566,7 +22098,7 @@ function groupTagsBySource2(rows) {
|
|
|
21566
22098
|
}
|
|
21567
22099
|
async function runFreshScan(deps) {
|
|
21568
22100
|
if (deps.options.noBuiltIns || deps.options.noPlugins) {
|
|
21569
|
-
throw new
|
|
22101
|
+
throw new HTTPException13(400, { message: SERVER_TEXTS.freshScanRequiresPipeline });
|
|
21570
22102
|
}
|
|
21571
22103
|
const resolveEnabledOverride = await buildBffResolverOverride(deps);
|
|
21572
22104
|
const outcome = await runScanForCommand({
|
|
@@ -21595,7 +22127,7 @@ async function runFreshScan(deps) {
|
|
|
21595
22127
|
printer: bffScanRunnerPrinter
|
|
21596
22128
|
});
|
|
21597
22129
|
if (outcome.kind !== "ok") {
|
|
21598
|
-
throw new
|
|
22130
|
+
throw new HTTPException13(500, {
|
|
21599
22131
|
message: outcome.kind === "guard-trip" ? tx(SERVER_TEXTS.freshScanGuardTrip, { existing: outcome.existing }) : outcome.message
|
|
21600
22132
|
});
|
|
21601
22133
|
}
|
|
@@ -21629,7 +22161,7 @@ function emptyScanResult() {
|
|
|
21629
22161
|
}
|
|
21630
22162
|
|
|
21631
22163
|
// server/routes/sidecar.ts
|
|
21632
|
-
import { HTTPException as
|
|
22164
|
+
import { HTTPException as HTTPException14 } from "hono/http-exception";
|
|
21633
22165
|
import { resolve as resolve34 } from "path";
|
|
21634
22166
|
var STATUS_FRESH = "fresh";
|
|
21635
22167
|
var ENVELOPE_KIND2 = "sidecar.bumped";
|
|
@@ -21666,11 +22198,11 @@ function registerSidecarRoutes(app, deps) {
|
|
|
21666
22198
|
assertContained(deps.runtimeContext.cwd, node.path);
|
|
21667
22199
|
absPath = resolve34(deps.runtimeContext.cwd, node.path);
|
|
21668
22200
|
} catch (err) {
|
|
21669
|
-
throw new
|
|
22201
|
+
throw new HTTPException14(500, { message: formatErrorMessage(err) });
|
|
21670
22202
|
}
|
|
21671
22203
|
const result = invokeBump2(node, absPath, body);
|
|
21672
22204
|
if (result.report.ok === false && result.report.reason === "fresh") {
|
|
21673
|
-
throw new
|
|
22205
|
+
throw new HTTPException14(409, { message: SERVER_TEXTS.sidecarFreshRefusal });
|
|
21674
22206
|
}
|
|
21675
22207
|
if (result.report.ok === true && result.report.noop === true) {
|
|
21676
22208
|
const envelope2 = {
|
|
@@ -21697,7 +22229,7 @@ function registerSidecarRoutes(app, deps) {
|
|
|
21697
22229
|
}
|
|
21698
22230
|
} catch (err) {
|
|
21699
22231
|
if (err instanceof EConsentRequiredError) throw err;
|
|
21700
|
-
throw new
|
|
22232
|
+
throw new HTTPException14(500, { message: formatErrorMessage(err) });
|
|
21701
22233
|
}
|
|
21702
22234
|
if (body.confirm === true) {
|
|
21703
22235
|
deps.configService.reload();
|
|
@@ -21734,7 +22266,7 @@ async function loadNode(deps, nodePath) {
|
|
|
21734
22266
|
);
|
|
21735
22267
|
const node = persisted?.nodes.find((n) => n.path === nodePath);
|
|
21736
22268
|
if (!node) {
|
|
21737
|
-
throw new
|
|
22269
|
+
throw new HTTPException14(404, {
|
|
21738
22270
|
message: tx(SERVER_TEXTS.nodeNotFound, { path: sanitizeForTerminal(nodePath) })
|
|
21739
22271
|
});
|
|
21740
22272
|
}
|
|
@@ -21742,7 +22274,7 @@ async function loadNode(deps, nodePath) {
|
|
|
21742
22274
|
}
|
|
21743
22275
|
function invokeBump2(node, absPath, body) {
|
|
21744
22276
|
if (!bumpAction.invoke) {
|
|
21745
|
-
throw new
|
|
22277
|
+
throw new HTTPException14(500, { message: SERVER_TEXTS.sidecarBumpInvokeMissing });
|
|
21746
22278
|
}
|
|
21747
22279
|
const input = {};
|
|
21748
22280
|
if (body.force === true) input.force = true;
|
|
@@ -21788,9 +22320,9 @@ function registerUpdateStatusRoute(app, deps) {
|
|
|
21788
22320
|
}
|
|
21789
22321
|
|
|
21790
22322
|
// server/static.ts
|
|
21791
|
-
import { existsSync as
|
|
22323
|
+
import { existsSync as existsSync28 } from "fs";
|
|
21792
22324
|
import { readFile as readFile5 } from "fs/promises";
|
|
21793
|
-
import { extname, join as
|
|
22325
|
+
import { extname, join as join18 } from "path";
|
|
21794
22326
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
21795
22327
|
var INDEX_HTML = "index.html";
|
|
21796
22328
|
var PLACEHOLDER_HTML = `<!doctype html>
|
|
@@ -21842,8 +22374,8 @@ function createSpaFallback(opts) {
|
|
|
21842
22374
|
return async (c, _next) => {
|
|
21843
22375
|
if (c.req.method !== "GET" && c.req.method !== "HEAD") return c.notFound();
|
|
21844
22376
|
if (opts.uiDist === null) return htmlResponse(c, placeholder);
|
|
21845
|
-
const indexPath =
|
|
21846
|
-
if (!
|
|
22377
|
+
const indexPath = join18(opts.uiDist, INDEX_HTML);
|
|
22378
|
+
if (!existsSync28(indexPath)) return htmlResponse(c, placeholder);
|
|
21847
22379
|
return fileResponse(c, indexPath);
|
|
21848
22380
|
};
|
|
21849
22381
|
}
|
|
@@ -21929,13 +22461,13 @@ function attachBroadcasterRoute(app, broadcaster) {
|
|
|
21929
22461
|
|
|
21930
22462
|
// server/app.ts
|
|
21931
22463
|
var BODY_LIMIT_BYTES = 1024 * 1024;
|
|
21932
|
-
var DbMissingError = class extends
|
|
22464
|
+
var DbMissingError = class extends HTTPException15 {
|
|
21933
22465
|
constructor(message) {
|
|
21934
22466
|
super(500, { message });
|
|
21935
22467
|
this.name = "DbMissingError";
|
|
21936
22468
|
}
|
|
21937
22469
|
};
|
|
21938
|
-
var BulkValidationError = class extends
|
|
22470
|
+
var BulkValidationError = class extends HTTPException15 {
|
|
21939
22471
|
id;
|
|
21940
22472
|
code;
|
|
21941
22473
|
constructor(init) {
|
|
@@ -21945,7 +22477,7 @@ var BulkValidationError = class extends HTTPException14 {
|
|
|
21945
22477
|
this.code = init.code;
|
|
21946
22478
|
}
|
|
21947
22479
|
};
|
|
21948
|
-
var LoopbackGateError = class extends
|
|
22480
|
+
var LoopbackGateError = class extends HTTPException15 {
|
|
21949
22481
|
code;
|
|
21950
22482
|
constructor(init) {
|
|
21951
22483
|
super(403, { message: init.message });
|
|
@@ -21965,7 +22497,7 @@ function createApp(deps) {
|
|
|
21965
22497
|
bodyLimit({
|
|
21966
22498
|
maxSize: BODY_LIMIT_BYTES,
|
|
21967
22499
|
onError: () => {
|
|
21968
|
-
throw new
|
|
22500
|
+
throw new HTTPException15(413, { message: tx(SERVER_TEXTS.bodyTooLarge, { maxBytes: String(BODY_LIMIT_BYTES) }) });
|
|
21969
22501
|
}
|
|
21970
22502
|
})
|
|
21971
22503
|
);
|
|
@@ -22006,9 +22538,10 @@ function createApp(deps) {
|
|
|
22006
22538
|
registerUpdateStatusRoute(app, routeDeps);
|
|
22007
22539
|
registerPreferencesRoute(app, routeDeps);
|
|
22008
22540
|
registerProjectPreferencesRoute(app, routeDeps);
|
|
22541
|
+
registerActiveProviderRoute(app, routeDeps);
|
|
22009
22542
|
registerProjectIgnoreRoute(app, routeDeps);
|
|
22010
22543
|
app.all("/api/*", (c) => {
|
|
22011
|
-
throw new
|
|
22544
|
+
throw new HTTPException15(404, {
|
|
22012
22545
|
message: tx(SERVER_TEXTS.unknownApiEndpoint, { path: sanitizeForTerminal(c.req.path) })
|
|
22013
22546
|
});
|
|
22014
22547
|
});
|
|
@@ -22016,7 +22549,7 @@ function createApp(deps) {
|
|
|
22016
22549
|
app.use("*", createStaticHandler({ uiDist: deps.options.uiDist, noUi: deps.options.noUi }));
|
|
22017
22550
|
app.get("*", createSpaFallback({ uiDist: deps.options.uiDist, noUi: deps.options.noUi }));
|
|
22018
22551
|
app.notFound((c) => {
|
|
22019
|
-
throw new
|
|
22552
|
+
throw new HTTPException15(404, {
|
|
22020
22553
|
message: tx(SERVER_TEXTS.unknownPath, { path: sanitizeForTerminal(c.req.path) })
|
|
22021
22554
|
});
|
|
22022
22555
|
});
|
|
@@ -22071,7 +22604,7 @@ function formatError2(err, c) {
|
|
|
22071
22604
|
};
|
|
22072
22605
|
return c.json(envelope, 403);
|
|
22073
22606
|
}
|
|
22074
|
-
if (err instanceof
|
|
22607
|
+
if (err instanceof HTTPException15) {
|
|
22075
22608
|
const status = err.status;
|
|
22076
22609
|
const envelope = {
|
|
22077
22610
|
ok: false,
|
|
@@ -22414,10 +22947,10 @@ function validateNoUi(noUi, uiDist) {
|
|
|
22414
22947
|
}
|
|
22415
22948
|
|
|
22416
22949
|
// server/paths.ts
|
|
22417
|
-
import { existsSync as
|
|
22418
|
-
import { dirname as dirname18, isAbsolute as isAbsolute9, join as
|
|
22950
|
+
import { existsSync as existsSync29, statSync as statSync11 } from "fs";
|
|
22951
|
+
import { dirname as dirname18, isAbsolute as isAbsolute9, join as join19, resolve as resolve35 } from "path";
|
|
22419
22952
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
22420
|
-
var DEFAULT_UI_REL =
|
|
22953
|
+
var DEFAULT_UI_REL = join19("ui", "dist", "ui", "browser");
|
|
22421
22954
|
var PACKAGE_UI_REL = "ui";
|
|
22422
22955
|
var INDEX_HTML2 = "index.html";
|
|
22423
22956
|
function resolveDefaultUiDist(ctx) {
|
|
@@ -22429,10 +22962,10 @@ function resolveExplicitUiDist(ctx, raw) {
|
|
|
22429
22962
|
return isAbsolute9(raw) ? raw : resolve35(ctx.cwd, raw);
|
|
22430
22963
|
}
|
|
22431
22964
|
function isUiBundleDir(path) {
|
|
22432
|
-
if (!
|
|
22965
|
+
if (!existsSync29(path)) return false;
|
|
22433
22966
|
try {
|
|
22434
22967
|
if (!statSync11(path).isDirectory()) return false;
|
|
22435
|
-
return
|
|
22968
|
+
return existsSync29(join19(path, INDEX_HTML2));
|
|
22436
22969
|
} catch {
|
|
22437
22970
|
return false;
|
|
22438
22971
|
}
|
|
@@ -22449,9 +22982,9 @@ function resolvePackageBundledUi() {
|
|
|
22449
22982
|
function resolvePackageBundledUiFrom(here) {
|
|
22450
22983
|
let current = here;
|
|
22451
22984
|
for (let i = 0; i < 8; i++) {
|
|
22452
|
-
const candidate =
|
|
22985
|
+
const candidate = join19(current, PACKAGE_UI_REL);
|
|
22453
22986
|
if (isUiBundleDir(candidate)) return candidate;
|
|
22454
|
-
const distHere =
|
|
22987
|
+
const distHere = join19(current, "dist", PACKAGE_UI_REL);
|
|
22455
22988
|
if (isUiBundleDir(distHere)) return distHere;
|
|
22456
22989
|
const parent = dirname18(current);
|
|
22457
22990
|
if (parent === current) return null;
|
|
@@ -22462,7 +22995,7 @@ function resolvePackageBundledUiFrom(here) {
|
|
|
22462
22995
|
function walkUpForUi(startDir) {
|
|
22463
22996
|
let current = resolve35(startDir);
|
|
22464
22997
|
for (let i = 0; i < 64; i++) {
|
|
22465
|
-
const candidate =
|
|
22998
|
+
const candidate = join19(current, DEFAULT_UI_REL);
|
|
22466
22999
|
if (isUiBundleDir(candidate)) return candidate;
|
|
22467
23000
|
const parent = dirname18(current);
|
|
22468
23001
|
if (parent === current) return null;
|
|
@@ -22896,7 +23429,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
22896
23429
|
return ExitCode.Error;
|
|
22897
23430
|
}
|
|
22898
23431
|
const dbPath = resolveDbPath({ db: this.db, ...runtimeCtx });
|
|
22899
|
-
if (this.db !== void 0 && !
|
|
23432
|
+
if (this.db !== void 0 && !existsSync30(dbPath)) {
|
|
22900
23433
|
this.printer.info(
|
|
22901
23434
|
tx(SERVE_TEXTS.dbNotFound, { path: sanitizeForTerminal(dbPath) })
|
|
22902
23435
|
);
|
|
@@ -23307,22 +23840,27 @@ function renderLinksSection(direction, links, ansi) {
|
|
|
23307
23840
|
const aggregated = aggregateLinks(links, projectField);
|
|
23308
23841
|
const headerTpl = direction === "out" ? SHOW_TEXTS.linksOutSection : SHOW_TEXTS.linksInSection;
|
|
23309
23842
|
const kindWidth = Math.max(...aggregated.map((g) => g.kind.length));
|
|
23310
|
-
const
|
|
23843
|
+
const confLabels = aggregated.map((g) => formatConfidence(g.confidence));
|
|
23844
|
+
const confWidth = Math.max(...confLabels.map((l) => l.length));
|
|
23311
23845
|
const lines = [tx(headerTpl, { count: links.length })];
|
|
23312
|
-
|
|
23846
|
+
aggregated.forEach((grp, idx) => {
|
|
23313
23847
|
const dup = grp.rowCount > 1 ? ansi.dim(tx(SHOW_TEXTS.linkDup, { count: grp.rowCount })) : "";
|
|
23314
23848
|
lines.push(
|
|
23315
23849
|
tx(SHOW_TEXTS.linkRow, {
|
|
23316
23850
|
arrow: ansi.dim(arrow),
|
|
23317
23851
|
kind: sanitizeForTerminal(grp.kind).padEnd(kindWidth),
|
|
23318
|
-
confidence: ansi.dim(
|
|
23852
|
+
confidence: ansi.dim(confLabels[idx].padEnd(confWidth)),
|
|
23319
23853
|
endpoint: sanitizeForTerminal(grp.endpoint),
|
|
23320
23854
|
dup
|
|
23321
23855
|
})
|
|
23322
23856
|
);
|
|
23323
|
-
}
|
|
23857
|
+
});
|
|
23324
23858
|
return lines.join("");
|
|
23325
23859
|
}
|
|
23860
|
+
function formatConfidence(c) {
|
|
23861
|
+
if (typeof c !== "number" || !Number.isFinite(c)) return "?";
|
|
23862
|
+
return `${Math.round(c * 100)}%`;
|
|
23863
|
+
}
|
|
23326
23864
|
function renderIssuesSection(issues, nodePath, ansi) {
|
|
23327
23865
|
const lines = [tx(SHOW_TEXTS.issuesSection, { count: issues.length })];
|
|
23328
23866
|
const analyzerWidth = Math.max(
|
|
@@ -23389,17 +23927,12 @@ function aggregateLinks(links, endpointSide) {
|
|
|
23389
23927
|
return a.kind.localeCompare(b.kind);
|
|
23390
23928
|
});
|
|
23391
23929
|
}
|
|
23392
|
-
var CONFIDENCE_RANK = {
|
|
23393
|
-
high: 2,
|
|
23394
|
-
medium: 1,
|
|
23395
|
-
low: 0
|
|
23396
|
-
};
|
|
23397
23930
|
function rankConfidenceForGrouping(c) {
|
|
23398
|
-
return
|
|
23931
|
+
return c;
|
|
23399
23932
|
}
|
|
23400
23933
|
|
|
23401
23934
|
// cli/commands/sidecar.ts
|
|
23402
|
-
import { existsSync as
|
|
23935
|
+
import { existsSync as existsSync31, unlinkSync as unlinkSync2 } from "fs";
|
|
23403
23936
|
import { resolve as resolve36 } from "path";
|
|
23404
23937
|
import { Command as Command35, Option as Option33 } from "clipanion";
|
|
23405
23938
|
|
|
@@ -23840,7 +24373,7 @@ var SidecarAnnotateCommand = class extends SmCommand {
|
|
|
23840
24373
|
return ExitCode.Error;
|
|
23841
24374
|
}
|
|
23842
24375
|
const sidecarAbsPath = sidecarPathFor(absPath);
|
|
23843
|
-
if (
|
|
24376
|
+
if (existsSync31(sidecarAbsPath) && this.force !== true) {
|
|
23844
24377
|
this.printer.error(
|
|
23845
24378
|
tx(SIDECAR_TEXTS.annotateExists, {
|
|
23846
24379
|
glyph: errGlyph,
|
|
@@ -23850,7 +24383,7 @@ var SidecarAnnotateCommand = class extends SmCommand {
|
|
|
23850
24383
|
);
|
|
23851
24384
|
return ExitCode.Error;
|
|
23852
24385
|
}
|
|
23853
|
-
if (
|
|
24386
|
+
if (existsSync31(sidecarAbsPath) && this.force === true) {
|
|
23854
24387
|
try {
|
|
23855
24388
|
unlinkSync2(sidecarAbsPath);
|
|
23856
24389
|
} catch (err) {
|
|
@@ -24080,8 +24613,8 @@ var STUB_COMMANDS = [
|
|
|
24080
24613
|
];
|
|
24081
24614
|
|
|
24082
24615
|
// cli/commands/tutorial.ts
|
|
24083
|
-
import { cpSync as cpSync2, existsSync as
|
|
24084
|
-
import { dirname as dirname19, join as
|
|
24616
|
+
import { cpSync as cpSync2, existsSync as existsSync32, mkdirSync as mkdirSync7, rmSync as rmSync2, statSync as statSync12 } from "fs";
|
|
24617
|
+
import { dirname as dirname19, join as join20, resolve as resolve37 } from "path";
|
|
24085
24618
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
24086
24619
|
import { Command as Command37, Option as Option35 } from "clipanion";
|
|
24087
24620
|
|
|
@@ -24177,9 +24710,9 @@ var TutorialCommand = class extends SmCommand {
|
|
|
24177
24710
|
}
|
|
24178
24711
|
const variant = rawVariant ?? DEFAULT_VARIANT;
|
|
24179
24712
|
const spec = VARIANT_SPECS[variant];
|
|
24180
|
-
const targetDir =
|
|
24713
|
+
const targetDir = join20(ctx.cwd, ".claude", "skills", spec.slug);
|
|
24181
24714
|
const targetDisplay = `.claude/skills/${spec.slug}/`;
|
|
24182
|
-
if (
|
|
24715
|
+
if (existsSync32(targetDir) && !this.force) {
|
|
24183
24716
|
this.printer.error(
|
|
24184
24717
|
tx(TUTORIAL_TEXTS.alreadyExists, {
|
|
24185
24718
|
glyph: errGlyph,
|
|
@@ -24262,7 +24795,7 @@ function resolveSkillSourceDir(variant) {
|
|
|
24262
24795
|
resolve37(here, "../cli/tutorial", spec.slug)
|
|
24263
24796
|
];
|
|
24264
24797
|
for (const candidate of candidates) {
|
|
24265
|
-
if (
|
|
24798
|
+
if (existsSync32(candidate) && statSync12(candidate).isDirectory()) {
|
|
24266
24799
|
cachedSourceDirs.set(variant, candidate);
|
|
24267
24800
|
return candidate;
|
|
24268
24801
|
}
|
|
@@ -24439,7 +24972,7 @@ await lifecycleDispatcher.dispatch(
|
|
|
24439
24972
|
process.exit(exitCode);
|
|
24440
24973
|
function resolveBareDefault() {
|
|
24441
24974
|
const ctx = defaultRuntimeContext();
|
|
24442
|
-
if (
|
|
24975
|
+
if (existsSync33(defaultProjectDbPath(ctx))) {
|
|
24443
24976
|
return ["serve"];
|
|
24444
24977
|
}
|
|
24445
24978
|
process.stderr.write(tx(ENTRY_TEXTS.bareNoProject, { cwd: ctx.cwd }));
|