@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.
- package/dist/__tests__/plugin-config.test.js +130 -0
- package/dist/__tests__/plugin-config.test.js.map +1 -0
- package/dist/cli/cli-program.js +198 -11
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/installer.js +39 -30
- package/dist/cli/installer.js.map +1 -1
- package/dist/cli/ui.js +23 -0
- package/dist/cli/ui.js.map +1 -1
- package/dist/hooks/__tests__/idle-suggestions.test.js +15 -0
- package/dist/hooks/__tests__/idle-suggestions.test.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin-config.js +11 -0
- package/dist/plugin-config.js.map +1 -1
- package/dist/tools/init-vault.js +56 -0
- package/dist/tools/init-vault.js.map +1 -1
- package/dist/tools/switch-provider.js +34 -0
- package/dist/tools/switch-provider.js.map +1 -0
- package/dist/vault/__tests__/create.test.js +130 -0
- package/dist/vault/__tests__/create.test.js.map +1 -0
- package/dist/vault/__tests__/doctor.test.js +88 -0
- package/dist/vault/__tests__/doctor.test.js.map +1 -0
- package/dist/vault/__tests__/glossary.test.js +57 -0
- package/dist/vault/__tests__/glossary.test.js.map +1 -0
- package/dist/vault/__tests__/mcp.test.js +88 -0
- package/dist/vault/__tests__/mcp.test.js.map +1 -0
- package/dist/vault/__tests__/member.test.js +87 -0
- package/dist/vault/__tests__/member.test.js.map +1 -0
- package/dist/vault/__tests__/obsidian-plugins.test.js +366 -0
- package/dist/vault/__tests__/obsidian-plugins.test.js.map +1 -0
- package/dist/vault/__tests__/provider.test.js +82 -0
- package/dist/vault/__tests__/provider.test.js.map +1 -0
- package/dist/vault/__tests__/status.test.js +134 -0
- package/dist/vault/__tests__/status.test.js.map +1 -0
- package/dist/vault/__tests__/template.test.js +33 -0
- package/dist/vault/__tests__/template.test.js.map +1 -0
- package/dist/vault/create.js +128 -18
- package/dist/vault/create.js.map +1 -1
- package/dist/vault/mcp.js +31 -0
- package/dist/vault/mcp.js.map +1 -0
- package/dist/vault/obsidian-plugins.js +209 -0
- package/dist/vault/obsidian-plugins.js.map +1 -0
- package/dist/vault/opencode-config.js +36 -0
- package/dist/vault/opencode-config.js.map +1 -0
- package/dist/vault/provider.js +67 -0
- package/dist/vault/provider.js.map +1 -0
- package/package.json +7 -2
- package/src/assets/presets/pm-tpm/preset.json +25 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
const BRAT_PLUGIN_ID = "obsidian42-brat";
|
|
5
|
+
const BRAT_REPO = "TfTHacker/obsidian42-brat";
|
|
6
|
+
const REQUIRED_ASSETS = ["main.js", "manifest.json"];
|
|
7
|
+
const OPTIONAL_ASSETS = ["styles.css"];
|
|
8
|
+
const FETCH_TIMEOUT_MS = 30_000;
|
|
9
|
+
function getHeaders() {
|
|
10
|
+
const headers = {
|
|
11
|
+
Accept: "application/vnd.github.v3+json",
|
|
12
|
+
};
|
|
13
|
+
const token = process.env.GITHUB_TOKEN;
|
|
14
|
+
if (token) {
|
|
15
|
+
headers.Authorization = `token ${token}`;
|
|
16
|
+
}
|
|
17
|
+
return headers;
|
|
18
|
+
}
|
|
19
|
+
function getReleaseUrl(repo, version) {
|
|
20
|
+
if (version === "latest") {
|
|
21
|
+
return `https://api.github.com/repos/${repo}/releases/latest`;
|
|
22
|
+
}
|
|
23
|
+
return `https://api.github.com/repos/${repo}/releases/tags/${version}`;
|
|
24
|
+
}
|
|
25
|
+
async function fetchWithTimeout(url, options = {}) {
|
|
26
|
+
const controller = new AbortController();
|
|
27
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
28
|
+
try {
|
|
29
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve command names to absolute paths in plugin config.
|
|
37
|
+
* Obsidian GUI apps don't inherit terminal PATH, so commands like "opencode"
|
|
38
|
+
* must be resolved to their full path (e.g., "/Users/jay/.opencode/bin/opencode").
|
|
39
|
+
*/
|
|
40
|
+
function resolveCommandPaths(config) {
|
|
41
|
+
const result = { ...config };
|
|
42
|
+
// Resolve command in customAgents array
|
|
43
|
+
if (Array.isArray(result.customAgents)) {
|
|
44
|
+
result.customAgents = result.customAgents.map((agent) => {
|
|
45
|
+
if (typeof agent.command === "string" && !agent.command.startsWith("/")) {
|
|
46
|
+
try {
|
|
47
|
+
const resolved = execSync(`which ${agent.command}`, { encoding: "utf-8" }).trim();
|
|
48
|
+
if (resolved) {
|
|
49
|
+
return { ...agent, command: resolved };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Command not found — leave as-is
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return agent;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Download a plugin from GitHub Releases into .obsidian/plugins/<id>/.
|
|
63
|
+
* Caller must check if plugin already exists before calling.
|
|
64
|
+
* Throws on failure.
|
|
65
|
+
*/
|
|
66
|
+
async function downloadPlugin(pluginId, repo, version, pluginsDir, config) {
|
|
67
|
+
const headers = getHeaders();
|
|
68
|
+
// 1. Fetch release metadata
|
|
69
|
+
const releaseUrl = getReleaseUrl(repo, version);
|
|
70
|
+
const releaseRes = await fetchWithTimeout(releaseUrl, { headers });
|
|
71
|
+
if (!releaseRes.ok) {
|
|
72
|
+
const msg = releaseRes.status === 403
|
|
73
|
+
? "GitHub API rate limited — try setting GITHUB_TOKEN env var"
|
|
74
|
+
: `GitHub API error: ${releaseRes.status} ${releaseRes.statusText}`;
|
|
75
|
+
throw new Error(msg);
|
|
76
|
+
}
|
|
77
|
+
const release = (await releaseRes.json());
|
|
78
|
+
// 2. Validate required assets
|
|
79
|
+
const assetMap = new Map(release.assets.map((a) => [a.name, a.browser_download_url]));
|
|
80
|
+
const missingRequired = REQUIRED_ASSETS.filter((name) => !assetMap.has(name));
|
|
81
|
+
if (missingRequired.length > 0) {
|
|
82
|
+
throw new Error(`Plugin release missing required assets: ${missingRequired.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
// 3. Download assets
|
|
85
|
+
const pluginDir = path.join(pluginsDir, pluginId);
|
|
86
|
+
await fs.ensureDir(pluginDir);
|
|
87
|
+
const allAssets = [...REQUIRED_ASSETS, ...OPTIONAL_ASSETS];
|
|
88
|
+
for (const assetName of allAssets) {
|
|
89
|
+
const url = assetMap.get(assetName);
|
|
90
|
+
if (!url)
|
|
91
|
+
continue;
|
|
92
|
+
const assetRes = await fetchWithTimeout(url, { headers });
|
|
93
|
+
if (assetRes.ok) {
|
|
94
|
+
const content = await assetRes.text();
|
|
95
|
+
await fs.writeFile(path.join(pluginDir, assetName), content);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 4. Write plugin config if provided, resolving command paths to absolute
|
|
99
|
+
if (config) {
|
|
100
|
+
const resolved = resolveCommandPaths(config);
|
|
101
|
+
await fs.writeJson(path.join(pluginDir, "data.json"), resolved, { spaces: 2 });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Download and configure Obsidian community plugins from a preset.
|
|
106
|
+
* Three-step install: BRAT → plugins → BRAT registration.
|
|
107
|
+
*/
|
|
108
|
+
export async function configureObsidianPlugins(vaultPath, presetConfig) {
|
|
109
|
+
const obsidianPlugins = presetConfig.obsidianPlugins;
|
|
110
|
+
if (!obsidianPlugins || Object.keys(obsidianPlugins).length === 0) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const pluginsDir = path.join(vaultPath, ".obsidian", "plugins");
|
|
114
|
+
await fs.ensureDir(pluginsDir);
|
|
115
|
+
let bratNewlyInstalled = false;
|
|
116
|
+
const pluginsAdded = [];
|
|
117
|
+
const pluginsSkipped = [];
|
|
118
|
+
const errors = [];
|
|
119
|
+
// Step 1: Install BRAT if not present
|
|
120
|
+
const bratMainJs = path.join(pluginsDir, BRAT_PLUGIN_ID, "main.js");
|
|
121
|
+
if (!(await fs.pathExists(bratMainJs))) {
|
|
122
|
+
try {
|
|
123
|
+
await downloadPlugin(BRAT_PLUGIN_ID, BRAT_REPO, "latest", pluginsDir);
|
|
124
|
+
bratNewlyInstalled = true;
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
errors.push({
|
|
128
|
+
pluginId: BRAT_PLUGIN_ID,
|
|
129
|
+
error: err instanceof Error ? err.message : String(err),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Step 2: Install each preset plugin
|
|
134
|
+
for (const [pluginId, pluginDef] of Object.entries(obsidianPlugins)) {
|
|
135
|
+
const pluginMainJs = path.join(pluginsDir, pluginId, "main.js");
|
|
136
|
+
if (await fs.pathExists(pluginMainJs)) {
|
|
137
|
+
pluginsSkipped.push(pluginId);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
await downloadPlugin(pluginId, pluginDef.repo, pluginDef.version ?? "latest", pluginsDir, pluginDef.config);
|
|
142
|
+
pluginsAdded.push(pluginId);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
errors.push({
|
|
146
|
+
pluginId,
|
|
147
|
+
error: err instanceof Error ? err.message : String(err),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Update community-plugins.json
|
|
152
|
+
const communityPluginsPath = path.join(vaultPath, ".obsidian", "community-plugins.json");
|
|
153
|
+
let communityPlugins = [];
|
|
154
|
+
if (await fs.pathExists(communityPluginsPath)) {
|
|
155
|
+
try {
|
|
156
|
+
communityPlugins = await fs.readJson(communityPluginsPath);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Invalid JSON — start fresh
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Always ensure BRAT is in community-plugins.json when plugins are declared
|
|
163
|
+
// (handles edge case where BRAT dir exists but was removed from JSON)
|
|
164
|
+
const bratDirExists = await fs.pathExists(path.join(pluginsDir, BRAT_PLUGIN_ID));
|
|
165
|
+
const allPluginIds = [
|
|
166
|
+
...(bratNewlyInstalled || bratDirExists ? [BRAT_PLUGIN_ID] : []),
|
|
167
|
+
...pluginsAdded,
|
|
168
|
+
];
|
|
169
|
+
for (const id of allPluginIds) {
|
|
170
|
+
if (!communityPlugins.includes(id)) {
|
|
171
|
+
communityPlugins.push(id);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (allPluginIds.length > 0) {
|
|
175
|
+
await fs.writeJson(communityPluginsPath, communityPlugins, { spaces: 2 });
|
|
176
|
+
}
|
|
177
|
+
// Step 3: Register plugins in BRAT config
|
|
178
|
+
const bratDataPath = path.join(pluginsDir, BRAT_PLUGIN_ID, "data.json");
|
|
179
|
+
if (pluginsAdded.length > 0 && await fs.pathExists(path.join(pluginsDir, BRAT_PLUGIN_ID))) {
|
|
180
|
+
let bratData = {
|
|
181
|
+
pluginList: [],
|
|
182
|
+
pluginSubListFrozenVersion: [],
|
|
183
|
+
themesList: [],
|
|
184
|
+
updateAtStartup: true,
|
|
185
|
+
updateThemesAtStartup: false,
|
|
186
|
+
ribbonIconEnabled: true,
|
|
187
|
+
loggingEnabled: false,
|
|
188
|
+
};
|
|
189
|
+
if (await fs.pathExists(bratDataPath)) {
|
|
190
|
+
try {
|
|
191
|
+
bratData = { ...bratData, ...(await fs.readJson(bratDataPath)) };
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// Invalid JSON — use defaults
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const pluginList = bratData.pluginList || [];
|
|
198
|
+
for (const pluginId of pluginsAdded) {
|
|
199
|
+
const repo = obsidianPlugins[pluginId]?.repo;
|
|
200
|
+
if (repo && !pluginList.includes(repo)) {
|
|
201
|
+
pluginList.push(repo);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
bratData.pluginList = pluginList;
|
|
205
|
+
await fs.writeJson(bratDataPath, bratData, { spaces: 2 });
|
|
206
|
+
}
|
|
207
|
+
return { bratNewlyInstalled, pluginsAdded, pluginsSkipped, errors };
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=obsidian-plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obsidian-plugins.js","sourceRoot":"","sources":["../../src/vault/obsidian-plugins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,cAAc,GAAG,iBAAiB,CAAC;AACzC,MAAM,SAAS,GAAG,2BAA2B,CAAC;AAC9C,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AACrD,MAAM,eAAe,GAAG,CAAC,YAAY,CAAC,CAAC;AACvC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAShC,SAAS,UAAU;IACjB,MAAM,OAAO,GAA2B;QACtC,MAAM,EAAE,gCAAgC;KACzC,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACvC,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,aAAa,GAAG,SAAS,KAAK,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,OAAe;IAClD,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,gCAAgC,IAAI,kBAAkB,CAAC;IAChE,CAAC;IACD,OAAO,gCAAgC,IAAI,kBAAkB,OAAO,EAAE,CAAC;AACzE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,UAAuB,EAAE;IACpE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,MAA+B;IAC1D,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAE7B,wCAAwC;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,YAAY,GAAI,MAAM,CAAC,YAA+C,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1F,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxE,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;oBAClF,IAAI,QAAQ,EAAE,CAAC;wBACb,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;oBACzC,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,kCAAkC;gBACpC,CAAC;YACH,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAC3B,QAAgB,EAChB,IAAY,EACZ,OAAe,EACf,UAAkB,EAClB,MAAgC;IAEhC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,4BAA4B;IAC5B,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAEnE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,KAAK,GAAG;YACnC,CAAC,CAAC,4DAA4D;YAC9D,CAAC,CAAC,qBAAqB,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,EAAE,CAEvC,CAAC;IAEF,8BAA8B;IAC9B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACtF,MAAM,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,2CAA2C,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,qBAAqB;IACrB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,eAAe,CAAC,CAAC;IAE3D,KAAK,MAAM,SAAS,IAAI,SAAS,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1D,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACtC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,SAAiB,EACjB,YAA0B;IAE1B,MAAM,eAAe,GAAG,YAAY,CAAC,eAAe,CAAC;IACrD,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IAChE,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAE/B,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAC/B,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,MAAM,GAA+C,EAAE,CAAC;IAE9D,sCAAsC;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,cAAc,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;YACtE,kBAAkB,GAAG,IAAI,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,cAAc;gBACxB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,KAAK,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QACpE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAEhE,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACtC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,cAAc,CAClB,QAAQ,EACR,SAAS,CAAC,IAAI,EACd,SAAS,CAAC,OAAO,IAAI,QAAQ,EAC7B,UAAU,EACV,SAAS,CAAC,MAAM,CACjB,CAAC;YACF,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ;gBACR,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,MAAM,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,wBAAwB,CAAC,CAAC;IACzF,IAAI,gBAAgB,GAAa,EAAE,CAAC;IACpC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC;YACH,gBAAgB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,sEAAsE;IACtE,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;IACjF,MAAM,YAAY,GAAG;QACnB,GAAG,CAAC,kBAAkB,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,YAAY;KAChB,CAAC;IACF,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;QAC9B,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YACnC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,EAAE,CAAC,SAAS,CAAC,oBAAoB,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,0CAA0C;IAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IACxE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QAC1F,IAAI,QAAQ,GAA4B;YACtC,UAAU,EAAE,EAAE;YACd,0BAA0B,EAAE,EAAE;YAC9B,UAAU,EAAE,EAAE;YACd,eAAe,EAAE,IAAI;YACrB,qBAAqB,EAAE,KAAK;YAC5B,iBAAiB,EAAE,IAAI;YACvB,cAAc,EAAE,KAAK;SACtB,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,QAAQ,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACnE,CAAC;YAAC,MAAM,CAAC;gBACP,8BAA8B;YAChC,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAI,QAAQ,CAAC,UAAuB,IAAI,EAAE,CAAC;QAC3D,KAAK,MAAM,QAAQ,IAAI,YAAY,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;YAC7C,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;QACjC,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
const OPENCODE_CONFIG_PATHS = [
|
|
5
|
+
path.join(os.homedir(), ".config/opencode/opencode.json"),
|
|
6
|
+
path.join(os.homedir(), ".config/opencode/.opencode.json"),
|
|
7
|
+
];
|
|
8
|
+
/** Find the first existing OpenCode config file, or return the default path. */
|
|
9
|
+
export function findOpencodeConfig() {
|
|
10
|
+
for (const p of OPENCODE_CONFIG_PATHS) {
|
|
11
|
+
if (fs.existsSync(p))
|
|
12
|
+
return p;
|
|
13
|
+
}
|
|
14
|
+
return OPENCODE_CONFIG_PATHS[0];
|
|
15
|
+
}
|
|
16
|
+
/** Read the OpenCode config, returning empty object if missing or invalid. */
|
|
17
|
+
export async function readOpencodeConfig() {
|
|
18
|
+
const configPath = findOpencodeConfig();
|
|
19
|
+
if (await fs.pathExists(configPath)) {
|
|
20
|
+
try {
|
|
21
|
+
return await fs.readJson(configPath);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Invalid JSON — return empty
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
/** Write the OpenCode config, ensuring the directory exists. */
|
|
30
|
+
export async function writeOpencodeConfig(config) {
|
|
31
|
+
const configPath = findOpencodeConfig();
|
|
32
|
+
await fs.ensureDir(path.dirname(configPath));
|
|
33
|
+
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
34
|
+
return configPath;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=opencode-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-config.js","sourceRoot":"","sources":["../../src/vault/opencode-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,qBAAqB,GAAG;IAC5B,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,gCAAgC,CAAC;IACzD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,iCAAiC,CAAC;CAC3D,CAAC;AAEF,gFAAgF;AAChF,MAAM,UAAU,kBAAkB;IAChC,KAAK,MAAM,CAAC,IAAI,qBAAqB,EAAE,CAAC;QACtC,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,UAAU,GAAG,kBAAkB,EAAE,CAAC;IACxC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAA+B;IAE/B,MAAM,UAAU,GAAG,kBAAkB,EAAE,CAAC;IACxC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACtD,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { findOpencodeConfig, readOpencodeConfig, writeOpencodeConfig, } from "./opencode-config.js";
|
|
2
|
+
const GEMINI_AUTH_PLUGIN = "opencode-gemini-auth";
|
|
3
|
+
/**
|
|
4
|
+
* Configure an AI provider in the global OpenCode config.
|
|
5
|
+
* For Gemini: adds the auth plugin and projectId.
|
|
6
|
+
* For Copilot: no config changes needed (built-in provider).
|
|
7
|
+
* Idempotent — skips entries that already exist.
|
|
8
|
+
*/
|
|
9
|
+
export async function configureProvider(provider, gcpProjectId) {
|
|
10
|
+
const configPath = findOpencodeConfig();
|
|
11
|
+
if (provider === "copilot") {
|
|
12
|
+
return {
|
|
13
|
+
provider: "copilot",
|
|
14
|
+
configPath,
|
|
15
|
+
pluginAdded: false,
|
|
16
|
+
pluginSkipped: false,
|
|
17
|
+
projectIdSet: false,
|
|
18
|
+
projectIdSkipped: false,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Gemini requires a projectId
|
|
22
|
+
if (!gcpProjectId) {
|
|
23
|
+
throw new Error("GCP Project ID is required for Google Gemini provider");
|
|
24
|
+
}
|
|
25
|
+
const config = await readOpencodeConfig();
|
|
26
|
+
// 1. Add plugin
|
|
27
|
+
const plugins = config.plugin || [];
|
|
28
|
+
let pluginAdded = false;
|
|
29
|
+
let pluginSkipped = false;
|
|
30
|
+
const hasPlugin = plugins.some((p) => p.startsWith(GEMINI_AUTH_PLUGIN));
|
|
31
|
+
if (hasPlugin) {
|
|
32
|
+
pluginSkipped = true;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
plugins.push(GEMINI_AUTH_PLUGIN);
|
|
36
|
+
config.plugin = plugins;
|
|
37
|
+
pluginAdded = true;
|
|
38
|
+
}
|
|
39
|
+
// 2. Set provider.google.options.projectId
|
|
40
|
+
const providerConfig = config.provider || {};
|
|
41
|
+
const googleConfig = providerConfig.google || {};
|
|
42
|
+
const googleOptions = googleConfig.options || {};
|
|
43
|
+
let projectIdSet = false;
|
|
44
|
+
let projectIdSkipped = false;
|
|
45
|
+
if (googleOptions.projectId) {
|
|
46
|
+
projectIdSkipped = true;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
googleOptions.projectId = gcpProjectId;
|
|
50
|
+
projectIdSet = true;
|
|
51
|
+
}
|
|
52
|
+
googleConfig.options = googleOptions;
|
|
53
|
+
providerConfig.google = googleConfig;
|
|
54
|
+
config.provider = providerConfig;
|
|
55
|
+
if (pluginAdded || projectIdSet) {
|
|
56
|
+
await writeOpencodeConfig(config);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
provider: "gemini",
|
|
60
|
+
configPath,
|
|
61
|
+
pluginAdded,
|
|
62
|
+
pluginSkipped,
|
|
63
|
+
projectIdSet,
|
|
64
|
+
projectIdSkipped,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/vault/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAalD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAwB,EACxB,YAAqB;IAErB,MAAM,UAAU,GAAG,kBAAkB,EAAE,CAAC;IAExC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,UAAU;YACV,WAAW,EAAE,KAAK;YAClB,aAAa,EAAE,KAAK;YACpB,YAAY,EAAE,KAAK;YACnB,gBAAgB,EAAE,KAAK;SACxB,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAE1C,gBAAgB;IAChB,MAAM,OAAO,GAAI,MAAM,CAAC,MAA+B,IAAI,EAAE,CAAC;IAC9D,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACxE,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;QACxB,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,2CAA2C;IAC3C,MAAM,cAAc,GAAI,MAAM,CAAC,QAAoC,IAAI,EAAE,CAAC;IAC1E,MAAM,YAAY,GACf,cAAc,CAAC,MAAkC,IAAI,EAAE,CAAC;IAC3D,MAAM,aAAa,GAChB,YAAY,CAAC,OAAmC,IAAI,EAAE,CAAC;IAE1D,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;QAC5B,gBAAgB,GAAG,IAAI,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,SAAS,GAAG,YAAY,CAAC;QACvC,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,YAAY,CAAC,OAAO,GAAG,aAAa,CAAC;IACrC,cAAc,CAAC,MAAM,GAAG,YAAY,CAAC;IACrC,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAC;IAEjC,IAAI,WAAW,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,QAAQ;QAClB,UAAU;QACV,WAAW;QACX,aAAa;QACb,YAAY;QACZ,gBAAgB;KACjB,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jayjiang/byoao",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Build Your Own AI OS — Obsidian + AI Agent",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18.0.0"
|
|
8
|
+
},
|
|
6
9
|
"main": "dist/index.js",
|
|
7
10
|
"types": "dist/index.d.ts",
|
|
8
11
|
"bin": {
|
|
@@ -11,6 +14,7 @@
|
|
|
11
14
|
"scripts": {
|
|
12
15
|
"build": "tsc",
|
|
13
16
|
"dev": "node --import tsx src/cli/cli-program.ts",
|
|
17
|
+
"test": "vitest run",
|
|
14
18
|
"typecheck": "tsc --noEmit",
|
|
15
19
|
"prepublishOnly": "npm run build"
|
|
16
20
|
},
|
|
@@ -53,6 +57,7 @@
|
|
|
53
57
|
"@types/inquirer": "^9.0.0",
|
|
54
58
|
"@types/node": "^20.0.0",
|
|
55
59
|
"tsx": "^4.21.0",
|
|
56
|
-
"typescript": "^5.4.0"
|
|
60
|
+
"typescript": "^5.4.0",
|
|
61
|
+
"vitest": "^4.1.0"
|
|
57
62
|
}
|
|
58
63
|
}
|
|
@@ -8,5 +8,29 @@
|
|
|
8
8
|
"project": ["jira", "stakeholders", "priority"],
|
|
9
9
|
"sprint": ["sprint-dates", "jira-board"]
|
|
10
10
|
},
|
|
11
|
-
"templates": ["Feature Doc.md", "Sprint Handoff.md"]
|
|
11
|
+
"templates": ["Feature Doc.md", "Sprint Handoff.md"],
|
|
12
|
+
"mcpServers": {
|
|
13
|
+
"atlassian": {
|
|
14
|
+
"type": "remote",
|
|
15
|
+
"url": "https://mcp.atlassian.com/v1/sse"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"obsidianPlugins": {
|
|
19
|
+
"agent-client": {
|
|
20
|
+
"repo": "RAIT-09/obsidian-agent-client",
|
|
21
|
+
"version": "latest",
|
|
22
|
+
"config": {
|
|
23
|
+
"defaultAgentId": "opencode-acp",
|
|
24
|
+
"customAgents": [
|
|
25
|
+
{
|
|
26
|
+
"id": "opencode-acp",
|
|
27
|
+
"displayName": "OpenCode",
|
|
28
|
+
"command": "opencode",
|
|
29
|
+
"args": ["acp"],
|
|
30
|
+
"env": []
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
12
36
|
}
|