@jayjiang/byoao 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/plugin-config.test.js +11 -8
- package/dist/__tests__/plugin-config.test.js.map +1 -1
- package/dist/cli/cli-program.js +253 -157
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/installer.js +4 -11
- package/dist/cli/installer.js.map +1 -1
- package/dist/hooks/idle-suggestions.js +3 -3
- package/dist/hooks/idle-suggestions.js.map +1 -1
- package/dist/hooks/system-transform.js +37 -14
- package/dist/hooks/system-transform.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin-config.js +5 -2
- package/dist/plugin-config.js.map +1 -1
- package/dist/tools/add-glossary-term.js +2 -0
- package/dist/tools/add-glossary-term.js.map +1 -1
- package/dist/tools/add-person.js +21 -0
- package/dist/tools/add-person.js.map +1 -0
- package/dist/tools/init-vault.js +11 -9
- package/dist/tools/init-vault.js.map +1 -1
- package/dist/tools/vault-upgrade.js +77 -0
- package/dist/tools/vault-upgrade.js.map +1 -0
- package/dist/vault/__tests__/create.test.js +105 -39
- package/dist/vault/__tests__/create.test.js.map +1 -1
- package/dist/vault/__tests__/glossary.test.js +25 -14
- package/dist/vault/__tests__/glossary.test.js.map +1 -1
- package/dist/vault/__tests__/manifest.test.js +76 -0
- package/dist/vault/__tests__/manifest.test.js.map +1 -0
- package/dist/vault/__tests__/member.test.js +2 -4
- package/dist/vault/__tests__/member.test.js.map +1 -1
- package/dist/vault/__tests__/upgrade.test.js +181 -0
- package/dist/vault/__tests__/upgrade.test.js.map +1 -0
- package/dist/vault/create.js +211 -146
- package/dist/vault/create.js.map +1 -1
- package/dist/vault/doctor.js +1 -1
- package/dist/vault/doctor.js.map +1 -1
- package/dist/vault/glossary.js +8 -14
- package/dist/vault/glossary.js.map +1 -1
- package/dist/vault/manifest.js +68 -0
- package/dist/vault/manifest.js.map +1 -0
- package/dist/vault/member.js +1 -1
- package/dist/vault/member.js.map +1 -1
- package/dist/vault/project.js +1 -1
- package/dist/vault/project.js.map +1 -1
- package/dist/vault/upgrade.js +266 -0
- package/dist/vault/upgrade.js.map +1 -0
- package/dist/vault/vault-detect.js +30 -0
- package/dist/vault/vault-detect.js.map +1 -1
- package/package.json +3 -1
- package/src/assets/presets/common/AGENT.md.hbs +34 -67
- package/src/assets/presets/common/Glossary.md.hbs +7 -35
- package/src/assets/presets/common/Start Here.md.hbs +32 -64
- package/src/assets/presets/minimal/preset.json +28 -0
- package/src/skills/{vault-doctor.md → diagnose.md} +12 -12
- package/src/skills/{system-explainer.md → explain.md} +8 -8
- package/src/skills/weave.md +240 -0
- package/src/assets/web-clipper/confluence-page.json +0 -63
- package/src/assets/web-clipper/general-article.json +0 -53
- package/src/assets/web-clipper/jira-issue.json +0 -68
- package/src/assets/web-clipper/meeting-notes.json +0 -53
- package/src/skills/enrich-document.md +0 -52
|
@@ -3,27 +3,29 @@ import { VaultConfigSchema, PresetConfigSchema } from "../plugin-config.js";
|
|
|
3
3
|
describe("VaultConfigSchema", () => {
|
|
4
4
|
it("validates minimal config with defaults", () => {
|
|
5
5
|
const result = VaultConfigSchema.parse({
|
|
6
|
-
|
|
6
|
+
kbName: "My KB",
|
|
7
7
|
vaultPath: "/tmp/vault",
|
|
8
8
|
});
|
|
9
|
-
expect(result.
|
|
9
|
+
expect(result.kbName).toBe("My KB");
|
|
10
|
+
expect(result.ownerName).toBe("");
|
|
10
11
|
expect(result.members).toEqual([]);
|
|
11
12
|
expect(result.projects).toEqual([]);
|
|
12
13
|
expect(result.glossaryEntries).toEqual([]);
|
|
13
|
-
expect(result.preset).toBe("
|
|
14
|
+
expect(result.preset).toBe("minimal");
|
|
14
15
|
});
|
|
15
|
-
it("rejects missing
|
|
16
|
+
it("rejects missing kbName", () => {
|
|
16
17
|
expect(() => VaultConfigSchema.parse({ vaultPath: "/tmp" })).toThrow();
|
|
17
18
|
});
|
|
18
|
-
it("rejects empty
|
|
19
|
-
expect(() => VaultConfigSchema.parse({
|
|
19
|
+
it("rejects empty kbName", () => {
|
|
20
|
+
expect(() => VaultConfigSchema.parse({ kbName: "", vaultPath: "/tmp" })).toThrow();
|
|
20
21
|
});
|
|
21
22
|
it("rejects missing vaultPath", () => {
|
|
22
|
-
expect(() => VaultConfigSchema.parse({
|
|
23
|
+
expect(() => VaultConfigSchema.parse({ kbName: "KB" })).toThrow();
|
|
23
24
|
});
|
|
24
25
|
it("validates full config", () => {
|
|
25
26
|
const result = VaultConfigSchema.parse({
|
|
26
|
-
|
|
27
|
+
kbName: "Alpha KB",
|
|
28
|
+
ownerName: "Alice",
|
|
27
29
|
vaultPath: "/v",
|
|
28
30
|
members: [{ name: "A", role: "Eng" }],
|
|
29
31
|
projects: [{ name: "P" }],
|
|
@@ -34,6 +36,7 @@ describe("VaultConfigSchema", () => {
|
|
|
34
36
|
});
|
|
35
37
|
expect(result.members).toHaveLength(1);
|
|
36
38
|
expect(result.projects[0].description).toBe("");
|
|
39
|
+
expect(result.ownerName).toBe("Alice");
|
|
37
40
|
});
|
|
38
41
|
});
|
|
39
42
|
describe("PresetConfigSchema", () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-config.test.js","sourceRoot":"","sources":["../../src/__tests__/plugin-config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC;YACrC,
|
|
1
|
+
{"version":3,"file":"plugin-config.test.js","sourceRoot":"","sources":["../../src/__tests__/plugin-config.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/cli-program.js
CHANGED
|
@@ -11,26 +11,18 @@ import { spawn } from "node:child_process";
|
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import os from "node:os";
|
|
14
|
+
import { upgradeVault } from "../vault/upgrade.js";
|
|
15
|
+
import { detectVaultContext, detectInitMode } from "../vault/vault-detect.js";
|
|
14
16
|
const require = createRequire(import.meta.url);
|
|
15
17
|
const PKG_VERSION = require("../../package.json").version;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
function getAuthCommand(provider) {
|
|
23
|
-
const cmd = AUTH_COMMANDS[provider];
|
|
24
|
-
if (!cmd)
|
|
25
|
-
return `opencode auth login`;
|
|
26
|
-
return `opencode ${cmd.args.join(" ")}`;
|
|
27
|
-
}
|
|
28
|
-
function runProviderAuth(provider) {
|
|
29
|
-
const cmd = AUTH_COMMANDS[provider];
|
|
30
|
-
if (!cmd)
|
|
31
|
-
return Promise.resolve(false);
|
|
18
|
+
/**
|
|
19
|
+
* Run `opencode auth login` — launches the interactive provider selector.
|
|
20
|
+
* The old `-p <provider>` flag was removed in newer opencode versions;
|
|
21
|
+
* the CLI now presents a built-in picker when called without arguments.
|
|
22
|
+
*/
|
|
23
|
+
function runProviderAuth() {
|
|
32
24
|
return new Promise((resolve) => {
|
|
33
|
-
const child = spawn("opencode",
|
|
25
|
+
const child = spawn("opencode", ["auth", "login"], {
|
|
34
26
|
stdio: "inherit",
|
|
35
27
|
env: { ...process.env },
|
|
36
28
|
});
|
|
@@ -135,12 +127,14 @@ program
|
|
|
135
127
|
// ── byoao init ───────────────────────────────────────────────────
|
|
136
128
|
program
|
|
137
129
|
.command("init")
|
|
138
|
-
.description("Create a
|
|
139
|
-
"glossary, and an AI routing index (AGENT.md)"
|
|
140
|
-
|
|
141
|
-
.option("--
|
|
142
|
-
.option("--
|
|
143
|
-
.option("--
|
|
130
|
+
.description("Create a personal knowledge base — sets up folders, templates, " +
|
|
131
|
+
"glossary, and an AI routing index (AGENT.md). Works with empty " +
|
|
132
|
+
"directories or adopts existing folders.")
|
|
133
|
+
.option("--kb <name>", "Knowledge base name (skips interactive prompt)")
|
|
134
|
+
.option("--name <name>", "Your name (default: OS username in non-interactive mode)")
|
|
135
|
+
.option("--path <path>", "Where to create the vault (default: ~/Documents/<kb name>)")
|
|
136
|
+
.option("--from <path>", "Adopt an existing folder as a knowledge base")
|
|
137
|
+
.option("--preset <name>", "Role preset — determines folder structure and templates (default: minimal)")
|
|
144
138
|
.option("--provider <name>", "AI provider: copilot, gemini, or skip (default: skip in non-interactive)")
|
|
145
139
|
.option("--gcp-project <id>", "GCP Project ID (required when --provider=gemini)")
|
|
146
140
|
.action(async (opts) => {
|
|
@@ -151,100 +145,133 @@ program
|
|
|
151
145
|
console.log("\nPlease install Obsidian first, then try again.");
|
|
152
146
|
process.exit(1);
|
|
153
147
|
}
|
|
154
|
-
let
|
|
155
|
-
let
|
|
156
|
-
let
|
|
148
|
+
let kbName = opts.kb;
|
|
149
|
+
let ownerName = opts.name || "";
|
|
150
|
+
let vaultPath = opts.path || opts.from;
|
|
151
|
+
let presetName = opts.preset || "minimal";
|
|
157
152
|
let members = [];
|
|
158
|
-
// Interactive TUI when --
|
|
159
|
-
if (!
|
|
153
|
+
// Interactive TUI when --kb is not provided and stdout is TTY
|
|
154
|
+
if (!kbName && process.stdout.isTTY) {
|
|
160
155
|
try {
|
|
161
156
|
const { default: inquirer } = await import("inquirer");
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
{
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
157
|
+
// Auto-detect mode from --from or cwd
|
|
158
|
+
const targetForDetection = opts.from || vaultPath;
|
|
159
|
+
const initMode = targetForDetection ? detectInitMode(path.resolve(targetForDetection)) : "fresh";
|
|
160
|
+
if (initMode === "existing" || initMode === "obsidian-vault") {
|
|
161
|
+
const resolvedFrom = path.resolve(targetForDetection);
|
|
162
|
+
const fileCount = (await import("fs-extra")).default.readdirSync(resolvedFrom, { recursive: true })
|
|
163
|
+
.filter((f) => String(f).endsWith(".md")).length;
|
|
164
|
+
printEvent("Adopting existing folder as knowledge base");
|
|
165
|
+
console.log();
|
|
166
|
+
if (initMode === "obsidian-vault") {
|
|
167
|
+
printEventDetail("Detected existing Obsidian vault — .obsidian/ config will be preserved");
|
|
168
|
+
}
|
|
169
|
+
const { confirmAdopt } = await inquirer.prompt([{
|
|
170
|
+
type: "confirm",
|
|
171
|
+
name: "confirmAdopt",
|
|
172
|
+
message: `Detected ${fileCount} markdown files. Set up this folder as a knowledge base?`,
|
|
173
|
+
default: true,
|
|
174
|
+
}]);
|
|
175
|
+
if (!confirmAdopt) {
|
|
176
|
+
console.log("Cancelled.");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
vaultPath = resolvedFrom;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
printEvent("Creating a new knowledge base");
|
|
183
|
+
console.log();
|
|
184
|
+
}
|
|
185
|
+
// 1. Your name
|
|
190
186
|
const { yourName } = await inquirer.prompt([{
|
|
191
187
|
type: "input",
|
|
192
188
|
name: "yourName",
|
|
193
189
|
message: "Your name:",
|
|
194
190
|
validate: (v) => v.trim() ? true : "Your name is required",
|
|
195
191
|
}]);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const {
|
|
202
|
-
type: "
|
|
203
|
-
name: "
|
|
204
|
-
message: "
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
{ name: "Choose custom path", value: "custom" },
|
|
208
|
-
],
|
|
192
|
+
ownerName = yourName.trim();
|
|
193
|
+
// 2. Knowledge base name
|
|
194
|
+
const defaultKbName = vaultPath
|
|
195
|
+
? path.basename(vaultPath)
|
|
196
|
+
: `${ownerName}'s KB`;
|
|
197
|
+
const { enteredKbName } = await inquirer.prompt([{
|
|
198
|
+
type: "input",
|
|
199
|
+
name: "enteredKbName",
|
|
200
|
+
message: "Knowledge base name:",
|
|
201
|
+
default: defaultKbName,
|
|
202
|
+
validate: (v) => v.trim() ? true : "Name is required",
|
|
209
203
|
}]);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
204
|
+
kbName = enteredKbName.trim();
|
|
205
|
+
// 3. Vault path (skip if adopting existing folder)
|
|
206
|
+
if (!vaultPath) {
|
|
207
|
+
const defaultPath = path.join(os.homedir(), "Documents", kbName);
|
|
208
|
+
const { pathChoice } = await inquirer.prompt([{
|
|
209
|
+
type: "list",
|
|
210
|
+
name: "pathChoice",
|
|
211
|
+
message: "Vault location",
|
|
212
|
+
choices: [
|
|
213
|
+
{ name: `Use default (${defaultPath})`, value: "default" },
|
|
214
|
+
{ name: "Choose custom path", value: "custom" },
|
|
215
|
+
],
|
|
216
|
+
}]);
|
|
217
|
+
vaultPath = defaultPath;
|
|
218
|
+
if (pathChoice === "custom") {
|
|
219
|
+
const { customPath } = await inquirer.prompt([{
|
|
220
|
+
type: "input",
|
|
221
|
+
name: "customPath",
|
|
222
|
+
message: "Custom path:",
|
|
223
|
+
}]);
|
|
224
|
+
vaultPath = customPath;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// 4. Optional work preset
|
|
228
|
+
const presets = listPresets().filter(p => p.name !== "minimal");
|
|
229
|
+
if (presets.length > 0) {
|
|
230
|
+
const { selectedPreset } = await inquirer.prompt([{
|
|
231
|
+
type: "list",
|
|
232
|
+
name: "selectedPreset",
|
|
233
|
+
message: "Add a work preset? (optional)",
|
|
234
|
+
choices: [
|
|
235
|
+
{ name: "No — start with a minimal personal KB", value: "minimal" },
|
|
236
|
+
...presets.map(p => ({
|
|
237
|
+
name: `${p.displayName} — ${p.description}`,
|
|
238
|
+
value: p.name,
|
|
239
|
+
})),
|
|
240
|
+
],
|
|
216
241
|
}]);
|
|
217
|
-
|
|
242
|
+
presetName = selectedPreset;
|
|
243
|
+
}
|
|
244
|
+
// Create owner as a member if a preset with People/ is selected
|
|
245
|
+
if (ownerName && presetName !== "minimal") {
|
|
246
|
+
members.push({ name: ownerName, role: presetName === "pm-tpm" ? "PM/TPM" : "Team Member" });
|
|
218
247
|
}
|
|
219
248
|
}
|
|
220
249
|
catch {
|
|
221
|
-
// inquirer not available — fall through to require --
|
|
222
|
-
if (!
|
|
223
|
-
console.error("Error: --
|
|
250
|
+
// inquirer not available — fall through to require --kb
|
|
251
|
+
if (!kbName) {
|
|
252
|
+
console.error("Error: --kb flag is required in non-interactive mode");
|
|
224
253
|
process.exit(1);
|
|
225
254
|
}
|
|
226
255
|
}
|
|
227
256
|
}
|
|
228
|
-
if (!
|
|
229
|
-
console.error("Error: --
|
|
257
|
+
if (!kbName) {
|
|
258
|
+
console.error("Error: --kb flag is required");
|
|
230
259
|
process.exit(1);
|
|
231
260
|
}
|
|
232
261
|
// In non-interactive mode, use --name flag or fall back to OS username
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
if (userName) {
|
|
236
|
-
members.push({ name: userName, role: presetName === "pm-tpm" ? "PM/TPM" : "Team Member" });
|
|
237
|
-
}
|
|
262
|
+
if (!ownerName) {
|
|
263
|
+
ownerName = os.userInfo().username || "";
|
|
238
264
|
}
|
|
239
|
-
vaultPath = vaultPath || path.join(os.homedir(), "Documents",
|
|
265
|
+
vaultPath = vaultPath || path.join(os.homedir(), "Documents", kbName);
|
|
240
266
|
if (opts.provider === "gemini" && !opts.gcpProject) {
|
|
241
267
|
console.error("Error: --gcp-project is required when --provider=gemini");
|
|
242
268
|
process.exit(1);
|
|
243
269
|
}
|
|
244
270
|
const providerOpt = opts.provider || "skip";
|
|
245
|
-
|
|
271
|
+
const gcpProjectOpt = opts.gcpProject || "";
|
|
246
272
|
const config = VaultConfigSchema.parse({
|
|
247
|
-
|
|
273
|
+
kbName,
|
|
274
|
+
ownerName,
|
|
248
275
|
vaultPath,
|
|
249
276
|
members,
|
|
250
277
|
projects: [],
|
|
@@ -252,9 +279,9 @@ program
|
|
|
252
279
|
provider: providerOpt,
|
|
253
280
|
gcpProjectId: gcpProjectOpt,
|
|
254
281
|
});
|
|
255
|
-
const spinner = startSpinner(`Creating
|
|
282
|
+
const spinner = startSpinner(`Creating knowledge base "${kbName}"`);
|
|
256
283
|
const result = await createVault(config);
|
|
257
|
-
spinner.stop(`
|
|
284
|
+
spinner.stop(`Knowledge base ready`);
|
|
258
285
|
printEventCheck(`Path: ${result.vaultPath}`);
|
|
259
286
|
printEventCheck(`Files: ${result.filesCreated}`);
|
|
260
287
|
printEventCheck(`Wikilinks: ${result.wikilinksCreated}`);
|
|
@@ -302,8 +329,6 @@ program
|
|
|
302
329
|
printWarning("Obsidian is running — restart it or use 'Reload app without saving' to activate new plugins");
|
|
303
330
|
}
|
|
304
331
|
}
|
|
305
|
-
// ── AI Provider Display (non-interactive path) ───────────────
|
|
306
|
-
// This fires when --provider flag was set and createVault ran configureProvider.
|
|
307
332
|
if (result.providerResult) {
|
|
308
333
|
console.log();
|
|
309
334
|
printEventDone(`AI provider configured: ${result.providerResult.provider}`);
|
|
@@ -321,91 +346,46 @@ program
|
|
|
321
346
|
}
|
|
322
347
|
printEventCheck(`Config: ${result.providerResult.configPath}`);
|
|
323
348
|
}
|
|
324
|
-
// ──
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
let providerForAuth = config.provider;
|
|
328
|
-
if (providerForAuth === "skip" && process.stdout.isTTY && !opts.provider) {
|
|
349
|
+
// ── Auth Prompt (TTY only) ─────────────────────────────────
|
|
350
|
+
let wantsAuth = config.provider !== "skip";
|
|
351
|
+
if (!wantsAuth && process.stdout.isTTY && !opts.provider) {
|
|
329
352
|
try {
|
|
330
353
|
const { default: inquirer } = await import("inquirer");
|
|
331
354
|
console.log();
|
|
332
|
-
const {
|
|
333
|
-
type: "
|
|
334
|
-
name: "
|
|
335
|
-
message: "Set up AI provider (
|
|
336
|
-
|
|
337
|
-
{
|
|
338
|
-
name: "GitHub Copilot — authenticate via GitHub account",
|
|
339
|
-
value: "copilot",
|
|
340
|
-
},
|
|
341
|
-
{
|
|
342
|
-
name: "Google Gemini — authenticate via GCP project + Google account",
|
|
343
|
-
value: "gemini",
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
name: "Skip — configure later",
|
|
347
|
-
value: "skip",
|
|
348
|
-
},
|
|
349
|
-
],
|
|
355
|
+
const { doAuth } = await inquirer.prompt([{
|
|
356
|
+
type: "confirm",
|
|
357
|
+
name: "doAuth",
|
|
358
|
+
message: "Set up AI provider now? (you can always run 'opencode auth login' later)",
|
|
359
|
+
default: true,
|
|
350
360
|
}]);
|
|
351
|
-
|
|
352
|
-
if (providerForAuth === "gemini" && !gcpProjectOpt) {
|
|
353
|
-
const { projectId } = await inquirer.prompt([{
|
|
354
|
-
type: "input",
|
|
355
|
-
name: "projectId",
|
|
356
|
-
message: "GCP Project ID (ask your engineering lead, e.g. wonder-sandbox):",
|
|
357
|
-
validate: (v) => v.trim() ? true : "Project ID is required for Gemini",
|
|
358
|
-
}]);
|
|
359
|
-
gcpProjectOpt = projectId.trim();
|
|
360
|
-
// Write the Gemini config now (vault already created without it)
|
|
361
|
-
const { configureProvider } = await import("../vault/provider.js");
|
|
362
|
-
const lateProviderResult = await configureProvider("gemini", gcpProjectOpt);
|
|
363
|
-
if (lateProviderResult) {
|
|
364
|
-
printEventDone("AI provider configured: gemini");
|
|
365
|
-
if (lateProviderResult.pluginAdded) {
|
|
366
|
-
printEventCheck("Plugin added: opencode-gemini-auth");
|
|
367
|
-
}
|
|
368
|
-
printEventCheck(`GCP Project: ${gcpProjectOpt}`);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
// Copilot needs no config — just auth (handled below)
|
|
372
|
-
if (providerForAuth === "copilot") {
|
|
373
|
-
printEventDone("AI provider: Copilot (built-in, no config changes needed)");
|
|
374
|
-
}
|
|
361
|
+
wantsAuth = doAuth;
|
|
375
362
|
}
|
|
376
363
|
catch {
|
|
377
364
|
// inquirer not available — skip
|
|
378
365
|
}
|
|
379
366
|
}
|
|
380
|
-
|
|
381
|
-
// Uses providerForAuth which is set by either:
|
|
382
|
-
// - Non-interactive: providerOpt from --provider flag
|
|
383
|
-
// - Interactive: selectedProvider from the prompt above
|
|
384
|
-
if (providerForAuth !== "skip" && process.stdout.isTTY) {
|
|
367
|
+
if (wantsAuth && process.stdout.isTTY) {
|
|
385
368
|
console.log();
|
|
386
|
-
printEvent("
|
|
387
|
-
const authSuccess = await runProviderAuth(
|
|
369
|
+
printEvent("Launching AI provider authentication...");
|
|
370
|
+
const authSuccess = await runProviderAuth();
|
|
388
371
|
if (authSuccess) {
|
|
389
372
|
printEventDone("Authentication complete");
|
|
390
373
|
}
|
|
391
374
|
else {
|
|
392
375
|
printWarning("Authentication was not completed. Your vault is ready — run this later:\n" +
|
|
393
|
-
|
|
376
|
+
"opencode auth login");
|
|
394
377
|
}
|
|
395
378
|
}
|
|
379
|
+
// ── Onboarding sequence ──────────────────────────────────
|
|
380
|
+
console.log();
|
|
381
|
+
printEventDone(`Knowledge base ready at ${result.vaultPath}`);
|
|
396
382
|
console.log();
|
|
397
383
|
printEventDetail("Next steps:");
|
|
398
384
|
printEventDetail(" 1. Open Obsidian → Manage vaults → Open folder as vault");
|
|
399
385
|
printEventDetail(` ${result.vaultPath}`);
|
|
400
|
-
printEventDetail(
|
|
401
|
-
printEventDetail(
|
|
402
|
-
|
|
403
|
-
printEventDetail(` 4. When ready for AI: cd "${result.vaultPath}" && opencode`);
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
printEventDetail(` 4. Set up AI: opencode auth login`);
|
|
407
|
-
printEventDetail(` 5. When ready: cd "${result.vaultPath}" && opencode`);
|
|
408
|
-
}
|
|
386
|
+
printEventDetail(" 2. Enable Obsidian CLI: Settings → General → Advanced → Command-line interface");
|
|
387
|
+
printEventDetail(' 3. Read "Start Here.md" for a quick orientation');
|
|
388
|
+
printEventDetail(" 4. Open the Agent Client panel and run /weave to connect your notes");
|
|
409
389
|
});
|
|
410
390
|
// ── byoao status ─────────────────────────────────────────────────
|
|
411
391
|
program
|
|
@@ -429,5 +409,121 @@ program
|
|
|
429
409
|
const status = checkObsidian();
|
|
430
410
|
console.log(formatObsidianStatus(status));
|
|
431
411
|
});
|
|
412
|
+
// ── byoao upgrade ────────────────────────────────────────────────
|
|
413
|
+
program
|
|
414
|
+
.command("upgrade")
|
|
415
|
+
.argument("[path]", "Path to vault root (default: detect from current directory)")
|
|
416
|
+
.description("Upgrade vault infrastructure to the latest BYOAO version — updates skills, " +
|
|
417
|
+
"commands, templates, and Obsidian config")
|
|
418
|
+
.option("-y, --yes", "Skip confirmation prompt", false)
|
|
419
|
+
.option("--dry-run", "Show upgrade plan without executing", false)
|
|
420
|
+
.option("--force", "Run even if versions match or on downgrade", false)
|
|
421
|
+
.option("--preset <name>", "Override preset during bootstrap (ignored if manifest exists)")
|
|
422
|
+
.action(async (vaultArg, opts) => {
|
|
423
|
+
printLogo();
|
|
424
|
+
printVersion(PKG_VERSION);
|
|
425
|
+
// 1. Detect vault
|
|
426
|
+
const targetPath = vaultArg ?? process.cwd();
|
|
427
|
+
const vaultRoot = detectVaultContext(targetPath);
|
|
428
|
+
if (!vaultRoot) {
|
|
429
|
+
printWarning("No BYOAO vault found. Run `byoao init` to create one.");
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
printEvent("Upgrading vault");
|
|
433
|
+
printEventDetail(`Vault: ${vaultRoot}`);
|
|
434
|
+
try {
|
|
435
|
+
// Try dry run first to show the plan
|
|
436
|
+
const preview = await upgradeVault(vaultRoot, {
|
|
437
|
+
preset: opts.preset,
|
|
438
|
+
dryRun: true,
|
|
439
|
+
force: opts.force,
|
|
440
|
+
});
|
|
441
|
+
// Up-to-date check
|
|
442
|
+
if (preview.added.length === 0 &&
|
|
443
|
+
preview.updated.length === 0 &&
|
|
444
|
+
preview.deprecated.length === 0) {
|
|
445
|
+
printEventDone(`Vault is already up to date at v${preview.toVersion}`);
|
|
446
|
+
if (!opts.force)
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
printEventDetail(`From v${preview.fromVersion} → v${preview.toVersion}`);
|
|
450
|
+
console.log();
|
|
451
|
+
// Show plan
|
|
452
|
+
printEvent("Upgrade plan");
|
|
453
|
+
for (const f of preview.added) {
|
|
454
|
+
printEventDetail(`+ ${path.basename(f)} (add → ${getCategoryLabel(f)})`);
|
|
455
|
+
}
|
|
456
|
+
for (const f of preview.updated) {
|
|
457
|
+
printEventDetail(`~ ${path.basename(f)} (update → ${getCategoryLabel(f)})`);
|
|
458
|
+
}
|
|
459
|
+
for (const f of preview.deprecated) {
|
|
460
|
+
printEventDetail(`○ ${path.basename(f)} (deprecated → ${getCategoryLabel(f)})`);
|
|
461
|
+
}
|
|
462
|
+
const total = preview.added.length + preview.updated.length + preview.deprecated.length;
|
|
463
|
+
console.log();
|
|
464
|
+
printEventDetail(`${total} changes (${preview.added.length} add, ${preview.updated.length} update, ${preview.deprecated.length} deprecated)`);
|
|
465
|
+
if (opts.dryRun)
|
|
466
|
+
return;
|
|
467
|
+
// Confirm
|
|
468
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
469
|
+
try {
|
|
470
|
+
const { default: inquirer } = await import("inquirer");
|
|
471
|
+
const { proceed } = await inquirer.prompt([{
|
|
472
|
+
type: "confirm",
|
|
473
|
+
name: "proceed",
|
|
474
|
+
message: "Proceed with upgrade?",
|
|
475
|
+
default: true,
|
|
476
|
+
}]);
|
|
477
|
+
if (!proceed) {
|
|
478
|
+
console.log("Cancelled.");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
// inquirer not available — proceed
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
console.log();
|
|
487
|
+
const spinner = startSpinner("Upgrading vault...");
|
|
488
|
+
const result = await upgradeVault(vaultRoot, {
|
|
489
|
+
preset: opts.preset,
|
|
490
|
+
force: opts.force,
|
|
491
|
+
});
|
|
492
|
+
spinner.stop("Upgrade complete");
|
|
493
|
+
if (result.added.length > 0) {
|
|
494
|
+
printEventCheck(`${result.added.length} files added`);
|
|
495
|
+
}
|
|
496
|
+
if (result.updated.length > 0) {
|
|
497
|
+
printEventCheck(`${result.updated.length} files updated`);
|
|
498
|
+
}
|
|
499
|
+
if (result.errors.length > 0) {
|
|
500
|
+
for (const e of result.errors) {
|
|
501
|
+
printWarning(`Failed: ${e.file} (${e.error})`);
|
|
502
|
+
}
|
|
503
|
+
printWarning("Re-run upgrade to retry failed files");
|
|
504
|
+
}
|
|
505
|
+
printEventCheck(`Manifest updated to v${result.toVersion}`);
|
|
506
|
+
console.log();
|
|
507
|
+
printEventDone("Done");
|
|
508
|
+
if (result.errors.length > 0)
|
|
509
|
+
process.exit(1);
|
|
510
|
+
}
|
|
511
|
+
catch (err) {
|
|
512
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
513
|
+
printWarning(msg);
|
|
514
|
+
process.exit(1);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
function getCategoryLabel(filePath) {
|
|
518
|
+
if (filePath.startsWith(".opencode/skills/"))
|
|
519
|
+
return "skills";
|
|
520
|
+
if (filePath.startsWith(".opencode/commands/"))
|
|
521
|
+
return "commands";
|
|
522
|
+
if (filePath.startsWith(".obsidian/"))
|
|
523
|
+
return "obsidian config";
|
|
524
|
+
if (filePath.startsWith("Knowledge/templates/"))
|
|
525
|
+
return "templates";
|
|
526
|
+
return "other";
|
|
527
|
+
}
|
|
432
528
|
program.parse();
|
|
433
529
|
//# sourceMappingURL=cli-program.js.map
|