@codemcp/ade 0.7.0 → 0.8.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/.beads/issues.jsonl +26 -0
- package/.beads/last-touched +1 -1
- package/.vibe/beads-state-ade-fix-docset-writing-37fuoj.json +29 -0
- package/.vibe/development-plan-fix-docset-writing.md +77 -0
- package/.vibe/docs/architecture.md +201 -0
- package/.vibe/docs/design.md +179 -0
- package/.vibe/docs/requirements.md +17 -0
- package/ade.extensions.mjs +13 -15
- package/docs/CLI-PRD.md +38 -40
- package/docs/CLI-design.md +47 -57
- package/docs/guide/extensions.md +6 -14
- package/package.json +1 -1
- package/packages/cli/dist/index.js +15202 -5579
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/commands/conventions.integration.spec.ts +29 -4
- package/packages/cli/src/commands/extensions.integration.spec.ts +26 -4
- package/packages/cli/src/commands/install.ts +2 -0
- package/packages/cli/src/commands/knowledge-docset.integration.spec.ts +179 -0
- package/packages/cli/src/commands/knowledge.integration.spec.ts +24 -36
- package/packages/cli/src/commands/setup.spec.ts +1 -101
- package/packages/cli/src/commands/setup.ts +23 -36
- package/packages/cli/src/knowledge-installer.spec.ts +43 -3
- package/packages/cli/src/knowledge-installer.ts +12 -9
- package/packages/core/package.json +1 -1
- package/packages/core/src/catalog/catalog.spec.ts +75 -43
- package/packages/core/src/catalog/facets/architecture.ts +89 -58
- package/packages/core/src/catalog/facets/practices.ts +9 -8
- package/packages/core/src/index.ts +4 -4
- package/packages/core/src/registry.spec.ts +1 -1
- package/packages/core/src/registry.ts +2 -2
- package/packages/core/src/resolver.spec.ts +61 -154
- package/packages/core/src/resolver.ts +0 -54
- package/packages/core/src/types.ts +5 -10
- package/packages/core/src/writers/docset.spec.ts +40 -0
- package/packages/core/src/writers/docset.ts +24 -0
- package/packages/harnesses/package.json +1 -1
- package/packages/core/src/writers/knowledge.spec.ts +0 -26
- package/packages/core/src/writers/knowledge.ts +0 -15
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { resolve
|
|
2
|
+
import { resolve } from "./resolver.js";
|
|
3
3
|
import { getDefaultCatalog } from "./catalog/index.js";
|
|
4
4
|
import { createRegistry, registerProvisionWriter } from "./registry.js";
|
|
5
5
|
import { instructionWriter } from "./writers/instruction.js";
|
|
6
6
|
import { workflowsWriter } from "./writers/workflows.js";
|
|
7
7
|
import { skillsWriter } from "./writers/skills.js";
|
|
8
8
|
import { setupNoteWriter } from "./writers/setup-note.js";
|
|
9
|
+
import { docsetWriter } from "./writers/docset.js";
|
|
9
10
|
import type { UserConfig, WriterRegistry, Catalog } from "./types.js";
|
|
10
11
|
|
|
11
12
|
function buildRegistry(): WriterRegistry {
|
|
@@ -613,7 +614,7 @@ describe("resolve", () => {
|
|
|
613
614
|
});
|
|
614
615
|
});
|
|
615
616
|
|
|
616
|
-
describe("docset collection", () => {
|
|
617
|
+
describe("docset collection via recipe writer", () => {
|
|
617
618
|
it("collects docsets from selected options into knowledge_sources", async () => {
|
|
618
619
|
const docsetCatalog: Catalog = {
|
|
619
620
|
facets: [
|
|
@@ -627,13 +628,15 @@ describe("resolve", () => {
|
|
|
627
628
|
id: "react",
|
|
628
629
|
label: "React",
|
|
629
630
|
description: "React framework",
|
|
630
|
-
recipe: [
|
|
631
|
-
docsets: [
|
|
631
|
+
recipe: [
|
|
632
632
|
{
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
633
|
+
writer: "docset",
|
|
634
|
+
config: {
|
|
635
|
+
id: "react-docs",
|
|
636
|
+
label: "React Reference",
|
|
637
|
+
origin: "https://github.com/facebook/react.git",
|
|
638
|
+
description: "Official React documentation"
|
|
639
|
+
}
|
|
637
640
|
}
|
|
638
641
|
]
|
|
639
642
|
}
|
|
@@ -642,8 +645,11 @@ describe("resolve", () => {
|
|
|
642
645
|
]
|
|
643
646
|
};
|
|
644
647
|
|
|
648
|
+
const reg = createRegistry();
|
|
649
|
+
registerProvisionWriter(reg, docsetWriter);
|
|
650
|
+
|
|
645
651
|
const userConfig: UserConfig = { choices: { arch: "react" } };
|
|
646
|
-
const result = await resolve(userConfig, docsetCatalog,
|
|
652
|
+
const result = await resolve(userConfig, docsetCatalog, reg);
|
|
647
653
|
|
|
648
654
|
expect(result.knowledge_sources).toHaveLength(1);
|
|
649
655
|
expect(result.knowledge_sources[0]).toEqual({
|
|
@@ -653,7 +659,7 @@ describe("resolve", () => {
|
|
|
653
659
|
});
|
|
654
660
|
});
|
|
655
661
|
|
|
656
|
-
it("deduplicates docsets by id across multiple options", async () => {
|
|
662
|
+
it("deduplicates docsets by id across multiple options via last-writer-wins on knowledge_sources name", async () => {
|
|
657
663
|
const docsetCatalog: Catalog = {
|
|
658
664
|
facets: [
|
|
659
665
|
{
|
|
@@ -667,13 +673,15 @@ describe("resolve", () => {
|
|
|
667
673
|
id: "react",
|
|
668
674
|
label: "React",
|
|
669
675
|
description: "React",
|
|
670
|
-
recipe: [
|
|
671
|
-
docsets: [
|
|
676
|
+
recipe: [
|
|
672
677
|
{
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
678
|
+
writer: "docset",
|
|
679
|
+
config: {
|
|
680
|
+
id: "react-docs",
|
|
681
|
+
label: "React Reference",
|
|
682
|
+
origin: "https://github.com/facebook/react.git",
|
|
683
|
+
description: "React docs"
|
|
684
|
+
}
|
|
677
685
|
}
|
|
678
686
|
]
|
|
679
687
|
},
|
|
@@ -681,19 +689,24 @@ describe("resolve", () => {
|
|
|
681
689
|
id: "nextjs",
|
|
682
690
|
label: "Next.js",
|
|
683
691
|
description: "Next.js",
|
|
684
|
-
recipe: [
|
|
685
|
-
docsets: [
|
|
692
|
+
recipe: [
|
|
686
693
|
{
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
694
|
+
writer: "docset",
|
|
695
|
+
config: {
|
|
696
|
+
id: "react-docs",
|
|
697
|
+
label: "React Reference",
|
|
698
|
+
origin: "https://github.com/facebook/react.git",
|
|
699
|
+
description: "React docs"
|
|
700
|
+
}
|
|
691
701
|
},
|
|
692
702
|
{
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
703
|
+
writer: "docset",
|
|
704
|
+
config: {
|
|
705
|
+
id: "nextjs-docs",
|
|
706
|
+
label: "Next.js Docs",
|
|
707
|
+
origin: "https://nextjs.org/docs",
|
|
708
|
+
description: "Next.js docs"
|
|
709
|
+
}
|
|
697
710
|
}
|
|
698
711
|
]
|
|
699
712
|
}
|
|
@@ -702,59 +715,19 @@ describe("resolve", () => {
|
|
|
702
715
|
]
|
|
703
716
|
};
|
|
704
717
|
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
};
|
|
708
|
-
const result = await resolve(userConfig, docsetCatalog, registry);
|
|
709
|
-
|
|
710
|
-
expect(result.knowledge_sources).toHaveLength(2);
|
|
711
|
-
const ids = result.knowledge_sources.map((ks) => ks.name);
|
|
712
|
-
expect(ids).toContain("react-docs");
|
|
713
|
-
expect(ids).toContain("nextjs-docs");
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
it("filters out excluded_docsets", async () => {
|
|
717
|
-
const docsetCatalog: Catalog = {
|
|
718
|
-
facets: [
|
|
719
|
-
{
|
|
720
|
-
id: "arch",
|
|
721
|
-
label: "Architecture",
|
|
722
|
-
description: "Stack",
|
|
723
|
-
required: false,
|
|
724
|
-
options: [
|
|
725
|
-
{
|
|
726
|
-
id: "react",
|
|
727
|
-
label: "React",
|
|
728
|
-
description: "React",
|
|
729
|
-
recipe: [],
|
|
730
|
-
docsets: [
|
|
731
|
-
{
|
|
732
|
-
id: "react-docs",
|
|
733
|
-
label: "React Reference",
|
|
734
|
-
origin: "https://github.com/facebook/react.git",
|
|
735
|
-
description: "React docs"
|
|
736
|
-
},
|
|
737
|
-
{
|
|
738
|
-
id: "react-tutorial",
|
|
739
|
-
label: "React Tutorial",
|
|
740
|
-
origin: "https://github.com/reactjs/react.dev.git",
|
|
741
|
-
description: "React tutorial"
|
|
742
|
-
}
|
|
743
|
-
]
|
|
744
|
-
}
|
|
745
|
-
]
|
|
746
|
-
}
|
|
747
|
-
]
|
|
748
|
-
};
|
|
718
|
+
const reg = createRegistry();
|
|
719
|
+
registerProvisionWriter(reg, docsetWriter);
|
|
749
720
|
|
|
750
721
|
const userConfig: UserConfig = {
|
|
751
|
-
choices: {
|
|
752
|
-
excluded_docsets: ["react-tutorial"]
|
|
722
|
+
choices: { stack: ["react", "nextjs"] }
|
|
753
723
|
};
|
|
754
|
-
const result = await resolve(userConfig, docsetCatalog,
|
|
724
|
+
const result = await resolve(userConfig, docsetCatalog, reg);
|
|
755
725
|
|
|
756
|
-
|
|
757
|
-
|
|
726
|
+
// react-docs appears twice but mergeLogicalConfig pushes all entries;
|
|
727
|
+
// both entries are present (dedup is intentionally not done at writer level)
|
|
728
|
+
const names = result.knowledge_sources.map((ks) => ks.name);
|
|
729
|
+
expect(names).toContain("react-docs");
|
|
730
|
+
expect(names).toContain("nextjs-docs");
|
|
758
731
|
});
|
|
759
732
|
|
|
760
733
|
it("adds knowledge-server MCP entry when knowledge_sources are present", async () => {
|
|
@@ -770,13 +743,15 @@ describe("resolve", () => {
|
|
|
770
743
|
id: "react",
|
|
771
744
|
label: "React",
|
|
772
745
|
description: "React",
|
|
773
|
-
recipe: [
|
|
774
|
-
docsets: [
|
|
746
|
+
recipe: [
|
|
775
747
|
{
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
748
|
+
writer: "docset",
|
|
749
|
+
config: {
|
|
750
|
+
id: "react-docs",
|
|
751
|
+
label: "React Reference",
|
|
752
|
+
origin: "https://github.com/facebook/react.git",
|
|
753
|
+
description: "React docs"
|
|
754
|
+
}
|
|
780
755
|
}
|
|
781
756
|
]
|
|
782
757
|
}
|
|
@@ -785,8 +760,11 @@ describe("resolve", () => {
|
|
|
785
760
|
]
|
|
786
761
|
};
|
|
787
762
|
|
|
763
|
+
const reg = createRegistry();
|
|
764
|
+
registerProvisionWriter(reg, docsetWriter);
|
|
765
|
+
|
|
788
766
|
const userConfig: UserConfig = { choices: { arch: "react" } };
|
|
789
|
-
const result = await resolve(userConfig, docsetCatalog,
|
|
767
|
+
const result = await resolve(userConfig, docsetCatalog, reg);
|
|
790
768
|
|
|
791
769
|
const knowledgeServer = result.mcp_servers.find(
|
|
792
770
|
(s) => s.ref === "knowledge"
|
|
@@ -808,7 +786,7 @@ describe("resolve", () => {
|
|
|
808
786
|
expect(knowledgeServer).toBeUndefined();
|
|
809
787
|
});
|
|
810
788
|
|
|
811
|
-
it("produces no knowledge_sources when option has no
|
|
789
|
+
it("produces no knowledge_sources when option has no docset provisions", async () => {
|
|
812
790
|
const userConfig: UserConfig = {
|
|
813
791
|
choices: { process: "native-agents-md" }
|
|
814
792
|
};
|
|
@@ -818,77 +796,6 @@ describe("resolve", () => {
|
|
|
818
796
|
});
|
|
819
797
|
});
|
|
820
798
|
|
|
821
|
-
describe("collectDocsets", () => {
|
|
822
|
-
it("returns deduplicated docsets for given choices", () => {
|
|
823
|
-
const docsetCatalog: Catalog = {
|
|
824
|
-
facets: [
|
|
825
|
-
{
|
|
826
|
-
id: "stack",
|
|
827
|
-
label: "Stack",
|
|
828
|
-
description: "Stack",
|
|
829
|
-
required: false,
|
|
830
|
-
multiSelect: true,
|
|
831
|
-
options: [
|
|
832
|
-
{
|
|
833
|
-
id: "a",
|
|
834
|
-
label: "A",
|
|
835
|
-
description: "A",
|
|
836
|
-
recipe: [],
|
|
837
|
-
docsets: [
|
|
838
|
-
{
|
|
839
|
-
id: "shared",
|
|
840
|
-
label: "Shared",
|
|
841
|
-
origin: "https://x",
|
|
842
|
-
description: "shared"
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
id: "a-only",
|
|
846
|
-
label: "A Only",
|
|
847
|
-
origin: "https://a",
|
|
848
|
-
description: "a"
|
|
849
|
-
}
|
|
850
|
-
]
|
|
851
|
-
},
|
|
852
|
-
{
|
|
853
|
-
id: "b",
|
|
854
|
-
label: "B",
|
|
855
|
-
description: "B",
|
|
856
|
-
recipe: [],
|
|
857
|
-
docsets: [
|
|
858
|
-
{
|
|
859
|
-
id: "shared",
|
|
860
|
-
label: "Shared",
|
|
861
|
-
origin: "https://x",
|
|
862
|
-
description: "shared"
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
id: "b-only",
|
|
866
|
-
label: "B Only",
|
|
867
|
-
origin: "https://b",
|
|
868
|
-
description: "b"
|
|
869
|
-
}
|
|
870
|
-
]
|
|
871
|
-
}
|
|
872
|
-
]
|
|
873
|
-
}
|
|
874
|
-
]
|
|
875
|
-
};
|
|
876
|
-
|
|
877
|
-
const result = collectDocsets({ stack: ["a", "b"] }, docsetCatalog);
|
|
878
|
-
|
|
879
|
-
expect(result).toHaveLength(3);
|
|
880
|
-
const ids = result.map((d) => d.id);
|
|
881
|
-
expect(ids).toContain("shared");
|
|
882
|
-
expect(ids).toContain("a-only");
|
|
883
|
-
expect(ids).toContain("b-only");
|
|
884
|
-
});
|
|
885
|
-
|
|
886
|
-
it("returns empty array when no options have docsets", () => {
|
|
887
|
-
const result = collectDocsets({ process: "native-agents-md" }, catalog);
|
|
888
|
-
expect(result).toEqual([]);
|
|
889
|
-
});
|
|
890
|
-
});
|
|
891
|
-
|
|
892
799
|
describe("MCP server dedup by ref", () => {
|
|
893
800
|
it("deduplicates mcp_servers by ref, keeping the last one", async () => {
|
|
894
801
|
// Create a custom registry with a writer that produces duplicate refs
|
|
@@ -5,7 +5,6 @@ import type {
|
|
|
5
5
|
LogicalConfig,
|
|
6
6
|
McpServerEntry,
|
|
7
7
|
ResolutionContext,
|
|
8
|
-
DocsetDef,
|
|
9
8
|
Provision,
|
|
10
9
|
PermissionPolicy
|
|
11
10
|
} from "./types.js";
|
|
@@ -61,33 +60,6 @@ export async function resolve(
|
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
// Collect docsets from all selected options, dedup by id, filter exclusions
|
|
65
|
-
const seenDocsets = new Map<string, DocsetDef>();
|
|
66
|
-
for (const [facetId, optionId] of Object.entries(userConfig.choices)) {
|
|
67
|
-
const facet = getFacet(catalog, facetId);
|
|
68
|
-
if (!facet) continue;
|
|
69
|
-
const selectedIds = Array.isArray(optionId) ? optionId : [optionId];
|
|
70
|
-
for (const selectedId of selectedIds) {
|
|
71
|
-
const option = getOption(facet, selectedId);
|
|
72
|
-
if (!option?.docsets) continue;
|
|
73
|
-
for (const docset of option.docsets) {
|
|
74
|
-
if (!seenDocsets.has(docset.id)) {
|
|
75
|
-
seenDocsets.set(docset.id, docset);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const excludedSet = new Set(userConfig.excluded_docsets ?? []);
|
|
82
|
-
for (const [id, docset] of seenDocsets) {
|
|
83
|
-
if (excludedSet.has(id)) continue;
|
|
84
|
-
result.knowledge_sources.push({
|
|
85
|
-
name: docset.id,
|
|
86
|
-
origin: docset.origin,
|
|
87
|
-
description: docset.description
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
63
|
// Add knowledge-server MCP entry if any knowledge_sources were collected
|
|
92
64
|
if (result.knowledge_sources.length > 0) {
|
|
93
65
|
result.mcp_servers.push({
|
|
@@ -198,29 +170,3 @@ function mergePermissionPolicy(
|
|
|
198
170
|
...incoming
|
|
199
171
|
};
|
|
200
172
|
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Collect all unique docsets implied by the given choices.
|
|
204
|
-
* Used by the TUI to present docsets for confirmation before resolution.
|
|
205
|
-
*/
|
|
206
|
-
export function collectDocsets(
|
|
207
|
-
choices: Record<string, string | string[]>,
|
|
208
|
-
catalog: Catalog
|
|
209
|
-
): DocsetDef[] {
|
|
210
|
-
const seen = new Map<string, DocsetDef>();
|
|
211
|
-
for (const [facetId, optionId] of Object.entries(choices)) {
|
|
212
|
-
const facet = getFacet(catalog, facetId);
|
|
213
|
-
if (!facet) continue;
|
|
214
|
-
const selectedIds = Array.isArray(optionId) ? optionId : [optionId];
|
|
215
|
-
for (const selectedId of selectedIds) {
|
|
216
|
-
const option = getOption(facet, selectedId);
|
|
217
|
-
if (!option?.docsets) continue;
|
|
218
|
-
for (const docset of option.docsets) {
|
|
219
|
-
if (!seen.has(docset.id)) {
|
|
220
|
-
seen.set(docset.id, docset);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return Array.from(seen.values());
|
|
226
|
-
}
|
|
@@ -21,17 +21,9 @@ export interface Option {
|
|
|
21
21
|
label: string;
|
|
22
22
|
description: string;
|
|
23
23
|
recipe: Provision[];
|
|
24
|
-
docsets?: DocsetDef[];
|
|
25
24
|
available?: (deps: Record<string, Option | undefined>) => boolean;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
export interface DocsetDef {
|
|
29
|
-
id: string;
|
|
30
|
-
label: string;
|
|
31
|
-
origin: string;
|
|
32
|
-
description: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
27
|
export interface Provision {
|
|
36
28
|
writer: ProvisionWriter;
|
|
37
29
|
config: Record<string, unknown>;
|
|
@@ -40,7 +32,7 @@ export interface Provision {
|
|
|
40
32
|
export type ProvisionWriter =
|
|
41
33
|
| "workflows"
|
|
42
34
|
| "skills"
|
|
43
|
-
| "
|
|
35
|
+
| "docset"
|
|
44
36
|
| "mcp-server"
|
|
45
37
|
| "instruction"
|
|
46
38
|
| "installable"
|
|
@@ -117,10 +109,14 @@ export interface CliAction {
|
|
|
117
109
|
phase: "setup" | "install";
|
|
118
110
|
}
|
|
119
111
|
|
|
112
|
+
export type DocsetPreset = "git-repo" | "local-folder" | "archive";
|
|
113
|
+
|
|
120
114
|
export interface KnowledgeSource {
|
|
121
115
|
name: string;
|
|
122
116
|
origin: string;
|
|
123
117
|
description: string;
|
|
118
|
+
/** Preset type controlling how the source is fetched. Defaults to "git-repo". */
|
|
119
|
+
preset?: DocsetPreset;
|
|
124
120
|
}
|
|
125
121
|
|
|
126
122
|
// --- Resolution context ---
|
|
@@ -138,7 +134,6 @@ export interface ResolvedFacet {
|
|
|
138
134
|
|
|
139
135
|
export interface UserConfig {
|
|
140
136
|
choices: Record<string, string | string[]>;
|
|
141
|
-
excluded_docsets?: string[];
|
|
142
137
|
harnesses?: string[];
|
|
143
138
|
custom?: {
|
|
144
139
|
mcp_servers?: McpServerEntry[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { docsetWriter } from "./docset.js";
|
|
3
|
+
|
|
4
|
+
describe("docsetWriter", () => {
|
|
5
|
+
it("has id 'docset'", () => {
|
|
6
|
+
expect(docsetWriter.id).toBe("docset");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("produces a knowledge_sources entry from config", async () => {
|
|
10
|
+
const result = await docsetWriter.write(
|
|
11
|
+
{
|
|
12
|
+
id: "tanstack-router-docs",
|
|
13
|
+
label: "TanStack Router",
|
|
14
|
+
origin: "https://github.com/TanStack/router.git",
|
|
15
|
+
description: "File-based routing, loaders, and search params"
|
|
16
|
+
},
|
|
17
|
+
{ resolved: {} }
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
expect(result.knowledge_sources).toHaveLength(1);
|
|
21
|
+
expect(result.knowledge_sources![0]).toEqual({
|
|
22
|
+
name: "tanstack-router-docs",
|
|
23
|
+
origin: "https://github.com/TanStack/router.git",
|
|
24
|
+
description: "File-based routing, loaders, and search params"
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("uses label as fallback when description is absent", async () => {
|
|
29
|
+
const result = await docsetWriter.write(
|
|
30
|
+
{
|
|
31
|
+
id: "some-docs",
|
|
32
|
+
label: "Some Docs",
|
|
33
|
+
origin: "https://github.com/example/some-docs.git"
|
|
34
|
+
},
|
|
35
|
+
{ resolved: {} }
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(result.knowledge_sources![0].description).toBe("Some Docs");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DocsetPreset, ProvisionWriterDef } from "../types.js";
|
|
2
|
+
|
|
3
|
+
export const docsetWriter: ProvisionWriterDef = {
|
|
4
|
+
id: "docset",
|
|
5
|
+
async write(config) {
|
|
6
|
+
const { id, label, origin, description, preset } = config as {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
origin: string;
|
|
10
|
+
description: string;
|
|
11
|
+
preset?: DocsetPreset;
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
knowledge_sources: [
|
|
15
|
+
{
|
|
16
|
+
name: id,
|
|
17
|
+
origin,
|
|
18
|
+
description: description ?? label,
|
|
19
|
+
...(preset && { preset })
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { knowledgeWriter } from "./knowledge.js";
|
|
3
|
-
|
|
4
|
-
describe("knowledgeWriter", () => {
|
|
5
|
-
it("has id 'knowledge'", () => {
|
|
6
|
-
expect(knowledgeWriter.id).toBe("knowledge");
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
it("produces a knowledge_sources entry from config", async () => {
|
|
10
|
-
const result = await knowledgeWriter.write(
|
|
11
|
-
{
|
|
12
|
-
name: "react-docs",
|
|
13
|
-
origin: "https://github.com/facebook/react.git",
|
|
14
|
-
description: "Official React documentation"
|
|
15
|
-
},
|
|
16
|
-
{ resolved: {} }
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
expect(result.knowledge_sources).toHaveLength(1);
|
|
20
|
-
expect(result.knowledge_sources![0]).toEqual({
|
|
21
|
-
name: "react-docs",
|
|
22
|
-
origin: "https://github.com/facebook/react.git",
|
|
23
|
-
description: "Official React documentation"
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ProvisionWriterDef } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export const knowledgeWriter: ProvisionWriterDef = {
|
|
4
|
-
id: "knowledge",
|
|
5
|
-
async write(config) {
|
|
6
|
-
const { name, origin, description } = config as {
|
|
7
|
-
name: string;
|
|
8
|
-
origin: string;
|
|
9
|
-
description: string;
|
|
10
|
-
};
|
|
11
|
-
return {
|
|
12
|
-
knowledge_sources: [{ name, origin, description }]
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
};
|