clawvault 3.1.0 → 3.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 (289) hide show
  1. package/README.md +422 -141
  2. package/bin/clawvault.js +10 -2
  3. package/bin/command-registration.test.js +3 -1
  4. package/bin/command-runtime.js +9 -1
  5. package/bin/register-core-commands.js +23 -28
  6. package/bin/register-maintenance-commands.js +39 -3
  7. package/bin/register-query-commands.js +58 -29
  8. package/bin/register-tailscale-commands.js +106 -0
  9. package/bin/register-task-commands.js +18 -1
  10. package/bin/register-task-commands.test.js +16 -0
  11. package/bin/register-vault-operations-commands.js +29 -1
  12. package/bin/register-workgraph-commands.js +1368 -0
  13. package/dashboard/lib/graph-diff.js +104 -0
  14. package/dashboard/lib/graph-diff.test.js +75 -0
  15. package/dashboard/lib/vault-parser.js +556 -0
  16. package/dashboard/lib/vault-parser.test.js +254 -0
  17. package/dashboard/public/app.js +796 -0
  18. package/dashboard/public/index.html +52 -0
  19. package/dashboard/public/styles.css +221 -0
  20. package/dashboard/server.js +374 -0
  21. package/dist/{chunk-F2JEUD4J.js → chunk-23YDQ3QU.js} +6 -8
  22. package/dist/{chunk-C7OK5WKP.js → chunk-2JQ3O2YL.js} +4 -4
  23. package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
  24. package/dist/chunk-2ZDO52B4.js +52 -0
  25. package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
  26. package/dist/chunk-33VSQP4J.js +37 -0
  27. package/dist/chunk-4BQTQMJP.js +93 -0
  28. package/dist/{chunk-GUKMRGM7.js → chunk-4OXMU5S2.js} +1 -1
  29. package/dist/{chunk-62YTUT6J.js → chunk-4PY655YM.js} +15 -3
  30. package/dist/chunk-6FH3IULF.js +352 -0
  31. package/dist/{chunk-3NSBOUT3.js → chunk-77Q5CSPJ.js} +404 -80
  32. package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
  33. package/dist/chunk-BSJ6RIT7.js +447 -0
  34. package/dist/chunk-BUEW6IIK.js +364 -0
  35. package/dist/{chunk-LI4O6NVK.js → chunk-CLJTREDS.js} +74 -14
  36. package/dist/chunk-EK6S23ZB.js +469 -0
  37. package/dist/{chunk-LNJA2UGL.js → chunk-ESFLMDRB.js} +9 -86
  38. package/dist/{chunk-H34S76MB.js → chunk-ESVS6K2B.js} +6 -6
  39. package/dist/{chunk-WAZ3NLWL.js → chunk-F55HGNU4.js} +0 -47
  40. package/dist/{chunk-QK3UCXWL.js → chunk-FHFUXL6G.js} +2 -2
  41. package/dist/{chunk-H62BP7RI.js → chunk-GAOWA7GR.js} +212 -46
  42. package/dist/chunk-GGA32J2R.js +784 -0
  43. package/dist/chunk-GNJL4YGR.js +79 -0
  44. package/dist/chunk-IVRIKYFE.js +520 -0
  45. package/dist/chunk-MDIH26GC.js +183 -0
  46. package/dist/{chunk-LYHGEHXG.js → chunk-MFAWT5O5.js} +0 -1
  47. package/dist/chunk-MM6QGW3P.js +207 -0
  48. package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
  49. package/dist/chunk-NCKFNBHJ.js +257 -0
  50. package/dist/{chunk-QBLMXKF2.js → chunk-OIWVQYQF.js} +1 -1
  51. package/dist/{chunk-42MXU7A6.js → chunk-P62WHA27.js} +58 -47
  52. package/dist/chunk-PBACDKKP.js +66 -0
  53. package/dist/{chunk-VGLOTGAS.js → chunk-QSHD36LH.js} +2 -2
  54. package/dist/{chunk-OZ7RIXTO.js → chunk-QSRRMEYM.js} +2 -2
  55. package/dist/chunk-QVEERJSP.js +152 -0
  56. package/dist/{chunk-N2AXRYLC.js → chunk-QWQ3TIKS.js} +1 -1
  57. package/dist/{chunk-3DHXQHYG.js → chunk-R2MIW5G7.js} +1 -1
  58. package/dist/{chunk-SJSFRIYS.js → chunk-SLXOR3CC.js} +2 -2
  59. package/dist/chunk-SS4B7P7V.js +99 -0
  60. package/dist/{chunk-JY6FYXIT.js → chunk-STCQGCEQ.js} +6 -11
  61. package/dist/chunk-TIGW564L.js +628 -0
  62. package/dist/chunk-U4O6C46S.js +154 -0
  63. package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
  64. package/dist/chunk-VSL7KY3M.js +189 -0
  65. package/dist/{chunk-U55BGUAU.js → chunk-W4SPAEE7.js} +6 -6
  66. package/dist/chunk-WMGIIABP.js +15 -0
  67. package/dist/{chunk-33UGEQRT.js → chunk-X3SPPUFG.js} +151 -64
  68. package/dist/chunk-Y6VJKXGL.js +373 -0
  69. package/dist/{chunk-3WRJEKN4.js → chunk-ZN54U2OZ.js} +123 -10
  70. package/dist/cli/index.js +34 -24
  71. package/dist/commands/archive.js +3 -3
  72. package/dist/commands/backlog.js +3 -3
  73. package/dist/commands/blocked.js +3 -3
  74. package/dist/commands/canvas.d.ts +15 -0
  75. package/dist/commands/canvas.js +200 -0
  76. package/dist/commands/checkpoint.js +2 -2
  77. package/dist/commands/compat.js +2 -2
  78. package/dist/commands/context.js +8 -6
  79. package/dist/commands/doctor.d.ts +11 -7
  80. package/dist/commands/doctor.js +18 -16
  81. package/dist/commands/embed.js +5 -6
  82. package/dist/commands/entities.js +2 -2
  83. package/dist/commands/graph.js +4 -4
  84. package/dist/commands/inject.d.ts +1 -1
  85. package/dist/commands/inject.js +5 -6
  86. package/dist/commands/kanban.js +4 -4
  87. package/dist/commands/link.js +5 -5
  88. package/dist/commands/migrate-observations.js +4 -4
  89. package/dist/commands/observe.d.ts +0 -1
  90. package/dist/commands/observe.js +14 -13
  91. package/dist/commands/project.js +5 -5
  92. package/dist/commands/rebuild-embeddings.d.ts +21 -0
  93. package/dist/commands/rebuild-embeddings.js +91 -0
  94. package/dist/commands/rebuild.js +12 -11
  95. package/dist/commands/recover.js +3 -3
  96. package/dist/commands/reflect.js +6 -7
  97. package/dist/commands/repair-session.js +1 -1
  98. package/dist/commands/replay.js +14 -14
  99. package/dist/commands/session-recap.js +1 -1
  100. package/dist/commands/setup.d.ts +2 -89
  101. package/dist/commands/setup.js +3 -21
  102. package/dist/commands/shell-init.js +1 -1
  103. package/dist/commands/sleep.d.ts +1 -1
  104. package/dist/commands/sleep.js +20 -19
  105. package/dist/commands/status.d.ts +2 -0
  106. package/dist/commands/status.js +57 -35
  107. package/dist/commands/sync-bd.d.ts +10 -0
  108. package/dist/commands/sync-bd.js +10 -0
  109. package/dist/commands/tailscale.d.ts +52 -0
  110. package/dist/commands/tailscale.js +26 -0
  111. package/dist/commands/task.js +4 -4
  112. package/dist/commands/template.js +2 -2
  113. package/dist/commands/wake.d.ts +1 -1
  114. package/dist/commands/wake.js +11 -10
  115. package/dist/commands/workgraph.d.ts +124 -0
  116. package/dist/commands/workgraph.js +38 -0
  117. package/dist/index.d.ts +341 -191
  118. package/dist/index.js +446 -116
  119. package/dist/{inject-Bzi5E-By.d.ts → inject-DYUrDqQO.d.ts} +3 -3
  120. package/dist/ledger-B7g7jhqG.d.ts +44 -0
  121. package/dist/lib/auto-linker.js +2 -2
  122. package/dist/lib/canvas-layout.d.ts +115 -0
  123. package/dist/lib/canvas-layout.js +35 -0
  124. package/dist/lib/config.d.ts +27 -3
  125. package/dist/lib/config.js +4 -2
  126. package/dist/lib/entity-index.js +1 -1
  127. package/dist/lib/project-utils.js +4 -4
  128. package/dist/lib/session-repair.js +1 -1
  129. package/dist/lib/session-utils.js +1 -1
  130. package/dist/lib/tailscale.d.ts +225 -0
  131. package/dist/lib/tailscale.js +50 -0
  132. package/dist/lib/task-utils.js +3 -3
  133. package/dist/lib/template-engine.js +1 -1
  134. package/dist/lib/webdav.d.ts +109 -0
  135. package/dist/lib/webdav.js +35 -0
  136. package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
  137. package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
  138. package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
  139. package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
  140. package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
  141. package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
  142. package/dist/openclaw-plugin.d.ts +8 -0
  143. package/dist/openclaw-plugin.js +14 -0
  144. package/dist/registry-BR4326o0.d.ts +30 -0
  145. package/dist/store-CA-6sKCJ.d.ts +34 -0
  146. package/dist/thread-B9LhXNU0.d.ts +41 -0
  147. package/dist/transformers.node-A2ZRORSQ.js +46775 -0
  148. package/dist/{types-Y2_Um2Ls.d.ts → types-BbWJoC1c.d.ts} +1 -44
  149. package/dist/workgraph/index.d.ts +5 -0
  150. package/dist/workgraph/index.js +23 -0
  151. package/dist/workgraph/ledger.d.ts +2 -0
  152. package/dist/workgraph/ledger.js +25 -0
  153. package/dist/workgraph/registry.d.ts +2 -0
  154. package/dist/workgraph/registry.js +19 -0
  155. package/dist/workgraph/store.d.ts +2 -0
  156. package/dist/workgraph/store.js +25 -0
  157. package/dist/workgraph/thread.d.ts +2 -0
  158. package/dist/workgraph/thread.js +25 -0
  159. package/dist/workgraph/types.d.ts +54 -0
  160. package/dist/workgraph/types.js +7 -0
  161. package/hooks/clawvault/HOOK.md +113 -0
  162. package/hooks/clawvault/handler.js +1561 -0
  163. package/hooks/clawvault/handler.test.js +510 -0
  164. package/hooks/clawvault/openclaw.plugin.json +72 -0
  165. package/openclaw.plugin.json +65 -38
  166. package/package.json +25 -22
  167. package/dist/chunk-3RG5ZIWI.js +0 -10
  168. package/dist/chunk-3ZIH425O.js +0 -871
  169. package/dist/chunk-6U6MK36V.js +0 -205
  170. package/dist/chunk-CMB7UL7C.js +0 -327
  171. package/dist/chunk-D2H45LON.js +0 -1074
  172. package/dist/chunk-E7MFQB6D.js +0 -163
  173. package/dist/chunk-GQSLDZTS.js +0 -560
  174. package/dist/chunk-MFM6K7PU.js +0 -374
  175. package/dist/chunk-MXSSG3QU.js +0 -42
  176. package/dist/chunk-OCGVIN3L.js +0 -88
  177. package/dist/chunk-PAH27GSN.js +0 -108
  178. package/dist/chunk-YCUNCH2I.js +0 -78
  179. package/dist/cli/index.cjs +0 -8584
  180. package/dist/cli/index.d.cts +0 -5
  181. package/dist/commands/archive.cjs +0 -287
  182. package/dist/commands/archive.d.cts +0 -11
  183. package/dist/commands/backlog.cjs +0 -721
  184. package/dist/commands/backlog.d.cts +0 -53
  185. package/dist/commands/blocked.cjs +0 -204
  186. package/dist/commands/blocked.d.cts +0 -26
  187. package/dist/commands/checkpoint.cjs +0 -244
  188. package/dist/commands/checkpoint.d.cts +0 -41
  189. package/dist/commands/compat.cjs +0 -294
  190. package/dist/commands/compat.d.cts +0 -28
  191. package/dist/commands/context.cjs +0 -2990
  192. package/dist/commands/context.d.cts +0 -2
  193. package/dist/commands/doctor.cjs +0 -2986
  194. package/dist/commands/doctor.d.cts +0 -21
  195. package/dist/commands/embed.cjs +0 -232
  196. package/dist/commands/embed.d.cts +0 -17
  197. package/dist/commands/entities.cjs +0 -141
  198. package/dist/commands/entities.d.cts +0 -7
  199. package/dist/commands/graph.cjs +0 -501
  200. package/dist/commands/graph.d.cts +0 -21
  201. package/dist/commands/inject.cjs +0 -1636
  202. package/dist/commands/inject.d.cts +0 -2
  203. package/dist/commands/kanban.cjs +0 -884
  204. package/dist/commands/kanban.d.cts +0 -63
  205. package/dist/commands/link.cjs +0 -965
  206. package/dist/commands/link.d.cts +0 -11
  207. package/dist/commands/migrate-observations.cjs +0 -362
  208. package/dist/commands/migrate-observations.d.cts +0 -19
  209. package/dist/commands/observe.cjs +0 -4099
  210. package/dist/commands/observe.d.cts +0 -23
  211. package/dist/commands/project.cjs +0 -1341
  212. package/dist/commands/project.d.cts +0 -85
  213. package/dist/commands/rebuild.cjs +0 -3136
  214. package/dist/commands/rebuild.d.cts +0 -11
  215. package/dist/commands/recover.cjs +0 -361
  216. package/dist/commands/recover.d.cts +0 -38
  217. package/dist/commands/reflect.cjs +0 -1008
  218. package/dist/commands/reflect.d.cts +0 -11
  219. package/dist/commands/repair-session.cjs +0 -457
  220. package/dist/commands/repair-session.d.cts +0 -38
  221. package/dist/commands/replay.cjs +0 -4103
  222. package/dist/commands/replay.d.cts +0 -16
  223. package/dist/commands/session-recap.cjs +0 -353
  224. package/dist/commands/session-recap.d.cts +0 -27
  225. package/dist/commands/setup.cjs +0 -1278
  226. package/dist/commands/setup.d.cts +0 -99
  227. package/dist/commands/shell-init.cjs +0 -75
  228. package/dist/commands/shell-init.d.cts +0 -7
  229. package/dist/commands/sleep.cjs +0 -6029
  230. package/dist/commands/sleep.d.cts +0 -36
  231. package/dist/commands/status.cjs +0 -2737
  232. package/dist/commands/status.d.cts +0 -52
  233. package/dist/commands/task.cjs +0 -1236
  234. package/dist/commands/task.d.cts +0 -97
  235. package/dist/commands/template.cjs +0 -457
  236. package/dist/commands/template.d.cts +0 -36
  237. package/dist/commands/wake.cjs +0 -2627
  238. package/dist/commands/wake.d.cts +0 -22
  239. package/dist/context-BUGaWpyL.d.cts +0 -46
  240. package/dist/index.cjs +0 -12373
  241. package/dist/index.d.cts +0 -854
  242. package/dist/inject-Bzi5E-By.d.cts +0 -137
  243. package/dist/lib/auto-linker.cjs +0 -176
  244. package/dist/lib/auto-linker.d.cts +0 -26
  245. package/dist/lib/config.cjs +0 -78
  246. package/dist/lib/config.d.cts +0 -11
  247. package/dist/lib/entity-index.cjs +0 -84
  248. package/dist/lib/entity-index.d.cts +0 -26
  249. package/dist/lib/project-utils.cjs +0 -864
  250. package/dist/lib/project-utils.d.cts +0 -97
  251. package/dist/lib/session-repair.cjs +0 -239
  252. package/dist/lib/session-repair.d.cts +0 -110
  253. package/dist/lib/session-utils.cjs +0 -209
  254. package/dist/lib/session-utils.d.cts +0 -63
  255. package/dist/lib/task-utils.cjs +0 -1137
  256. package/dist/lib/task-utils.d.cts +0 -208
  257. package/dist/lib/template-engine.cjs +0 -47
  258. package/dist/lib/template-engine.d.cts +0 -11
  259. package/dist/plugin/index.cjs +0 -1907
  260. package/dist/plugin/index.d.cts +0 -36
  261. package/dist/plugin/index.d.ts +0 -36
  262. package/dist/plugin/index.js +0 -572
  263. package/dist/plugin/inject.cjs +0 -356
  264. package/dist/plugin/inject.d.cts +0 -54
  265. package/dist/plugin/inject.d.ts +0 -54
  266. package/dist/plugin/inject.js +0 -17
  267. package/dist/plugin/observe.cjs +0 -631
  268. package/dist/plugin/observe.d.cts +0 -39
  269. package/dist/plugin/observe.d.ts +0 -39
  270. package/dist/plugin/observe.js +0 -18
  271. package/dist/plugin/templates.cjs +0 -593
  272. package/dist/plugin/templates.d.cts +0 -52
  273. package/dist/plugin/templates.d.ts +0 -52
  274. package/dist/plugin/templates.js +0 -25
  275. package/dist/plugin/types.cjs +0 -18
  276. package/dist/plugin/types.d.cts +0 -209
  277. package/dist/plugin/types.d.ts +0 -209
  278. package/dist/plugin/types.js +0 -0
  279. package/dist/plugin/vault.cjs +0 -927
  280. package/dist/plugin/vault.d.cts +0 -68
  281. package/dist/plugin/vault.d.ts +0 -68
  282. package/dist/plugin/vault.js +0 -22
  283. package/dist/types-Y2_Um2Ls.d.cts +0 -205
  284. package/templates/memory-event.md +0 -67
  285. package/templates/party.md +0 -63
  286. package/templates/primitive-registry.yaml +0 -551
  287. package/templates/run.md +0 -68
  288. package/templates/trigger.md +0 -68
  289. package/templates/workspace.md +0 -50
@@ -83,7 +83,8 @@ describe('CLI command registration modules', () => {
83
83
  'sync',
84
84
  'reindex',
85
85
  'remember',
86
- 'shell-init'
86
+ 'shell-init',
87
+ 'dashboard'
87
88
  ]));
88
89
  });
89
90
 
@@ -129,6 +130,7 @@ describe('CLI command registration modules', () => {
129
130
  'archive',
130
131
  'migrate-observations',
131
132
  'replay',
133
+ 'sync-bd',
132
134
  'checkpoint',
133
135
  'recover',
134
136
  'status',
@@ -4,6 +4,7 @@ import path from 'path';
4
4
  import {
5
5
  ClawVault,
6
6
  QmdUnavailableError,
7
+ QmdConfigurationError,
7
8
  QMD_INSTALL_COMMAND,
8
9
  resolveVaultPath as resolveConfiguredVaultPath
9
10
  } from '../dist/index.js';
@@ -90,4 +91,11 @@ export function printQmdMissing() {
90
91
  console.log(chalk.dim(`Install: ${QMD_INSTALL_COMMAND}`));
91
92
  }
92
93
 
93
- export { QmdUnavailableError };
94
+ export function printQmdConfigError(err) {
95
+ console.error(chalk.red(`Error: ${err.message}`));
96
+ if (err.hint) {
97
+ console.log(chalk.yellow(`Hint: ${err.hint}`));
98
+ }
99
+ }
100
+
101
+ export { QmdUnavailableError, QmdConfigurationError };
@@ -19,6 +19,7 @@ export function registerCoreCommands(
19
19
  .option('--no-tasks', 'Skip tasks/ and backlog/ directories')
20
20
  .option('--no-graph', 'Skip initial graph build')
21
21
  .option('--categories <list>', 'Comma-separated list of custom categories to create')
22
+ .option('--canvas', 'Generate a vault status canvas dashboard on init')
22
23
  .option('--theme <style>', 'Graph color theme to apply (neural, minimal, none) (default: none)', 'none')
23
24
  .option('--minimal', 'Create minimal vault (memory categories only, no tasks/bases/graph)')
24
25
  .action(async (vaultPath, options) => {
@@ -80,14 +81,8 @@ export function registerCoreCommands(
80
81
  '**/*.md'
81
82
  ]);
82
83
  console.log(chalk.green('✓ qmd collection created'));
83
- } catch (err) {
84
- if (err instanceof QmdUnavailableError || err?.message?.includes('ENOENT') || err?.message?.includes('ERR_MODULE_NOT_FOUND')) {
85
- console.log(chalk.yellow('⚠ qmd not available — skipping semantic search setup'));
86
- console.log(chalk.dim(' Install qmd for semantic search: npm install -g github:tobi/qmd'));
87
- console.log(chalk.dim(' Vault initialized successfully without qmd.'));
88
- } else {
89
- console.log(chalk.yellow('⚠ qmd collection may already exist'));
90
- }
84
+ } catch {
85
+ console.log(chalk.yellow('⚠ qmd collection may already exist'));
91
86
  }
92
87
 
93
88
  // Apply theme if requested
@@ -97,6 +92,7 @@ export function registerCoreCommands(
97
92
  await setupCommand({
98
93
  graphColors: true,
99
94
  bases: false,
95
+ canvas: false,
100
96
  theme: options.theme,
101
97
  vault: resolvedPath
102
98
  });
@@ -105,6 +101,22 @@ export function registerCoreCommands(
105
101
  }
106
102
  }
107
103
 
104
+ // Generate canvas if requested
105
+ if (options.canvas) {
106
+ try {
107
+ const { setupCommand } = await import('../dist/commands/setup.js');
108
+ await setupCommand({
109
+ graphColors: false,
110
+ bases: false,
111
+ canvas: true,
112
+ theme: 'none',
113
+ vault: resolvedPath
114
+ });
115
+ } catch {
116
+ console.log(chalk.yellow(`⚠ Could not generate canvas`));
117
+ }
118
+ }
119
+
108
120
  console.log(chalk.green('\n✅ ClawVault ready!\n'));
109
121
  console.log(' ' + chalk.bold('Try these:'));
110
122
  console.log(chalk.dim(' clawvault capture "my first thought" # quick capture'));
@@ -128,6 +140,8 @@ export function registerCoreCommands(
128
140
  .option('--no-graph-colors', 'Skip graph color configuration')
129
141
  .option('--bases', 'Generate Obsidian Bases views for task management')
130
142
  .option('--no-bases', 'Skip Bases file generation')
143
+ .option('--canvas', 'Generate vault status canvas dashboard')
144
+ .option('--no-canvas', 'Skip canvas generation')
131
145
  .option('--theme <style>', 'Graph color theme (neural, minimal, none) (default: neural)', 'neural')
132
146
  .option('--force', 'Overwrite existing configuration files')
133
147
  .option('-v, --vault <path>', 'Vault path')
@@ -137,6 +151,7 @@ export function registerCoreCommands(
137
151
  await setupCommand({
138
152
  graphColors: options.graphColors,
139
153
  bases: options.bases,
154
+ canvas: options.canvas,
140
155
  theme: options.theme,
141
156
  force: options.force,
142
157
  vault: options.vault
@@ -219,24 +234,4 @@ export function registerCoreCommands(
219
234
  process.exit(1);
220
235
  }
221
236
  });
222
- // === PLUGIN-PATH ===
223
- program
224
- .command('plugin-path')
225
- .description('Print the OpenClaw plugin path for configuration')
226
- .action(() => {
227
- const pluginDir = path.dirname(path.dirname(new URL(import.meta.url).pathname));
228
- const pluginPath = path.join(pluginDir, 'dist', 'plugin', 'index.js');
229
- if (fs.existsSync(pluginPath)) {
230
- console.log(pluginPath);
231
- } else {
232
- // Dev mode — use source
233
- const srcPath = path.join(pluginDir, 'src', 'plugin', 'index.ts');
234
- if (fs.existsSync(srcPath)) {
235
- console.log(srcPath);
236
- } else {
237
- console.error('Plugin not found. Run: npm run build');
238
- process.exit(1);
239
- }
240
- }
241
- });
242
237
  }
@@ -26,8 +26,8 @@ export function registerMaintenanceCommands(program, { chalk }) {
26
26
 
27
27
  console.log(chalk.cyan('\n🩺 ClawVault Health Check\n'));
28
28
  console.log(chalk.dim(`Vault: ${report.vaultPath}`));
29
- if (report.qmdCollection) console.log(chalk.dim(`qmd collection: ${report.qmdCollection}`));
30
- if (report.qmdRoot) console.log(chalk.dim(`qmd root: ${report.qmdRoot}`));
29
+ console.log(chalk.dim(`qmd collection: ${report.qmdCollection}`));
30
+ console.log(chalk.dim(`qmd root: ${report.qmdRoot}`));
31
31
  console.log();
32
32
 
33
33
  for (const check of report.checks) {
@@ -36,7 +36,7 @@ export function registerMaintenanceCommands(program, { chalk }) {
36
36
  : check.status === 'warn'
37
37
  ? chalk.yellow('⚠')
38
38
  : chalk.red('✗');
39
- const line = check.detail ? `${check.label}: ${check.detail}` : check.label;
39
+ const line = `${check.label}: ${check.detail}`;
40
40
  const renderedLine = check.status === 'ok'
41
41
  ? chalk.green(line)
42
42
  : check.status === 'warn'
@@ -80,6 +80,25 @@ export function registerMaintenanceCommands(program, { chalk }) {
80
80
  }
81
81
  });
82
82
 
83
+ // === REBUILD-EMBEDDINGS ===
84
+ program
85
+ .command('rebuild-embeddings')
86
+ .description('Rebuild local embedding cache for hybrid search (uses all-MiniLM-L6-v2)')
87
+ .option('-v, --vault <path>', 'Vault path')
88
+ .option('--force', 'Force rebuild all embeddings (ignore cache)')
89
+ .action(async (options) => {
90
+ try {
91
+ const { rebuildEmbeddingsCommand } = await import('../dist/commands/rebuild-embeddings.js');
92
+ await rebuildEmbeddingsCommand({
93
+ vaultPath: options.vault,
94
+ force: options.force
95
+ });
96
+ } catch (err) {
97
+ console.error(chalk.red(`Error: ${err.message}`));
98
+ process.exit(1);
99
+ }
100
+ });
101
+
83
102
  // === COMPAT (OpenClaw compatibility) ===
84
103
  program
85
104
  .command('compat')
@@ -262,4 +281,21 @@ export function registerMaintenanceCommands(program, { chalk }) {
262
281
  });
263
282
 
264
283
  // === SYNC-BD ===
284
+ program
285
+ .command('sync-bd')
286
+ .description('Sync active Beads tasks into views/now.md (optional)')
287
+ .option('--dry-run', 'Show sync output without writing')
288
+ .option('-v, --vault <path>', 'Vault path')
289
+ .action(async (options) => {
290
+ try {
291
+ const { syncBdCommand } = await import('../dist/commands/sync-bd.js');
292
+ await syncBdCommand({
293
+ vaultPath: options.vault,
294
+ dryRun: options.dryRun
295
+ });
296
+ } catch (err) {
297
+ console.error(chalk.red(`Error: ${err.message}`));
298
+ process.exit(1);
299
+ }
300
+ });
265
301
  }
@@ -9,13 +9,15 @@ export function registerQueryCommands(
9
9
  getVault,
10
10
  resolveVaultPath,
11
11
  QmdUnavailableError,
12
- printQmdMissing
12
+ QmdConfigurationError,
13
+ printQmdMissing,
14
+ printQmdConfigError
13
15
  }
14
16
  ) {
15
17
  // === SEARCH ===
16
18
  program
17
19
  .command('search <query>')
18
- .description('Search the vault via qmd (BM25)')
20
+ .description('Search the vault via qmd (BM25), optionally with semantic hybrid search')
19
21
  .option('-n, --limit <n>', 'Max results (default: 10)', '10')
20
22
  .option('-c, --category <category>', 'Filter by category')
21
23
  .option('--tags <tags>', 'Filter by tags (comma-separated)')
@@ -23,20 +25,57 @@ export function registerQueryCommands(
23
25
  .option('--full', 'Include full content in results')
24
26
  .option('-v, --vault <path>', 'Vault path')
25
27
  .option('--json', 'Output as JSON')
28
+ .option('--semantic', 'Enable hybrid search (BM25 + semantic with RRF)')
29
+ .option('--rebuild-embeddings', 'Rebuild the embedding cache before searching')
26
30
  .action(async (query, options) => {
27
31
  try {
32
+ const vaultPath = resolveVaultPath(options.vault);
28
33
  const vault = await getVault(options.vault);
29
34
 
30
- const results = await vault.find(query, {
31
- limit: parseInt(options.limit, 10),
35
+ // Handle --rebuild-embeddings flag
36
+ if (options.rebuildEmbeddings) {
37
+ const { rebuildEmbeddingsForVault } = await import('../dist/commands/rebuild-embeddings.js');
38
+ console.log(chalk.cyan('Rebuilding embedding cache...'));
39
+ const stats = await rebuildEmbeddingsForVault(vaultPath, {
40
+ onProgress: (current, total) => {
41
+ process.stdout.write(`\r Embedding ${current}/${total} documents...`);
42
+ }
43
+ });
44
+ console.log(chalk.green(`\n Done. ${stats.total} embeddings (${stats.added} new, ${stats.skipped} cached)`));
45
+ console.log();
46
+ }
47
+
48
+ // Get BM25 results
49
+ const bm25Results = await vault.find(query, {
50
+ limit: options.semantic ? 50 : parseInt(options.limit, 10),
32
51
  category: options.category,
33
52
  tags: options.tags?.split(',').map((value) => value.trim()),
34
53
  fullContent: options.full,
35
54
  temporalBoost: options.recent
36
55
  });
37
56
 
57
+ let results = bm25Results;
58
+ let searchMode = 'BM25';
59
+
60
+ // Apply hybrid search if --semantic flag is set
61
+ if (options.semantic) {
62
+ const { EmbeddingCache, hybridSearch } = await import('../dist/lib/hybrid-search.js');
63
+ const cache = new EmbeddingCache(vaultPath);
64
+ cache.load();
65
+
66
+ if (cache.size === 0) {
67
+ console.log(chalk.yellow('Warning: No embeddings found. Run with --rebuild-embeddings to build the cache.'));
68
+ } else {
69
+ results = await hybridSearch(query, bm25Results, cache, {
70
+ topK: parseInt(options.limit, 10),
71
+ rrfK: 60
72
+ });
73
+ searchMode = 'Hybrid (BM25 + Semantic)';
74
+ }
75
+ }
76
+
38
77
  if (options.json) {
39
- console.log(JSON.stringify(results, null, 2));
78
+ console.log(JSON.stringify({ searchMode, results }, null, 2));
40
79
  return;
41
80
  }
42
81
 
@@ -45,7 +84,8 @@ export function registerQueryCommands(
45
84
  return;
46
85
  }
47
86
 
48
- console.log(chalk.cyan(`\n🔍 Found ${results.length} result(s) for "${query}":\n`));
87
+ const icon = options.semantic ? '🔍🧠' : '🔍';
88
+ console.log(chalk.cyan(`\n${icon} Found ${results.length} result(s) for "${query}" [${searchMode}]:\n`));
49
89
 
50
90
  for (const result of results) {
51
91
  const scoreBar = '█'.repeat(Math.round(result.score * 10)).padEnd(10, '░');
@@ -62,6 +102,10 @@ export function registerQueryCommands(
62
102
  printQmdMissing();
63
103
  process.exit(1);
64
104
  }
105
+ if (err instanceof QmdConfigurationError) {
106
+ printQmdConfigError(err);
107
+ process.exit(1);
108
+ }
65
109
  console.error(chalk.red(`Error: ${err.message}`));
66
110
  process.exit(1);
67
111
  }
@@ -117,6 +161,10 @@ export function registerQueryCommands(
117
161
  printQmdMissing();
118
162
  process.exit(1);
119
163
  }
164
+ if (err instanceof QmdConfigurationError) {
165
+ printQmdConfigError(err);
166
+ process.exit(1);
167
+ }
120
168
  console.error(chalk.red(`Error: ${err.message}`));
121
169
  process.exit(1);
122
170
  }
@@ -163,6 +211,10 @@ export function registerQueryCommands(
163
211
  printQmdMissing();
164
212
  process.exit(1);
165
213
  }
214
+ if (err instanceof QmdConfigurationError) {
215
+ printQmdConfigError(err);
216
+ process.exit(1);
217
+ }
166
218
  console.error(chalk.red(`Error: ${err.message}`));
167
219
  process.exit(1);
168
220
  }
@@ -292,29 +344,6 @@ export function registerQueryCommands(
292
344
  }
293
345
  });
294
346
 
295
- // === REWEAVE ===
296
- program
297
- .command('reweave')
298
- .description('Backward memory consolidation — detect and mark superseded observations')
299
- .option('--since <date>', 'Only check observations since this date (YYYY-MM-DD)')
300
- .option('--dry-run', 'Show what would be superseded without writing')
301
- .option('--threshold <n>', 'Entity similarity threshold (0-1, default 0.3)', '0.3')
302
- .option('-v, --vault <path>', 'Vault path')
303
- .action(async (options) => {
304
- try {
305
- const { reweaveCommand } = await import('../dist/commands/reweave.js');
306
- await reweaveCommand({
307
- vaultPath: resolveVaultPath(options.vault),
308
- since: options.since,
309
- dryRun: options.dryRun,
310
- threshold: parseFloat(options.threshold),
311
- });
312
- } catch (err) {
313
- console.error(chalk.red(`Error: ${err.message}`));
314
- process.exit(1);
315
- }
316
- });
317
-
318
347
  // === SESSION-RECAP ===
319
348
  program
320
349
  .command('session-recap <sessionKey>')
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Tailscale networking command registrations.
3
+ * Provides vault synchronization over Tailscale networks.
4
+ */
5
+
6
+ export function registerTailscaleCommands(program, { chalk }) {
7
+ // === TAILSCALE-STATUS ===
8
+ program
9
+ .command('tailscale-status')
10
+ .alias('ts-status')
11
+ .description('Show Tailscale connection status and peers')
12
+ .option('--json', 'Output as JSON')
13
+ .option('--peers', 'Show all peers including offline')
14
+ .action(async (options) => {
15
+ try {
16
+ const { tailscaleStatusCommand } = await import('../dist/commands/tailscale.js');
17
+ await tailscaleStatusCommand({
18
+ json: options.json,
19
+ peers: options.peers
20
+ });
21
+ } catch (err) {
22
+ console.error(chalk.red(`Error: ${err.message}`));
23
+ process.exit(1);
24
+ }
25
+ });
26
+
27
+ // === TAILSCALE-SYNC ===
28
+ program
29
+ .command('tailscale-sync')
30
+ .alias('ts-sync')
31
+ .description('Sync vault with a peer on the Tailscale network')
32
+ .requiredOption('--peer <hostname>', 'Peer hostname or IP to sync with')
33
+ .option('-v, --vault <path>', 'Vault path')
34
+ .option('--port <number>', 'Port on the peer (default: 8384)', parseInt)
35
+ .option('--direction <dir>', 'Sync direction: push, pull, or bidirectional (default: bidirectional)', 'bidirectional')
36
+ .option('--dry-run', 'Show what would be synced without making changes')
37
+ .option('--delete-orphans', 'Delete files that exist locally but not on peer (pull only)')
38
+ .option('--categories <list>', 'Comma-separated list of categories to sync')
39
+ .option('--https', 'Use HTTPS for connection')
40
+ .option('--json', 'Output as JSON')
41
+ .action(async (options) => {
42
+ try {
43
+ const { tailscaleSyncCommand } = await import('../dist/commands/tailscale.js');
44
+ await tailscaleSyncCommand({
45
+ peer: options.peer,
46
+ vaultPath: options.vault,
47
+ port: options.port,
48
+ direction: options.direction,
49
+ dryRun: options.dryRun,
50
+ deleteOrphans: options.deleteOrphans,
51
+ categories: options.categories?.split(',').map(c => c.trim()),
52
+ https: options.https,
53
+ json: options.json
54
+ });
55
+ } catch (err) {
56
+ console.error(chalk.red(`Error: ${err.message}`));
57
+ process.exit(1);
58
+ }
59
+ });
60
+
61
+ // === TAILSCALE-SERVE ===
62
+ program
63
+ .command('tailscale-serve')
64
+ .alias('ts-serve')
65
+ .description('Serve vault for sync over Tailscale')
66
+ .option('-v, --vault <path>', 'Vault path')
67
+ .option('--port <number>', 'Port to serve on (default: 8384)', parseInt)
68
+ .option('--funnel', 'Expose via Tailscale Funnel (public internet)')
69
+ .option('--background', 'Run in background')
70
+ .option('--stop', 'Stop serving')
71
+ .action(async (options) => {
72
+ try {
73
+ const { tailscaleServeCommand } = await import('../dist/commands/tailscale.js');
74
+ await tailscaleServeCommand({
75
+ vaultPath: options.vault,
76
+ port: options.port,
77
+ funnel: options.funnel,
78
+ background: options.background,
79
+ stop: options.stop
80
+ });
81
+ } catch (err) {
82
+ console.error(chalk.red(`Error: ${err.message}`));
83
+ process.exit(1);
84
+ }
85
+ });
86
+
87
+ // === TAILSCALE-DISCOVER ===
88
+ program
89
+ .command('tailscale-discover')
90
+ .alias('ts-discover')
91
+ .description('Discover ClawVault peers on the Tailscale network')
92
+ .option('--port <number>', 'Port to check (default: 8384)', parseInt)
93
+ .option('--json', 'Output as JSON')
94
+ .action(async (options) => {
95
+ try {
96
+ const { tailscaleDiscoverCommand } = await import('../dist/commands/tailscale.js');
97
+ await tailscaleDiscoverCommand({
98
+ port: options.port,
99
+ json: options.json
100
+ });
101
+ } catch (err) {
102
+ console.error(chalk.red(`Error: ${err.message}`));
103
+ process.exit(1);
104
+ }
105
+ });
106
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Task tracking command registrations for ClawVault
3
- * Registers task, backlog, and blocked commands
3
+ * Registers task, backlog, blocked, and canvas commands
4
4
  */
5
5
 
6
6
  function parseCsvList(value) {
@@ -328,4 +328,21 @@ export function registerTaskCommands(
328
328
  });
329
329
 
330
330
  // === CANVAS ===
331
+ program
332
+ .command('canvas')
333
+ .description('Generate an Obsidian canvas dashboard file')
334
+ .option('-v, --vault <path>', 'Vault path (default: find nearest)')
335
+ .option('--output <path>', 'Output file path (default: dashboard.canvas)')
336
+ .action(async (options) => {
337
+ try {
338
+ const vaultPath = resolveVaultPath(options.vault);
339
+ const { canvasCommand } = await import('../dist/commands/canvas.js');
340
+ await canvasCommand(vaultPath, {
341
+ output: options.output
342
+ });
343
+ } catch (err) {
344
+ console.error(chalk.red(`Error: ${err.message}`));
345
+ process.exit(1);
346
+ }
347
+ });
331
348
  }
@@ -50,4 +50,20 @@ describe('register-task-commands', () => {
50
50
  ]));
51
51
  });
52
52
 
53
+ it('adds simplified canvas flags', () => {
54
+ const program = new Command();
55
+ registerTaskCommands(program, {
56
+ chalk: chalkStub,
57
+ resolveVaultPath: stubResolveVaultPath
58
+ });
59
+
60
+ const canvasCommand = program.commands.find((command) => command.name() === 'canvas');
61
+ expect(canvasCommand).toBeDefined();
62
+
63
+ const optionFlags = canvasCommand?.options.map((option) => option.flags) ?? [];
64
+ expect(optionFlags).toEqual(expect.arrayContaining([
65
+ '-v, --vault <path>',
66
+ '--output <path>'
67
+ ]));
68
+ });
53
69
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Vault operation command registrations (browse/sync/reindex/remember/shell-init).
2
+ * Vault operation command registrations (browse/sync/reindex/remember/shell-init/dashboard).
3
3
  */
4
4
 
5
5
  import { validatePathWithinBase } from './command-runtime.js';
@@ -269,4 +269,32 @@ export function registerVaultOperationsCommands(
269
269
  }
270
270
  });
271
271
 
272
+ // === DASHBOARD ===
273
+ program
274
+ .command('dashboard')
275
+ .description('Run the local vault graph dashboard server')
276
+ .option('-p, --port <port>', 'Dashboard port (default: 3377)', '3377')
277
+ .option('-v, --vault <path>', 'Vault path')
278
+ .action(async (options) => {
279
+ try {
280
+ const parsedPort = Number.parseInt(options.port, 10);
281
+ if (Number.isNaN(parsedPort)) {
282
+ console.error(chalk.red(`Error: Invalid port: ${options.port}`));
283
+ process.exit(1);
284
+ }
285
+
286
+ const vaultPath = options.vault
287
+ ? path.resolve(options.vault)
288
+ : resolveVaultPath(undefined);
289
+
290
+ const { startDashboard } = await import('../dashboard/server.js');
291
+ await startDashboard({
292
+ port: parsedPort,
293
+ vaultPath
294
+ });
295
+ } catch (err) {
296
+ console.error(chalk.red(`Error: ${err.message}`));
297
+ process.exit(1);
298
+ }
299
+ });
272
300
  }