@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.
Files changed (61) hide show
  1. package/dist/__tests__/plugin-config.test.js +11 -8
  2. package/dist/__tests__/plugin-config.test.js.map +1 -1
  3. package/dist/cli/cli-program.js +253 -157
  4. package/dist/cli/cli-program.js.map +1 -1
  5. package/dist/cli/installer.js +4 -11
  6. package/dist/cli/installer.js.map +1 -1
  7. package/dist/hooks/idle-suggestions.js +3 -3
  8. package/dist/hooks/idle-suggestions.js.map +1 -1
  9. package/dist/hooks/system-transform.js +37 -14
  10. package/dist/hooks/system-transform.js.map +1 -1
  11. package/dist/index.js +4 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/plugin-config.js +5 -2
  14. package/dist/plugin-config.js.map +1 -1
  15. package/dist/tools/add-glossary-term.js +2 -0
  16. package/dist/tools/add-glossary-term.js.map +1 -1
  17. package/dist/tools/add-person.js +21 -0
  18. package/dist/tools/add-person.js.map +1 -0
  19. package/dist/tools/init-vault.js +11 -9
  20. package/dist/tools/init-vault.js.map +1 -1
  21. package/dist/tools/vault-upgrade.js +77 -0
  22. package/dist/tools/vault-upgrade.js.map +1 -0
  23. package/dist/vault/__tests__/create.test.js +105 -39
  24. package/dist/vault/__tests__/create.test.js.map +1 -1
  25. package/dist/vault/__tests__/glossary.test.js +25 -14
  26. package/dist/vault/__tests__/glossary.test.js.map +1 -1
  27. package/dist/vault/__tests__/manifest.test.js +76 -0
  28. package/dist/vault/__tests__/manifest.test.js.map +1 -0
  29. package/dist/vault/__tests__/member.test.js +2 -4
  30. package/dist/vault/__tests__/member.test.js.map +1 -1
  31. package/dist/vault/__tests__/upgrade.test.js +181 -0
  32. package/dist/vault/__tests__/upgrade.test.js.map +1 -0
  33. package/dist/vault/create.js +211 -146
  34. package/dist/vault/create.js.map +1 -1
  35. package/dist/vault/doctor.js +1 -1
  36. package/dist/vault/doctor.js.map +1 -1
  37. package/dist/vault/glossary.js +8 -14
  38. package/dist/vault/glossary.js.map +1 -1
  39. package/dist/vault/manifest.js +68 -0
  40. package/dist/vault/manifest.js.map +1 -0
  41. package/dist/vault/member.js +1 -1
  42. package/dist/vault/member.js.map +1 -1
  43. package/dist/vault/project.js +1 -1
  44. package/dist/vault/project.js.map +1 -1
  45. package/dist/vault/upgrade.js +266 -0
  46. package/dist/vault/upgrade.js.map +1 -0
  47. package/dist/vault/vault-detect.js +30 -0
  48. package/dist/vault/vault-detect.js.map +1 -1
  49. package/package.json +3 -1
  50. package/src/assets/presets/common/AGENT.md.hbs +34 -67
  51. package/src/assets/presets/common/Glossary.md.hbs +7 -35
  52. package/src/assets/presets/common/Start Here.md.hbs +32 -64
  53. package/src/assets/presets/minimal/preset.json +28 -0
  54. package/src/skills/{vault-doctor.md → diagnose.md} +12 -12
  55. package/src/skills/{system-explainer.md → explain.md} +8 -8
  56. package/src/skills/weave.md +240 -0
  57. package/src/assets/web-clipper/confluence-page.json +0 -63
  58. package/src/assets/web-clipper/general-article.json +0 -53
  59. package/src/assets/web-clipper/jira-issue.json +0 -68
  60. package/src/assets/web-clipper/meeting-notes.json +0 -53
  61. 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
- teamName: "MyTeam",
6
+ kbName: "My KB",
7
7
  vaultPath: "/tmp/vault",
8
8
  });
9
- expect(result.teamName).toBe("MyTeam");
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("pm-tpm");
14
+ expect(result.preset).toBe("minimal");
14
15
  });
15
- it("rejects missing teamName", () => {
16
+ it("rejects missing kbName", () => {
16
17
  expect(() => VaultConfigSchema.parse({ vaultPath: "/tmp" })).toThrow();
17
18
  });
18
- it("rejects empty teamName", () => {
19
- expect(() => VaultConfigSchema.parse({ teamName: "", vaultPath: "/tmp" })).toThrow();
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({ teamName: "Team" })).toThrow();
23
+ expect(() => VaultConfigSchema.parse({ kbName: "KB" })).toThrow();
23
24
  });
24
25
  it("validates full config", () => {
25
26
  const result = VaultConfigSchema.parse({
26
- teamName: "Alpha",
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":"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"}
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,MAAM,EAAE,OAAO;YACf,SAAS,EAAE,YAAY;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,GAAG,EAAE,CACV,iBAAiB,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAC/C,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,GAAG,EAAE,CACV,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAC3D,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,EAAE,CACV,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAC1C,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC;YACrC,MAAM,EAAE,UAAU;YAClB,SAAS,EAAE,OAAO;YAClB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACrC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;YACzB,eAAe,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;YACjD,QAAQ,EAAE,kBAAkB;YAC5B,WAAW,EAAE,MAAM;YACnB,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC;YACtC,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,aAAa;YAC1B,WAAW,EAAE,QAAQ;YACrB,gBAAgB,EAAE,YAAY;SAC/B,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC;YACtC,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,GAAG;YAChB,gBAAgB,EAAE,GAAG;YACrB,UAAU,EAAE;gBACV,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,kCAAkC;iBACxC;aACF;SACF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,GAAG,EAAE,CACV,kBAAkB,CAAC,KAAK,CAAC;YACvB,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,GAAG;YAChB,gBAAgB,EAAE,GAAG;YACrB,UAAU,EAAE;gBACV,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE;aAC1C;SACF,CAAC,CACH,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,GAAG,EAAE,CACV,kBAAkB,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAC3C,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC;YACtC,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,GAAG;YAChB,gBAAgB,EAAE,GAAG;YACrB,eAAe,EAAE;gBACf,uBAAuB,EAAE;oBACvB,IAAI,EAAE,+BAA+B;oBACrC,OAAO,EAAE,QAAQ;iBAClB;aACF;SACF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAC/D,+BAA+B,CAChC,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC;YACtC,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,GAAG;YAChB,gBAAgB,EAAE,GAAG;SACtB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC;YACtC,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,GAAG;YAChB,gBAAgB,EAAE,GAAG;YACrB,eAAe,EAAE;gBACf,WAAW,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;aACpC;SACF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,EAAE,CACV,kBAAkB,CAAC,KAAK,CAAC;YACvB,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,GAAG;YAChB,gBAAgB,EAAE,GAAG;YACrB,eAAe,EAAE;gBACf,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;aACpC;SACF,CAAC,CACH,CAAC,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -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
- const AUTH_COMMANDS = {
17
- copilot: { args: ["auth", "login", "-p", "github-copilot"] },
18
- gemini: {
19
- args: ["auth", "login", "-p", "google", "-m", "OAuth with Google (Gemini CLI)"],
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", cmd.args, {
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 new Obsidian knowledge base for your team — sets up folders, templates, " +
139
- "glossary, and an AI routing index (AGENT.md)")
140
- .option("--team <name>", "Team name (skips interactive prompt)")
141
- .option("--name <name>", "Your name — creates a person note (default: OS username in non-interactive mode)")
142
- .option("--path <path>", "Where to create the vault (default: ~/Documents/<team> Workspace)")
143
- .option("--preset <name>", "Role preset determines folder structure and templates (default: pm-tpm)")
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 teamName = opts.team;
155
- let vaultPath = opts.path;
156
- let presetName = opts.preset || "pm-tpm";
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 --team is not provided and stdout is TTY
159
- if (!teamName && process.stdout.isTTY) {
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
- printEvent("Creating a new knowledge base");
163
- console.log();
164
- // 1. Role selection
165
- const presets = listPresets();
166
- const { selectedPreset } = await inquirer.prompt([{
167
- type: "list",
168
- name: "selectedPreset",
169
- message: "Choose your role",
170
- choices: [
171
- ...presets.map(p => ({
172
- name: `${p.displayName}${p.description}`,
173
- value: p.name,
174
- })),
175
- new inquirer.Separator(),
176
- { name: "Engineer (coming soon)", disabled: true },
177
- { name: "Designer (coming soon)", disabled: true },
178
- ],
179
- }]);
180
- presetName = selectedPreset;
181
- // 2. Team name
182
- const teamAnswer = await inquirer.prompt([{
183
- type: "input",
184
- name: "teamName",
185
- message: "Team name:",
186
- validate: (v) => v.trim() ? true : "Team name is required",
187
- }]);
188
- teamName = teamAnswer.teamName;
189
- // 3. Your name (creates your own People note)
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
- if (yourName.trim()) {
197
- members.push({ name: yourName.trim(), role: presetName === "pm-tpm" ? "PM/TPM" : "Team Member" });
198
- }
199
- // 4. Vault path
200
- const defaultPath = path.join(os.homedir(), "Documents", `${teamName} Workspace`);
201
- const { pathChoice } = await inquirer.prompt([{
202
- type: "list",
203
- name: "pathChoice",
204
- message: "Vault location",
205
- choices: [
206
- { name: `Use default (${defaultPath})`, value: "default" },
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
- vaultPath = defaultPath;
211
- if (pathChoice === "custom") {
212
- const { customPath } = await inquirer.prompt([{
213
- type: "input",
214
- name: "customPath",
215
- message: "Custom path:",
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
- vaultPath = customPath;
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 --team
222
- if (!teamName) {
223
- console.error("Error: --team flag is required in non-interactive mode");
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 (!teamName) {
229
- console.error("Error: --team flag is required");
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 (members.length === 0) {
234
- const userName = opts.name || os.userInfo().username;
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", `${teamName} Workspace`);
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
- let gcpProjectOpt = opts.gcpProject || "";
271
+ const gcpProjectOpt = opts.gcpProject || "";
246
272
  const config = VaultConfigSchema.parse({
247
- teamName,
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 vault for "${teamName}"`);
282
+ const spinner = startSpinner(`Creating knowledge base "${kbName}"`);
256
283
  const result = await createVault(config);
257
- spinner.stop(`Vault created`);
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
- // ── Interactive Provider Prompt (TTY only, --provider not set) ──
325
- // This is a NEW inquirer session AFTER vault creation. No conflict
326
- // with the earlier prompts since those are already finished.
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 { selectedProvider } = await inquirer.prompt([{
333
- type: "list",
334
- name: "selectedProvider",
335
- message: "Set up AI provider (optional)",
336
- choices: [
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
- providerForAuth = selectedProvider;
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
- // ── Auth Spawn (both paths) ──────────────────────────────────
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("Authenticating with AI provider...");
387
- const authSuccess = await runProviderAuth(providerForAuth);
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
- getAuthCommand(providerForAuth));
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(' 2. Read "Start Here.md" it explains the vault structure');
401
- printEventDetail(" 3. Start adding notes meeting notes, project docs, daily notes");
402
- if (providerForAuth !== "skip") {
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