@weavelogic/knowledge-graph-agent 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -3
  3. package/dist/_virtual/__vite-browser-external.js +2 -2
  4. package/dist/_virtual/__vite-browser-external.js.map +1 -1
  5. package/dist/_virtual/index12.js +7 -0
  6. package/dist/_virtual/index12.js.map +1 -0
  7. package/dist/_virtual/ort-web.min.js +8 -0
  8. package/dist/_virtual/ort-web.min.js.map +1 -0
  9. package/dist/_virtual/ort-web.min2.js +5 -0
  10. package/dist/_virtual/ort-web.min2.js.map +1 -0
  11. package/dist/agents/base-agent.d.ts +63 -0
  12. package/dist/agents/base-agent.d.ts.map +1 -1
  13. package/dist/agents/base-agent.js +139 -0
  14. package/dist/agents/base-agent.js.map +1 -1
  15. package/dist/agents/coordinator-agent.d.ts +422 -0
  16. package/dist/agents/coordinator-agent.d.ts.map +1 -0
  17. package/dist/agents/documenter-agent.d.ts +298 -0
  18. package/dist/agents/documenter-agent.d.ts.map +1 -0
  19. package/dist/agents/index.d.ts +11 -1
  20. package/dist/agents/index.d.ts.map +1 -1
  21. package/dist/agents/index.js +4 -0
  22. package/dist/agents/index.js.map +1 -1
  23. package/dist/agents/mixins/index.d.ts +9 -0
  24. package/dist/agents/mixins/index.d.ts.map +1 -0
  25. package/dist/agents/mixins/trajectory-mixin.d.ts +112 -0
  26. package/dist/agents/mixins/trajectory-mixin.d.ts.map +1 -0
  27. package/dist/agents/optimizer-agent.d.ts +388 -0
  28. package/dist/agents/optimizer-agent.d.ts.map +1 -0
  29. package/dist/agents/planner-agent.d.ts +395 -0
  30. package/dist/agents/planner-agent.d.ts.map +1 -0
  31. package/dist/agents/registry.d.ts.map +1 -1
  32. package/dist/agents/registry.js +5 -0
  33. package/dist/agents/registry.js.map +1 -1
  34. package/dist/agents/reviewer-agent.d.ts +330 -0
  35. package/dist/agents/reviewer-agent.d.ts.map +1 -0
  36. package/dist/agents/types.d.ts +12 -1
  37. package/dist/agents/types.d.ts.map +1 -1
  38. package/dist/agents/types.js +1 -0
  39. package/dist/agents/types.js.map +1 -1
  40. package/dist/cli/commands/hive-mind/add-frontmatter.d.ts +102 -0
  41. package/dist/cli/commands/hive-mind/add-frontmatter.d.ts.map +1 -0
  42. package/dist/cli/commands/hive-mind/add-frontmatter.js +439 -0
  43. package/dist/cli/commands/hive-mind/add-frontmatter.js.map +1 -0
  44. package/dist/cli/commands/hive-mind/analyze-links.d.ts +80 -0
  45. package/dist/cli/commands/hive-mind/analyze-links.d.ts.map +1 -0
  46. package/dist/cli/commands/hive-mind/analyze-links.js +367 -0
  47. package/dist/cli/commands/hive-mind/analyze-links.js.map +1 -0
  48. package/dist/cli/commands/hive-mind/find-connections.d.ts +75 -0
  49. package/dist/cli/commands/hive-mind/find-connections.d.ts.map +1 -0
  50. package/dist/cli/commands/hive-mind/find-connections.js +347 -0
  51. package/dist/cli/commands/hive-mind/find-connections.js.map +1 -0
  52. package/dist/cli/commands/hive-mind/index.d.ts +37 -0
  53. package/dist/cli/commands/hive-mind/index.d.ts.map +1 -0
  54. package/dist/cli/commands/hive-mind/index.js +33 -0
  55. package/dist/cli/commands/hive-mind/index.js.map +1 -0
  56. package/dist/cli/commands/hive-mind/validate-names.d.ts +79 -0
  57. package/dist/cli/commands/hive-mind/validate-names.d.ts.map +1 -0
  58. package/dist/cli/commands/hive-mind/validate-names.js +353 -0
  59. package/dist/cli/commands/hive-mind/validate-names.js.map +1 -0
  60. package/dist/cli/commands/vector.js +2 -0
  61. package/dist/cli/commands/vector.js.map +1 -1
  62. package/dist/cli/index.d.ts.map +1 -1
  63. package/dist/cli/index.js +7 -0
  64. package/dist/cli/index.js.map +1 -1
  65. package/dist/equilibrium/agent-equilibrium.d.ts +194 -0
  66. package/dist/equilibrium/agent-equilibrium.d.ts.map +1 -0
  67. package/dist/equilibrium/agent-equilibrium.js +304 -0
  68. package/dist/equilibrium/agent-equilibrium.js.map +1 -0
  69. package/dist/equilibrium/graph-equilibrium.d.ts +177 -0
  70. package/dist/equilibrium/graph-equilibrium.d.ts.map +1 -0
  71. package/dist/equilibrium/index.d.ts +11 -0
  72. package/dist/equilibrium/index.d.ts.map +1 -0
  73. package/dist/equilibrium/memory-equilibrium.d.ts +153 -0
  74. package/dist/equilibrium/memory-equilibrium.d.ts.map +1 -0
  75. package/dist/graphql/resolvers/index.d.ts.map +1 -1
  76. package/dist/graphql/resolvers/queries.d.ts +11 -0
  77. package/dist/graphql/resolvers/queries.d.ts.map +1 -1
  78. package/dist/index.d.ts +2 -0
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +10 -4
  81. package/dist/index.js.map +1 -1
  82. package/dist/inference/index.d.ts +9 -0
  83. package/dist/inference/index.d.ts.map +1 -0
  84. package/dist/inference/model-selection.d.ts +131 -0
  85. package/dist/inference/model-selection.d.ts.map +1 -0
  86. package/dist/integrations/agentic-flow/adapters/agent-booster-adapter.d.ts +265 -0
  87. package/dist/integrations/agentic-flow/adapters/agent-booster-adapter.d.ts.map +1 -0
  88. package/dist/integrations/agentic-flow/adapters/agentdb-adapter.d.ts +197 -0
  89. package/dist/integrations/agentic-flow/adapters/agentdb-adapter.d.ts.map +1 -0
  90. package/dist/integrations/agentic-flow/adapters/agentdb-vector-store.d.ts +249 -0
  91. package/dist/integrations/agentic-flow/adapters/agentdb-vector-store.d.ts.map +1 -0
  92. package/dist/integrations/agentic-flow/adapters/base-adapter.d.ts +120 -0
  93. package/dist/integrations/agentic-flow/adapters/base-adapter.d.ts.map +1 -0
  94. package/dist/integrations/agentic-flow/adapters/federation-hub-adapter.d.ts +444 -0
  95. package/dist/integrations/agentic-flow/adapters/federation-hub-adapter.d.ts.map +1 -0
  96. package/dist/integrations/agentic-flow/adapters/index.d.ts +17 -0
  97. package/dist/integrations/agentic-flow/adapters/index.d.ts.map +1 -0
  98. package/dist/integrations/agentic-flow/adapters/model-router-adapter.d.ts +242 -0
  99. package/dist/integrations/agentic-flow/adapters/model-router-adapter.d.ts.map +1 -0
  100. package/dist/integrations/agentic-flow/adapters/quic-transport-adapter.d.ts +364 -0
  101. package/dist/integrations/agentic-flow/adapters/quic-transport-adapter.d.ts.map +1 -0
  102. package/dist/integrations/agentic-flow/adapters/reasoning-bank-adapter.d.ts +209 -0
  103. package/dist/integrations/agentic-flow/adapters/reasoning-bank-adapter.d.ts.map +1 -0
  104. package/dist/integrations/agentic-flow/benchmark/index.d.ts +9 -0
  105. package/dist/integrations/agentic-flow/benchmark/index.d.ts.map +1 -0
  106. package/dist/integrations/agentic-flow/benchmark/vector-benchmark.d.ts +253 -0
  107. package/dist/integrations/agentic-flow/benchmark/vector-benchmark.d.ts.map +1 -0
  108. package/dist/integrations/agentic-flow/config.d.ts +109 -0
  109. package/dist/integrations/agentic-flow/config.d.ts.map +1 -0
  110. package/dist/integrations/agentic-flow/feature-flags.d.ts +140 -0
  111. package/dist/integrations/agentic-flow/feature-flags.d.ts.map +1 -0
  112. package/dist/integrations/agentic-flow/index.d.ts +22 -0
  113. package/dist/integrations/agentic-flow/index.d.ts.map +1 -0
  114. package/dist/integrations/agentic-flow/migration/index.d.ts +9 -0
  115. package/dist/integrations/agentic-flow/migration/index.d.ts.map +1 -0
  116. package/dist/integrations/agentic-flow/migration/migrate-to-agentdb.d.ts +242 -0
  117. package/dist/integrations/agentic-flow/migration/migrate-to-agentdb.d.ts.map +1 -0
  118. package/dist/learning/index.d.ts +91 -0
  119. package/dist/learning/index.d.ts.map +1 -0
  120. package/dist/learning/learning-loop.d.ts +176 -0
  121. package/dist/learning/learning-loop.d.ts.map +1 -0
  122. package/dist/learning/services/ab-testing-framework.d.ts +135 -0
  123. package/dist/learning/services/ab-testing-framework.d.ts.map +1 -0
  124. package/dist/learning/services/agent-priming-service.d.ts +207 -0
  125. package/dist/learning/services/agent-priming-service.d.ts.map +1 -0
  126. package/dist/learning/services/daily-log-generator.d.ts +113 -0
  127. package/dist/learning/services/daily-log-generator.d.ts.map +1 -0
  128. package/dist/learning/services/index.d.ts +14 -0
  129. package/dist/learning/services/index.d.ts.map +1 -0
  130. package/dist/learning/services/memory-extraction-service.d.ts +87 -0
  131. package/dist/learning/services/memory-extraction-service.d.ts.map +1 -0
  132. package/dist/learning/services/task-completion-consumer.d.ts +162 -0
  133. package/dist/learning/services/task-completion-consumer.d.ts.map +1 -0
  134. package/dist/learning/services/trajectory-tracker.d.ts +174 -0
  135. package/dist/learning/services/trajectory-tracker.d.ts.map +1 -0
  136. package/dist/learning/types.d.ts +516 -0
  137. package/dist/learning/types.d.ts.map +1 -0
  138. package/dist/mcp/clients/claude-flow-memory-client.d.ts +259 -0
  139. package/dist/mcp/clients/claude-flow-memory-client.d.ts.map +1 -0
  140. package/dist/mcp/clients/claude-flow-memory-client.js +305 -0
  141. package/dist/mcp/clients/claude-flow-memory-client.js.map +1 -0
  142. package/dist/mcp/clients/index.d.ts +11 -0
  143. package/dist/mcp/clients/index.d.ts.map +1 -0
  144. package/dist/mcp/clients/mcp-client-adapter.d.ts +146 -0
  145. package/dist/mcp/clients/mcp-client-adapter.d.ts.map +1 -0
  146. package/dist/mcp/clients/mcp-client-adapter.js +372 -0
  147. package/dist/mcp/clients/mcp-client-adapter.js.map +1 -0
  148. package/dist/mcp/index.d.ts +10 -0
  149. package/dist/mcp/index.d.ts.map +1 -0
  150. package/dist/memory/vault-sync.d.ts +12 -0
  151. package/dist/memory/vault-sync.d.ts.map +1 -1
  152. package/dist/memory/vault-sync.js +94 -11
  153. package/dist/memory/vault-sync.js.map +1 -1
  154. package/dist/node_modules/@huggingface/jinja/dist/index.js +118 -0
  155. package/dist/node_modules/@huggingface/jinja/dist/index.js.map +1 -0
  156. package/dist/node_modules/@typescript-eslint/project-service/dist/index.js +1 -1
  157. package/dist/node_modules/@xenova/transformers/src/backends/onnx.js +24 -0
  158. package/dist/node_modules/@xenova/transformers/src/backends/onnx.js.map +1 -0
  159. package/dist/node_modules/@xenova/transformers/src/configs.js +52 -0
  160. package/dist/node_modules/@xenova/transformers/src/configs.js.map +1 -0
  161. package/dist/node_modules/@xenova/transformers/src/env.js +35 -0
  162. package/dist/node_modules/@xenova/transformers/src/env.js.map +1 -0
  163. package/dist/node_modules/@xenova/transformers/src/models.js +3852 -0
  164. package/dist/node_modules/@xenova/transformers/src/models.js.map +1 -0
  165. package/dist/node_modules/@xenova/transformers/src/tokenizers.js +144 -0
  166. package/dist/node_modules/@xenova/transformers/src/tokenizers.js.map +1 -0
  167. package/dist/node_modules/@xenova/transformers/src/utils/core.js +52 -0
  168. package/dist/node_modules/@xenova/transformers/src/utils/core.js.map +1 -0
  169. package/dist/node_modules/@xenova/transformers/src/utils/generation.js +623 -0
  170. package/dist/node_modules/@xenova/transformers/src/utils/generation.js.map +1 -0
  171. package/dist/node_modules/@xenova/transformers/src/utils/hub.js +395 -0
  172. package/dist/node_modules/@xenova/transformers/src/utils/hub.js.map +1 -0
  173. package/dist/node_modules/@xenova/transformers/src/utils/image.js +12 -0
  174. package/dist/node_modules/@xenova/transformers/src/utils/image.js.map +1 -0
  175. package/dist/node_modules/@xenova/transformers/src/utils/maths.js +89 -0
  176. package/dist/node_modules/@xenova/transformers/src/utils/maths.js.map +1 -0
  177. package/dist/node_modules/@xenova/transformers/src/utils/tensor.js +750 -0
  178. package/dist/node_modules/@xenova/transformers/src/utils/tensor.js.map +1 -0
  179. package/dist/node_modules/fdir/dist/index.js +13 -13
  180. package/dist/node_modules/fdir/dist/index.js.map +1 -1
  181. package/dist/node_modules/onnxruntime-common/dist/lib/backend-impl.js +67 -0
  182. package/dist/node_modules/onnxruntime-common/dist/lib/backend-impl.js.map +1 -0
  183. package/dist/node_modules/onnxruntime-common/dist/lib/env-impl.js +24 -0
  184. package/dist/node_modules/onnxruntime-common/dist/lib/env-impl.js.map +1 -0
  185. package/dist/node_modules/onnxruntime-common/dist/lib/env.js +6 -0
  186. package/dist/node_modules/onnxruntime-common/dist/lib/env.js.map +1 -0
  187. package/dist/node_modules/onnxruntime-common/dist/lib/index.js +11 -0
  188. package/dist/node_modules/onnxruntime-common/dist/lib/index.js.map +1 -0
  189. package/dist/node_modules/onnxruntime-common/dist/lib/inference-session-impl.js +162 -0
  190. package/dist/node_modules/onnxruntime-common/dist/lib/inference-session-impl.js.map +1 -0
  191. package/dist/node_modules/onnxruntime-common/dist/lib/inference-session.js +6 -0
  192. package/dist/node_modules/onnxruntime-common/dist/lib/inference-session.js.map +1 -0
  193. package/dist/node_modules/onnxruntime-common/dist/lib/tensor-impl.js +393 -0
  194. package/dist/node_modules/onnxruntime-common/dist/lib/tensor-impl.js.map +1 -0
  195. package/dist/node_modules/onnxruntime-common/dist/lib/tensor.js +6 -0
  196. package/dist/node_modules/onnxruntime-common/dist/lib/tensor.js.map +1 -0
  197. package/dist/node_modules/onnxruntime-web/dist/ort-web.min.js +12919 -0
  198. package/dist/node_modules/onnxruntime-web/dist/ort-web.min.js.map +1 -0
  199. package/dist/node_modules/tinyglobby/dist/index.js +14 -14
  200. package/dist/node_modules/tinyglobby/dist/index.js.map +1 -1
  201. package/dist/node_modules/typescript/lib/typescript.js +24 -24
  202. package/dist/node_modules/typescript/lib/typescript.js.map +1 -1
  203. package/dist/transport/agent-transport.d.ts +269 -0
  204. package/dist/transport/agent-transport.d.ts.map +1 -0
  205. package/dist/transport/index.d.ts +10 -0
  206. package/dist/transport/index.d.ts.map +1 -0
  207. package/dist/vector/index.d.ts +1 -1
  208. package/dist/vector/index.d.ts.map +1 -1
  209. package/dist/vector/services/embedding-service.d.ts +244 -0
  210. package/dist/vector/services/embedding-service.d.ts.map +1 -0
  211. package/dist/vector/services/embedding-service.js +10 -0
  212. package/dist/vector/services/embedding-service.js.map +1 -0
  213. package/dist/vector/services/hybrid-search.d.ts +320 -0
  214. package/dist/vector/services/hybrid-search.d.ts.map +1 -0
  215. package/dist/vector/services/hybrid-search.js +3 -0
  216. package/dist/vector/services/hybrid-search.js.map +1 -0
  217. package/dist/vector/services/index.d.ts +4 -0
  218. package/dist/vector/services/index.d.ts.map +1 -1
  219. package/package.json +10 -1
@@ -0,0 +1,439 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import * as path from "path";
4
+ import { writeFile, readFile } from "fs/promises";
5
+ import { glob } from "fast-glob";
6
+ import matter from "gray-matter";
7
+ import * as yaml from "js-yaml";
8
+ class FrontmatterEnricher {
9
+ /**
10
+ * Enrich frontmatter for all files in a vault
11
+ */
12
+ async enrichVault(vaultPath, options = {}) {
13
+ const resolvedPath = path.resolve(vaultPath);
14
+ const files = await glob("**/*.md", {
15
+ cwd: resolvedPath,
16
+ ignore: ["node_modules/**", ".git/**", "dist/**"],
17
+ absolute: false
18
+ });
19
+ if (files.length === 0) {
20
+ throw new Error(`No markdown files found in: ${resolvedPath}`);
21
+ }
22
+ const enriched = [];
23
+ const skipped = [];
24
+ const errors = [];
25
+ let tagsAdded = 0;
26
+ let aliasesAdded = 0;
27
+ let linksExtracted = 0;
28
+ for (const file of files) {
29
+ try {
30
+ const result = await this.enrichFile(
31
+ path.join(resolvedPath, file),
32
+ file,
33
+ options
34
+ );
35
+ if (result) {
36
+ enriched.push(result);
37
+ tagsAdded += result.frontmatter.tags.length;
38
+ aliasesAdded += result.frontmatter.aliases.length;
39
+ linksExtracted += result.frontmatter.links.length;
40
+ } else {
41
+ skipped.push(file);
42
+ }
43
+ } catch (error) {
44
+ errors.push({
45
+ file,
46
+ error: error instanceof Error ? error.message : "Unknown error"
47
+ });
48
+ }
49
+ }
50
+ return {
51
+ enriched,
52
+ skipped,
53
+ errors,
54
+ statistics: {
55
+ totalFiles: files.length,
56
+ enrichedCount: enriched.length,
57
+ skippedCount: skipped.length,
58
+ errorCount: errors.length,
59
+ tagsAdded,
60
+ aliasesAdded,
61
+ linksExtracted
62
+ }
63
+ };
64
+ }
65
+ /**
66
+ * Enrich a single file's frontmatter
67
+ */
68
+ async enrichFile(filePath, relativePath, options) {
69
+ const content = await readFile(filePath, "utf-8");
70
+ const parsed = matter(content);
71
+ const existingFm = parsed.data;
72
+ const hasExistingFm = Object.keys(existingFm).length > 0;
73
+ if (hasExistingFm && !options.overwrite) {
74
+ const needsTags = options.tags && (!existingFm.tags || existingFm.tags.length === 0);
75
+ const needsAliases = options.aliases && (!existingFm.aliases || existingFm.aliases.length === 0);
76
+ const needsLinks = options.links && (!existingFm.links || existingFm.links.length === 0);
77
+ if (!needsTags && !needsAliases && !needsLinks && existingFm.title) {
78
+ return null;
79
+ }
80
+ }
81
+ const metadata = this.extractMetadata(parsed.content, relativePath);
82
+ const added = [];
83
+ const updated = [];
84
+ const newFm = {
85
+ title: existingFm.title || metadata.title,
86
+ created: existingFm.created || metadata.created,
87
+ modified: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
88
+ tags: [],
89
+ aliases: [],
90
+ links: [],
91
+ type: existingFm.type || metadata.type,
92
+ status: existingFm.status || "active"
93
+ };
94
+ if (!existingFm.title) added.push("title");
95
+ if (!existingFm.created) added.push("created");
96
+ if (!existingFm.type) added.push("type");
97
+ if (!existingFm.status) added.push("status");
98
+ updated.push("modified");
99
+ if (options.tags !== false) {
100
+ const existingTags = existingFm.tags || [];
101
+ const extractedTags = metadata.tags;
102
+ const mergedTags = [.../* @__PURE__ */ new Set([...existingTags, ...extractedTags])];
103
+ newFm.tags = mergedTags;
104
+ const newTagCount = mergedTags.length - existingTags.length;
105
+ if (newTagCount > 0) added.push(`${newTagCount} tags`);
106
+ }
107
+ if (options.aliases !== false) {
108
+ const existingAliases = existingFm.aliases || [];
109
+ const extractedAliases = metadata.aliases;
110
+ const mergedAliases = [.../* @__PURE__ */ new Set([...existingAliases, ...extractedAliases])];
111
+ newFm.aliases = mergedAliases;
112
+ const newAliasCount = mergedAliases.length - existingAliases.length;
113
+ if (newAliasCount > 0) added.push(`${newAliasCount} aliases`);
114
+ }
115
+ if (options.links !== false) {
116
+ const existingLinks = existingFm.links || [];
117
+ const extractedLinks = metadata.links;
118
+ const mergedLinks = [.../* @__PURE__ */ new Set([...existingLinks, ...extractedLinks])];
119
+ newFm.links = mergedLinks;
120
+ const newLinkCount = mergedLinks.length - existingLinks.length;
121
+ if (newLinkCount > 0) added.push(`${newLinkCount} links`);
122
+ }
123
+ if (!existingFm.description && metadata.description) {
124
+ newFm.description = metadata.description;
125
+ added.push("description");
126
+ }
127
+ if (!options.dryRun) {
128
+ const newContent = this.buildMarkdownWithFrontmatter(newFm, parsed.content);
129
+ await writeFile(filePath, newContent);
130
+ }
131
+ return {
132
+ file: relativePath,
133
+ added,
134
+ updated,
135
+ frontmatter: newFm
136
+ };
137
+ }
138
+ /**
139
+ * Extract metadata from content and filename
140
+ */
141
+ extractMetadata(content, filename) {
142
+ const basename = path.basename(filename, ".md");
143
+ let title = basename;
144
+ const headingMatch = content.match(/^#\s+(.+)$/m);
145
+ if (headingMatch) {
146
+ title = headingMatch[1].trim();
147
+ }
148
+ const aliases = this.generateAliases(title, basename);
149
+ const tags = this.extractHashtags(content);
150
+ const type = this.inferType(content, basename);
151
+ const links = this.extractWikiLinks(content);
152
+ const description = this.extractDescription(content);
153
+ const created = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
154
+ return { title, created, type, tags, aliases, links, description };
155
+ }
156
+ /**
157
+ * Generate aliases from title
158
+ */
159
+ generateAliases(title, filename) {
160
+ const aliases = [];
161
+ const cleanFilename = filename.replace(/-/g, " ").toLowerCase();
162
+ const cleanTitle = title.toLowerCase();
163
+ if (cleanFilename !== cleanTitle) {
164
+ const readableFilename = filename.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
165
+ if (readableFilename !== title) {
166
+ aliases.push(readableFilename);
167
+ }
168
+ }
169
+ if (title !== title.toLowerCase() && !aliases.includes(title.toLowerCase())) {
170
+ aliases.push(title.toLowerCase());
171
+ }
172
+ const words = title.split(/\s+/);
173
+ if (words.length >= 2 && words.length <= 5) {
174
+ const acronym = words.map((w) => w[0]).filter((c) => c && /[A-Z]/.test(c)).join("");
175
+ if (acronym.length >= 2 && !aliases.includes(acronym)) {
176
+ aliases.push(acronym);
177
+ }
178
+ }
179
+ return aliases.slice(0, 5);
180
+ }
181
+ /**
182
+ * Extract hashtags from content
183
+ */
184
+ extractHashtags(content) {
185
+ const tags = /* @__PURE__ */ new Set();
186
+ const regex = /(?:^|\s)#([a-zA-Z][a-zA-Z0-9_-]*)/g;
187
+ let match;
188
+ while ((match = regex.exec(content)) !== null) {
189
+ const tag = match[1].toLowerCase();
190
+ if (tag.length > 1 && tag.length < 30) {
191
+ tags.add(tag);
192
+ }
193
+ }
194
+ const inferredTags = this.inferTagsFromContent(content);
195
+ for (const tag of inferredTags) {
196
+ tags.add(tag);
197
+ }
198
+ return Array.from(tags).slice(0, 10);
199
+ }
200
+ /**
201
+ * Infer tags from content analysis
202
+ */
203
+ inferTagsFromContent(content) {
204
+ const tags = [];
205
+ const lowerContent = content.toLowerCase();
206
+ const patterns = [
207
+ { pattern: /\b(api|endpoint|rest|graphql)\b/i, tag: "api" },
208
+ { pattern: /\b(database|sql|postgres|mysql|mongo)\b/i, tag: "database" },
209
+ { pattern: /\b(test|testing|jest|vitest|unittest)\b/i, tag: "testing" },
210
+ { pattern: /\b(docker|container|kubernetes|k8s)\b/i, tag: "devops" },
211
+ { pattern: /\b(security|auth|authentication|oauth)\b/i, tag: "security" },
212
+ { pattern: /\b(performance|optimization|cache)\b/i, tag: "performance" },
213
+ { pattern: /\b(react|vue|angular|frontend)\b/i, tag: "frontend" },
214
+ { pattern: /\b(node|express|backend|server)\b/i, tag: "backend" },
215
+ { pattern: /\b(typescript|javascript|python|rust)\b/i, tag: "programming" },
216
+ { pattern: /\b(guide|tutorial|howto|how-to)\b/i, tag: "guide" },
217
+ { pattern: /\b(architecture|design|pattern)\b/i, tag: "architecture" },
218
+ { pattern: /\b(config|configuration|setup)\b/i, tag: "configuration" }
219
+ ];
220
+ for (const { pattern, tag } of patterns) {
221
+ if (pattern.test(lowerContent)) {
222
+ tags.push(tag);
223
+ }
224
+ }
225
+ return tags;
226
+ }
227
+ /**
228
+ * Infer document type from content
229
+ */
230
+ inferType(content, filename) {
231
+ content.toLowerCase();
232
+ const lowerFilename = filename.toLowerCase();
233
+ if (lowerFilename.includes("readme") || lowerFilename.includes("index")) {
234
+ return "guide";
235
+ }
236
+ if (lowerFilename.includes("api") || lowerFilename.includes("endpoint")) {
237
+ return "technical";
238
+ }
239
+ if (lowerFilename.includes("standard") || lowerFilename.includes("convention")) {
240
+ return "standard";
241
+ }
242
+ if (/```[a-z]+\n/i.test(content)) {
243
+ return "technical";
244
+ }
245
+ if (/##\s*installation|##\s*getting started|##\s*usage/i.test(content)) {
246
+ return "guide";
247
+ }
248
+ if (/##\s*api|##\s*endpoints|##\s*methods/i.test(content)) {
249
+ return "technical";
250
+ }
251
+ if (/##\s*overview|##\s*introduction|##\s*background/i.test(content)) {
252
+ return "concept";
253
+ }
254
+ return "concept";
255
+ }
256
+ /**
257
+ * Extract wiki-links from content
258
+ */
259
+ extractWikiLinks(content) {
260
+ const links = /* @__PURE__ */ new Set();
261
+ const regex = /\[\[([^\]|#]+)(?:#[^\]|]*)?(?:\|[^\]]+)?\]\]/g;
262
+ let match;
263
+ while ((match = regex.exec(content)) !== null) {
264
+ const link = match[1].trim();
265
+ if (link) {
266
+ links.add(link);
267
+ }
268
+ }
269
+ return Array.from(links);
270
+ }
271
+ /**
272
+ * Extract first paragraph as description
273
+ */
274
+ extractDescription(content) {
275
+ const lines = content.split("\n");
276
+ let foundContent = false;
277
+ const paragraphLines = [];
278
+ for (const line of lines) {
279
+ const trimmed = line.trim();
280
+ if (!foundContent && !trimmed) continue;
281
+ if (trimmed.startsWith("#")) {
282
+ if (foundContent) break;
283
+ continue;
284
+ }
285
+ if (trimmed.startsWith("```")) continue;
286
+ if (trimmed) {
287
+ foundContent = true;
288
+ paragraphLines.push(trimmed);
289
+ } else if (foundContent) {
290
+ break;
291
+ }
292
+ }
293
+ const description = paragraphLines.join(" ").slice(0, 200);
294
+ return description || void 0;
295
+ }
296
+ /**
297
+ * Build markdown content with frontmatter
298
+ */
299
+ buildMarkdownWithFrontmatter(fm, content) {
300
+ const cleanFm = {};
301
+ if (fm.title) cleanFm.title = fm.title;
302
+ if (fm.description) cleanFm.description = fm.description;
303
+ if (fm.type) cleanFm.type = fm.type;
304
+ if (fm.status) cleanFm.status = fm.status;
305
+ if (fm.created) cleanFm.created = fm.created;
306
+ if (fm.modified) cleanFm.modified = fm.modified;
307
+ if (fm.tags && fm.tags.length > 0) cleanFm.tags = fm.tags;
308
+ if (fm.aliases && fm.aliases.length > 0) cleanFm.aliases = fm.aliases;
309
+ if (fm.links && fm.links.length > 0) cleanFm.links = fm.links;
310
+ const yamlStr = yaml.dump(cleanFm, {
311
+ lineWidth: -1,
312
+ quotingType: '"',
313
+ forceQuotes: false
314
+ });
315
+ return `---
316
+ ${yamlStr}---
317
+
318
+ ${content.trim()}
319
+ `;
320
+ }
321
+ /**
322
+ * Generate report
323
+ */
324
+ generateReport(result) {
325
+ const lines = [];
326
+ lines.push("# Frontmatter Enrichment Report\n");
327
+ lines.push(`Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
328
+ `);
329
+ lines.push("");
330
+ lines.push("## Summary\n");
331
+ lines.push(`| Metric | Value |`);
332
+ lines.push(`|--------|-------|`);
333
+ lines.push(`| Total Files | ${result.statistics.totalFiles} |`);
334
+ lines.push(`| Enriched | ${result.statistics.enrichedCount} |`);
335
+ lines.push(`| Skipped | ${result.statistics.skippedCount} |`);
336
+ lines.push(`| Errors | ${result.statistics.errorCount} |`);
337
+ lines.push(`| Tags Added | ${result.statistics.tagsAdded} |`);
338
+ lines.push(`| Aliases Added | ${result.statistics.aliasesAdded} |`);
339
+ lines.push(`| Links Extracted | ${result.statistics.linksExtracted} |`);
340
+ lines.push("");
341
+ if (result.enriched.length > 0) {
342
+ lines.push("## Enriched Files\n");
343
+ for (const { file, added } of result.enriched.slice(0, 50)) {
344
+ if (added.length > 0) {
345
+ lines.push(`- \`${file}\`: ${added.join(", ")}`);
346
+ }
347
+ }
348
+ if (result.enriched.length > 50) {
349
+ lines.push(`
350
+ *... and ${result.enriched.length - 50} more*`);
351
+ }
352
+ lines.push("");
353
+ }
354
+ if (result.errors.length > 0) {
355
+ lines.push("## Errors\n");
356
+ for (const { file, error } of result.errors) {
357
+ lines.push(`- \`${file}\`: ${error}`);
358
+ }
359
+ lines.push("");
360
+ }
361
+ return lines.join("\n");
362
+ }
363
+ }
364
+ function createAddFrontmatterCommand() {
365
+ const command = new Command("add-frontmatter").description("Add/enrich YAML frontmatter in markdown files").argument("<vault-path>", "Path to Obsidian vault or docs directory").option("--overwrite", "Overwrite existing frontmatter fields").option("--tags", "Auto-generate tags from content (default: true)").option("--no-tags", "Skip tag generation").option("--aliases", "Generate aliases from title (default: true)").option("--no-aliases", "Skip alias generation").option("--links", "Extract wiki-links to frontmatter (default: true)").option("--no-links", "Skip link extraction").option("--dry-run", "Preview changes without writing files").option("-o, --output <file>", "Output file for report").option("--json", "Output as JSON").option("-v, --verbose", "Show detailed output").action(async (vaultPath, options) => {
366
+ const enricher = new FrontmatterEnricher();
367
+ const mode = options.dryRun ? " (dry run)" : "";
368
+ console.log(chalk.cyan(`
369
+ Enriching frontmatter${mode}...
370
+ `));
371
+ try {
372
+ const result = await enricher.enrichVault(vaultPath, options);
373
+ if (options.json) {
374
+ if (options.output) {
375
+ await writeFile(options.output, JSON.stringify(result, null, 2));
376
+ console.log(chalk.green(`Results written to: ${options.output}`));
377
+ } else {
378
+ console.log(JSON.stringify(result, null, 2));
379
+ }
380
+ } else {
381
+ console.log(chalk.bold("Summary:"));
382
+ console.log(chalk.white(` Total Files: ${result.statistics.totalFiles}`));
383
+ console.log(chalk.green(` Enriched: ${result.statistics.enrichedCount}`));
384
+ console.log(chalk.gray(` Skipped: ${result.statistics.skippedCount}`));
385
+ if (result.statistics.errorCount > 0) {
386
+ console.log(chalk.red(` Errors: ${result.statistics.errorCount}`));
387
+ }
388
+ console.log("");
389
+ console.log(chalk.bold("Additions:"));
390
+ console.log(chalk.white(` Tags Added: ${result.statistics.tagsAdded}`));
391
+ console.log(chalk.white(` Aliases Added: ${result.statistics.aliasesAdded}`));
392
+ console.log(chalk.white(` Links Extracted: ${result.statistics.linksExtracted}`));
393
+ console.log("");
394
+ if (options.verbose && result.enriched.length > 0) {
395
+ console.log(chalk.bold("Enriched Files:"));
396
+ for (const { file, added } of result.enriched.slice(0, 20)) {
397
+ if (added.length > 0) {
398
+ console.log(chalk.green(` ${file}`));
399
+ console.log(chalk.gray(` Added: ${added.join(", ")}`));
400
+ }
401
+ }
402
+ if (result.enriched.length > 20) {
403
+ console.log(chalk.gray(` ... and ${result.enriched.length - 20} more`));
404
+ }
405
+ console.log("");
406
+ }
407
+ if (result.errors.length > 0) {
408
+ console.log(chalk.bold(chalk.red("Errors:")));
409
+ for (const { file, error } of result.errors.slice(0, 10)) {
410
+ console.log(chalk.red(` ${file}: ${error}`));
411
+ }
412
+ if (result.errors.length > 10) {
413
+ console.log(chalk.gray(` ... and ${result.errors.length - 10} more`));
414
+ }
415
+ console.log("");
416
+ }
417
+ if (options.output && !options.json) {
418
+ const report = enricher.generateReport(result);
419
+ await writeFile(options.output, report);
420
+ console.log(chalk.green(`Report written to: ${options.output}`));
421
+ }
422
+ if (options.dryRun) {
423
+ console.log(chalk.yellow("Dry run complete - no files were modified."));
424
+ console.log(chalk.gray("Remove --dry-run to apply changes.\n"));
425
+ }
426
+ }
427
+ } catch (error) {
428
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
429
+ process.exit(1);
430
+ }
431
+ });
432
+ return command;
433
+ }
434
+ export {
435
+ FrontmatterEnricher,
436
+ createAddFrontmatterCommand,
437
+ createAddFrontmatterCommand as default
438
+ };
439
+ //# sourceMappingURL=add-frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-frontmatter.js","sources":["../../../../src/cli/commands/hive-mind/add-frontmatter.ts"],"sourcesContent":["/**\n * Hive Mind - Frontmatter Enricher\n *\n * Adds or enriches YAML frontmatter in markdown files to improve discoverability\n * and enable better linking between documents.\n *\n * SPEC-003: Hive Mind Reconnection Tools\n */\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport * as path from 'path';\nimport { readFile, writeFile } from 'fs/promises';\nimport { glob } from 'fast-glob';\nimport matter from 'gray-matter';\nimport * as yaml from 'js-yaml';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EnrichOptions {\n overwrite?: boolean;\n tags?: boolean;\n aliases?: boolean;\n links?: boolean;\n dryRun?: boolean;\n output?: string;\n json?: boolean;\n verbose?: boolean;\n}\n\nexport interface FrontmatterTemplate {\n title: string;\n created: string;\n modified: string;\n tags: string[];\n aliases: string[];\n links: string[];\n type: string;\n status: string;\n description?: string;\n}\n\nexport interface EnrichedFile {\n file: string;\n added: string[];\n updated: string[];\n frontmatter: FrontmatterTemplate;\n}\n\nexport interface EnrichResult {\n enriched: EnrichedFile[];\n skipped: string[];\n errors: Array<{ file: string; error: string }>;\n statistics: {\n totalFiles: number;\n enrichedCount: number;\n skippedCount: number;\n errorCount: number;\n tagsAdded: number;\n aliasesAdded: number;\n linksExtracted: number;\n };\n}\n\n// ============================================================================\n// Frontmatter Enricher Class\n// ============================================================================\n\nexport class FrontmatterEnricher {\n /**\n * Enrich frontmatter for all files in a vault\n */\n async enrichVault(vaultPath: string, options: EnrichOptions = {}): Promise<EnrichResult> {\n const resolvedPath = path.resolve(vaultPath);\n\n // Find all markdown files\n const files = await glob('**/*.md', {\n cwd: resolvedPath,\n ignore: ['node_modules/**', '.git/**', 'dist/**'],\n absolute: false,\n });\n\n if (files.length === 0) {\n throw new Error(`No markdown files found in: ${resolvedPath}`);\n }\n\n const enriched: EnrichedFile[] = [];\n const skipped: string[] = [];\n const errors: Array<{ file: string; error: string }> = [];\n let tagsAdded = 0;\n let aliasesAdded = 0;\n let linksExtracted = 0;\n\n for (const file of files) {\n try {\n const result = await this.enrichFile(\n path.join(resolvedPath, file),\n file,\n options\n );\n\n if (result) {\n enriched.push(result);\n tagsAdded += result.frontmatter.tags.length;\n aliasesAdded += result.frontmatter.aliases.length;\n linksExtracted += result.frontmatter.links.length;\n } else {\n skipped.push(file);\n }\n } catch (error) {\n errors.push({\n file,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n\n return {\n enriched,\n skipped,\n errors,\n statistics: {\n totalFiles: files.length,\n enrichedCount: enriched.length,\n skippedCount: skipped.length,\n errorCount: errors.length,\n tagsAdded,\n aliasesAdded,\n linksExtracted,\n },\n };\n }\n\n /**\n * Enrich a single file's frontmatter\n */\n async enrichFile(\n filePath: string,\n relativePath: string,\n options: EnrichOptions\n ): Promise<EnrichedFile | null> {\n const content = await readFile(filePath, 'utf-8');\n const parsed = matter(content);\n\n const existingFm = parsed.data as Partial<FrontmatterTemplate>;\n const hasExistingFm = Object.keys(existingFm).length > 0;\n\n // Skip if has frontmatter and not overwriting\n if (hasExistingFm && !options.overwrite) {\n // Check if we need to add anything\n const needsTags = options.tags && (!existingFm.tags || existingFm.tags.length === 0);\n const needsAliases = options.aliases && (!existingFm.aliases || existingFm.aliases.length === 0);\n const needsLinks = options.links && (!existingFm.links || existingFm.links.length === 0);\n\n if (!needsTags && !needsAliases && !needsLinks && existingFm.title) {\n return null;\n }\n }\n\n // Extract metadata from content\n const metadata = this.extractMetadata(parsed.content, relativePath);\n\n // Build new frontmatter\n const added: string[] = [];\n const updated: string[] = [];\n const newFm: FrontmatterTemplate = {\n title: existingFm.title || metadata.title,\n created: existingFm.created || metadata.created,\n modified: new Date().toISOString().split('T')[0],\n tags: [],\n aliases: [],\n links: [],\n type: existingFm.type || metadata.type,\n status: existingFm.status || 'active',\n };\n\n // Track what was added/updated\n if (!existingFm.title) added.push('title');\n if (!existingFm.created) added.push('created');\n if (!existingFm.type) added.push('type');\n if (!existingFm.status) added.push('status');\n updated.push('modified');\n\n // Handle tags\n if (options.tags !== false) {\n const existingTags = existingFm.tags || [];\n const extractedTags = metadata.tags;\n const mergedTags = [...new Set([...existingTags, ...extractedTags])];\n newFm.tags = mergedTags;\n\n const newTagCount = mergedTags.length - existingTags.length;\n if (newTagCount > 0) added.push(`${newTagCount} tags`);\n }\n\n // Handle aliases\n if (options.aliases !== false) {\n const existingAliases = existingFm.aliases || [];\n const extractedAliases = metadata.aliases;\n const mergedAliases = [...new Set([...existingAliases, ...extractedAliases])];\n newFm.aliases = mergedAliases;\n\n const newAliasCount = mergedAliases.length - existingAliases.length;\n if (newAliasCount > 0) added.push(`${newAliasCount} aliases`);\n }\n\n // Handle links\n if (options.links !== false) {\n const existingLinks = existingFm.links || [];\n const extractedLinks = metadata.links;\n const mergedLinks = [...new Set([...existingLinks, ...extractedLinks])];\n newFm.links = mergedLinks;\n\n const newLinkCount = mergedLinks.length - existingLinks.length;\n if (newLinkCount > 0) added.push(`${newLinkCount} links`);\n }\n\n // Add description if missing\n if (!existingFm.description && metadata.description) {\n newFm.description = metadata.description;\n added.push('description');\n }\n\n // Write file if not dry run\n if (!options.dryRun) {\n const newContent = this.buildMarkdownWithFrontmatter(newFm, parsed.content);\n await writeFile(filePath, newContent);\n }\n\n return {\n file: relativePath,\n added,\n updated,\n frontmatter: newFm,\n };\n }\n\n /**\n * Extract metadata from content and filename\n */\n private extractMetadata(content: string, filename: string): {\n title: string;\n created: string;\n type: string;\n tags: string[];\n aliases: string[];\n links: string[];\n description?: string;\n } {\n const basename = path.basename(filename, '.md');\n\n // Extract title from first heading or filename\n let title = basename;\n const headingMatch = content.match(/^#\\s+(.+)$/m);\n if (headingMatch) {\n title = headingMatch[1].trim();\n }\n\n // Generate aliases from title variations\n const aliases = this.generateAliases(title, basename);\n\n // Extract tags from hashtags in content\n const tags = this.extractHashtags(content);\n\n // Infer type from content and filename\n const type = this.inferType(content, basename);\n\n // Extract wiki-links\n const links = this.extractWikiLinks(content);\n\n // Extract first paragraph as description\n const description = this.extractDescription(content);\n\n // Use current date for created\n const created = new Date().toISOString().split('T')[0];\n\n return { title, created, type, tags, aliases, links, description };\n }\n\n /**\n * Generate aliases from title\n */\n private generateAliases(title: string, filename: string): string[] {\n const aliases: string[] = [];\n\n // Add filename if different from title\n const cleanFilename = filename.replace(/-/g, ' ').toLowerCase();\n const cleanTitle = title.toLowerCase();\n if (cleanFilename !== cleanTitle) {\n // Convert filename to readable form\n const readableFilename = filename\n .replace(/-/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase());\n if (readableFilename !== title) {\n aliases.push(readableFilename);\n }\n }\n\n // Add lowercase version if title has caps\n if (title !== title.toLowerCase() && !aliases.includes(title.toLowerCase())) {\n aliases.push(title.toLowerCase());\n }\n\n // Add acronym if title has multiple words\n const words = title.split(/\\s+/);\n if (words.length >= 2 && words.length <= 5) {\n const acronym = words\n .map(w => w[0])\n .filter(c => c && /[A-Z]/.test(c))\n .join('');\n if (acronym.length >= 2 && !aliases.includes(acronym)) {\n aliases.push(acronym);\n }\n }\n\n return aliases.slice(0, 5); // Limit to 5 aliases\n }\n\n /**\n * Extract hashtags from content\n */\n private extractHashtags(content: string): string[] {\n const tags = new Set<string>();\n\n // Match #tag patterns (but not #headings)\n const regex = /(?:^|\\s)#([a-zA-Z][a-zA-Z0-9_-]*)/g;\n let match;\n\n while ((match = regex.exec(content)) !== null) {\n const tag = match[1].toLowerCase();\n if (tag.length > 1 && tag.length < 30) {\n tags.add(tag);\n }\n }\n\n // Also infer tags from content keywords\n const inferredTags = this.inferTagsFromContent(content);\n for (const tag of inferredTags) {\n tags.add(tag);\n }\n\n return Array.from(tags).slice(0, 10); // Limit to 10 tags\n }\n\n /**\n * Infer tags from content analysis\n */\n private inferTagsFromContent(content: string): string[] {\n const tags: string[] = [];\n const lowerContent = content.toLowerCase();\n\n // Common topic patterns\n const patterns: Array<{ pattern: RegExp; tag: string }> = [\n { pattern: /\\b(api|endpoint|rest|graphql)\\b/i, tag: 'api' },\n { pattern: /\\b(database|sql|postgres|mysql|mongo)\\b/i, tag: 'database' },\n { pattern: /\\b(test|testing|jest|vitest|unittest)\\b/i, tag: 'testing' },\n { pattern: /\\b(docker|container|kubernetes|k8s)\\b/i, tag: 'devops' },\n { pattern: /\\b(security|auth|authentication|oauth)\\b/i, tag: 'security' },\n { pattern: /\\b(performance|optimization|cache)\\b/i, tag: 'performance' },\n { pattern: /\\b(react|vue|angular|frontend)\\b/i, tag: 'frontend' },\n { pattern: /\\b(node|express|backend|server)\\b/i, tag: 'backend' },\n { pattern: /\\b(typescript|javascript|python|rust)\\b/i, tag: 'programming' },\n { pattern: /\\b(guide|tutorial|howto|how-to)\\b/i, tag: 'guide' },\n { pattern: /\\b(architecture|design|pattern)\\b/i, tag: 'architecture' },\n { pattern: /\\b(config|configuration|setup)\\b/i, tag: 'configuration' },\n ];\n\n for (const { pattern, tag } of patterns) {\n if (pattern.test(lowerContent)) {\n tags.push(tag);\n }\n }\n\n return tags;\n }\n\n /**\n * Infer document type from content\n */\n private inferType(content: string, filename: string): string {\n const lowerContent = content.toLowerCase();\n const lowerFilename = filename.toLowerCase();\n\n // Check filename patterns\n if (lowerFilename.includes('readme') || lowerFilename.includes('index')) {\n return 'guide';\n }\n if (lowerFilename.includes('api') || lowerFilename.includes('endpoint')) {\n return 'technical';\n }\n if (lowerFilename.includes('standard') || lowerFilename.includes('convention')) {\n return 'standard';\n }\n\n // Check content patterns\n if (/```[a-z]+\\n/i.test(content)) {\n return 'technical';\n }\n if (/##\\s*installation|##\\s*getting started|##\\s*usage/i.test(content)) {\n return 'guide';\n }\n if (/##\\s*api|##\\s*endpoints|##\\s*methods/i.test(content)) {\n return 'technical';\n }\n if (/##\\s*overview|##\\s*introduction|##\\s*background/i.test(content)) {\n return 'concept';\n }\n\n return 'concept'; // Default type\n }\n\n /**\n * Extract wiki-links from content\n */\n private extractWikiLinks(content: string): string[] {\n const links = new Set<string>();\n const regex = /\\[\\[([^\\]|#]+)(?:#[^\\]|]*)?(?:\\|[^\\]]+)?\\]\\]/g;\n let match;\n\n while ((match = regex.exec(content)) !== null) {\n const link = match[1].trim();\n if (link) {\n links.add(link);\n }\n }\n\n return Array.from(links);\n }\n\n /**\n * Extract first paragraph as description\n */\n private extractDescription(content: string): string | undefined {\n // Skip headings and find first paragraph\n const lines = content.split('\\n');\n let foundContent = false;\n const paragraphLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines at start\n if (!foundContent && !trimmed) continue;\n\n // Skip headings\n if (trimmed.startsWith('#')) {\n if (foundContent) break;\n continue;\n }\n\n // Skip code blocks\n if (trimmed.startsWith('```')) continue;\n\n // Found content\n if (trimmed) {\n foundContent = true;\n paragraphLines.push(trimmed);\n } else if (foundContent) {\n // End of paragraph\n break;\n }\n }\n\n const description = paragraphLines.join(' ').slice(0, 200);\n return description || undefined;\n }\n\n /**\n * Build markdown content with frontmatter\n */\n private buildMarkdownWithFrontmatter(fm: FrontmatterTemplate, content: string): string {\n // Clean frontmatter - remove empty arrays and undefined values\n const cleanFm: Record<string, unknown> = {};\n\n if (fm.title) cleanFm.title = fm.title;\n if (fm.description) cleanFm.description = fm.description;\n if (fm.type) cleanFm.type = fm.type;\n if (fm.status) cleanFm.status = fm.status;\n if (fm.created) cleanFm.created = fm.created;\n if (fm.modified) cleanFm.modified = fm.modified;\n if (fm.tags && fm.tags.length > 0) cleanFm.tags = fm.tags;\n if (fm.aliases && fm.aliases.length > 0) cleanFm.aliases = fm.aliases;\n if (fm.links && fm.links.length > 0) cleanFm.links = fm.links;\n\n const yamlStr = yaml.dump(cleanFm, {\n lineWidth: -1,\n quotingType: '\"',\n forceQuotes: false,\n });\n\n return `---\\n${yamlStr}---\\n\\n${content.trim()}\\n`;\n }\n\n /**\n * Generate report\n */\n generateReport(result: EnrichResult): string {\n const lines: string[] = [];\n\n lines.push('# Frontmatter Enrichment Report\\n');\n lines.push(`Generated: ${new Date().toISOString()}\\n`);\n lines.push('');\n\n lines.push('## Summary\\n');\n lines.push(`| Metric | Value |`);\n lines.push(`|--------|-------|`);\n lines.push(`| Total Files | ${result.statistics.totalFiles} |`);\n lines.push(`| Enriched | ${result.statistics.enrichedCount} |`);\n lines.push(`| Skipped | ${result.statistics.skippedCount} |`);\n lines.push(`| Errors | ${result.statistics.errorCount} |`);\n lines.push(`| Tags Added | ${result.statistics.tagsAdded} |`);\n lines.push(`| Aliases Added | ${result.statistics.aliasesAdded} |`);\n lines.push(`| Links Extracted | ${result.statistics.linksExtracted} |`);\n lines.push('');\n\n if (result.enriched.length > 0) {\n lines.push('## Enriched Files\\n');\n for (const { file, added } of result.enriched.slice(0, 50)) {\n if (added.length > 0) {\n lines.push(`- \\`${file}\\`: ${added.join(', ')}`);\n }\n }\n if (result.enriched.length > 50) {\n lines.push(`\\n*... and ${result.enriched.length - 50} more*`);\n }\n lines.push('');\n }\n\n if (result.errors.length > 0) {\n lines.push('## Errors\\n');\n for (const { file, error } of result.errors) {\n lines.push(`- \\`${file}\\`: ${error}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n}\n\n// ============================================================================\n// CLI Command\n// ============================================================================\n\nexport function createAddFrontmatterCommand(): Command {\n const command = new Command('add-frontmatter')\n .description('Add/enrich YAML frontmatter in markdown files')\n .argument('<vault-path>', 'Path to Obsidian vault or docs directory')\n .option('--overwrite', 'Overwrite existing frontmatter fields')\n .option('--tags', 'Auto-generate tags from content (default: true)')\n .option('--no-tags', 'Skip tag generation')\n .option('--aliases', 'Generate aliases from title (default: true)')\n .option('--no-aliases', 'Skip alias generation')\n .option('--links', 'Extract wiki-links to frontmatter (default: true)')\n .option('--no-links', 'Skip link extraction')\n .option('--dry-run', 'Preview changes without writing files')\n .option('-o, --output <file>', 'Output file for report')\n .option('--json', 'Output as JSON')\n .option('-v, --verbose', 'Show detailed output')\n .action(async (vaultPath: string, options: EnrichOptions) => {\n const enricher = new FrontmatterEnricher();\n\n const mode = options.dryRun ? ' (dry run)' : '';\n console.log(chalk.cyan(`\\nEnriching frontmatter${mode}...\\n`));\n\n try {\n const result = await enricher.enrichVault(vaultPath, options);\n\n if (options.json) {\n if (options.output) {\n await writeFile(options.output, JSON.stringify(result, null, 2));\n console.log(chalk.green(`Results written to: ${options.output}`));\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n } else {\n // Display summary\n console.log(chalk.bold('Summary:'));\n console.log(chalk.white(` Total Files: ${result.statistics.totalFiles}`));\n console.log(chalk.green(` Enriched: ${result.statistics.enrichedCount}`));\n console.log(chalk.gray(` Skipped: ${result.statistics.skippedCount}`));\n if (result.statistics.errorCount > 0) {\n console.log(chalk.red(` Errors: ${result.statistics.errorCount}`));\n }\n console.log('');\n\n console.log(chalk.bold('Additions:'));\n console.log(chalk.white(` Tags Added: ${result.statistics.tagsAdded}`));\n console.log(chalk.white(` Aliases Added: ${result.statistics.aliasesAdded}`));\n console.log(chalk.white(` Links Extracted: ${result.statistics.linksExtracted}`));\n console.log('');\n\n if (options.verbose && result.enriched.length > 0) {\n console.log(chalk.bold('Enriched Files:'));\n for (const { file, added } of result.enriched.slice(0, 20)) {\n if (added.length > 0) {\n console.log(chalk.green(` ${file}`));\n console.log(chalk.gray(` Added: ${added.join(', ')}`));\n }\n }\n if (result.enriched.length > 20) {\n console.log(chalk.gray(` ... and ${result.enriched.length - 20} more`));\n }\n console.log('');\n }\n\n if (result.errors.length > 0) {\n console.log(chalk.bold(chalk.red('Errors:')));\n for (const { file, error } of result.errors.slice(0, 10)) {\n console.log(chalk.red(` ${file}: ${error}`));\n }\n if (result.errors.length > 10) {\n console.log(chalk.gray(` ... and ${result.errors.length - 10} more`));\n }\n console.log('');\n }\n\n // Write report if output specified\n if (options.output && !options.json) {\n const report = enricher.generateReport(result);\n await writeFile(options.output, report);\n console.log(chalk.green(`Report written to: ${options.output}`));\n }\n\n // Show dry-run notice\n if (options.dryRun) {\n console.log(chalk.yellow('Dry run complete - no files were modified.'));\n console.log(chalk.gray('Remove --dry-run to apply changes.\\n'));\n }\n }\n } catch (error) {\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n\n return command;\n}\n\nexport default createAddFrontmatterCommand;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Hive Mind - Link Analyzer
3
+ *
4
+ * Analyzes wiki-links and markdown links in a vault to build an adjacency list
5
+ * and identify orphan files.
6
+ *
7
+ * SPEC-003: Hive Mind Reconnection Tools
8
+ */
9
+ import { Command } from 'commander';
10
+ export interface AnalyzeOptions {
11
+ output?: string;
12
+ json?: boolean;
13
+ verbose?: boolean;
14
+ includeContent?: boolean;
15
+ }
16
+ export interface BrokenLink {
17
+ source: string;
18
+ target: string;
19
+ type: 'wikilink' | 'markdown';
20
+ lineNumber?: number;
21
+ }
22
+ export interface LinkAnalysisResult {
23
+ totalFiles: number;
24
+ filesWithLinks: number;
25
+ orphanFiles: string[];
26
+ orphanRate: number;
27
+ linkDensity: number;
28
+ adjacencyList: Map<string, string[]>;
29
+ brokenLinks: BrokenLink[];
30
+ statistics: {
31
+ totalLinks: number;
32
+ wikiLinks: number;
33
+ markdownLinks: number;
34
+ averageLinksPerFile: number;
35
+ maxLinksInFile: number;
36
+ maxLinksFile: string;
37
+ isolatedClusters: number;
38
+ };
39
+ }
40
+ export declare class LinkAnalyzer {
41
+ private fileMap;
42
+ private allFiles;
43
+ /**
44
+ * Analyze a vault for links and build adjacency list
45
+ */
46
+ analyzeVault(vaultPath: string, options?: AnalyzeOptions): Promise<LinkAnalysisResult>;
47
+ /**
48
+ * Build a map from filename (without extension) to full path
49
+ */
50
+ private buildFileMap;
51
+ /**
52
+ * Parse [[wiki-links]] from content
53
+ * Handles: [[link]], [[link|alias]], [[folder/link]], [[link#heading]]
54
+ */
55
+ parseWikiLinks(content: string): string[];
56
+ /**
57
+ * Parse [markdown](links) from content
58
+ * Handles: [text](link.md), [text](./link.md), [text](../folder/link.md)
59
+ */
60
+ parseMarkdownLinks(content: string): string[];
61
+ /**
62
+ * Check if a link is external (http, https, etc.)
63
+ */
64
+ private isExternalLink;
65
+ /**
66
+ * Resolve a link to a file in the vault
67
+ */
68
+ private resolveLink;
69
+ /**
70
+ * Count isolated clusters using union-find algorithm
71
+ */
72
+ private countClusters;
73
+ /**
74
+ * Generate a detailed report
75
+ */
76
+ generateReport(result: LinkAnalysisResult): string;
77
+ }
78
+ export declare function createAnalyzeLinksCommand(): Command;
79
+ export default createAnalyzeLinksCommand;
80
+ //# sourceMappingURL=analyze-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-links.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/hive-mind/analyze-links.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAMD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAA0B;IAE1C;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4IhG;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAgBzC;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAiB7C;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,WAAW;IA2BnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoDrB;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM;CAiDnD;AAMD,wBAAgB,yBAAyB,IAAI,OAAO,CA4FnD;AAED,eAAe,yBAAyB,CAAC"}