clawvault 3.1.0 → 3.2.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 (273) 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 +451 -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-C7OK5WKP.js → chunk-2JQ3O2YL.js} +4 -4
  22. package/dist/{chunk-VR5NE7PZ.js → chunk-2RAZ4ZFE.js} +1 -1
  23. package/dist/{chunk-F2JEUD4J.js → chunk-4ITRXIVT.js} +5 -7
  24. package/dist/{chunk-GUKMRGM7.js → chunk-4OXMU5S2.js} +1 -1
  25. package/dist/chunk-5PJ4STIC.js +465 -0
  26. package/dist/{chunk-62YTUT6J.js → chunk-AZYOKJYC.js} +2 -2
  27. package/dist/chunk-BSJ6RIT7.js +447 -0
  28. package/dist/chunk-ECRZL5XR.js +50 -0
  29. package/dist/chunk-ERNE2FZ5.js +189 -0
  30. package/dist/{chunk-WAZ3NLWL.js → chunk-F55HGNU4.js} +0 -47
  31. package/dist/{chunk-VGLOTGAS.js → chunk-FAKNOB7Y.js} +2 -2
  32. package/dist/{chunk-QK3UCXWL.js → chunk-FHFUXL6G.js} +2 -2
  33. package/dist/chunk-GNJL4YGR.js +79 -0
  34. package/dist/chunk-HR4KN6S2.js +152 -0
  35. package/dist/{chunk-OZ7RIXTO.js → chunk-IIOU45CK.js} +1 -1
  36. package/dist/chunk-IJBFGPCS.js +33 -0
  37. package/dist/chunk-IVRIKYFE.js +520 -0
  38. package/dist/chunk-K7PNYS45.js +93 -0
  39. package/dist/chunk-MDIH26GC.js +183 -0
  40. package/dist/{chunk-LYHGEHXG.js → chunk-MFAWT5O5.js} +0 -1
  41. package/dist/{chunk-H34S76MB.js → chunk-MNPUYCHQ.js} +6 -6
  42. package/dist/chunk-NTOPJI7W.js +207 -0
  43. package/dist/{chunk-QBLMXKF2.js → chunk-OIWVQYQF.js} +1 -1
  44. package/dist/chunk-PG56HX5T.js +154 -0
  45. package/dist/{chunk-LNJA2UGL.js → chunk-PI4WMLMG.js} +7 -84
  46. package/dist/chunk-QMHPQYUV.js +363 -0
  47. package/dist/{chunk-H62BP7RI.js → chunk-QPDDIHXE.js} +209 -43
  48. package/dist/{chunk-N2AXRYLC.js → chunk-QWQ3TIKS.js} +1 -1
  49. package/dist/{chunk-3DHXQHYG.js → chunk-R2MIW5G7.js} +1 -1
  50. package/dist/{chunk-SJSFRIYS.js → chunk-S5OJEGFG.js} +2 -2
  51. package/dist/chunk-SS4B7P7V.js +99 -0
  52. package/dist/chunk-TIGW564L.js +628 -0
  53. package/dist/chunk-U67V476Y.js +35 -0
  54. package/dist/{chunk-JY6FYXIT.js → chunk-UCQAOZHW.js} +6 -11
  55. package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
  56. package/dist/chunk-WIOLLGAD.js +190 -0
  57. package/dist/{chunk-3WRJEKN4.js → chunk-WJVWINEM.js} +72 -8
  58. package/dist/chunk-WMGIIABP.js +15 -0
  59. package/dist/{chunk-33UGEQRT.js → chunk-X3SPPUFG.js} +151 -64
  60. package/dist/{chunk-3NSBOUT3.js → chunk-Y3TIJEBP.js} +314 -79
  61. package/dist/chunk-Y6VJKXGL.js +373 -0
  62. package/dist/{chunk-LI4O6NVK.js → chunk-YDWHS4LJ.js} +49 -9
  63. package/dist/{chunk-U55BGUAU.js → chunk-YNIPYN4F.js} +5 -5
  64. package/dist/chunk-YXQCA6B7.js +226 -0
  65. package/dist/cli/index.js +26 -22
  66. package/dist/commands/archive.js +3 -3
  67. package/dist/commands/backlog.js +3 -3
  68. package/dist/commands/blocked.js +3 -3
  69. package/dist/commands/canvas.d.ts +15 -0
  70. package/dist/commands/canvas.js +200 -0
  71. package/dist/commands/checkpoint.js +2 -2
  72. package/dist/commands/compat.js +2 -2
  73. package/dist/commands/context.js +7 -5
  74. package/dist/commands/doctor.d.ts +11 -7
  75. package/dist/commands/doctor.js +16 -14
  76. package/dist/commands/embed.js +5 -6
  77. package/dist/commands/entities.js +2 -2
  78. package/dist/commands/graph.js +3 -3
  79. package/dist/commands/inject.d.ts +1 -1
  80. package/dist/commands/inject.js +4 -5
  81. package/dist/commands/kanban.js +4 -4
  82. package/dist/commands/link.js +2 -2
  83. package/dist/commands/migrate-observations.js +4 -4
  84. package/dist/commands/observe.d.ts +0 -1
  85. package/dist/commands/observe.js +13 -12
  86. package/dist/commands/project.js +5 -5
  87. package/dist/commands/rebuild-embeddings.d.ts +21 -0
  88. package/dist/commands/rebuild-embeddings.js +91 -0
  89. package/dist/commands/rebuild.js +12 -11
  90. package/dist/commands/recover.js +3 -3
  91. package/dist/commands/reflect.js +6 -7
  92. package/dist/commands/repair-session.js +1 -1
  93. package/dist/commands/replay.js +14 -14
  94. package/dist/commands/session-recap.js +1 -1
  95. package/dist/commands/setup.d.ts +2 -89
  96. package/dist/commands/setup.js +3 -21
  97. package/dist/commands/shell-init.js +1 -1
  98. package/dist/commands/sleep.d.ts +1 -1
  99. package/dist/commands/sleep.js +18 -17
  100. package/dist/commands/status.d.ts +2 -0
  101. package/dist/commands/status.js +40 -30
  102. package/dist/commands/sync-bd.d.ts +10 -0
  103. package/dist/commands/sync-bd.js +10 -0
  104. package/dist/commands/tailscale.d.ts +52 -0
  105. package/dist/commands/tailscale.js +26 -0
  106. package/dist/commands/task.js +4 -4
  107. package/dist/commands/template.js +2 -2
  108. package/dist/commands/wake.d.ts +1 -1
  109. package/dist/commands/wake.js +11 -10
  110. package/dist/index.d.ts +334 -191
  111. package/dist/index.js +432 -108
  112. package/dist/{inject-Bzi5E-By.d.ts → inject-DYUrDqQO.d.ts} +3 -3
  113. package/dist/ledger-B7g7jhqG.d.ts +44 -0
  114. package/dist/lib/auto-linker.js +1 -1
  115. package/dist/lib/canvas-layout.d.ts +115 -0
  116. package/dist/lib/canvas-layout.js +35 -0
  117. package/dist/lib/config.d.ts +27 -3
  118. package/dist/lib/config.js +4 -2
  119. package/dist/lib/entity-index.js +1 -1
  120. package/dist/lib/project-utils.js +4 -4
  121. package/dist/lib/session-repair.js +1 -1
  122. package/dist/lib/session-utils.js +1 -1
  123. package/dist/lib/tailscale.d.ts +225 -0
  124. package/dist/lib/tailscale.js +50 -0
  125. package/dist/lib/task-utils.js +3 -3
  126. package/dist/lib/template-engine.js +1 -1
  127. package/dist/lib/webdav.d.ts +109 -0
  128. package/dist/lib/webdav.js +35 -0
  129. package/dist/plugin/index.d.ts +344 -28
  130. package/dist/plugin/index.js +3919 -227
  131. package/dist/registry-BR4326o0.d.ts +30 -0
  132. package/dist/store-CA-6sKCJ.d.ts +34 -0
  133. package/dist/thread-B9LhXNU0.d.ts +41 -0
  134. package/dist/{types-Y2_Um2Ls.d.ts → types-BbWJoC1c.d.ts} +1 -44
  135. package/dist/workgraph/index.d.ts +5 -0
  136. package/dist/workgraph/index.js +23 -0
  137. package/dist/workgraph/ledger.d.ts +2 -0
  138. package/dist/workgraph/ledger.js +25 -0
  139. package/dist/workgraph/registry.d.ts +2 -0
  140. package/dist/workgraph/registry.js +19 -0
  141. package/dist/workgraph/store.d.ts +2 -0
  142. package/dist/workgraph/store.js +25 -0
  143. package/dist/workgraph/thread.d.ts +2 -0
  144. package/dist/workgraph/thread.js +25 -0
  145. package/dist/workgraph/types.d.ts +54 -0
  146. package/dist/workgraph/types.js +7 -0
  147. package/hooks/clawvault/HOOK.md +113 -0
  148. package/hooks/clawvault/handler.js +1559 -0
  149. package/hooks/clawvault/handler.test.js +510 -0
  150. package/hooks/clawvault/openclaw.plugin.json +72 -0
  151. package/openclaw.plugin.json +235 -30
  152. package/package.json +20 -20
  153. package/dist/chunk-3RG5ZIWI.js +0 -10
  154. package/dist/chunk-3ZIH425O.js +0 -871
  155. package/dist/chunk-6U6MK36V.js +0 -205
  156. package/dist/chunk-CMB7UL7C.js +0 -327
  157. package/dist/chunk-D2H45LON.js +0 -1074
  158. package/dist/chunk-E7MFQB6D.js +0 -163
  159. package/dist/chunk-GQSLDZTS.js +0 -560
  160. package/dist/chunk-MFM6K7PU.js +0 -374
  161. package/dist/chunk-MXSSG3QU.js +0 -42
  162. package/dist/chunk-OCGVIN3L.js +0 -88
  163. package/dist/chunk-PAH27GSN.js +0 -108
  164. package/dist/chunk-YCUNCH2I.js +0 -78
  165. package/dist/cli/index.cjs +0 -8584
  166. package/dist/cli/index.d.cts +0 -5
  167. package/dist/commands/archive.cjs +0 -287
  168. package/dist/commands/archive.d.cts +0 -11
  169. package/dist/commands/backlog.cjs +0 -721
  170. package/dist/commands/backlog.d.cts +0 -53
  171. package/dist/commands/blocked.cjs +0 -204
  172. package/dist/commands/blocked.d.cts +0 -26
  173. package/dist/commands/checkpoint.cjs +0 -244
  174. package/dist/commands/checkpoint.d.cts +0 -41
  175. package/dist/commands/compat.cjs +0 -294
  176. package/dist/commands/compat.d.cts +0 -28
  177. package/dist/commands/context.cjs +0 -2990
  178. package/dist/commands/context.d.cts +0 -2
  179. package/dist/commands/doctor.cjs +0 -2986
  180. package/dist/commands/doctor.d.cts +0 -21
  181. package/dist/commands/embed.cjs +0 -232
  182. package/dist/commands/embed.d.cts +0 -17
  183. package/dist/commands/entities.cjs +0 -141
  184. package/dist/commands/entities.d.cts +0 -7
  185. package/dist/commands/graph.cjs +0 -501
  186. package/dist/commands/graph.d.cts +0 -21
  187. package/dist/commands/inject.cjs +0 -1636
  188. package/dist/commands/inject.d.cts +0 -2
  189. package/dist/commands/kanban.cjs +0 -884
  190. package/dist/commands/kanban.d.cts +0 -63
  191. package/dist/commands/link.cjs +0 -965
  192. package/dist/commands/link.d.cts +0 -11
  193. package/dist/commands/migrate-observations.cjs +0 -362
  194. package/dist/commands/migrate-observations.d.cts +0 -19
  195. package/dist/commands/observe.cjs +0 -4099
  196. package/dist/commands/observe.d.cts +0 -23
  197. package/dist/commands/project.cjs +0 -1341
  198. package/dist/commands/project.d.cts +0 -85
  199. package/dist/commands/rebuild.cjs +0 -3136
  200. package/dist/commands/rebuild.d.cts +0 -11
  201. package/dist/commands/recover.cjs +0 -361
  202. package/dist/commands/recover.d.cts +0 -38
  203. package/dist/commands/reflect.cjs +0 -1008
  204. package/dist/commands/reflect.d.cts +0 -11
  205. package/dist/commands/repair-session.cjs +0 -457
  206. package/dist/commands/repair-session.d.cts +0 -38
  207. package/dist/commands/replay.cjs +0 -4103
  208. package/dist/commands/replay.d.cts +0 -16
  209. package/dist/commands/session-recap.cjs +0 -353
  210. package/dist/commands/session-recap.d.cts +0 -27
  211. package/dist/commands/setup.cjs +0 -1278
  212. package/dist/commands/setup.d.cts +0 -99
  213. package/dist/commands/shell-init.cjs +0 -75
  214. package/dist/commands/shell-init.d.cts +0 -7
  215. package/dist/commands/sleep.cjs +0 -6029
  216. package/dist/commands/sleep.d.cts +0 -36
  217. package/dist/commands/status.cjs +0 -2737
  218. package/dist/commands/status.d.cts +0 -52
  219. package/dist/commands/task.cjs +0 -1236
  220. package/dist/commands/task.d.cts +0 -97
  221. package/dist/commands/template.cjs +0 -457
  222. package/dist/commands/template.d.cts +0 -36
  223. package/dist/commands/wake.cjs +0 -2627
  224. package/dist/commands/wake.d.cts +0 -22
  225. package/dist/context-BUGaWpyL.d.cts +0 -46
  226. package/dist/index.cjs +0 -12373
  227. package/dist/index.d.cts +0 -854
  228. package/dist/inject-Bzi5E-By.d.cts +0 -137
  229. package/dist/lib/auto-linker.cjs +0 -176
  230. package/dist/lib/auto-linker.d.cts +0 -26
  231. package/dist/lib/config.cjs +0 -78
  232. package/dist/lib/config.d.cts +0 -11
  233. package/dist/lib/entity-index.cjs +0 -84
  234. package/dist/lib/entity-index.d.cts +0 -26
  235. package/dist/lib/project-utils.cjs +0 -864
  236. package/dist/lib/project-utils.d.cts +0 -97
  237. package/dist/lib/session-repair.cjs +0 -239
  238. package/dist/lib/session-repair.d.cts +0 -110
  239. package/dist/lib/session-utils.cjs +0 -209
  240. package/dist/lib/session-utils.d.cts +0 -63
  241. package/dist/lib/task-utils.cjs +0 -1137
  242. package/dist/lib/task-utils.d.cts +0 -208
  243. package/dist/lib/template-engine.cjs +0 -47
  244. package/dist/lib/template-engine.d.cts +0 -11
  245. package/dist/plugin/index.cjs +0 -1907
  246. package/dist/plugin/index.d.cts +0 -36
  247. package/dist/plugin/inject.cjs +0 -356
  248. package/dist/plugin/inject.d.cts +0 -54
  249. package/dist/plugin/inject.d.ts +0 -54
  250. package/dist/plugin/inject.js +0 -17
  251. package/dist/plugin/observe.cjs +0 -631
  252. package/dist/plugin/observe.d.cts +0 -39
  253. package/dist/plugin/observe.d.ts +0 -39
  254. package/dist/plugin/observe.js +0 -18
  255. package/dist/plugin/templates.cjs +0 -593
  256. package/dist/plugin/templates.d.cts +0 -52
  257. package/dist/plugin/templates.d.ts +0 -52
  258. package/dist/plugin/templates.js +0 -25
  259. package/dist/plugin/types.cjs +0 -18
  260. package/dist/plugin/types.d.cts +0 -209
  261. package/dist/plugin/types.d.ts +0 -209
  262. package/dist/plugin/types.js +0 -0
  263. package/dist/plugin/vault.cjs +0 -927
  264. package/dist/plugin/vault.d.cts +0 -68
  265. package/dist/plugin/vault.d.ts +0 -68
  266. package/dist/plugin/vault.js +0 -22
  267. package/dist/types-Y2_Um2Ls.d.cts +0 -205
  268. package/templates/memory-event.md +0 -67
  269. package/templates/party.md +0 -63
  270. package/templates/primitive-registry.yaml +0 -551
  271. package/templates/run.md +0 -68
  272. package/templates/trigger.md +0 -68
  273. package/templates/workspace.md +0 -50
@@ -6,20 +6,26 @@ import {
6
6
  } from "./chunk-4VQTUVH7.js";
7
7
  import {
8
8
  getObserverStaleness
9
- } from "./chunk-LNJA2UGL.js";
10
- import {
11
- checkOpenClawCompatibility
12
- } from "./chunk-33UGEQRT.js";
9
+ } from "./chunk-PI4WMLMG.js";
13
10
  import {
14
11
  ClawVault,
15
12
  findVault
16
- } from "./chunk-LI4O6NVK.js";
13
+ } from "./chunk-YDWHS4LJ.js";
14
+ import {
15
+ listQmdCollections,
16
+ loadVaultQmdConfig
17
+ } from "./chunk-WIOLLGAD.js";
17
18
  import {
19
+ QMD_INSTALL_COMMAND,
20
+ QMD_INSTALL_URL,
18
21
  hasQmd
19
- } from "./chunk-D2H45LON.js";
22
+ } from "./chunk-5PJ4STIC.js";
20
23
  import {
21
24
  loadMemoryGraphIndex
22
25
  } from "./chunk-ZZA73MFY.js";
26
+ import {
27
+ checkOpenClawCompatibility
28
+ } from "./chunk-X3SPPUFG.js";
23
29
 
24
30
  // src/commands/doctor.ts
25
31
  import * as fs from "fs";
@@ -29,6 +35,12 @@ var CLAWVAULT_DIR = ".clawvault";
29
35
  var CHECKPOINT_FILE = "last-checkpoint.json";
30
36
  var DAY_MS = 24 * 60 * 60 * 1e3;
31
37
  var ACTIVE_USE_DAYS = 7;
38
+ var V2_COLLECTION_PATTERNS = [
39
+ /^clawvault$/i,
40
+ /^vault$/i,
41
+ /^memory$/i,
42
+ /^notes$/i
43
+ ];
32
44
  function daysSince(date, now = Date.now()) {
33
45
  return Math.max(0, Math.floor((now - date.getTime()) / DAY_MS));
34
46
  }
@@ -51,7 +63,7 @@ function getShellConfigPaths(shellPath) {
51
63
  const home = os.homedir();
52
64
  const shellName = shellPath ? path.basename(shellPath) : "bash";
53
65
  if (shellName === "zsh") {
54
- return [path.join(home, ".zshenv"), path.join(home, ".zshrc"), path.join(home, ".zprofile")];
66
+ return [path.join(home, ".zshrc"), path.join(home, ".zprofile")];
55
67
  }
56
68
  if (shellName === "fish") {
57
69
  return [path.join(home, ".config", "fish", "config.fish")];
@@ -71,6 +83,124 @@ function hasClawvaultPathConfig(paths) {
71
83
  }
72
84
  return false;
73
85
  }
86
+ function isLikelyV2CollectionName(name) {
87
+ return V2_COLLECTION_PATTERNS.some((pattern) => pattern.test(name));
88
+ }
89
+ function checkQmdCollectionExists(collections, expectedName) {
90
+ const found = collections.find((c) => c.name === expectedName);
91
+ return { exists: !!found, collection: found };
92
+ }
93
+ function checkCollectionPathMatches(collection, expectedRoot) {
94
+ if (!collection.root) return false;
95
+ const normalizedCollectionRoot = path.resolve(collection.root);
96
+ const normalizedExpectedRoot = path.resolve(expectedRoot);
97
+ return normalizedCollectionRoot === normalizedExpectedRoot;
98
+ }
99
+ function detectMigrationIssues(vaultPath, configuredCollection, configuredRoot) {
100
+ const issues = [];
101
+ if (!hasQmd()) {
102
+ return issues;
103
+ }
104
+ let collections;
105
+ try {
106
+ collections = listQmdCollections();
107
+ } catch {
108
+ return issues;
109
+ }
110
+ const vaultConfig = loadVaultQmdConfig(vaultPath);
111
+ const expectedCollection = configuredCollection || vaultConfig.qmdCollection;
112
+ const expectedRoot = configuredRoot || vaultConfig.qmdRoot;
113
+ const { exists, collection } = checkQmdCollectionExists(collections, expectedCollection);
114
+ if (!exists) {
115
+ const potentialV2Collections = collections.filter(
116
+ (c) => isLikelyV2CollectionName(c.name) && c.root && path.resolve(c.root) === path.resolve(expectedRoot)
117
+ );
118
+ if (potentialV2Collections.length > 0) {
119
+ issues.push({
120
+ type: "stale_collection_name",
121
+ description: `Found v2-style collection "${potentialV2Collections[0].name}" that should be renamed to "${expectedCollection}"`,
122
+ autoFixable: true,
123
+ details: {
124
+ oldName: potentialV2Collections[0].name,
125
+ newName: expectedCollection,
126
+ root: potentialV2Collections[0].root
127
+ }
128
+ });
129
+ } else {
130
+ issues.push({
131
+ type: "missing_qmd_collection",
132
+ description: `qmd collection "${expectedCollection}" does not exist`,
133
+ autoFixable: true,
134
+ details: {
135
+ collectionName: expectedCollection,
136
+ expectedRoot
137
+ }
138
+ });
139
+ }
140
+ } else if (collection && !checkCollectionPathMatches(collection, expectedRoot)) {
141
+ issues.push({
142
+ type: "wrong_vault_path",
143
+ description: `Collection "${expectedCollection}" points to "${collection.root}" but vault is at "${expectedRoot}"`,
144
+ autoFixable: true,
145
+ details: {
146
+ collectionName: expectedCollection,
147
+ currentRoot: collection.root,
148
+ expectedRoot
149
+ }
150
+ });
151
+ }
152
+ const orphanedCollections = collections.filter((c) => {
153
+ if (c.name === expectedCollection) return false;
154
+ if (!c.root) return false;
155
+ const collectionRoot = path.resolve(c.root);
156
+ const vaultRoot = path.resolve(expectedRoot);
157
+ return collectionRoot === vaultRoot || collectionRoot.startsWith(vaultRoot + path.sep);
158
+ });
159
+ for (const orphan of orphanedCollections) {
160
+ issues.push({
161
+ type: "orphaned_collection",
162
+ description: `Orphaned collection "${orphan.name}" points to vault path but is not the configured collection`,
163
+ autoFixable: true,
164
+ details: {
165
+ collectionName: orphan.name,
166
+ root: orphan.root
167
+ }
168
+ });
169
+ }
170
+ const configPath = path.join(vaultPath, ".clawvault.json");
171
+ if (fs.existsSync(configPath)) {
172
+ try {
173
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
174
+ if (!config.qmdCollection || !config.qmdRoot) {
175
+ issues.push({
176
+ type: "missing_qmd_config",
177
+ description: "Vault config is missing qmdCollection or qmdRoot settings",
178
+ autoFixable: true,
179
+ details: {
180
+ hasQmdCollection: !!config.qmdCollection,
181
+ hasQmdRoot: !!config.qmdRoot
182
+ }
183
+ });
184
+ }
185
+ } catch {
186
+ issues.push({
187
+ type: "legacy_config_format",
188
+ description: "Unable to parse .clawvault.json - may need migration",
189
+ autoFixable: false
190
+ });
191
+ }
192
+ }
193
+ return issues;
194
+ }
195
+ function migrationIssuesToChecks(issues) {
196
+ return issues.map((issue) => ({
197
+ label: `migration: ${issue.type.replace(/_/g, " ")}`,
198
+ status: "warn",
199
+ detail: issue.description,
200
+ hint: issue.autoFixable ? "Run `clawvault migrate` to auto-fix this issue." : "Manual intervention required.",
201
+ category: "migration"
202
+ }));
203
+ }
74
204
  async function resolveVault(vaultPath) {
75
205
  if (vaultPath) {
76
206
  const vault = new ClawVault(path.resolve(vaultPath));
@@ -89,19 +219,19 @@ async function resolveVault(vaultPath) {
89
219
  }
90
220
  return found;
91
221
  }
92
- async function doctor(options) {
93
- const vaultPath = typeof options === "string" ? options : options?.vaultPath;
94
- const _fix = typeof options === "object" ? options?.fix : false;
222
+ async function doctor(vaultPath) {
95
223
  const checks = [];
96
224
  let warnings = 0;
97
225
  let errors = 0;
226
+ const migrationIssues = [];
98
227
  const compatReport = checkOpenClawCompatibility();
99
228
  if (compatReport.errors > 0) {
100
229
  checks.push({
101
230
  label: "OpenClaw compatibility",
102
231
  status: "error",
103
232
  detail: `${compatReport.errors} error(s), ${compatReport.warnings} warning(s)`,
104
- hint: "Run `clawvault compat` for full compatibility diagnostics."
233
+ hint: "Run `clawvault compat` for full compatibility diagnostics.",
234
+ category: "system"
105
235
  });
106
236
  errors++;
107
237
  } else if (compatReport.warnings > 0) {
@@ -109,22 +239,29 @@ async function doctor(options) {
109
239
  label: "OpenClaw compatibility",
110
240
  status: "warn",
111
241
  detail: `${compatReport.warnings} warning(s)`,
112
- hint: "Run `clawvault compat` for full compatibility diagnostics."
242
+ hint: "Run `clawvault compat` for full compatibility diagnostics.",
243
+ category: "system"
113
244
  });
114
245
  warnings++;
115
246
  } else {
116
247
  checks.push({
117
248
  label: "OpenClaw compatibility",
118
- status: "ok"
249
+ status: "ok",
250
+ category: "system"
119
251
  });
120
252
  }
121
253
  if (hasQmd()) {
122
- checks.push({ label: "qmd installed", status: "ok" });
254
+ checks.push({ label: "qmd installed", status: "ok", category: "system" });
123
255
  } else {
124
256
  checks.push({
125
257
  label: "qmd installed",
126
258
  status: "error",
127
- hint: "Install qmd to enable ClawVault commands."
259
+ detail: "qmd binary not found in PATH",
260
+ hint: `Install qmd to enable ClawVault search and indexing:
261
+ ${QMD_INSTALL_COMMAND}
262
+
263
+ For more information: ${QMD_INSTALL_URL}`,
264
+ category: "system"
128
265
  });
129
266
  errors++;
130
267
  }
@@ -133,45 +270,57 @@ async function doctor(options) {
133
270
  checks.push({
134
271
  label: "CLAWVAULT_PATH in shell config",
135
272
  status: "ok",
136
- detail: shellConfigs.map((p) => path.basename(p)).join(", ")
273
+ detail: shellConfigs.map((p) => path.basename(p)).join(", "),
274
+ category: "system"
137
275
  });
138
276
  } else {
139
277
  checks.push({
140
278
  label: "CLAWVAULT_PATH in shell config",
141
279
  status: "warn",
142
- hint: "Run `clawvault shell-init` and add it to your shell rc."
280
+ hint: "Run `clawvault shell-init` and add it to your shell rc.",
281
+ category: "system"
143
282
  });
144
283
  warnings++;
145
284
  }
146
285
  if (!hasQmd()) {
147
- return { vaultPath, checks, warnings, errors };
286
+ return { vaultPath, checks, warnings, errors, migrationIssues };
148
287
  }
149
288
  let vault;
150
289
  try {
151
290
  vault = await resolveVault(vaultPath);
152
- checks.push({ label: "vault found", status: "ok", detail: vault.getPath() });
291
+ checks.push({ label: "vault found", status: "ok", detail: vault.getPath(), category: "system" });
153
292
  } catch (err) {
154
293
  checks.push({
155
294
  label: "vault found",
156
295
  status: "error",
157
- detail: err?.message || "Unable to locate vault"
296
+ detail: err?.message || "Unable to locate vault",
297
+ category: "system"
158
298
  });
159
299
  errors++;
160
- return { vaultPath, checks, warnings, errors };
300
+ return { vaultPath, checks, warnings, errors, migrationIssues };
161
301
  }
162
- const qmdCollection = vault.getQmdCollection();
163
- const qmdRoot = vault.getQmdRoot();
302
+ const detectedMigrationIssues = detectMigrationIssues(
303
+ vault.getPath(),
304
+ vault.getQmdCollection(),
305
+ vault.getQmdRoot()
306
+ );
307
+ migrationIssues.push(...detectedMigrationIssues);
308
+ const migrationChecks = migrationIssuesToChecks(detectedMigrationIssues);
309
+ checks.push(...migrationChecks);
310
+ warnings += migrationChecks.length;
164
311
  const stats = await vault.stats();
165
312
  const documents = await vault.list();
166
313
  const handoffs = await vault.list("handoffs");
167
314
  const inbox = await vault.list("inbox");
315
+ const qmdCollection = vault.getQmdCollection();
168
316
  if (qmdCollection) {
169
- checks.push({ label: "qmd collection configured", status: "ok", detail: qmdCollection });
317
+ checks.push({ label: "qmd collection configured", status: "ok", detail: qmdCollection, category: "system" });
170
318
  } else {
171
319
  checks.push({
172
320
  label: "qmd collection configured",
173
321
  status: "warn",
174
- hint: "Set qmd collection in .clawvault.json"
322
+ hint: "Set qmd collection in .clawvault.json or run `clawvault migrate`.",
323
+ category: "system"
175
324
  });
176
325
  warnings++;
177
326
  }
@@ -183,7 +332,8 @@ async function doctor(options) {
183
332
  label: "memory graph index",
184
333
  status: "warn",
185
334
  detail: "No graph index found",
186
- hint: "Run `clawvault graph --refresh` to build .clawvault/graph-index.json."
335
+ hint: "Run `clawvault graph --refresh` to build .clawvault/graph-index.json.",
336
+ category: "health"
187
337
  });
188
338
  warnings++;
189
339
  } else {
@@ -195,14 +345,16 @@ async function doctor(options) {
195
345
  label: "memory graph index",
196
346
  status: "warn",
197
347
  detail: `Stale graph index (generated ${generatedAge} ago)`,
198
- hint: "Run `clawvault graph --refresh` to resync index."
348
+ hint: "Run `clawvault graph --refresh` to resync index.",
349
+ category: "health"
199
350
  });
200
351
  warnings++;
201
352
  } else {
202
353
  checks.push({
203
354
  label: "memory graph index",
204
355
  status: "ok",
205
- detail: `${graphIndex.graph.stats.nodeCount} nodes, ${graphIndex.graph.stats.edgeCount} edges`
356
+ detail: `${graphIndex.graph.stats.nodeCount} nodes, ${graphIndex.graph.stats.edgeCount} edges`,
357
+ category: "health"
206
358
  });
207
359
  }
208
360
  }
@@ -211,7 +363,8 @@ async function doctor(options) {
211
363
  checks.push({
212
364
  label: "recent handoff",
213
365
  status: "warn",
214
- hint: "Run `clawvault sleep` at the end of sessions."
366
+ hint: "Run `clawvault sleep` at the end of sessions.",
367
+ category: "health"
215
368
  });
216
369
  warnings++;
217
370
  } else {
@@ -223,14 +376,16 @@ async function doctor(options) {
223
376
  label: "recent handoff",
224
377
  status: "warn",
225
378
  detail: `Last handoff ${ageLabel} ago`,
226
- hint: "Run `clawvault sleep` before long pauses."
379
+ hint: "Run `clawvault sleep` before long pauses.",
380
+ category: "health"
227
381
  });
228
382
  warnings++;
229
383
  } else {
230
384
  checks.push({
231
385
  label: "recent handoff",
232
386
  status: "ok",
233
- detail: `Last handoff ${ageLabel} ago`
387
+ detail: `Last handoff ${ageLabel} ago`,
388
+ category: "health"
234
389
  });
235
390
  }
236
391
  }
@@ -240,7 +395,8 @@ async function doctor(options) {
240
395
  checks.push({
241
396
  label: "checkpoint freshness",
242
397
  status: "warn",
243
- detail: checkpointInfo.error
398
+ detail: checkpointInfo.error,
399
+ category: "health"
244
400
  });
245
401
  warnings++;
246
402
  } else if (!checkpointInfo.timestamp) {
@@ -250,7 +406,8 @@ async function doctor(options) {
250
406
  label: "checkpoint freshness",
251
407
  status,
252
408
  detail: activeUse ? "No checkpoint found" : "No checkpoint found (vault appears inactive)",
253
- hint: activeUse ? "Run `clawvault checkpoint` during heavy work." : void 0
409
+ hint: activeUse ? "Run `clawvault checkpoint` during heavy work." : void 0,
410
+ category: "health"
254
411
  });
255
412
  } else {
256
413
  const checkpointDate = new Date(checkpointInfo.timestamp);
@@ -261,14 +418,16 @@ async function doctor(options) {
261
418
  label: "checkpoint freshness",
262
419
  status: "warn",
263
420
  detail: `Last checkpoint ${ageLabel} ago`,
264
- hint: "Checkpoint at least once per active day."
421
+ hint: "Checkpoint at least once per active day.",
422
+ category: "health"
265
423
  });
266
424
  warnings++;
267
425
  } else {
268
426
  checks.push({
269
427
  label: "checkpoint freshness",
270
428
  status: "ok",
271
- detail: `Last checkpoint ${ageLabel} ago`
429
+ detail: `Last checkpoint ${ageLabel} ago`,
430
+ category: "health"
272
431
  });
273
432
  }
274
433
  }
@@ -278,13 +437,15 @@ async function doctor(options) {
278
437
  label: "observer freshness",
279
438
  status: "warn",
280
439
  detail: `${observerStaleness.staleCount} stale session cursor(s); oldest ${formatAge(observerStaleness.oldestMs)} ago`,
281
- hint: "Run `clawvault observe --cron` and verify cron/hook scheduling."
440
+ hint: "Run `clawvault observe --cron` and verify cron/hook scheduling.",
441
+ category: "health"
282
442
  });
283
443
  warnings++;
284
444
  } else {
285
445
  checks.push({
286
446
  label: "observer freshness",
287
- status: "ok"
447
+ status: "ok",
448
+ category: "health"
288
449
  });
289
450
  }
290
451
  const linkScan = scanVaultLinks(vault.getPath());
@@ -293,14 +454,16 @@ async function doctor(options) {
293
454
  label: "orphan links",
294
455
  status: "warn",
295
456
  detail: `${linkScan.orphans.length} orphan link(s)`,
296
- hint: "Run `clawvault link --orphans` to review."
457
+ hint: "Run `clawvault link --orphans` to review.",
458
+ category: "health"
297
459
  });
298
460
  warnings++;
299
461
  } else {
300
462
  checks.push({
301
463
  label: "orphan links",
302
464
  status: "ok",
303
- detail: `${linkScan.orphans.length} orphan link(s)`
465
+ detail: `${linkScan.orphans.length} orphan link(s)`,
466
+ category: "health"
304
467
  });
305
468
  }
306
469
  if (inbox.length > 5) {
@@ -308,14 +471,16 @@ async function doctor(options) {
308
471
  label: "inbox backlog",
309
472
  status: "warn",
310
473
  detail: `${inbox.length} inbox item(s) pending`,
311
- hint: "Process inbox items to keep memory tidy."
474
+ hint: "Process inbox items to keep memory tidy.",
475
+ category: "health"
312
476
  });
313
477
  warnings++;
314
478
  } else {
315
479
  checks.push({
316
480
  label: "inbox backlog",
317
481
  status: "ok",
318
- detail: `${inbox.length} inbox item(s) pending`
482
+ detail: `${inbox.length} inbox item(s) pending`,
483
+ category: "health"
319
484
  });
320
485
  }
321
486
  if (stats.documents < 5) {
@@ -323,11 +488,12 @@ async function doctor(options) {
323
488
  label: "vault activity",
324
489
  status: "warn",
325
490
  detail: `${stats.documents} total documents`,
326
- hint: "Start capturing decisions, lessons, and projects."
491
+ hint: "Start capturing decisions, lessons, and projects.",
492
+ category: "health"
327
493
  });
328
494
  warnings++;
329
495
  }
330
- return { vaultPath: vault.getPath(), qmdCollection, qmdRoot, checks, warnings, errors };
496
+ return { vaultPath: vault.getPath(), checks, warnings, errors, migrationIssues };
331
497
  }
332
498
 
333
499
  export {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadSchemaTemplateDefinition,
3
3
  renderDocumentFromTemplate
4
- } from "./chunk-LYHGEHXG.js";
4
+ } from "./chunk-MFAWT5O5.js";
5
5
 
6
6
  // src/lib/task-utils.ts
7
7
  import * as fs2 from "fs";
@@ -8,7 +8,7 @@ import {
8
8
  queryTransitions,
9
9
  readTask,
10
10
  updateTask
11
- } from "./chunk-N2AXRYLC.js";
11
+ } from "./chunk-QWQ3TIKS.js";
12
12
 
13
13
  // src/commands/task.ts
14
14
  function taskAdd(vaultPath, title, options = {}) {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runReflection
3
- } from "./chunk-H34S76MB.js";
3
+ } from "./chunk-MNPUYCHQ.js";
4
4
  import {
5
5
  resolveVaultPath
6
- } from "./chunk-MXSSG3QU.js";
6
+ } from "./chunk-GNJL4YGR.js";
7
7
 
8
8
  // src/commands/reflect.ts
9
9
  function parsePositiveInteger(raw, label) {
@@ -0,0 +1,99 @@
1
+ import {
2
+ resolveVaultPath
3
+ } from "./chunk-GNJL4YGR.js";
4
+
5
+ // src/commands/sync-bd.ts
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+ import { spawnSync } from "child_process";
9
+ function hasBdBinary() {
10
+ const probe = spawnSync("bd", ["--version"], { stdio: "ignore" });
11
+ return !probe.error;
12
+ }
13
+ function parseBdTasksFromJson(raw) {
14
+ const parsed = JSON.parse(raw);
15
+ if (!Array.isArray(parsed)) {
16
+ return [];
17
+ }
18
+ return parsed.map((entry) => {
19
+ if (!entry || typeof entry !== "object") return null;
20
+ const record = entry;
21
+ const title = typeof record.title === "string" ? record.title.trim() : typeof record.name === "string" ? record.name.trim() : "";
22
+ const status = typeof record.status === "string" ? record.status.trim().toLowerCase() : void 0;
23
+ if (!title) return null;
24
+ return status ? { title, status } : { title };
25
+ }).filter((entry) => entry !== null);
26
+ }
27
+ function loadActiveBdTasks() {
28
+ const jsonAttempt = spawnSync("bd", ["list", "--json"], { encoding: "utf-8" });
29
+ if (!jsonAttempt.error && typeof jsonAttempt.stdout === "string" && jsonAttempt.stdout.trim()) {
30
+ const tasks = parseBdTasksFromJson(jsonAttempt.stdout);
31
+ if (tasks.length > 0) {
32
+ return tasks.filter((task) => task.status !== "done" && task.status !== "completed" && task.status !== "closed");
33
+ }
34
+ }
35
+ const textAttempt = spawnSync("bd", ["list"], { encoding: "utf-8" });
36
+ if (textAttempt.error || typeof textAttempt.stdout !== "string") {
37
+ return [];
38
+ }
39
+ return textAttempt.stdout.split(/\r?\n/).map((line) => line.replace(/^\s*[-*]\s*/, "").trim()).filter(Boolean).map((title) => ({ title }));
40
+ }
41
+ function upsertSection(markdown, heading, bulletLines) {
42
+ const lines = markdown.split(/\r?\n/);
43
+ const headingIndex = lines.findIndex((line) => line.trim() === heading);
44
+ const sectionContent = [heading, ...bulletLines];
45
+ if (headingIndex === -1) {
46
+ const prefix = markdown.trim() ? `${markdown.trim()}
47
+
48
+ ` : "";
49
+ return `${prefix}${sectionContent.join("\n")}
50
+ `;
51
+ }
52
+ let sectionEnd = lines.length;
53
+ for (let index = headingIndex + 1; index < lines.length; index += 1) {
54
+ if (lines[index].startsWith("## ")) {
55
+ sectionEnd = index;
56
+ break;
57
+ }
58
+ }
59
+ const updated = [
60
+ ...lines.slice(0, headingIndex),
61
+ ...sectionContent,
62
+ ...lines.slice(sectionEnd)
63
+ ];
64
+ return `${updated.join("\n").trim()}
65
+ `;
66
+ }
67
+ async function syncBdCommand(options) {
68
+ if (!hasBdBinary()) {
69
+ console.log("bd binary not found; skipping sync-bd.");
70
+ return;
71
+ }
72
+ const tasks = loadActiveBdTasks();
73
+ const vaultPath = resolveVaultPath({ explicitPath: options.vaultPath });
74
+ const nowViewPath = path.join(vaultPath, "views", "now.md");
75
+ const heading = "## Active Tasks (from bd)";
76
+ const bulletLines = tasks.length > 0 ? tasks.map((task) => `- ${task.title}`) : ["- No active bd tasks."];
77
+ const existing = fs.existsSync(nowViewPath) ? fs.readFileSync(nowViewPath, "utf-8") : "# Now\n";
78
+ const next = upsertSection(existing, heading, bulletLines);
79
+ if (options.dryRun) {
80
+ console.log(`Dry run: would sync ${tasks.length} active bd task(s) to views/now.md.`);
81
+ return;
82
+ }
83
+ fs.mkdirSync(path.dirname(nowViewPath), { recursive: true });
84
+ fs.writeFileSync(nowViewPath, next, "utf-8");
85
+ console.log(`Synced ${tasks.length} active bd task(s) to views/now.md.`);
86
+ }
87
+ function registerSyncBdCommand(program) {
88
+ program.command("sync-bd").description("Sync active bd tasks into views/now.md").option("--dry-run", "Show task sync output without writing").option("-v, --vault <path>", "Vault path").action(async (rawOptions) => {
89
+ await syncBdCommand({
90
+ vaultPath: rawOptions.vault,
91
+ dryRun: rawOptions.dryRun
92
+ });
93
+ });
94
+ }
95
+
96
+ export {
97
+ syncBdCommand,
98
+ registerSyncBdCommand
99
+ };