@jayjiang/byoao 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/__tests__/plugin-config.test.js +130 -0
  2. package/dist/__tests__/plugin-config.test.js.map +1 -0
  3. package/dist/cli/cli-program.js +60 -10
  4. package/dist/cli/cli-program.js.map +1 -1
  5. package/dist/cli/installer.js +39 -30
  6. package/dist/cli/installer.js.map +1 -1
  7. package/dist/cli/ui.js +23 -0
  8. package/dist/cli/ui.js.map +1 -1
  9. package/dist/hooks/__tests__/idle-suggestions.test.js +15 -0
  10. package/dist/hooks/__tests__/idle-suggestions.test.js.map +1 -0
  11. package/dist/plugin-config.js +9 -0
  12. package/dist/plugin-config.js.map +1 -1
  13. package/dist/tools/init-vault.js +38 -0
  14. package/dist/tools/init-vault.js.map +1 -1
  15. package/dist/vault/__tests__/create.test.js +125 -0
  16. package/dist/vault/__tests__/create.test.js.map +1 -0
  17. package/dist/vault/__tests__/doctor.test.js +88 -0
  18. package/dist/vault/__tests__/doctor.test.js.map +1 -0
  19. package/dist/vault/__tests__/glossary.test.js +57 -0
  20. package/dist/vault/__tests__/glossary.test.js.map +1 -0
  21. package/dist/vault/__tests__/mcp.test.js +88 -0
  22. package/dist/vault/__tests__/mcp.test.js.map +1 -0
  23. package/dist/vault/__tests__/member.test.js +87 -0
  24. package/dist/vault/__tests__/member.test.js.map +1 -0
  25. package/dist/vault/__tests__/obsidian-plugins.test.js +366 -0
  26. package/dist/vault/__tests__/obsidian-plugins.test.js.map +1 -0
  27. package/dist/vault/__tests__/status.test.js +134 -0
  28. package/dist/vault/__tests__/status.test.js.map +1 -0
  29. package/dist/vault/__tests__/template.test.js +33 -0
  30. package/dist/vault/__tests__/template.test.js.map +1 -0
  31. package/dist/vault/create.js +121 -18
  32. package/dist/vault/create.js.map +1 -1
  33. package/dist/vault/mcp.js +54 -0
  34. package/dist/vault/mcp.js.map +1 -0
  35. package/dist/vault/obsidian-plugins.js +209 -0
  36. package/dist/vault/obsidian-plugins.js.map +1 -0
  37. package/package.json +7 -2
  38. package/src/assets/presets/pm-tpm/preset.json +25 -1
@@ -1 +1 @@
1
- {"version":3,"file":"init-vault.js","sourceRoot":"","sources":["../../src/tools/init-vault.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init-vault.js","sourceRoot":"","sources":["../../src/tools/init-vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { createVault } from "../create.js";
6
+ // Mock mcp.ts so we don't touch real OpenCode config
7
+ vi.mock("../mcp.js", () => ({
8
+ configureMcp: vi.fn().mockResolvedValue(null),
9
+ }));
10
+ vi.mock("../obsidian-plugins.js", () => ({
11
+ configureObsidianPlugins: vi.fn().mockResolvedValue(null),
12
+ }));
13
+ let tmpDir;
14
+ beforeEach(async () => {
15
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "byoao-create-"));
16
+ });
17
+ afterEach(async () => {
18
+ await fs.remove(tmpDir);
19
+ });
20
+ function makeConfig(overrides = {}) {
21
+ return {
22
+ teamName: "TestTeam",
23
+ vaultPath: path.join(tmpDir, "vault"),
24
+ members: [],
25
+ projects: [],
26
+ glossaryEntries: [],
27
+ jiraHost: "",
28
+ jiraProject: "",
29
+ preset: "pm-tpm",
30
+ ...overrides,
31
+ };
32
+ }
33
+ describe("createVault", () => {
34
+ it("creates expected directory structure", async () => {
35
+ const result = await createVault(makeConfig());
36
+ expect(result.directories).toContain("Inbox");
37
+ expect(result.directories).toContain("Knowledge");
38
+ expect(result.directories).toContain("People");
39
+ expect(result.directories).toContain("Projects");
40
+ expect(result.directories).toContain("Sprints");
41
+ for (const dir of result.directories) {
42
+ expect(await fs.pathExists(path.join(result.vaultPath, dir))).toBe(true);
43
+ }
44
+ });
45
+ it("generates AGENT.md and CLAUDE.md", async () => {
46
+ const result = await createVault(makeConfig());
47
+ const vp = result.vaultPath;
48
+ expect(await fs.pathExists(path.join(vp, "AGENT.md"))).toBe(true);
49
+ expect(await fs.pathExists(path.join(vp, "CLAUDE.md"))).toBe(true);
50
+ const agentContent = await fs.readFile(path.join(vp, "AGENT.md"), "utf-8");
51
+ expect(agentContent).toContain("TestTeam");
52
+ });
53
+ it("generates Start Here.md and Glossary.md", async () => {
54
+ const result = await createVault(makeConfig());
55
+ const vp = result.vaultPath;
56
+ expect(await fs.pathExists(path.join(vp, "Start Here.md"))).toBe(true);
57
+ expect(await fs.pathExists(path.join(vp, "Knowledge/Glossary.md"))).toBe(true);
58
+ const startHere = await fs.readFile(path.join(vp, "Start Here.md"), "utf-8");
59
+ expect(startHere).toContain("TestTeam");
60
+ });
61
+ it("creates people notes from members config", async () => {
62
+ const config = makeConfig({
63
+ members: [
64
+ { name: "Alice", role: "Engineer" },
65
+ { name: "Bob", role: "PM" },
66
+ ],
67
+ });
68
+ const result = await createVault(config);
69
+ const vp = result.vaultPath;
70
+ const alice = await fs.readFile(path.join(vp, "People/Alice.md"), "utf-8");
71
+ expect(alice).toContain('type: person');
72
+ expect(alice).toContain("Engineer");
73
+ expect(await fs.pathExists(path.join(vp, "People/Bob.md"))).toBe(true);
74
+ });
75
+ it("creates project notes from projects config", async () => {
76
+ const config = makeConfig({
77
+ projects: [{ name: "Widget", description: "Build a widget" }],
78
+ });
79
+ const result = await createVault(config);
80
+ const vp = result.vaultPath;
81
+ const widget = await fs.readFile(path.join(vp, "Projects/Widget.md"), "utf-8");
82
+ expect(widget).toContain("type: feature");
83
+ expect(widget).toContain("Build a widget");
84
+ });
85
+ it("returns correct filesCreated count", async () => {
86
+ const config = makeConfig({
87
+ members: [{ name: "Alice", role: "Eng" }],
88
+ projects: [{ name: "P1", description: "desc" }],
89
+ });
90
+ const result = await createVault(config);
91
+ // At minimum: obsidian configs + templates + glossary + start here + agent + claude + 1 person + 1 project + team index
92
+ expect(result.filesCreated).toBeGreaterThanOrEqual(9);
93
+ });
94
+ it("tracks wikilinks created for members and projects", async () => {
95
+ const config = makeConfig({
96
+ members: [{ name: "Alice", role: "Eng" }],
97
+ projects: [{ name: "P1", description: "d" }],
98
+ });
99
+ const result = await createVault(config);
100
+ // members wikilinks in AGENT.md + team index, projects in AGENT.md + team index
101
+ expect(result.wikilinksCreated).toBeGreaterThanOrEqual(4);
102
+ });
103
+ it("populates wikilinks in team index", async () => {
104
+ const config = makeConfig({
105
+ members: [
106
+ { name: "Alice", role: "Eng" },
107
+ { name: "Bob", role: "PM" },
108
+ ],
109
+ });
110
+ const result = await createVault(config);
111
+ const teamIndex = await fs.readFile(path.join(result.vaultPath, "People/TestTeam Team.md"), "utf-8");
112
+ expect(teamIndex).toContain("[[Alice]]");
113
+ expect(teamIndex).toContain("[[Bob]]");
114
+ });
115
+ it("includes glossary entries when provided", async () => {
116
+ const config = makeConfig({
117
+ glossaryEntries: [{ term: "API", definition: "Application interface" }],
118
+ });
119
+ const result = await createVault(config);
120
+ const glossary = await fs.readFile(path.join(result.vaultPath, "Knowledge/Glossary.md"), "utf-8");
121
+ expect(glossary).toContain("**API**");
122
+ expect(glossary).toContain("Application interface");
123
+ });
124
+ });
125
+ //# sourceMappingURL=create.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.test.js","sourceRoot":"","sources":["../../../src/vault/__tests__/create.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { getVaultDiagnosis } from "../doctor.js";
6
+ let tmpDir;
7
+ beforeEach(async () => {
8
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "byoao-doctor-"));
9
+ });
10
+ afterEach(async () => {
11
+ await fs.remove(tmpDir);
12
+ });
13
+ function writeNote(name, content) {
14
+ return fs.writeFile(path.join(tmpDir, name), content);
15
+ }
16
+ function noteWithFrontmatter(fields, body = "") {
17
+ const yaml = Object.entries(fields)
18
+ .map(([k, v]) => {
19
+ if (Array.isArray(v))
20
+ return `${k}: [${v.join(", ")}]`;
21
+ return `${k}: ${v}`;
22
+ })
23
+ .join("\n");
24
+ return `---\n${yaml}\n---\n\n${body}`;
25
+ }
26
+ describe("getVaultDiagnosis", () => {
27
+ it("reports zero issues for a clean vault", async () => {
28
+ await writeNote("note.md", noteWithFrontmatter({ type: "reference", tags: ["test"] }, "See [[other]]\n"));
29
+ await writeNote("other.md", noteWithFrontmatter({ type: "reference", tags: ["test"] }, "Back to [[note]]\n"));
30
+ const report = await getVaultDiagnosis(tmpDir);
31
+ expect(report.issues).toHaveLength(0);
32
+ expect(report.summary.totalNotes).toBe(2);
33
+ expect(report.summary.healthyNotes).toBe(2);
34
+ });
35
+ it("reports missing frontmatter", async () => {
36
+ await writeNote("bare.md", "# No frontmatter\n\nJust text.");
37
+ const report = await getVaultDiagnosis(tmpDir);
38
+ const fmIssues = report.issues.filter((i) => i.category === "frontmatter");
39
+ expect(fmIssues.length).toBeGreaterThanOrEqual(1);
40
+ expect(fmIssues[0].message).toContain("Missing frontmatter");
41
+ });
42
+ it("reports missing type field", async () => {
43
+ await writeNote("no-type.md", noteWithFrontmatter({ tags: ["test"] }, "Content"));
44
+ const report = await getVaultDiagnosis(tmpDir);
45
+ const typeIssue = report.issues.find((i) => i.message.includes("Missing `type`"));
46
+ expect(typeIssue).toBeDefined();
47
+ expect(typeIssue.severity).toBe("warning");
48
+ });
49
+ it("reports missing tags field", async () => {
50
+ await writeNote("no-tags.md", noteWithFrontmatter({ type: "reference" }, "Content"));
51
+ const report = await getVaultDiagnosis(tmpDir);
52
+ const tagsIssue = report.issues.find((i) => i.message.includes("Missing `tags`"));
53
+ expect(tagsIssue).toBeDefined();
54
+ expect(tagsIssue.severity).toBe("info");
55
+ });
56
+ it("reports orphan notes", async () => {
57
+ await writeNote("orphan.md", noteWithFrontmatter({ type: "reference", tags: ["test"] }, "No links."));
58
+ const report = await getVaultDiagnosis(tmpDir);
59
+ const orphanIssues = report.issues.filter((i) => i.category === "orphan");
60
+ expect(orphanIssues).toHaveLength(1);
61
+ expect(orphanIssues[0].file).toBe("orphan.md");
62
+ });
63
+ it("reports broken wikilinks", async () => {
64
+ await writeNote("source.md", noteWithFrontmatter({ type: "reference", tags: ["test"] }, "Links to [[nonexistent]]"));
65
+ const report = await getVaultDiagnosis(tmpDir);
66
+ const brokenLinks = report.issues.filter((i) => i.category === "broken-link");
67
+ expect(brokenLinks).toHaveLength(1);
68
+ expect(brokenLinks[0].message).toContain("[[nonexistent]]");
69
+ });
70
+ it("reports AGENT.md drift", async () => {
71
+ await writeNote("AGENT.md", "Team: [[Alice]] and [[Bob]]");
72
+ await fs.ensureDir(path.join(tmpDir, "People"));
73
+ await writeNote("People/Alice.md", noteWithFrontmatter({ type: "person", tags: ["person"] }));
74
+ // Bob doesn't exist
75
+ const report = await getVaultDiagnosis(tmpDir);
76
+ const driftIssues = report.issues.filter((i) => i.category === "agent-drift");
77
+ expect(driftIssues).toHaveLength(1);
78
+ expect(driftIssues[0].message).toContain("[[Bob]]");
79
+ });
80
+ it("skips template files", async () => {
81
+ await fs.ensureDir(path.join(tmpDir, "Knowledge/templates"));
82
+ await fs.writeFile(path.join(tmpDir, "Knowledge/templates/Template.md"), "# No frontmatter template");
83
+ const report = await getVaultDiagnosis(tmpDir);
84
+ const templateIssues = report.issues.filter((i) => i.file?.startsWith("Knowledge/templates/"));
85
+ expect(templateIssues).toHaveLength(0);
86
+ });
87
+ });
88
+ //# sourceMappingURL=doctor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.test.js","sourceRoot":"","sources":["../../../src/vault/__tests__/doctor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,IAAI,MAAc,CAAC;AAEnB,UAAU,CAAC,KAAK,IAAI,EAAE;IACpB,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,IAAY,EAAE,OAAe;IAC9C,OAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,mBAAmB,CAAC,MAA+B,EAAE,IAAI,GAAG,EAAE;IACrE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;QACd,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACvD,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;IACtB,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,QAAQ,IAAI,YAAY,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,SAAS,CACb,SAAS,EACT,mBAAmB,CACjB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EACrC,iBAAiB,CAClB,CACF,CAAC;QACF,MAAM,SAAS,CACb,UAAU,EACV,mBAAmB,CACjB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EACrC,oBAAoB,CACrB,CACF,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,SAAS,CAAC,SAAS,EAAE,gCAAgC,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC;QAC3E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,SAAS,CACb,YAAY,EACZ,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,CACnD,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACzC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACrC,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,CAAC,SAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,SAAS,CACb,YAAY,EACZ,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,SAAS,CAAC,CACtD,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACzC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACrC,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,CAAC,SAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,SAAS,CACb,WAAW,EACX,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,CACxE,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC1E,MAAM,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,SAAS,CACb,WAAW,EACX,mBAAmB,CACjB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EACrC,0BAA0B,CAC3B,CACF,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,aAAa,CACpC,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,SAAS,CAAC,UAAU,EAAE,6BAA6B,CAAC,CAAC;QAC3D,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;QAChD,MAAM,SAAS,CACb,iBAAiB,EACjB,mBAAmB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAC1D,CAAC;QACF,oBAAoB;QAEpB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,aAAa,CACpC,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,iCAAiC,CAAC,EACpD,2BAA2B,CAC5B,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,sBAAsB,CAAC,CAClD,CAAC;QACF,MAAM,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { addGlossaryTerm } from "../glossary.js";
6
+ let tmpDir;
7
+ beforeEach(async () => {
8
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "byoao-glossary-"));
9
+ await fs.ensureDir(path.join(tmpDir, "Knowledge"));
10
+ });
11
+ afterEach(async () => {
12
+ await fs.remove(tmpDir);
13
+ });
14
+ const GLOSSARY_TEMPLATE = `---
15
+ title: "Test Glossary"
16
+ type: reference
17
+ tags: [glossary]
18
+ ---
19
+
20
+ # Test Glossary
21
+
22
+ ## Core Terms
23
+
24
+ | Term | Definition |
25
+ |------|-----------|
26
+ | **API** | Application programming interface |
27
+
28
+ ---
29
+
30
+ ## How to Add a New Term
31
+
32
+ Just add it.
33
+ `;
34
+ describe("addGlossaryTerm", () => {
35
+ it("appends term to existing Core Terms table", async () => {
36
+ await fs.writeFile(path.join(tmpDir, "Knowledge/Glossary.md"), GLOSSARY_TEMPLATE);
37
+ const result = await addGlossaryTerm({
38
+ vaultPath: tmpDir,
39
+ term: "SDK",
40
+ definition: "Software development kit",
41
+ });
42
+ expect(result.termAdded).toBe("SDK");
43
+ const content = await fs.readFile(path.join(tmpDir, "Knowledge/Glossary.md"), "utf-8");
44
+ expect(content).toContain("**SDK**");
45
+ expect(content).toContain("Software development kit");
46
+ // Original term still present
47
+ expect(content).toContain("**API**");
48
+ });
49
+ it("throws when Glossary.md does not exist", async () => {
50
+ await expect(addGlossaryTerm({
51
+ vaultPath: tmpDir,
52
+ term: "Test",
53
+ definition: "A test",
54
+ })).rejects.toThrow("Glossary not found");
55
+ });
56
+ });
57
+ //# sourceMappingURL=glossary.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glossary.test.js","sourceRoot":"","sources":["../../../src/vault/__tests__/glossary.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,IAAI,MAAc,CAAC;AAEnB,UAAU,CAAC,KAAK,IAAI,EAAE;IACpB,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACrE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;CAmBzB,CAAC;AAEF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC1C,iBAAiB,CAClB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,SAAS,EAAE,MAAM;YACjB,IAAI,EAAE,KAAK;YACX,UAAU,EAAE,0BAA0B;SACvC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC1C,OAAO,CACR,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;QACtD,8BAA8B;QAC9B,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,MAAM,CACV,eAAe,CAAC;YACd,SAAS,EAAE,MAAM;YACjB,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,QAAQ;SACrB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ let tmpDir;
6
+ let configPath;
7
+ beforeEach(async () => {
8
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "byoao-mcp-"));
9
+ configPath = path.join(tmpDir, ".config/opencode/opencode.json");
10
+ await fs.ensureDir(path.dirname(configPath));
11
+ // Mock os.homedir() to point at our temp dir
12
+ vi.spyOn(os, "homedir").mockReturnValue(tmpDir);
13
+ });
14
+ afterEach(async () => {
15
+ vi.restoreAllMocks();
16
+ // Re-import to clear module cache with mocked homedir
17
+ vi.resetModules();
18
+ await fs.remove(tmpDir);
19
+ });
20
+ async function loadConfigureMcp() {
21
+ const mod = await import("../mcp.js");
22
+ return mod.configureMcp;
23
+ }
24
+ function makePreset(mcpServers = {}) {
25
+ return {
26
+ name: "test",
27
+ displayName: "Test",
28
+ description: "test preset",
29
+ directories: [],
30
+ agentDescription: "test",
31
+ frontmatterExtras: {},
32
+ templates: [],
33
+ mcpServers,
34
+ obsidianPlugins: {},
35
+ };
36
+ }
37
+ describe("configureMcp", () => {
38
+ it("returns null when preset has no mcpServers", async () => {
39
+ const configureMcp = await loadConfigureMcp();
40
+ const result = await configureMcp(makePreset());
41
+ expect(result).toBeNull();
42
+ });
43
+ it("adds servers to empty config", async () => {
44
+ const configureMcp = await loadConfigureMcp();
45
+ const preset = makePreset({
46
+ atlassian: { type: "remote", url: "https://mcp.atlassian.com/v1/sse" },
47
+ });
48
+ const result = await configureMcp(preset);
49
+ expect(result).not.toBeNull();
50
+ expect(result.serversAdded).toContain("atlassian");
51
+ expect(result.serversSkipped).toHaveLength(0);
52
+ const written = await fs.readJson(configPath);
53
+ expect(written.mcp.atlassian.url).toBe("https://mcp.atlassian.com/v1/sse");
54
+ });
55
+ it("skips servers that already exist (idempotent)", async () => {
56
+ // Pre-populate config
57
+ await fs.writeJson(configPath, {
58
+ mcp: {
59
+ atlassian: { type: "remote", url: "https://existing.example.com" },
60
+ },
61
+ });
62
+ const configureMcp = await loadConfigureMcp();
63
+ const preset = makePreset({
64
+ atlassian: { type: "remote", url: "https://mcp.atlassian.com/v1/sse" },
65
+ });
66
+ const result = await configureMcp(preset);
67
+ expect(result.serversSkipped).toContain("atlassian");
68
+ expect(result.serversAdded).toHaveLength(0);
69
+ // Original URL preserved
70
+ const written = await fs.readJson(configPath);
71
+ expect(written.mcp.atlassian.url).toBe("https://existing.example.com");
72
+ });
73
+ it("preserves other config fields when writing", async () => {
74
+ await fs.writeJson(configPath, {
75
+ theme: "dark",
76
+ mcp: {},
77
+ });
78
+ const configureMcp = await loadConfigureMcp();
79
+ const preset = makePreset({
80
+ linear: { type: "remote", url: "https://mcp.linear.app" },
81
+ });
82
+ await configureMcp(preset);
83
+ const written = await fs.readJson(configPath);
84
+ expect(written.theme).toBe("dark");
85
+ expect(written.mcp.linear).toBeDefined();
86
+ });
87
+ });
88
+ //# sourceMappingURL=mcp.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.test.js","sourceRoot":"","sources":["../../../src/vault/__tests__/mcp.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { addMember } from "../member.js";
6
+ let tmpDir;
7
+ beforeEach(async () => {
8
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "byoao-member-"));
9
+ await fs.ensureDir(path.join(tmpDir, "People"));
10
+ });
11
+ afterEach(async () => {
12
+ await fs.remove(tmpDir);
13
+ });
14
+ describe("addMember", () => {
15
+ it("creates person note with correct frontmatter", async () => {
16
+ const result = await addMember({
17
+ vaultPath: tmpDir,
18
+ name: "Alice",
19
+ role: "Engineer",
20
+ team: "Platform",
21
+ });
22
+ expect(result.filePath).toContain("People/Alice.md");
23
+ const content = await fs.readFile(path.join(tmpDir, "People/Alice.md"), "utf-8");
24
+ expect(content).toContain("type: person");
25
+ expect(content).toContain('team: "Platform"');
26
+ expect(content).toContain('role: "Engineer"');
27
+ expect(content).toContain("status: active");
28
+ });
29
+ it("updates team index table", async () => {
30
+ // Create a team index file
31
+ const teamIndexContent = `---
32
+ title: "Platform Team"
33
+ type: reference
34
+ ---
35
+
36
+ # Platform Team
37
+
38
+ ## Members
39
+
40
+ | Name | Role |
41
+ |------|------|
42
+
43
+ ## Active Projects
44
+ `;
45
+ await fs.writeFile(path.join(tmpDir, "People/Platform Team.md"), teamIndexContent);
46
+ await addMember({
47
+ vaultPath: tmpDir,
48
+ name: "Bob",
49
+ role: "PM",
50
+ team: "Platform",
51
+ });
52
+ const updated = await fs.readFile(path.join(tmpDir, "People/Platform Team.md"), "utf-8");
53
+ expect(updated).toContain("[[Bob]]");
54
+ expect(updated).toContain("PM");
55
+ });
56
+ it("updates AGENT.md and CLAUDE.md wikilinks", async () => {
57
+ // Create AGENT.md and CLAUDE.md with placeholder
58
+ const agentContent = `# Agent
59
+
60
+ ## Team
61
+
62
+ (No members added yet — create notes in People/)
63
+ `;
64
+ await fs.writeFile(path.join(tmpDir, "AGENT.md"), agentContent);
65
+ await fs.writeFile(path.join(tmpDir, "CLAUDE.md"), agentContent);
66
+ const result = await addMember({
67
+ vaultPath: tmpDir,
68
+ name: "Carol",
69
+ role: "Designer",
70
+ team: "Platform",
71
+ });
72
+ expect(result.wikilinksAdded).toBeGreaterThanOrEqual(2);
73
+ const agent = await fs.readFile(path.join(tmpDir, "AGENT.md"), "utf-8");
74
+ expect(agent).toContain("[[Carol]]");
75
+ expect(agent).not.toContain("No members added yet");
76
+ });
77
+ it("throws when person already exists", async () => {
78
+ await fs.writeFile(path.join(tmpDir, "People/Alice.md"), "# Alice");
79
+ await expect(addMember({
80
+ vaultPath: tmpDir,
81
+ name: "Alice",
82
+ role: "Eng",
83
+ team: "T",
84
+ })).rejects.toThrow("already exists");
85
+ });
86
+ });
87
+ //# sourceMappingURL=member.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"member.test.js","sourceRoot":"","sources":["../../../src/vault/__tests__/member.test.ts"],"names":[],"mappings":"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"}