@jayjiang/byoao 0.2.3 → 0.3.1

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 (48) 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 +198 -11
  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/index.js +2 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/plugin-config.js +11 -0
  14. package/dist/plugin-config.js.map +1 -1
  15. package/dist/tools/init-vault.js +56 -0
  16. package/dist/tools/init-vault.js.map +1 -1
  17. package/dist/tools/switch-provider.js +34 -0
  18. package/dist/tools/switch-provider.js.map +1 -0
  19. package/dist/vault/__tests__/create.test.js +130 -0
  20. package/dist/vault/__tests__/create.test.js.map +1 -0
  21. package/dist/vault/__tests__/doctor.test.js +88 -0
  22. package/dist/vault/__tests__/doctor.test.js.map +1 -0
  23. package/dist/vault/__tests__/glossary.test.js +57 -0
  24. package/dist/vault/__tests__/glossary.test.js.map +1 -0
  25. package/dist/vault/__tests__/mcp.test.js +88 -0
  26. package/dist/vault/__tests__/mcp.test.js.map +1 -0
  27. package/dist/vault/__tests__/member.test.js +87 -0
  28. package/dist/vault/__tests__/member.test.js.map +1 -0
  29. package/dist/vault/__tests__/obsidian-plugins.test.js +366 -0
  30. package/dist/vault/__tests__/obsidian-plugins.test.js.map +1 -0
  31. package/dist/vault/__tests__/provider.test.js +82 -0
  32. package/dist/vault/__tests__/provider.test.js.map +1 -0
  33. package/dist/vault/__tests__/status.test.js +134 -0
  34. package/dist/vault/__tests__/status.test.js.map +1 -0
  35. package/dist/vault/__tests__/template.test.js +33 -0
  36. package/dist/vault/__tests__/template.test.js.map +1 -0
  37. package/dist/vault/create.js +128 -18
  38. package/dist/vault/create.js.map +1 -1
  39. package/dist/vault/mcp.js +31 -0
  40. package/dist/vault/mcp.js.map +1 -0
  41. package/dist/vault/obsidian-plugins.js +209 -0
  42. package/dist/vault/obsidian-plugins.js.map +1 -0
  43. package/dist/vault/opencode-config.js +36 -0
  44. package/dist/vault/opencode-config.js.map +1 -0
  45. package/dist/vault/provider.js +67 -0
  46. package/dist/vault/provider.js.map +1 -0
  47. package/package.json +7 -2
  48. package/src/assets/presets/pm-tpm/preset.json +25 -1
@@ -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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"}
@@ -0,0 +1,366 @@
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
+ beforeEach(async () => {
7
+ vi.resetModules();
8
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "byoao-plugins-"));
9
+ await fs.ensureDir(path.join(tmpDir, ".obsidian"));
10
+ });
11
+ afterEach(async () => {
12
+ vi.restoreAllMocks();
13
+ vi.unstubAllEnvs();
14
+ vi.unstubAllGlobals();
15
+ await fs.remove(tmpDir);
16
+ });
17
+ function makePreset(obsidianPlugins = {}) {
18
+ return {
19
+ name: "test",
20
+ displayName: "Test",
21
+ description: "test preset",
22
+ directories: [],
23
+ agentDescription: "test",
24
+ frontmatterExtras: {},
25
+ templates: [],
26
+ mcpServers: {},
27
+ obsidianPlugins,
28
+ };
29
+ }
30
+ function mockGitHubRelease(assets) {
31
+ return { assets };
32
+ }
33
+ const FAKE_MAIN_JS = "console.log('plugin');";
34
+ const FAKE_MANIFEST = JSON.stringify({ id: "test-plugin", version: "1.0.0" });
35
+ const FAKE_BRAT_MAIN = "console.log('brat');";
36
+ const FAKE_BRAT_MANIFEST = JSON.stringify({ id: "obsidian42-brat", version: "1.0.0" });
37
+ // Helper: mock fetch for BRAT + one plugin (6 calls: BRAT release + 2 assets, plugin release + 2 assets)
38
+ function mockFetchForBratAndPlugin() {
39
+ return vi.fn()
40
+ // BRAT release metadata
41
+ .mockResolvedValueOnce({
42
+ ok: true,
43
+ json: async () => mockGitHubRelease([
44
+ { name: "main.js", browser_download_url: "https://example.com/brat/main.js" },
45
+ { name: "manifest.json", browser_download_url: "https://example.com/brat/manifest.json" },
46
+ ]),
47
+ })
48
+ // BRAT main.js
49
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_BRAT_MAIN })
50
+ // BRAT manifest.json
51
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_BRAT_MANIFEST })
52
+ // Plugin release metadata
53
+ .mockResolvedValueOnce({
54
+ ok: true,
55
+ json: async () => mockGitHubRelease([
56
+ { name: "main.js", browser_download_url: "https://example.com/plugin/main.js" },
57
+ { name: "manifest.json", browser_download_url: "https://example.com/plugin/manifest.json" },
58
+ ]),
59
+ })
60
+ // Plugin main.js
61
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MAIN_JS })
62
+ // Plugin manifest.json
63
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MANIFEST });
64
+ }
65
+ describe("configureObsidianPlugins", () => {
66
+ it("returns null when preset has no obsidianPlugins", async () => {
67
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
68
+ const result = await configureObsidianPlugins(tmpDir, makePreset());
69
+ expect(result).toBeNull();
70
+ });
71
+ it("installs BRAT automatically when plugins declared", async () => {
72
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
73
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
74
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
75
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
76
+ }));
77
+ expect(result.bratNewlyInstalled).toBe(true);
78
+ expect(await fs.pathExists(path.join(tmpDir, ".obsidian/plugins/obsidian42-brat/main.js"))).toBe(true);
79
+ expect(await fs.pathExists(path.join(tmpDir, ".obsidian/plugins/obsidian42-brat/manifest.json"))).toBe(true);
80
+ });
81
+ it("skips BRAT when already installed", async () => {
82
+ // Pre-create BRAT
83
+ const bratDir = path.join(tmpDir, ".obsidian/plugins/obsidian42-brat");
84
+ await fs.ensureDir(bratDir);
85
+ await fs.writeFile(path.join(bratDir, "main.js"), "existing-brat");
86
+ // Only need plugin fetch (3 calls: release + 2 assets)
87
+ const mockFetch = vi.fn()
88
+ .mockResolvedValueOnce({
89
+ ok: true,
90
+ json: async () => mockGitHubRelease([
91
+ { name: "main.js", browser_download_url: "https://example.com/plugin/main.js" },
92
+ { name: "manifest.json", browser_download_url: "https://example.com/plugin/manifest.json" },
93
+ ]),
94
+ })
95
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MAIN_JS })
96
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MANIFEST });
97
+ vi.stubGlobal("fetch", mockFetch);
98
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
99
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
100
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
101
+ }));
102
+ expect(result.bratNewlyInstalled).toBe(false);
103
+ // BRAT not overwritten
104
+ const bratContent = await fs.readFile(path.join(bratDir, "main.js"), "utf-8");
105
+ expect(bratContent).toBe("existing-brat");
106
+ });
107
+ it("downloads and installs plugin files", async () => {
108
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
109
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
110
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
111
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
112
+ }));
113
+ expect(result.pluginsAdded).toContain("test-plugin");
114
+ expect(await fs.pathExists(path.join(tmpDir, ".obsidian/plugins/test-plugin/main.js"))).toBe(true);
115
+ expect(await fs.pathExists(path.join(tmpDir, ".obsidian/plugins/test-plugin/manifest.json"))).toBe(true);
116
+ });
117
+ it("writes data.json when config provided", async () => {
118
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
119
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
120
+ await configureObsidianPlugins(tmpDir, makePreset({
121
+ "test-plugin": {
122
+ repo: "owner/test-plugin",
123
+ version: "latest",
124
+ config: { defaultAgent: "opencode" },
125
+ },
126
+ }));
127
+ const dataJson = await fs.readJson(path.join(tmpDir, ".obsidian/plugins/test-plugin/data.json"));
128
+ expect(dataJson.defaultAgent).toBe("opencode");
129
+ });
130
+ it("does not write data.json when config undefined", async () => {
131
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
132
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
133
+ await configureObsidianPlugins(tmpDir, makePreset({
134
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
135
+ }));
136
+ expect(await fs.pathExists(path.join(tmpDir, ".obsidian/plugins/test-plugin/data.json"))).toBe(false);
137
+ });
138
+ it("updates community-plugins.json with BRAT and plugin", async () => {
139
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
140
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
141
+ await configureObsidianPlugins(tmpDir, makePreset({
142
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
143
+ }));
144
+ const plugins = await fs.readJson(path.join(tmpDir, ".obsidian/community-plugins.json"));
145
+ expect(plugins).toContain("obsidian42-brat");
146
+ expect(plugins).toContain("test-plugin");
147
+ });
148
+ it("registers plugin in BRAT data.json pluginList", async () => {
149
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
150
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
151
+ await configureObsidianPlugins(tmpDir, makePreset({
152
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
153
+ }));
154
+ const bratData = await fs.readJson(path.join(tmpDir, ".obsidian/plugins/obsidian42-brat/data.json"));
155
+ expect(bratData.pluginList).toContain("owner/test-plugin");
156
+ });
157
+ it("preserves existing BRAT pluginList entries", async () => {
158
+ const bratDir = path.join(tmpDir, ".obsidian/plugins/obsidian42-brat");
159
+ await fs.ensureDir(bratDir);
160
+ await fs.writeFile(path.join(bratDir, "main.js"), "brat");
161
+ await fs.writeJson(path.join(bratDir, "data.json"), {
162
+ pluginList: ["other/existing-plugin"],
163
+ updateAtStartup: true,
164
+ });
165
+ const mockFetch = vi.fn()
166
+ .mockResolvedValueOnce({
167
+ ok: true,
168
+ json: async () => mockGitHubRelease([
169
+ { name: "main.js", browser_download_url: "https://example.com/main.js" },
170
+ { name: "manifest.json", browser_download_url: "https://example.com/manifest.json" },
171
+ ]),
172
+ })
173
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MAIN_JS })
174
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MANIFEST });
175
+ vi.stubGlobal("fetch", mockFetch);
176
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
177
+ await configureObsidianPlugins(tmpDir, makePreset({
178
+ "new-plugin": { repo: "owner/new-plugin", version: "latest" },
179
+ }));
180
+ const bratData = await fs.readJson(path.join(bratDir, "data.json"));
181
+ expect(bratData.pluginList).toContain("other/existing-plugin");
182
+ expect(bratData.pluginList).toContain("owner/new-plugin");
183
+ expect(bratData.updateAtStartup).toBe(true);
184
+ });
185
+ it("deduplicates BRAT pluginList", async () => {
186
+ const bratDir = path.join(tmpDir, ".obsidian/plugins/obsidian42-brat");
187
+ await fs.ensureDir(bratDir);
188
+ await fs.writeFile(path.join(bratDir, "main.js"), "brat");
189
+ await fs.writeJson(path.join(bratDir, "data.json"), {
190
+ pluginList: ["owner/test-plugin"],
191
+ });
192
+ const mockFetch = vi.fn()
193
+ .mockResolvedValueOnce({
194
+ ok: true,
195
+ json: async () => mockGitHubRelease([
196
+ { name: "main.js", browser_download_url: "https://example.com/main.js" },
197
+ { name: "manifest.json", browser_download_url: "https://example.com/manifest.json" },
198
+ ]),
199
+ })
200
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MAIN_JS })
201
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MANIFEST });
202
+ vi.stubGlobal("fetch", mockFetch);
203
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
204
+ await configureObsidianPlugins(tmpDir, makePreset({
205
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
206
+ }));
207
+ const bratData = await fs.readJson(path.join(bratDir, "data.json"));
208
+ const count = bratData.pluginList.filter((r) => r === "owner/test-plugin").length;
209
+ expect(count).toBe(1);
210
+ });
211
+ it("skips already-installed plugins (idempotent)", async () => {
212
+ const pluginDir = path.join(tmpDir, ".obsidian/plugins/test-plugin");
213
+ await fs.ensureDir(pluginDir);
214
+ await fs.writeFile(path.join(pluginDir, "main.js"), "existing");
215
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
216
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
217
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
218
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
219
+ }));
220
+ expect(result.pluginsSkipped).toContain("test-plugin");
221
+ expect(result.pluginsAdded).not.toContain("test-plugin");
222
+ const content = await fs.readFile(path.join(pluginDir, "main.js"), "utf-8");
223
+ expect(content).toBe("existing");
224
+ });
225
+ it("preserves existing community-plugins.json entries", async () => {
226
+ await fs.writeJson(path.join(tmpDir, ".obsidian/community-plugins.json"), ["existing-plugin"]);
227
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
228
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
229
+ await configureObsidianPlugins(tmpDir, makePreset({
230
+ "new-plugin": { repo: "owner/new-plugin", version: "latest" },
231
+ }));
232
+ const plugins = await fs.readJson(path.join(tmpDir, ".obsidian/community-plugins.json"));
233
+ expect(plugins).toContain("existing-plugin");
234
+ });
235
+ it("records error on download failure, continues", async () => {
236
+ // BRAT succeeds
237
+ const mockFetch = vi.fn()
238
+ .mockResolvedValueOnce({
239
+ ok: true,
240
+ json: async () => mockGitHubRelease([
241
+ { name: "main.js", browser_download_url: "https://example.com/brat/main.js" },
242
+ { name: "manifest.json", browser_download_url: "https://example.com/brat/manifest.json" },
243
+ ]),
244
+ })
245
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_BRAT_MAIN })
246
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_BRAT_MANIFEST })
247
+ // Plugin fails
248
+ .mockResolvedValueOnce({ ok: false, status: 404, statusText: "Not Found" });
249
+ vi.stubGlobal("fetch", mockFetch);
250
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
251
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
252
+ "bad-plugin": { repo: "owner/bad-plugin", version: "latest" },
253
+ }));
254
+ expect(result.errors).toHaveLength(1);
255
+ expect(result.errors[0].pluginId).toBe("bad-plugin");
256
+ expect(result.pluginsAdded).toHaveLength(0);
257
+ });
258
+ it("BRAT failure does not block plugin install", async () => {
259
+ // BRAT fails
260
+ const mockFetch = vi.fn()
261
+ .mockResolvedValueOnce({ ok: false, status: 404, statusText: "Not Found" })
262
+ // Plugin succeeds
263
+ .mockResolvedValueOnce({
264
+ ok: true,
265
+ json: async () => mockGitHubRelease([
266
+ { name: "main.js", browser_download_url: "https://example.com/main.js" },
267
+ { name: "manifest.json", browser_download_url: "https://example.com/manifest.json" },
268
+ ]),
269
+ })
270
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MAIN_JS })
271
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_MANIFEST });
272
+ vi.stubGlobal("fetch", mockFetch);
273
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
274
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
275
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
276
+ }));
277
+ expect(result.bratNewlyInstalled).toBe(false);
278
+ expect(result.pluginsAdded).toContain("test-plugin");
279
+ });
280
+ it("errors on missing required assets", async () => {
281
+ // BRAT succeeds
282
+ const mockFetch = vi.fn()
283
+ .mockResolvedValueOnce({
284
+ ok: true,
285
+ json: async () => mockGitHubRelease([
286
+ { name: "main.js", browser_download_url: "https://example.com/brat/main.js" },
287
+ { name: "manifest.json", browser_download_url: "https://example.com/brat/manifest.json" },
288
+ ]),
289
+ })
290
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_BRAT_MAIN })
291
+ .mockResolvedValueOnce({ ok: true, text: async () => FAKE_BRAT_MANIFEST })
292
+ // Plugin has no main.js
293
+ .mockResolvedValueOnce({
294
+ ok: true,
295
+ json: async () => mockGitHubRelease([
296
+ { name: "styles.css", browser_download_url: "https://example.com/styles.css" },
297
+ ]),
298
+ });
299
+ vi.stubGlobal("fetch", mockFetch);
300
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
301
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
302
+ "incomplete": { repo: "owner/incomplete", version: "latest" },
303
+ }));
304
+ expect(result.errors).toHaveLength(1);
305
+ expect(result.errors[0].error).toContain("missing required assets");
306
+ });
307
+ it("uses GITHUB_TOKEN when available", async () => {
308
+ vi.stubEnv("GITHUB_TOKEN", "test-token-123");
309
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
310
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
311
+ await configureObsidianPlugins(tmpDir, makePreset({
312
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
313
+ }));
314
+ const firstCall = vi.mocked(fetch).mock.calls[0];
315
+ expect(firstCall[1].headers).toHaveProperty("Authorization", "token test-token-123");
316
+ });
317
+ it("supports version pinning", async () => {
318
+ vi.stubGlobal("fetch", mockFetchForBratAndPlugin());
319
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
320
+ await configureObsidianPlugins(tmpDir, makePreset({
321
+ "test-plugin": { repo: "owner/test-plugin", version: "1.2.0" },
322
+ }));
323
+ // 4th call is the plugin release fetch (after 3 BRAT calls)
324
+ const pluginReleaseCall = vi.mocked(fetch).mock.calls[3];
325
+ expect(pluginReleaseCall[0]).toContain("/releases/tags/1.2.0");
326
+ });
327
+ it("times out after 30 seconds on hanging request", async () => {
328
+ // Mock a fetch that rejects when the signal aborts (mimicking real fetch behavior)
329
+ const mockFetch = vi.fn().mockImplementation((_url, opts) => new Promise((_resolve, reject) => {
330
+ if (opts?.signal) {
331
+ const signal = opts.signal;
332
+ if (signal.aborted) {
333
+ reject(new DOMException("The operation was aborted.", "AbortError"));
334
+ return;
335
+ }
336
+ signal.addEventListener("abort", () => {
337
+ reject(new DOMException("The operation was aborted.", "AbortError"));
338
+ });
339
+ }
340
+ // Otherwise never resolves
341
+ }));
342
+ vi.stubGlobal("fetch", mockFetch);
343
+ // Override AbortController to trigger immediately for test speed
344
+ const originalAbort = globalThis.AbortController;
345
+ vi.stubGlobal("AbortController", class {
346
+ controller = new originalAbort();
347
+ signal = this.controller.signal;
348
+ abort() { this.controller.abort(); }
349
+ });
350
+ // Patch the module's FETCH_TIMEOUT_MS by using a short setTimeout
351
+ // We can't easily patch the const, but since we replaced AbortController
352
+ // and the setTimeout still fires after 30s, let's just force immediate abort.
353
+ // Instead, override setTimeout to fire immediately for our test.
354
+ const origSetTimeout = globalThis.setTimeout;
355
+ vi.stubGlobal("setTimeout", (fn, _ms) => origSetTimeout(fn, 1));
356
+ const { configureObsidianPlugins } = await import("../obsidian-plugins.js");
357
+ const result = await configureObsidianPlugins(tmpDir, makePreset({
358
+ "test-plugin": { repo: "owner/test-plugin", version: "latest" },
359
+ }));
360
+ // Both BRAT and plugin should have errors due to timeout/abort
361
+ expect(result.errors.length).toBeGreaterThanOrEqual(1);
362
+ vi.stubGlobal("AbortController", originalAbort);
363
+ vi.stubGlobal("setTimeout", origSetTimeout);
364
+ }, 10_000);
365
+ });
366
+ //# sourceMappingURL=obsidian-plugins.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian-plugins.test.js","sourceRoot":"","sources":["../../../src/vault/__tests__/obsidian-plugins.test.ts"],"names":[],"mappings":"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"}