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
@@ -1,871 +0,0 @@
1
- import {
2
- loadTemplateDefinition,
3
- renderDocumentFromTemplate
4
- } from "./chunk-LYHGEHXG.js";
5
- import {
6
- hasQmd,
7
- withQmdIndexArgs
8
- } from "./chunk-D2H45LON.js";
9
- import {
10
- DEFAULT_CATEGORIES
11
- } from "./chunk-2CDEETQN.js";
12
-
13
- // src/commands/setup.ts
14
- import * as fs from "fs";
15
- import * as os from "os";
16
- import * as path from "path";
17
- import { execFileSync } from "child_process";
18
- import matter from "gray-matter";
19
- var CONFIG_FILE = ".clawvault.json";
20
- function resolveVaultTarget(vaultOverride) {
21
- if (vaultOverride) {
22
- const vaultPath = path.resolve(vaultOverride);
23
- return { vaultPath, source: "--vault flag", existed: fs.existsSync(vaultPath) };
24
- }
25
- const envPath = process.env.CLAWVAULT_PATH?.trim();
26
- const home = os.homedir();
27
- if (envPath) {
28
- const vaultPath = path.resolve(envPath);
29
- return { vaultPath, source: "CLAWVAULT_PATH", existed: fs.existsSync(vaultPath) };
30
- }
31
- const candidates = [
32
- { vaultPath: path.join(home, ".openclaw", "workspace", "memory"), source: "OpenClaw default" },
33
- { vaultPath: path.resolve(process.cwd(), "memory"), source: "./memory" },
34
- { vaultPath: path.join(home, "memory"), source: "~/memory" }
35
- ];
36
- for (const candidate of candidates) {
37
- if (fs.existsSync(candidate.vaultPath)) {
38
- return { ...candidate, existed: true };
39
- }
40
- }
41
- const fallback = candidates[0];
42
- return { ...fallback, existed: false };
43
- }
44
- function ensureVaultStructure(vaultPath) {
45
- fs.mkdirSync(vaultPath, { recursive: true });
46
- for (const category of DEFAULT_CATEGORIES) {
47
- fs.mkdirSync(path.join(vaultPath, category), { recursive: true });
48
- }
49
- const configPath = path.join(vaultPath, CONFIG_FILE);
50
- if (fs.existsSync(configPath)) return false;
51
- const now = (/* @__PURE__ */ new Date()).toISOString();
52
- const name = path.basename(vaultPath);
53
- const meta = {
54
- name,
55
- version: "1.0.0",
56
- created: now,
57
- lastUpdated: now,
58
- categories: DEFAULT_CATEGORIES,
59
- documentCount: 0,
60
- qmdCollection: name,
61
- qmdRoot: vaultPath
62
- };
63
- fs.writeFileSync(configPath, JSON.stringify(meta, null, 2));
64
- return true;
65
- }
66
- function writeBases(vaultPath, force) {
67
- const basesFiles = {
68
- "all-tasks.base": `filters:
69
- and:
70
- - file.inFolder("tasks")
71
- - status != "done"
72
- formulas:
73
- age: (now() - file.ctime).days
74
- status_icon: if(status == "blocked", "\u{1F534}", if(status == "in-progress", "\u{1F528}", if(status == "open", "\u26AA", "\u2705")))
75
- views:
76
- - type: table
77
- name: All Active Tasks
78
- groupBy:
79
- property: status
80
- direction: ASC
81
- order:
82
- - formula.status_icon
83
- - file.name
84
- - status
85
- - owner
86
- - project
87
- - priority
88
- - blocked_by
89
- - formula.age
90
- - type: cards
91
- name: Task Board
92
- groupBy:
93
- property: status
94
- direction: ASC
95
- order:
96
- - file.name
97
- - owner
98
- - project
99
- - priority`,
100
- "blocked.base": `filters:
101
- and:
102
- - file.inFolder("tasks")
103
- - status == "blocked"
104
- formulas:
105
- days_blocked: (now() - file.ctime).days
106
- views:
107
- - type: table
108
- name: Blocked Tasks
109
- order:
110
- - file.name
111
- - owner
112
- - project
113
- - blocked_by
114
- - formula.days_blocked
115
- - priority`,
116
- "by-project.base": `filters:
117
- and:
118
- - file.inFolder("tasks")
119
- - status != "done"
120
- formulas:
121
- status_icon: if(status == "blocked", "\u{1F534}", if(status == "in-progress", "\u{1F528}", "\u26AA"))
122
- views:
123
- - type: table
124
- name: By Project
125
- groupBy:
126
- property: project
127
- direction: ASC
128
- order:
129
- - formula.status_icon
130
- - file.name
131
- - status
132
- - owner
133
- - priority
134
- - type: cards
135
- name: Project Cards
136
- groupBy:
137
- property: project
138
- direction: ASC
139
- order:
140
- - file.name
141
- - owner
142
- - status`,
143
- "by-owner.base": `filters:
144
- and:
145
- - file.inFolder("tasks")
146
- - status != "done"
147
- views:
148
- - type: table
149
- name: By Owner
150
- groupBy:
151
- property: owner
152
- direction: ASC
153
- order:
154
- - file.name
155
- - status
156
- - project
157
- - priority`,
158
- "backlog.base": `filters:
159
- and:
160
- - file.inFolder("backlog")
161
- views:
162
- - type: table
163
- name: Backlog
164
- order:
165
- - file.name
166
- - source
167
- - project
168
- - file.ctime`
169
- };
170
- let written = 0;
171
- for (const [filename, content] of Object.entries(basesFiles)) {
172
- const filePath = path.join(vaultPath, filename);
173
- if (force || !fs.existsSync(filePath)) {
174
- fs.writeFileSync(filePath, content);
175
- written++;
176
- }
177
- }
178
- return written;
179
- }
180
- var NEURAL_GRAPH_CSS = `/* ClawVault Graph Colors \u2014 Neural Neural Style */
181
- /* Auto-generated by \`clawvault setup --theme neural\` */
182
-
183
- body.theme-dark .graph-view .graph-view-container { background-color: #0a0a0a; }
184
-
185
- body.theme-dark .graph-view .node.tag-person circle { fill: #00b4d8 !important; }
186
- body.theme-dark .graph-view .node.tag-project circle { fill: #2d6a4f !important; }
187
- body.theme-dark .graph-view .node.tag-decision circle { fill: #e8590c !important; }
188
- body.theme-dark .graph-view .node.tag-lesson circle { fill: #fcc419 !important; }
189
- body.theme-dark .graph-view .node.tag-commitment circle { fill: #e03131 !important; }
190
- body.theme-dark .graph-view .node.tag-task circle { fill: #22b8cf !important; }
191
- body.theme-dark .graph-view .node.tag-observation circle { fill: #7950f2 !important; }
192
- body.theme-dark .graph-view .node.tag-handoff circle { fill: #845ef7 !important; }
193
- body.theme-dark .graph-view .node.tag-daily circle { fill: #495057 !important; }
194
-
195
- body.theme-dark .graph-view .node.is-focused circle {
196
- fill: #e8a430 !important; stroke: #e8a430 !important;
197
- stroke-width: 3px; filter: drop-shadow(0 0 6px #e8a430);
198
- }
199
-
200
- body.theme-dark .graph-view .link { stroke: rgba(45, 200, 120, 0.15) !important; }
201
- body.theme-dark .graph-view .link.is-focused { stroke: rgba(45, 200, 120, 0.6) !important; }
202
- body.theme-dark .graph-view .node text { fill: #c1c2c5 !important; font-size: 0.8em; }
203
- `;
204
- var MINIMAL_GRAPH_CSS = `/* ClawVault Graph Colors \u2014 Minimal */
205
- /* Auto-generated by \`clawvault setup --theme minimal\` */
206
-
207
- body.theme-dark .graph-view .node.tag-person circle { fill: #4a90e8 !important; }
208
- body.theme-dark .graph-view .node.tag-project circle { fill: #4ae85d !important; }
209
- body.theme-dark .graph-view .node.tag-decision circle { fill: #e85d4a !important; }
210
- body.theme-dark .graph-view .node.tag-lesson circle { fill: #9b59b6 !important; }
211
- body.theme-dark .graph-view .node.tag-task circle { fill: #e8a430 !important; }
212
- `;
213
- var NEURAL_COLOR_GROUPS = [
214
- { query: "path:people", color: { a: 1, rgb: 47316 } },
215
- { query: "path:projects", color: { a: 1, rgb: 2976335 } },
216
- { query: "path:decisions", color: { a: 1, rgb: 15227916 } },
217
- { query: "path:lessons", color: { a: 1, rgb: 16565273 } },
218
- { query: "path:tasks", color: { a: 1, rgb: 2275535 } },
219
- { query: "path:commitments", color: { a: 1, rgb: 14680369 } },
220
- { query: "path:backlog", color: { a: 1, rgb: 9806262 } },
221
- { query: "path:inbox", color: { a: 1, rgb: 15964178 } },
222
- { query: "path:handoffs", color: { a: 1, rgb: 8675063 } },
223
- { query: "path:ledger", color: { a: 1, rgb: 7950066 } }
224
- ];
225
- var MINIMAL_COLOR_GROUPS = [
226
- { query: "path:people", color: { a: 1, rgb: 4886760 } },
227
- { query: "path:projects", color: { a: 1, rgb: 4909149 } },
228
- { query: "path:decisions", color: { a: 1, rgb: 15228234 } },
229
- { query: "path:lessons", color: { a: 1, rgb: 10181046 } },
230
- { query: "path:tasks", color: { a: 1, rgb: 15246384 } }
231
- ];
232
- function writeGraphColors(vaultPath, theme, force) {
233
- const obsidianDir = path.join(vaultPath, ".obsidian");
234
- if (!fs.existsSync(obsidianDir)) {
235
- return false;
236
- }
237
- const snippetsDir = path.join(obsidianDir, "snippets");
238
- fs.mkdirSync(snippetsDir, { recursive: true });
239
- const snippetName = "clawvault-graph";
240
- const snippetPath = path.join(snippetsDir, `${snippetName}.css`);
241
- if (!force && fs.existsSync(snippetPath)) {
242
- return false;
243
- }
244
- const css = theme === "neural" ? NEURAL_GRAPH_CSS : MINIMAL_GRAPH_CSS;
245
- fs.writeFileSync(snippetPath, css);
246
- const appearancePath = path.join(obsidianDir, "appearance.json");
247
- let appearance = {};
248
- if (fs.existsSync(appearancePath)) {
249
- try {
250
- appearance = JSON.parse(fs.readFileSync(appearancePath, "utf-8"));
251
- } catch {
252
- }
253
- }
254
- const snippets = appearance.enabledCssSnippets || [];
255
- if (!snippets.includes(snippetName)) {
256
- snippets.push(snippetName);
257
- appearance.enabledCssSnippets = snippets;
258
- fs.writeFileSync(appearancePath, JSON.stringify(appearance, null, 2));
259
- }
260
- const graphPath = path.join(obsidianDir, "graph.json");
261
- let graphConfig = {};
262
- if (fs.existsSync(graphPath)) {
263
- try {
264
- graphConfig = JSON.parse(fs.readFileSync(graphPath, "utf-8"));
265
- } catch {
266
- }
267
- }
268
- graphConfig.colorGroups = theme === "neural" ? NEURAL_COLOR_GROUPS : MINIMAL_COLOR_GROUPS;
269
- if (theme === "neural") {
270
- graphConfig.showTags = false;
271
- graphConfig.showAttachments = false;
272
- graphConfig.nodeSizeMultiplier = 1.2;
273
- graphConfig.lineSizeMultiplier = 0.8;
274
- graphConfig.textFadeMultiplier = 0;
275
- graphConfig.repelStrength = 10;
276
- graphConfig.linkDistance = 250;
277
- graphConfig.centerStrength = 0.5;
278
- }
279
- fs.writeFileSync(graphPath, JSON.stringify(graphConfig, null, 2));
280
- return true;
281
- }
282
- function getQmdConfig(vaultPath) {
283
- const configPath = path.join(vaultPath, CONFIG_FILE);
284
- if (fs.existsSync(configPath)) {
285
- try {
286
- const meta = JSON.parse(fs.readFileSync(configPath, "utf-8"));
287
- return {
288
- collection: meta.qmdCollection || meta.name || path.basename(vaultPath),
289
- root: meta.qmdRoot || vaultPath
290
- };
291
- } catch {
292
- return { collection: path.basename(vaultPath), root: vaultPath };
293
- }
294
- }
295
- return { collection: path.basename(vaultPath), root: vaultPath };
296
- }
297
- function slugify(text) {
298
- return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").trim();
299
- }
300
- function scanMarkdownFiles(dirPath) {
301
- const files = [];
302
- const resolvedPath = path.resolve(dirPath);
303
- if (!fs.existsSync(resolvedPath)) {
304
- return files;
305
- }
306
- const stat = fs.statSync(resolvedPath);
307
- if (stat.isFile() && resolvedPath.endsWith(".md")) {
308
- return [resolvedPath];
309
- }
310
- if (!stat.isDirectory()) {
311
- return files;
312
- }
313
- const entries = fs.readdirSync(resolvedPath, { withFileTypes: true });
314
- for (const entry of entries) {
315
- const fullPath = path.join(resolvedPath, entry.name);
316
- if (entry.isFile() && entry.name.endsWith(".md")) {
317
- files.push(fullPath);
318
- } else if (entry.isDirectory()) {
319
- files.push(...scanMarkdownFiles(fullPath));
320
- }
321
- }
322
- return files;
323
- }
324
- function extractPeople(content) {
325
- const people = [];
326
- const seenNames = /* @__PURE__ */ new Set();
327
- const emailPattern = /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\s*<([^>]+@[^>]+)>/g;
328
- let match;
329
- while ((match = emailPattern.exec(content)) !== null) {
330
- const name = match[1].trim();
331
- const email = match[2].trim();
332
- if (!seenNames.has(name.toLowerCase())) {
333
- seenNames.add(name.toLowerCase());
334
- people.push({ name, email });
335
- }
336
- }
337
- const rolePatterns = [
338
- /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\s*\(([^)]+)\)/g,
339
- /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+),\s*(CEO|CTO|CFO|COO|VP|Director|Manager|Engineer|Designer|Lead|Head of [A-Za-z]+)/gi
340
- ];
341
- for (const pattern of rolePatterns) {
342
- while ((match = pattern.exec(content)) !== null) {
343
- const name = match[1].trim();
344
- const role = match[2].trim();
345
- if (!seenNames.has(name.toLowerCase())) {
346
- seenNames.add(name.toLowerCase());
347
- people.push({ name, role });
348
- }
349
- }
350
- }
351
- const contextPatterns = [
352
- /(?:contact|met with|spoke with|emailed|called|messaged|talked to|meeting with)\s+([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)/g,
353
- /([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)\s+(?:said|mentioned|suggested|recommended|asked|told me)/g
354
- ];
355
- for (const pattern of contextPatterns) {
356
- while ((match = pattern.exec(content)) !== null) {
357
- const name = match[1].trim();
358
- if (!seenNames.has(name.toLowerCase()) && name.split(" ").length >= 2) {
359
- seenNames.add(name.toLowerCase());
360
- const lineStart = content.lastIndexOf("\n", match.index) + 1;
361
- const lineEnd = content.indexOf("\n", match.index + match[0].length);
362
- const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
363
- people.push({ name, context: context.slice(0, 200) });
364
- }
365
- }
366
- }
367
- return people;
368
- }
369
- function extractPreferences(content) {
370
- const preferences = [];
371
- const seenPrefs = /* @__PURE__ */ new Set();
372
- const patterns = [
373
- // "prefers X" / "prefer X" / "I prefer X"
374
- /(?:I\s+)?prefer(?:s)?\s+(?:to\s+)?([^.,\n]+)/gi,
375
- // "likes X" / "like X"
376
- /(?:I\s+)?like(?:s)?\s+(?:to\s+)?([^.,\n]+)/gi,
377
- // "always use X"
378
- /always\s+(?:use|uses?)\s+([^.,\n]+)/gi,
379
- // "never use X"
380
- /never\s+(?:use|uses?)\s+([^.,\n]+)/gi,
381
- // "favorite X is Y"
382
- /(?:my\s+)?favorite\s+(\w+)\s+is\s+([^.,\n]+)/gi,
383
- // "prefer X over Y"
384
- /prefer(?:s)?\s+([^.,\n]+)\s+over\s+([^.,\n]+)/gi,
385
- // "use X instead of Y"
386
- /use(?:s)?\s+([^.,\n]+)\s+instead\s+of\s+([^.,\n]+)/gi
387
- ];
388
- for (const pattern of patterns) {
389
- let match;
390
- while ((match = pattern.exec(content)) !== null) {
391
- const fullMatch = match[0].trim();
392
- const key = fullMatch.toLowerCase();
393
- if (!seenPrefs.has(key) && fullMatch.length > 5 && fullMatch.length < 200) {
394
- seenPrefs.add(key);
395
- const lineStart = content.lastIndexOf("\n", match.index) + 1;
396
- const lineEnd = content.indexOf("\n", match.index + match[0].length);
397
- const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
398
- let subject = "general";
399
- let preference = fullMatch;
400
- if (match[2]) {
401
- subject = match[1].trim();
402
- preference = match[2].trim();
403
- } else if (match[1]) {
404
- preference = match[1].trim();
405
- }
406
- preferences.push({ subject, preference, context: context.slice(0, 200) });
407
- }
408
- }
409
- }
410
- return preferences;
411
- }
412
- function extractDecisions(content) {
413
- const decisions = [];
414
- const seenDecisions = /* @__PURE__ */ new Set();
415
- const patterns = [
416
- // "decided to X"
417
- /(?:I\s+|we\s+)?decided\s+(?:to\s+)?([^.,\n]+)/gi,
418
- // "decision: X" or "Decision - X"
419
- /decision[:\s-]+([^.,\n]+)/gi,
420
- // "we chose X" / "chose to X"
421
- /(?:we\s+)?chose\s+(?:to\s+)?([^.,\n]+)/gi,
422
- // "going with X"
423
- /going\s+with\s+([^.,\n]+)/gi,
424
- // "settled on X"
425
- /settled\s+on\s+([^.,\n]+)/gi,
426
- // "will use X" / "using X going forward"
427
- /(?:will\s+use|using)\s+([^.,\n]+)\s+(?:going\s+forward|from\s+now\s+on)/gi
428
- ];
429
- for (const pattern of patterns) {
430
- let match;
431
- while ((match = pattern.exec(content)) !== null) {
432
- const decision = match[1].trim();
433
- const key = decision.toLowerCase();
434
- if (!seenDecisions.has(key) && decision.length > 5 && decision.length < 200) {
435
- seenDecisions.add(key);
436
- const lineStart = content.lastIndexOf("\n", match.index) + 1;
437
- const lineEnd = content.indexOf("\n", match.index + match[0].length);
438
- const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
439
- const title = decision.length > 50 ? decision.slice(0, 50).trim() + "..." : decision;
440
- decisions.push({ title, decision, context: context.slice(0, 200) });
441
- }
442
- }
443
- }
444
- return decisions;
445
- }
446
- function extractTasks(content) {
447
- const tasks = [];
448
- const seenTasks = /* @__PURE__ */ new Set();
449
- const patterns = [
450
- // Markdown checkbox "- [ ] task"
451
- /^[\s]*[-*]\s*\[\s*\]\s*(.+)$/gm,
452
- // "TODO: task" or "TODO - task"
453
- /TODO[:\s-]+(.+)/gi,
454
- // "FIXME: task"
455
- /FIXME[:\s-]+(.+)/gi,
456
- // "need to X"
457
- /(?:I\s+|we\s+)?need\s+to\s+([^.,\n]+)/gi,
458
- // "should X" (but not "should have" which is past)
459
- /(?:I\s+|we\s+)?should\s+(?!have)([^.,\n]+)/gi,
460
- // "must X"
461
- /(?:I\s+|we\s+)?must\s+([^.,\n]+)/gi,
462
- // "remember to X"
463
- /remember\s+to\s+([^.,\n]+)/gi,
464
- // "don't forget to X"
465
- /don'?t\s+forget\s+to\s+([^.,\n]+)/gi
466
- ];
467
- for (const pattern of patterns) {
468
- let match;
469
- while ((match = pattern.exec(content)) !== null) {
470
- const taskText = match[1].trim();
471
- const key = taskText.toLowerCase();
472
- if (!seenTasks.has(key) && taskText.length > 3 && taskText.length < 200) {
473
- seenTasks.add(key);
474
- let priority = "medium";
475
- const lowerTask = taskText.toLowerCase();
476
- if (lowerTask.includes("urgent") || lowerTask.includes("asap") || lowerTask.includes("critical")) {
477
- priority = "critical";
478
- } else if (lowerTask.includes("important") || lowerTask.includes("high priority")) {
479
- priority = "high";
480
- } else if (lowerTask.includes("low priority") || lowerTask.includes("eventually") || lowerTask.includes("someday")) {
481
- priority = "low";
482
- }
483
- tasks.push({ title: taskText, priority });
484
- }
485
- }
486
- }
487
- return tasks;
488
- }
489
- function extractFromContent(content) {
490
- return {
491
- people: extractPeople(content),
492
- preferences: extractPreferences(content),
493
- decisions: extractDecisions(content),
494
- tasks: extractTasks(content)
495
- };
496
- }
497
- function scanAndExtract(sourcePath) {
498
- const files = scanMarkdownFiles(sourcePath);
499
- const combined = {
500
- people: [],
501
- preferences: [],
502
- decisions: [],
503
- tasks: []
504
- };
505
- for (const file of files) {
506
- try {
507
- const content = fs.readFileSync(file, "utf-8");
508
- const extracted = extractFromContent(content);
509
- combined.people.push(...extracted.people);
510
- combined.preferences.push(...extracted.preferences);
511
- combined.decisions.push(...extracted.decisions);
512
- combined.tasks.push(...extracted.tasks);
513
- } catch {
514
- }
515
- }
516
- const seenPeople = /* @__PURE__ */ new Set();
517
- combined.people = combined.people.filter((p) => {
518
- const key = p.name.toLowerCase();
519
- if (seenPeople.has(key)) return false;
520
- seenPeople.add(key);
521
- return true;
522
- });
523
- const seenPrefs = /* @__PURE__ */ new Set();
524
- combined.preferences = combined.preferences.filter((p) => {
525
- const key = `${p.subject}:${p.preference}`.toLowerCase();
526
- if (seenPrefs.has(key)) return false;
527
- seenPrefs.add(key);
528
- return true;
529
- });
530
- const seenDecisions = /* @__PURE__ */ new Set();
531
- combined.decisions = combined.decisions.filter((d) => {
532
- const key = d.decision.toLowerCase();
533
- if (seenDecisions.has(key)) return false;
534
- seenDecisions.add(key);
535
- return true;
536
- });
537
- const seenTasks = /* @__PURE__ */ new Set();
538
- combined.tasks = combined.tasks.filter((t) => {
539
- const key = t.title.toLowerCase();
540
- if (seenTasks.has(key)) return false;
541
- seenTasks.add(key);
542
- return true;
543
- });
544
- return combined;
545
- }
546
- function fileExistsWithSimilarName(dir, slug) {
547
- if (!fs.existsSync(dir)) return false;
548
- const files = fs.readdirSync(dir);
549
- const targetSlug = slug.toLowerCase();
550
- return files.some((f) => {
551
- const fileSlug = path.basename(f, ".md").toLowerCase();
552
- return fileSlug === targetSlug || fileSlug.includes(targetSlug) || targetSlug.includes(fileSlug);
553
- });
554
- }
555
- function writePerson(vaultPath, person, force) {
556
- const peopleDir = path.join(vaultPath, "people");
557
- fs.mkdirSync(peopleDir, { recursive: true });
558
- const slug = slugify(person.name);
559
- if (!slug) return null;
560
- const filePath = path.join(peopleDir, `${slug}.md`);
561
- if (!force && (fs.existsSync(filePath) || fileExistsWithSimilarName(peopleDir, slug))) {
562
- return null;
563
- }
564
- const template = loadTemplateDefinition("person");
565
- const now = /* @__PURE__ */ new Date();
566
- const date = now.toISOString().split("T")[0];
567
- let content;
568
- if (template) {
569
- const rendered = renderDocumentFromTemplate(template, {
570
- title: person.name,
571
- now,
572
- overrides: {
573
- relationship: person.role ? "colleague" : "contact"
574
- }
575
- });
576
- let body = rendered.content;
577
- if (person.context) {
578
- body = body.replace(/## Context\n-\s*/, `## Context
579
- - ${person.context}
580
- `);
581
- }
582
- if (person.email || person.role) {
583
- const details = [];
584
- if (person.email) details.push(`- Contact: ${person.email}`);
585
- if (person.role) details.push(`- Role: ${person.role}`);
586
- body = body.replace(/## Details\n- Contact:\n- Role:\n- Timezone:/, `## Details
587
- ${details.join("\n")}
588
- - Timezone:`);
589
- }
590
- content = matter.stringify(body, rendered.frontmatter);
591
- } else {
592
- const frontmatter = {
593
- title: person.name,
594
- date,
595
- type: "person",
596
- relationship: person.role ? "colleague" : "contact"
597
- };
598
- let body = `# ${person.name}
599
-
600
- ## Context
601
- `;
602
- if (person.context) body += `- ${person.context}
603
- `;
604
- else body += "- \n";
605
- body += "\n## Details\n";
606
- if (person.email) body += `- Contact: ${person.email}
607
- `;
608
- else body += "- Contact:\n";
609
- if (person.role) body += `- Role: ${person.role}
610
- `;
611
- else body += "- Role:\n";
612
- body += "- Timezone:\n";
613
- body += `
614
- ## History
615
- - ${date}: Added from memory import
616
- `;
617
- content = matter.stringify(body, frontmatter);
618
- }
619
- fs.writeFileSync(filePath, content);
620
- return slug;
621
- }
622
- function writePreference(vaultPath, pref, force) {
623
- const prefsDir = path.join(vaultPath, "preferences");
624
- fs.mkdirSync(prefsDir, { recursive: true });
625
- const slug = slugify(`${pref.subject}-${pref.preference}`.slice(0, 60));
626
- if (!slug) return null;
627
- const filePath = path.join(prefsDir, `${slug}.md`);
628
- if (!force && (fs.existsSync(filePath) || fileExistsWithSimilarName(prefsDir, slug))) {
629
- return null;
630
- }
631
- const now = /* @__PURE__ */ new Date();
632
- const date = now.toISOString().split("T")[0];
633
- const frontmatter = {
634
- title: `${pref.subject}: ${pref.preference}`.slice(0, 100),
635
- date,
636
- type: "preference",
637
- category: pref.subject
638
- };
639
- let body = `# ${frontmatter.title}
640
-
641
- `;
642
- body += `## Preference
643
- - ${pref.preference}
644
- `;
645
- if (pref.context) {
646
- body += `
647
- ## Context
648
- - ${pref.context}
649
- `;
650
- }
651
- body += `
652
- ## Source
653
- - Imported from memory on ${date}
654
- `;
655
- const content = matter.stringify(body, frontmatter);
656
- fs.writeFileSync(filePath, content);
657
- return slug;
658
- }
659
- function writeDecision(vaultPath, decision, force) {
660
- const decisionsDir = path.join(vaultPath, "decisions");
661
- fs.mkdirSync(decisionsDir, { recursive: true });
662
- const slug = slugify(decision.title);
663
- if (!slug) return null;
664
- const filePath = path.join(decisionsDir, `${slug}.md`);
665
- if (!force && (fs.existsSync(filePath) || fileExistsWithSimilarName(decisionsDir, slug))) {
666
- return null;
667
- }
668
- const template = loadTemplateDefinition("decision");
669
- const now = /* @__PURE__ */ new Date();
670
- const date = now.toISOString().split("T")[0];
671
- let content;
672
- if (template) {
673
- const rendered = renderDocumentFromTemplate(template, {
674
- title: decision.title,
675
- now,
676
- overrides: {
677
- status: "decided"
678
- }
679
- });
680
- let body = rendered.content;
681
- if (decision.context) {
682
- body = body.replace(/## Context\n-\s*/, `## Context
683
- - ${decision.context}
684
- `);
685
- }
686
- body = body.replace(/## Decision\n-\s*/, `## Decision
687
- - ${decision.decision}
688
- `);
689
- body = body.replace(/## Consequences\n-\s*/, `## Consequences
690
- - Imported from memory on ${date}
691
- `);
692
- content = matter.stringify(body, rendered.frontmatter);
693
- } else {
694
- const frontmatter = {
695
- title: decision.title,
696
- date,
697
- type: "decision",
698
- status: "decided"
699
- };
700
- let body = `# Decision: ${decision.title}
701
-
702
- `;
703
- body += `## Context
704
- `;
705
- if (decision.context) body += `- ${decision.context}
706
- `;
707
- else body += "- \n";
708
- body += `
709
- ## Decision
710
- - ${decision.decision}
711
- `;
712
- body += `
713
- ## Consequences
714
- - Imported from memory on ${date}
715
- `;
716
- content = matter.stringify(body, frontmatter);
717
- }
718
- fs.writeFileSync(filePath, content);
719
- return slug;
720
- }
721
- function writeTask(vaultPath, task, force) {
722
- const tasksDir = path.join(vaultPath, "tasks");
723
- fs.mkdirSync(tasksDir, { recursive: true });
724
- const slug = slugify(task.title);
725
- if (!slug) return null;
726
- const filePath = path.join(tasksDir, `${slug}.md`);
727
- if (!force && (fs.existsSync(filePath) || fileExistsWithSimilarName(tasksDir, slug))) {
728
- return null;
729
- }
730
- const template = loadTemplateDefinition("task");
731
- const now = /* @__PURE__ */ new Date();
732
- const datetime = now.toISOString();
733
- let content;
734
- if (template) {
735
- const rendered = renderDocumentFromTemplate(template, {
736
- title: task.title,
737
- now,
738
- overrides: {
739
- status: "open",
740
- priority: task.priority || "medium",
741
- source: "memory-import",
742
- description: task.description
743
- },
744
- frontmatter: { pruneEmpty: true }
745
- });
746
- content = rendered.markdown;
747
- } else {
748
- const frontmatter = {
749
- status: "open",
750
- source: "memory-import",
751
- created: datetime,
752
- updated: datetime,
753
- priority: task.priority || "medium"
754
- };
755
- if (task.description) frontmatter.description = task.description;
756
- const body = `# ${task.title}
757
-
758
- `;
759
- content = matter.stringify(body, frontmatter);
760
- }
761
- fs.writeFileSync(filePath, content);
762
- return slug;
763
- }
764
- function importToVault(vaultPath, extracted, force) {
765
- const summary = {
766
- created: { people: [], preferences: [], decisions: [], tasks: [] },
767
- skipped: { people: [], preferences: [], decisions: [], tasks: [] }
768
- };
769
- for (const person of extracted.people) {
770
- const slug = writePerson(vaultPath, person, force);
771
- if (slug) {
772
- summary.created.people.push(person.name);
773
- } else {
774
- summary.skipped.people.push(person.name);
775
- }
776
- }
777
- for (const pref of extracted.preferences) {
778
- const slug = writePreference(vaultPath, pref, force);
779
- if (slug) {
780
- summary.created.preferences.push(`${pref.subject}: ${pref.preference}`.slice(0, 50));
781
- } else {
782
- summary.skipped.preferences.push(`${pref.subject}: ${pref.preference}`.slice(0, 50));
783
- }
784
- }
785
- for (const decision of extracted.decisions) {
786
- const slug = writeDecision(vaultPath, decision, force);
787
- if (slug) {
788
- summary.created.decisions.push(decision.title);
789
- } else {
790
- summary.skipped.decisions.push(decision.title);
791
- }
792
- }
793
- for (const task of extracted.tasks) {
794
- const slug = writeTask(vaultPath, task, force);
795
- if (slug) {
796
- summary.created.tasks.push(task.title);
797
- } else {
798
- summary.skipped.tasks.push(task.title);
799
- }
800
- }
801
- return summary;
802
- }
803
- async function setupCommand(options = {}) {
804
- const target = resolveVaultTarget(options.vault);
805
- if (target.existed && !fs.statSync(target.vaultPath).isDirectory()) {
806
- throw new Error(`Vault path is not a directory: ${target.vaultPath}`);
807
- }
808
- if (!target.existed) fs.mkdirSync(target.vaultPath, { recursive: true });
809
- console.log(`${target.existed ? "Found" : "Created"} vault path (${target.source}): ${target.vaultPath}`);
810
- const initialized = ensureVaultStructure(target.vaultPath);
811
- console.log(initialized ? "\u2713 Initialized vault structure." : "\u2713 Vault structure already present.");
812
- const force = options.force ?? false;
813
- const theme = options.theme ?? "neural";
814
- const explicitFlags = options.graphColors !== void 0 || options.bases !== void 0;
815
- const doGraphColors = explicitFlags ? options.graphColors !== false : true;
816
- const doBases = explicitFlags ? options.bases !== false : true;
817
- if (doGraphColors && theme !== "none") {
818
- const wrote = writeGraphColors(target.vaultPath, theme, force);
819
- if (wrote) {
820
- console.log(`\u2713 Graph colors configured (${theme} theme)`);
821
- } else {
822
- const obsidianDir = path.join(target.vaultPath, ".obsidian");
823
- if (!fs.existsSync(obsidianDir)) {
824
- console.log("\u2298 No .obsidian directory \u2014 skipping graph colors (not an Obsidian vault)");
825
- } else {
826
- console.log("\u2298 Graph colors already exist (use --force to overwrite)");
827
- }
828
- }
829
- } else if (doGraphColors && theme === "none") {
830
- console.log("\u2298 Graph colors skipped (--theme none)");
831
- }
832
- if (doBases) {
833
- const count = writeBases(target.vaultPath, force);
834
- if (count > 0) {
835
- console.log(`\u2713 Created ${count} Obsidian Bases view${count > 1 ? "s" : ""}`);
836
- } else {
837
- console.log("\u2298 Bases views already exist (use --force to overwrite)");
838
- }
839
- }
840
- if (hasQmd()) {
841
- const { collection, root } = getQmdConfig(target.vaultPath);
842
- try {
843
- execFileSync("qmd", withQmdIndexArgs(["collection", "add", root, "--name", collection, "--mask", "**/*.md"], options.qmdIndexName), {
844
- stdio: "ignore"
845
- });
846
- console.log(`\u2713 qmd collection ready: ${collection}`);
847
- } catch {
848
- console.log("\u2298 qmd collection already exists.");
849
- }
850
- } else {
851
- console.log("\u2298 qmd not found \u2014 skipping semantic search setup.");
852
- }
853
- console.log("\nTip: add this to your shell config:");
854
- console.log(` export CLAWVAULT_PATH="${target.vaultPath}"`);
855
- console.log("\nCustomize further:");
856
- console.log(" clawvault setup --theme neural # Neural neural graph colors");
857
- console.log(" clawvault setup --theme minimal # Subtle category colors");
858
- console.log(" clawvault setup --no-bases --no-graph-colors # Structure only");
859
- console.log(" clawvault setup --force # Overwrite existing configs");
860
- }
861
-
862
- export {
863
- extractPeople,
864
- extractPreferences,
865
- extractDecisions,
866
- extractTasks,
867
- extractFromContent,
868
- scanAndExtract,
869
- importToVault,
870
- setupCommand
871
- };