@jayjiang/byoao 0.2.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 (76) hide show
  1. package/dist/cli/cli-program.js +241 -0
  2. package/dist/cli/cli-program.js.map +1 -0
  3. package/dist/cli/installer.js +226 -0
  4. package/dist/cli/installer.js.map +1 -0
  5. package/dist/cli/ui.js +157 -0
  6. package/dist/cli/ui.js.map +1 -0
  7. package/dist/hooks/idle-suggestions.js +14 -0
  8. package/dist/hooks/idle-suggestions.js.map +1 -0
  9. package/dist/hooks/system-transform.js +34 -0
  10. package/dist/hooks/system-transform.js.map +1 -0
  11. package/dist/index.js +43 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/plugin-config.js +57 -0
  14. package/dist/plugin-config.js.map +1 -0
  15. package/dist/tools/add-glossary-term.js +19 -0
  16. package/dist/tools/add-glossary-term.js.map +1 -0
  17. package/dist/tools/add-member.js +21 -0
  18. package/dist/tools/add-member.js.map +1 -0
  19. package/dist/tools/add-project.js +24 -0
  20. package/dist/tools/add-project.js.map +1 -0
  21. package/dist/tools/init-vault.js +82 -0
  22. package/dist/tools/init-vault.js.map +1 -0
  23. package/dist/tools/vault-doctor.js +38 -0
  24. package/dist/tools/vault-doctor.js.map +1 -0
  25. package/dist/tools/vault-status.js +18 -0
  26. package/dist/tools/vault-status.js.map +1 -0
  27. package/dist/vault/create.js +230 -0
  28. package/dist/vault/create.js.map +1 -0
  29. package/dist/vault/doctor.js +148 -0
  30. package/dist/vault/doctor.js.map +1 -0
  31. package/dist/vault/glossary.js +33 -0
  32. package/dist/vault/glossary.js.map +1 -0
  33. package/dist/vault/member.js +67 -0
  34. package/dist/vault/member.js.map +1 -0
  35. package/dist/vault/obsidian-check.js +125 -0
  36. package/dist/vault/obsidian-check.js.map +1 -0
  37. package/dist/vault/obsidian-cli.js +47 -0
  38. package/dist/vault/obsidian-cli.js.map +1 -0
  39. package/dist/vault/opencode-check.js +65 -0
  40. package/dist/vault/opencode-check.js.map +1 -0
  41. package/dist/vault/preset.js +48 -0
  42. package/dist/vault/preset.js.map +1 -0
  43. package/dist/vault/project.js +68 -0
  44. package/dist/vault/project.js.map +1 -0
  45. package/dist/vault/status.js +135 -0
  46. package/dist/vault/status.js.map +1 -0
  47. package/dist/vault/template.js +14 -0
  48. package/dist/vault/template.js.map +1 -0
  49. package/package.json +58 -0
  50. package/src/assets/obsidian-skills/defuddle.md +41 -0
  51. package/src/assets/obsidian-skills/json-canvas.md +244 -0
  52. package/src/assets/obsidian-skills/obsidian-bases.md +497 -0
  53. package/src/assets/obsidian-skills/obsidian-cli.md +106 -0
  54. package/src/assets/obsidian-skills/obsidian-markdown.md +196 -0
  55. package/src/assets/presets/common/AGENT.md.hbs +29 -0
  56. package/src/assets/presets/common/Glossary.md.hbs +44 -0
  57. package/src/assets/presets/common/Start Here.md.hbs +95 -0
  58. package/src/assets/presets/common/obsidian/core-plugins.json +33 -0
  59. package/src/assets/presets/common/obsidian/daily-notes.json +5 -0
  60. package/src/assets/presets/common/obsidian/templates.json +3 -0
  61. package/src/assets/presets/common/templates/Daily Note.md +19 -0
  62. package/src/assets/presets/common/templates/Decision Record.md +32 -0
  63. package/src/assets/presets/common/templates/Investigation.md +34 -0
  64. package/src/assets/presets/common/templates/Meeting Notes.md +25 -0
  65. package/src/assets/presets/pm-tpm/agent-section.hbs +15 -0
  66. package/src/assets/presets/pm-tpm/preset.json +12 -0
  67. package/src/assets/presets/pm-tpm/templates/Feature Doc.md +45 -0
  68. package/src/assets/presets/pm-tpm/templates/Sprint Handoff.md +38 -0
  69. package/src/assets/web-clipper/confluence-page.json +63 -0
  70. package/src/assets/web-clipper/general-article.json +53 -0
  71. package/src/assets/web-clipper/jira-issue.json +68 -0
  72. package/src/assets/web-clipper/meeting-notes.json +53 -0
  73. package/src/skills/enrich-document.md +52 -0
  74. package/src/skills/init-knowledge-base.md +85 -0
  75. package/src/skills/system-explainer.md +58 -0
  76. package/src/skills/vault-doctor.md +73 -0
@@ -0,0 +1,47 @@
1
+ import { execFileSync } from "node:child_process";
2
+ /**
3
+ * Check if the `obsidian` CLI is available in PATH.
4
+ */
5
+ export function isObsidianCliAvailable() {
6
+ try {
7
+ execFileSync("obsidian", ["--version"], { stdio: "pipe" });
8
+ return true;
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ }
14
+ /**
15
+ * Execute an Obsidian CLI command and return the result.
16
+ * Uses execFileSync (array form) to avoid shell injection.
17
+ * @param args - Command arguments (e.g., ["orphans", "--vault", "MyVault"])
18
+ */
19
+ export function execObsidianCmd(args) {
20
+ try {
21
+ const output = execFileSync("obsidian", args, {
22
+ stdio: "pipe",
23
+ encoding: "utf-8",
24
+ timeout: 10000,
25
+ });
26
+ return { success: true, output: output.trim() };
27
+ }
28
+ catch (err) {
29
+ const msg = err instanceof Error ? err.message : String(err);
30
+ return { success: false, output: "", error: msg };
31
+ }
32
+ }
33
+ /**
34
+ * Execute an Obsidian CLI command and parse JSON output.
35
+ */
36
+ export function execObsidianJson(args) {
37
+ const result = execObsidianCmd([...args, "format=json"]);
38
+ if (!result.success)
39
+ return null;
40
+ try {
41
+ return JSON.parse(result.output);
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ //# sourceMappingURL=obsidian-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian-cli.js","sourceRoot":"","sources":["../../src/vault/obsidian-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAQlD;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,IAAI,CAAC;QACH,YAAY,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,EAAE,IAAI,EAAE;YAC5C,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;IAClD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACpD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAc,IAAc;IAC1D,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAM,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { execSync } from "node:child_process";
2
+ import { platform } from "node:os";
3
+ export function checkOpenCode() {
4
+ const installCommands = getInstallCommands();
5
+ try {
6
+ const result = execSync("opencode version", {
7
+ timeout: 5000,
8
+ encoding: "utf-8",
9
+ stdio: ["pipe", "pipe", "pipe"],
10
+ }).trim();
11
+ return {
12
+ installed: true,
13
+ version: result || "unknown",
14
+ installCommands,
15
+ };
16
+ }
17
+ catch {
18
+ // Also try just checking if the binary exists
19
+ try {
20
+ execSync("which opencode", {
21
+ timeout: 3000,
22
+ encoding: "utf-8",
23
+ stdio: ["pipe", "pipe", "pipe"],
24
+ });
25
+ return { installed: true, version: "unknown", installCommands };
26
+ }
27
+ catch {
28
+ // Not installed
29
+ }
30
+ }
31
+ return { installed: false, version: null, installCommands };
32
+ }
33
+ function getInstallCommands() {
34
+ const os = platform();
35
+ const commands = [];
36
+ if (os === "darwin") {
37
+ commands.push({
38
+ label: "Homebrew",
39
+ command: "brew install opencode-ai/tap/opencode",
40
+ });
41
+ }
42
+ commands.push({
43
+ label: "curl (official installer)",
44
+ command: "curl -fsSL https://opencode.ai/install | bash",
45
+ });
46
+ commands.push({
47
+ label: "npm",
48
+ command: "npm install -g opencode-ai",
49
+ });
50
+ return commands;
51
+ }
52
+ export function formatOpenCodeStatus(status) {
53
+ if (status.installed) {
54
+ return `āœ“ OpenCode is installed (${status.version})`;
55
+ }
56
+ const lines = [
57
+ "āš ļø OpenCode is NOT installed.",
58
+ " Available install methods:",
59
+ ];
60
+ for (const cmd of status.installCommands) {
61
+ lines.push(` - ${cmd.label}: ${cmd.command}`);
62
+ }
63
+ return lines.join("\n");
64
+ }
65
+ //# sourceMappingURL=opencode-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-check.js","sourceRoot":"","sources":["../../src/vault/opencode-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQnC,MAAM,UAAU,aAAa;IAC3B,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAE7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,kBAAkB,EAAE;YAC1C,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,OAAO;YACL,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,MAAM,IAAI,SAAS;YAC5B,eAAe;SAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,8CAA8C;QAC9C,IAAI,CAAC;YACH,QAAQ,CAAC,gBAAgB,EAAE;gBACzB,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAChC,CAAC,CAAC;YACH,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,MAAM,QAAQ,GAAyC,EAAE,CAAC;IAE1D,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,uCAAuC;SACjD,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC;QACZ,KAAK,EAAE,2BAA2B;QAClC,OAAO,EAAE,+CAA+C;KACzD,CAAC,CAAC;IAEH,QAAQ,CAAC,IAAI,CAAC;QACZ,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,4BAA4B;KACtC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,4BAA4B,MAAM,CAAC,OAAO,GAAG,CAAC;IACvD,CAAC;IAED,MAAM,KAAK,GAAG;QACZ,+BAA+B;QAC/B,+BAA+B;KAChC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,48 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { PresetConfigSchema } from "../plugin-config.js";
4
+ function getPresetsDir() {
5
+ const srcPresets = path.resolve(import.meta.dirname, "..", "assets", "presets");
6
+ const distPresets = path.resolve(import.meta.dirname, "..", "..", "src", "assets", "presets");
7
+ if (fs.existsSync(srcPresets))
8
+ return srcPresets;
9
+ if (fs.existsSync(distPresets))
10
+ return distPresets;
11
+ throw new Error(`Cannot find presets directory. Looked in:\n ${srcPresets}\n ${distPresets}`);
12
+ }
13
+ export function listPresets() {
14
+ const presetsDir = getPresetsDir();
15
+ const entries = fs.readdirSync(presetsDir, { withFileTypes: true });
16
+ const presets = [];
17
+ for (const entry of entries) {
18
+ if (!entry.isDirectory() || entry.name === "common")
19
+ continue;
20
+ const configPath = path.join(presetsDir, entry.name, "preset.json");
21
+ if (!fs.existsSync(configPath))
22
+ continue;
23
+ const raw = fs.readJsonSync(configPath);
24
+ const parsed = PresetConfigSchema.parse(raw);
25
+ presets.push({
26
+ name: parsed.name,
27
+ displayName: parsed.displayName,
28
+ description: parsed.description,
29
+ });
30
+ }
31
+ return presets;
32
+ }
33
+ export function loadPreset(name) {
34
+ const presetsDir = getPresetsDir();
35
+ const presetDir = path.join(presetsDir, name);
36
+ const configPath = path.join(presetDir, "preset.json");
37
+ if (!fs.existsSync(configPath)) {
38
+ const available = listPresets().map((p) => p.name);
39
+ throw new Error(`Preset "${name}" not found. Available presets: ${available.join(", ")}`);
40
+ }
41
+ const raw = fs.readJsonSync(configPath);
42
+ const config = PresetConfigSchema.parse(raw);
43
+ return { config, presetsDir };
44
+ }
45
+ export function getCommonDir() {
46
+ return path.join(getPresetsDir(), "common");
47
+ }
48
+ //# sourceMappingURL=preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.js","sourceRoot":"","sources":["../../src/vault/preset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAqB,MAAM,qBAAqB,CAAC;AAE5E,SAAS,aAAa;IACpB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAChF,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAC5D,CAAC;IACF,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IACjD,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,WAAW,CAAC;IACnD,MAAM,IAAI,KAAK,CACb,gDAAgD,UAAU,OAAO,WAAW,EAAE,CAC/E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,OAAO,GAAiE,EAAE,CAAC;IAEjF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QACzC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IAIrC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAEvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,mCAAmC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzE,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,68 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { today } from "./template.js";
4
+ export async function addProject(input) {
5
+ const { vaultPath, name, description, team } = input;
6
+ let wikilinksAdded = 0;
7
+ // 1. Create project note
8
+ const projectPath = path.join(vaultPath, `10-Projects/${name}.md`);
9
+ if (await fs.pathExists(projectPath)) {
10
+ throw new Error(`Project note already exists: ${projectPath}`);
11
+ }
12
+ const content = `---
13
+ title: "${name}"
14
+ type: feature
15
+ status: active
16
+ date: ${today()}
17
+ team: "${team}"
18
+ jira: ""
19
+ stakeholders: []
20
+ priority: ""
21
+ tags: [project]
22
+ ---
23
+
24
+ # ${name}
25
+
26
+ ${description}
27
+ `;
28
+ await fs.writeFile(projectPath, content);
29
+ // 2. Update team index if it exists
30
+ const peoplePath = path.join(vaultPath, "40-People");
31
+ if (await fs.pathExists(peoplePath)) {
32
+ const teamFiles = await fs.readdir(peoplePath);
33
+ const teamIndexFile = teamFiles.find((f) => f.endsWith("Team.md"));
34
+ if (teamIndexFile) {
35
+ const teamIndexPath = path.join(peoplePath, teamIndexFile);
36
+ let teamContent = await fs.readFile(teamIndexPath, "utf-8");
37
+ const projectLine = `- [[${name}]] — ${description}`;
38
+ if (teamContent.includes("(No projects added yet)")) {
39
+ teamContent = teamContent.replace("(No projects added yet)", projectLine);
40
+ }
41
+ else if (teamContent.includes("## Active Projects")) {
42
+ // Append to the projects section
43
+ teamContent = teamContent.replace(/(## Active Projects\n\n)([\s\S]*?)(\n\n|$)/, `$1$2\n${projectLine}$3`);
44
+ }
45
+ wikilinksAdded++;
46
+ await fs.writeFile(teamIndexPath, teamContent);
47
+ }
48
+ }
49
+ // 3. Update AGENT.md wikilinks
50
+ for (const agentFile of ["AGENT.md", "CLAUDE.md"]) {
51
+ const agentPath = path.join(vaultPath, agentFile);
52
+ if (await fs.pathExists(agentPath)) {
53
+ let agentContent = await fs.readFile(agentPath, "utf-8");
54
+ const projectLine = `- [[${name}]] — ${description}`;
55
+ if (agentContent.includes("(No projects added yet")) {
56
+ agentContent = agentContent.replace(/\(No projects added yet[^)]*\)/, projectLine);
57
+ wikilinksAdded++;
58
+ }
59
+ else if (agentContent.includes("## Active Projects")) {
60
+ agentContent = agentContent.replace(/(## Active Projects[^\n]*\n\n)([\s\S]*?)(\n\n|$)/, `$1$2\n${projectLine}$3`);
61
+ wikilinksAdded++;
62
+ }
63
+ await fs.writeFile(agentPath, agentContent);
64
+ }
65
+ }
66
+ return { filePath: projectPath, wikilinksAdded };
67
+ }
68
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/vault/project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ async function countFilesInDir(dirPath, ext = ".md") {
4
+ if (!(await fs.pathExists(dirPath)))
5
+ return 0;
6
+ const files = await fs.readdir(dirPath);
7
+ return files.filter((f) => f.endsWith(ext)).length;
8
+ }
9
+ async function getAllMarkdownFiles(dirPath) {
10
+ const results = [];
11
+ async function walk(dir) {
12
+ if (!(await fs.pathExists(dir)))
13
+ return;
14
+ const entries = await fs.readdir(dir, { withFileTypes: true });
15
+ for (const entry of entries) {
16
+ const fullPath = path.join(dir, entry.name);
17
+ if (entry.isDirectory()) {
18
+ // Skip .obsidian and hidden dirs
19
+ if (!entry.name.startsWith(".")) {
20
+ await walk(fullPath);
21
+ }
22
+ }
23
+ else if (entry.name.endsWith(".md")) {
24
+ results.push(fullPath);
25
+ }
26
+ }
27
+ }
28
+ await walk(dirPath);
29
+ return results;
30
+ }
31
+ function extractWikilinks(content) {
32
+ // Strip code blocks and inline code before extracting wikilinks
33
+ const stripped = content
34
+ .replace(/```[\s\S]*?```/g, "") // fenced code blocks
35
+ .replace(/`[^`]+`/g, ""); // inline code
36
+ const matches = stripped.match(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g);
37
+ if (!matches)
38
+ return [];
39
+ return matches.map((m) => m.replace(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/, "$1"));
40
+ }
41
+ export async function getVaultStatus(vaultPath) {
42
+ const exists = await fs.pathExists(vaultPath);
43
+ if (!exists) {
44
+ return {
45
+ exists: false,
46
+ vaultPath,
47
+ noteCount: 0,
48
+ wikilinkCount: 0,
49
+ brokenLinks: [],
50
+ directories: {},
51
+ hasObsidianConfig: false,
52
+ hasAgentMd: false,
53
+ hasGlossary: false,
54
+ };
55
+ }
56
+ const allFiles = await getAllMarkdownFiles(vaultPath);
57
+ const noteNames = new Set(allFiles.map((f) => path.basename(f, ".md")));
58
+ // Count wikilinks and find broken ones
59
+ let wikilinkCount = 0;
60
+ const brokenLinksSet = new Set();
61
+ for (const file of allFiles) {
62
+ const content = await fs.readFile(file, "utf-8");
63
+ const links = extractWikilinks(content);
64
+ wikilinkCount += links.length;
65
+ for (const link of links) {
66
+ if (!noteNames.has(link)) {
67
+ brokenLinksSet.add(link);
68
+ }
69
+ }
70
+ }
71
+ // Count per directory
72
+ const directories = {};
73
+ const topDirs = [
74
+ "Inbox",
75
+ "Projects",
76
+ "Sprints",
77
+ "Knowledge",
78
+ "People",
79
+ "Systems",
80
+ "Archive",
81
+ "Daily",
82
+ ];
83
+ for (const dir of topDirs) {
84
+ const dirPath = path.join(vaultPath, dir);
85
+ if (await fs.pathExists(dirPath)) {
86
+ const files = await getAllMarkdownFiles(dirPath);
87
+ directories[dir] = files.length;
88
+ }
89
+ }
90
+ return {
91
+ exists: true,
92
+ vaultPath,
93
+ noteCount: allFiles.length,
94
+ wikilinkCount,
95
+ brokenLinks: Array.from(brokenLinksSet),
96
+ directories,
97
+ hasObsidianConfig: await fs.pathExists(path.join(vaultPath, ".obsidian")),
98
+ hasAgentMd: await fs.pathExists(path.join(vaultPath, "AGENT.md")),
99
+ hasGlossary: await fs.pathExists(path.join(vaultPath, "Knowledge/Glossary.md")),
100
+ };
101
+ }
102
+ export function formatVaultStatus(status) {
103
+ if (!status.exists) {
104
+ return `āŒ Vault not found at: ${status.vaultPath}`;
105
+ }
106
+ const lines = [
107
+ `šŸ“‚ Vault: ${status.vaultPath}`,
108
+ `šŸ“ Notes: ${status.noteCount}`,
109
+ `šŸ”— Wikilinks: ${status.wikilinkCount}`,
110
+ "",
111
+ "Directory breakdown:",
112
+ ];
113
+ for (const [dir, count] of Object.entries(status.directories)) {
114
+ lines.push(` ${dir}: ${count} notes`);
115
+ }
116
+ lines.push("");
117
+ lines.push(`Config: ${status.hasObsidianConfig ? "āœ“" : "āœ—"} .obsidian/`);
118
+ lines.push(`Agent: ${status.hasAgentMd ? "āœ“" : "āœ—"} AGENT.md`);
119
+ lines.push(`Glossary: ${status.hasGlossary ? "āœ“" : "āœ—"} Glossary.md`);
120
+ if (status.brokenLinks.length > 0) {
121
+ lines.push("");
122
+ lines.push(`āš ļø Broken links (${status.brokenLinks.length}):`);
123
+ for (const link of status.brokenLinks.slice(0, 10)) {
124
+ lines.push(` - [[${link}]]`);
125
+ }
126
+ if (status.brokenLinks.length > 10) {
127
+ lines.push(` ... and ${status.brokenLinks.length - 10} more`);
128
+ }
129
+ }
130
+ else {
131
+ lines.push("\nāœ“ No broken links");
132
+ }
133
+ return lines.join("\n");
134
+ }
135
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/vault/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import Handlebars from "handlebars";
2
+ const templateCache = new Map();
3
+ export function renderTemplate(templateStr, data) {
4
+ let compiled = templateCache.get(templateStr);
5
+ if (!compiled) {
6
+ compiled = Handlebars.compile(templateStr, { noEscape: true });
7
+ templateCache.set(templateStr, compiled);
8
+ }
9
+ return compiled(data);
10
+ }
11
+ export function today() {
12
+ return new Date().toISOString().slice(0, 10);
13
+ }
14
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/vault/template.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AAEpC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAsC,CAAC;AAEpE,MAAM,UAAU,cAAc,CAC5B,WAAmB,EACnB,IAA6B;IAE7B,IAAI,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@jayjiang/byoao",
3
+ "version": "0.2.0",
4
+ "description": "Build Your Own AI OS — Obsidian + AI Agent",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "byoao": "dist/cli/cli-program.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "node --import tsx src/cli/cli-program.ts",
14
+ "typecheck": "tsc --noEmit",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "files": [
18
+ "dist/",
19
+ "src/assets/",
20
+ "src/skills/"
21
+ ],
22
+ "keywords": [
23
+ "opencode",
24
+ "opencode-plugin",
25
+ "obsidian",
26
+ "knowledge-os",
27
+ "preset",
28
+ "knowledge-management"
29
+ ],
30
+ "license": "MIT",
31
+ "author": "Jay Jiang",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/JayJiangCT/BYOAO.git",
35
+ "directory": "byoao"
36
+ },
37
+ "homepage": "https://github.com/JayJiangCT/BYOAO#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/JayJiangCT/BYOAO/issues"
40
+ },
41
+ "dependencies": {
42
+ "@opencode-ai/plugin": "^1.2.24",
43
+ "chalk": "^5.0.0",
44
+ "commander": "^12.0.0",
45
+ "fs-extra": "^11.0.0",
46
+ "gray-matter": "^4.0.0",
47
+ "handlebars": "^4.7.0",
48
+ "inquirer": "^9.0.0",
49
+ "zod": "^3.23.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/fs-extra": "^11.0.0",
53
+ "@types/inquirer": "^9.0.0",
54
+ "@types/node": "^20.0.0",
55
+ "tsx": "^4.21.0",
56
+ "typescript": "^5.4.0"
57
+ }
58
+ }
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: defuddle
3
+ description: Extract clean markdown content from web pages using Defuddle CLI, removing clutter and navigation to save tokens. Use instead of WebFetch when the user provides a URL to read or analyze, for online documentation, articles, blog posts, or any standard web page.
4
+ ---
5
+
6
+ # Defuddle
7
+
8
+ Use Defuddle CLI to extract clean readable content from web pages. Prefer over WebFetch for standard web pages — it removes navigation, ads, and clutter, reducing token usage.
9
+
10
+ If not installed: `npm install -g defuddle`
11
+
12
+ ## Usage
13
+
14
+ Always use `--md` for markdown output:
15
+
16
+ ```bash
17
+ defuddle parse <url> --md
18
+ ```
19
+
20
+ Save to file:
21
+
22
+ ```bash
23
+ defuddle parse <url> --md -o content.md
24
+ ```
25
+
26
+ Extract specific metadata:
27
+
28
+ ```bash
29
+ defuddle parse <url> -p title
30
+ defuddle parse <url> -p description
31
+ defuddle parse <url> -p domain
32
+ ```
33
+
34
+ ## Output formats
35
+
36
+ | Flag | Format |
37
+ |------|--------|
38
+ | `--md` | Markdown (default choice) |
39
+ | `--json` | JSON with both HTML and markdown |
40
+ | (none) | HTML |
41
+ | `-p <name>` | Specific metadata property |