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
@@ -0,0 +1,520 @@
1
+ // src/lib/webdav.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ var WEBDAV_PREFIX = "/webdav";
5
+ var BLOCKED_PATHS = [
6
+ ".clawvault",
7
+ ".git",
8
+ ".obsidian",
9
+ "node_modules"
10
+ ];
11
+ var SUPPORTED_METHODS = ["GET", "PUT", "DELETE", "MKCOL", "PROPFIND", "OPTIONS", "HEAD", "MOVE", "COPY"];
12
+ function toRequestSegments(requestPath) {
13
+ return requestPath.replace(/\\/g, "/").split("/").filter(Boolean);
14
+ }
15
+ function isWithinRoot(fullPath, rootPath) {
16
+ const resolvedRoot = path.resolve(rootPath);
17
+ const relative2 = path.relative(resolvedRoot, fullPath);
18
+ return !(relative2.startsWith("..") || path.isAbsolute(relative2));
19
+ }
20
+ function isPathSafe(requestPath, rootPath) {
21
+ const pathParts = toRequestSegments(requestPath);
22
+ if (pathParts.includes("..")) {
23
+ return false;
24
+ }
25
+ const normalizedRelativePath = path.normalize(pathParts.join(path.sep));
26
+ const fullPath = path.resolve(rootPath, normalizedRelativePath);
27
+ if (!isWithinRoot(fullPath, rootPath)) {
28
+ return false;
29
+ }
30
+ for (const part of pathParts) {
31
+ if (BLOCKED_PATHS.includes(part)) {
32
+ return false;
33
+ }
34
+ }
35
+ return true;
36
+ }
37
+ function resolveWebDAVPath(requestPath, rootPath) {
38
+ const pathParts = toRequestSegments(requestPath);
39
+ if (pathParts.includes("..")) {
40
+ return null;
41
+ }
42
+ const normalizedRelativePath = path.normalize(pathParts.join(path.sep));
43
+ const fullPath = path.resolve(rootPath, normalizedRelativePath);
44
+ if (!isWithinRoot(fullPath, rootPath)) {
45
+ return null;
46
+ }
47
+ return fullPath;
48
+ }
49
+ function checkAuth(req, auth) {
50
+ if (!auth) {
51
+ return true;
52
+ }
53
+ const authHeader = req.headers.authorization;
54
+ if (!authHeader || !authHeader.startsWith("Basic ")) {
55
+ return false;
56
+ }
57
+ const base64Credentials = authHeader.slice(6);
58
+ const credentials = Buffer.from(base64Credentials, "base64").toString("utf-8");
59
+ const [username, password] = credentials.split(":");
60
+ return username === auth.username && password === auth.password;
61
+ }
62
+ function escapeXml(str) {
63
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
64
+ }
65
+ function formatWebDAVDate(date) {
66
+ return date.toUTCString();
67
+ }
68
+ function generatePropfindEntry(href, stats, isCollection) {
69
+ const resourceType = isCollection ? "<D:resourcetype><D:collection/></D:resourcetype>" : "<D:resourcetype/>";
70
+ const contentLength = stats && !isCollection ? `<D:getcontentlength>${stats.size}</D:getcontentlength>` : "";
71
+ const lastModified = stats ? `<D:getlastmodified>${formatWebDAVDate(stats.mtime)}</D:getlastmodified>` : "";
72
+ const etag = stats ? `<D:getetag>"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"</D:getetag>` : "";
73
+ const contentType = !isCollection ? "<D:getcontenttype>application/octet-stream</D:getcontenttype>" : "";
74
+ return ` <D:response>
75
+ <D:href>${escapeXml(href)}</D:href>
76
+ <D:propstat>
77
+ <D:prop>
78
+ ${resourceType}
79
+ ${contentLength}
80
+ ${lastModified}
81
+ ${etag}
82
+ ${contentType}
83
+ </D:prop>
84
+ <D:status>HTTP/1.1 200 OK</D:status>
85
+ </D:propstat>
86
+ </D:response>`;
87
+ }
88
+ function generatePropfindResponse(entries) {
89
+ const responseEntries = entries.map(
90
+ (e) => generatePropfindEntry(e.href, e.stats, e.isCollection)
91
+ ).join("\n");
92
+ return `<?xml version="1.0" encoding="utf-8"?>
93
+ <D:multistatus xmlns:D="DAV:">
94
+ ${responseEntries}
95
+ </D:multistatus>`;
96
+ }
97
+ function handleOptions(res, prefix) {
98
+ res.writeHead(200, {
99
+ "Allow": SUPPORTED_METHODS.join(", "),
100
+ "DAV": "1, 2",
101
+ "Content-Length": "0",
102
+ "Access-Control-Allow-Origin": "*",
103
+ "Access-Control-Allow-Methods": SUPPORTED_METHODS.join(", "),
104
+ "Access-Control-Allow-Headers": "Content-Type, Depth, Destination, Overwrite, Authorization",
105
+ "MS-Author-Via": "DAV"
106
+ });
107
+ res.end();
108
+ }
109
+ function handleHead(res, filePath) {
110
+ try {
111
+ const stats = fs.statSync(filePath);
112
+ if (stats.isDirectory()) {
113
+ res.writeHead(200, {
114
+ "Content-Type": "httpd/unix-directory",
115
+ "Last-Modified": formatWebDAVDate(stats.mtime),
116
+ "ETag": `"${stats.mtime.getTime().toString(16)}"`,
117
+ "Access-Control-Allow-Origin": "*"
118
+ });
119
+ } else {
120
+ res.writeHead(200, {
121
+ "Content-Type": "application/octet-stream",
122
+ "Content-Length": stats.size.toString(),
123
+ "Last-Modified": formatWebDAVDate(stats.mtime),
124
+ "ETag": `"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"`,
125
+ "Access-Control-Allow-Origin": "*"
126
+ });
127
+ }
128
+ res.end();
129
+ } catch (err) {
130
+ res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
131
+ res.end("Not Found");
132
+ }
133
+ }
134
+ function handleGet(res, filePath) {
135
+ try {
136
+ const stats = fs.statSync(filePath);
137
+ if (stats.isDirectory()) {
138
+ const entries = fs.readdirSync(filePath);
139
+ const listing = entries.join("\n");
140
+ res.writeHead(200, {
141
+ "Content-Type": "text/plain",
142
+ "Content-Length": Buffer.byteLength(listing).toString(),
143
+ "Access-Control-Allow-Origin": "*"
144
+ });
145
+ res.end(listing);
146
+ } else {
147
+ const content = fs.readFileSync(filePath);
148
+ res.writeHead(200, {
149
+ "Content-Type": "application/octet-stream",
150
+ "Content-Length": content.length.toString(),
151
+ "Last-Modified": formatWebDAVDate(stats.mtime),
152
+ "ETag": `"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"`,
153
+ "Access-Control-Allow-Origin": "*"
154
+ });
155
+ res.end(content);
156
+ }
157
+ } catch (err) {
158
+ res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
159
+ res.end("Not Found");
160
+ }
161
+ }
162
+ function handlePut(res, filePath, body) {
163
+ try {
164
+ const exists = fs.existsSync(filePath);
165
+ const dir = path.dirname(filePath);
166
+ if (!fs.existsSync(dir)) {
167
+ fs.mkdirSync(dir, { recursive: true });
168
+ }
169
+ fs.writeFileSync(filePath, body);
170
+ const status = exists ? 204 : 201;
171
+ res.writeHead(status, {
172
+ "Content-Length": "0",
173
+ "Access-Control-Allow-Origin": "*"
174
+ });
175
+ res.end();
176
+ } catch (err) {
177
+ res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
178
+ res.end(`Error: ${err}`);
179
+ }
180
+ }
181
+ function handleDelete(res, filePath) {
182
+ try {
183
+ if (!fs.existsSync(filePath)) {
184
+ res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
185
+ res.end("Not Found");
186
+ return;
187
+ }
188
+ const stats = fs.statSync(filePath);
189
+ if (stats.isDirectory()) {
190
+ fs.rmSync(filePath, { recursive: true });
191
+ } else {
192
+ fs.unlinkSync(filePath);
193
+ }
194
+ res.writeHead(204, {
195
+ "Content-Length": "0",
196
+ "Access-Control-Allow-Origin": "*"
197
+ });
198
+ res.end();
199
+ } catch (err) {
200
+ res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
201
+ res.end(`Error: ${err}`);
202
+ }
203
+ }
204
+ function handleMkcol(res, filePath) {
205
+ try {
206
+ if (fs.existsSync(filePath)) {
207
+ res.writeHead(405, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
208
+ res.end("Resource already exists");
209
+ return;
210
+ }
211
+ const parent = path.dirname(filePath);
212
+ if (!fs.existsSync(parent)) {
213
+ res.writeHead(409, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
214
+ res.end("Parent directory does not exist");
215
+ return;
216
+ }
217
+ fs.mkdirSync(filePath);
218
+ res.writeHead(201, {
219
+ "Content-Length": "0",
220
+ "Access-Control-Allow-Origin": "*"
221
+ });
222
+ res.end();
223
+ } catch (err) {
224
+ res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
225
+ res.end(`Error: ${err}`);
226
+ }
227
+ }
228
+ function handlePropfind(res, filePath, webdavPath, prefix, depth) {
229
+ try {
230
+ if (!fs.existsSync(filePath)) {
231
+ res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
232
+ res.end("Not Found");
233
+ return;
234
+ }
235
+ const stats = fs.statSync(filePath);
236
+ const entries = [];
237
+ const normalizedWebdavPath = webdavPath.startsWith("/") ? webdavPath : "/" + webdavPath;
238
+ const href = prefix + normalizedWebdavPath;
239
+ entries.push({
240
+ href: href.endsWith("/") || stats.isDirectory() ? href : href,
241
+ stats,
242
+ isCollection: stats.isDirectory()
243
+ });
244
+ if (stats.isDirectory() && depth !== "0") {
245
+ try {
246
+ const children = fs.readdirSync(filePath);
247
+ for (const child of children) {
248
+ if (BLOCKED_PATHS.includes(child)) {
249
+ continue;
250
+ }
251
+ const childPath = path.join(filePath, child);
252
+ const childWebdavPath = normalizedWebdavPath.endsWith("/") ? normalizedWebdavPath + child : normalizedWebdavPath + "/" + child;
253
+ try {
254
+ const childStats = fs.statSync(childPath);
255
+ entries.push({
256
+ href: prefix + childWebdavPath,
257
+ stats: childStats,
258
+ isCollection: childStats.isDirectory()
259
+ });
260
+ } catch {
261
+ }
262
+ }
263
+ } catch {
264
+ }
265
+ }
266
+ const xml = generatePropfindResponse(entries);
267
+ res.writeHead(207, {
268
+ "Content-Type": "application/xml; charset=utf-8",
269
+ "Content-Length": Buffer.byteLength(xml).toString(),
270
+ "Access-Control-Allow-Origin": "*"
271
+ });
272
+ res.end(xml);
273
+ } catch (err) {
274
+ res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
275
+ res.end(`Error: ${err}`);
276
+ }
277
+ }
278
+ function handleMove(res, sourcePath, destinationPath, overwrite) {
279
+ try {
280
+ if (!fs.existsSync(sourcePath)) {
281
+ res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
282
+ res.end("Source not found");
283
+ return;
284
+ }
285
+ if (!destinationPath) {
286
+ res.writeHead(400, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
287
+ res.end("Destination header required");
288
+ return;
289
+ }
290
+ const destExists = fs.existsSync(destinationPath);
291
+ if (destExists && !overwrite) {
292
+ res.writeHead(412, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
293
+ res.end("Destination exists and Overwrite is F");
294
+ return;
295
+ }
296
+ const destDir = path.dirname(destinationPath);
297
+ if (!fs.existsSync(destDir)) {
298
+ fs.mkdirSync(destDir, { recursive: true });
299
+ }
300
+ if (destExists) {
301
+ const destStats = fs.statSync(destinationPath);
302
+ if (destStats.isDirectory()) {
303
+ fs.rmSync(destinationPath, { recursive: true });
304
+ } else {
305
+ fs.unlinkSync(destinationPath);
306
+ }
307
+ }
308
+ fs.renameSync(sourcePath, destinationPath);
309
+ const status = destExists ? 204 : 201;
310
+ res.writeHead(status, {
311
+ "Content-Length": "0",
312
+ "Access-Control-Allow-Origin": "*"
313
+ });
314
+ res.end();
315
+ } catch (err) {
316
+ res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
317
+ res.end(`Error: ${err}`);
318
+ }
319
+ }
320
+ function handleCopy(res, sourcePath, destinationPath, overwrite) {
321
+ try {
322
+ if (!fs.existsSync(sourcePath)) {
323
+ res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
324
+ res.end("Source not found");
325
+ return;
326
+ }
327
+ if (!destinationPath) {
328
+ res.writeHead(400, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
329
+ res.end("Destination header required");
330
+ return;
331
+ }
332
+ const destExists = fs.existsSync(destinationPath);
333
+ if (destExists && !overwrite) {
334
+ res.writeHead(412, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
335
+ res.end("Destination exists and Overwrite is F");
336
+ return;
337
+ }
338
+ const destDir = path.dirname(destinationPath);
339
+ if (!fs.existsSync(destDir)) {
340
+ fs.mkdirSync(destDir, { recursive: true });
341
+ }
342
+ const sourceStats = fs.statSync(sourcePath);
343
+ if (sourceStats.isDirectory()) {
344
+ copyDirRecursive(sourcePath, destinationPath);
345
+ } else {
346
+ fs.copyFileSync(sourcePath, destinationPath);
347
+ }
348
+ const status = destExists ? 204 : 201;
349
+ res.writeHead(status, {
350
+ "Content-Length": "0",
351
+ "Access-Control-Allow-Origin": "*"
352
+ });
353
+ res.end();
354
+ } catch (err) {
355
+ res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
356
+ res.end(`Error: ${err}`);
357
+ }
358
+ }
359
+ function copyDirRecursive(src, dest) {
360
+ if (!fs.existsSync(dest)) {
361
+ fs.mkdirSync(dest, { recursive: true });
362
+ }
363
+ const entries = fs.readdirSync(src, { withFileTypes: true });
364
+ for (const entry of entries) {
365
+ const srcPath = path.join(src, entry.name);
366
+ const destPath = path.join(dest, entry.name);
367
+ if (entry.isDirectory()) {
368
+ copyDirRecursive(srcPath, destPath);
369
+ } else {
370
+ fs.copyFileSync(srcPath, destPath);
371
+ }
372
+ }
373
+ }
374
+ function parseDestinationHeader(destinationHeader, prefix, rootPath) {
375
+ if (!destinationHeader) {
376
+ return null;
377
+ }
378
+ try {
379
+ let destPath;
380
+ if (destinationHeader.startsWith("http://") || destinationHeader.startsWith("https://")) {
381
+ const url = new URL(destinationHeader);
382
+ destPath = decodeURIComponent(url.pathname);
383
+ } else {
384
+ destPath = decodeURIComponent(destinationHeader);
385
+ }
386
+ if (destPath.startsWith(prefix)) {
387
+ destPath = destPath.slice(prefix.length);
388
+ }
389
+ return resolveWebDAVPath(destPath, rootPath);
390
+ } catch {
391
+ return null;
392
+ }
393
+ }
394
+ function createWebDAVHandler(config) {
395
+ const { rootPath, prefix = WEBDAV_PREFIX, auth } = config;
396
+ return async (req, res) => {
397
+ const rawUrl = req.url || "/";
398
+ if (rawUrl.includes("..")) {
399
+ if (rawUrl.startsWith(prefix)) {
400
+ res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
401
+ res.end("Forbidden");
402
+ return true;
403
+ }
404
+ }
405
+ const url = new URL(rawUrl, `http://${req.headers.host || "localhost"}`);
406
+ const pathname = decodeURIComponent(url.pathname);
407
+ if (!pathname.startsWith(prefix)) {
408
+ return false;
409
+ }
410
+ let webdavPath = pathname.slice(prefix.length);
411
+ if (!webdavPath.startsWith("/")) {
412
+ webdavPath = "/" + webdavPath;
413
+ }
414
+ if (req.method === "OPTIONS") {
415
+ handleOptions(res, prefix);
416
+ return true;
417
+ }
418
+ if (!checkAuth(req, auth)) {
419
+ res.writeHead(401, {
420
+ "WWW-Authenticate": 'Basic realm="ClawVault WebDAV"',
421
+ "Content-Type": "text/plain",
422
+ "Access-Control-Allow-Origin": "*"
423
+ });
424
+ res.end("Unauthorized");
425
+ return true;
426
+ }
427
+ if (!isPathSafe(webdavPath, rootPath)) {
428
+ res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
429
+ res.end("Forbidden");
430
+ return true;
431
+ }
432
+ const filePath = resolveWebDAVPath(webdavPath, rootPath);
433
+ if (!filePath) {
434
+ res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
435
+ res.end("Forbidden");
436
+ return true;
437
+ }
438
+ const depth = req.headers.depth || "infinity";
439
+ const overwrite = req.headers.overwrite?.toUpperCase() !== "F";
440
+ const destinationHeader = req.headers.destination;
441
+ switch (req.method) {
442
+ case "HEAD":
443
+ handleHead(res, filePath);
444
+ return true;
445
+ case "GET":
446
+ handleGet(res, filePath);
447
+ return true;
448
+ case "PUT": {
449
+ const chunks = [];
450
+ for await (const chunk of req) {
451
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
452
+ }
453
+ const body = Buffer.concat(chunks);
454
+ handlePut(res, filePath, body);
455
+ return true;
456
+ }
457
+ case "DELETE":
458
+ handleDelete(res, filePath);
459
+ return true;
460
+ case "MKCOL":
461
+ handleMkcol(res, filePath);
462
+ return true;
463
+ case "PROPFIND":
464
+ handlePropfind(res, filePath, webdavPath, prefix, depth);
465
+ return true;
466
+ case "MOVE": {
467
+ const destPath = parseDestinationHeader(destinationHeader, prefix, rootPath);
468
+ if (destPath && destinationHeader) {
469
+ const destWebdavPath = destinationHeader.includes(prefix) ? destinationHeader.slice(destinationHeader.indexOf(prefix) + prefix.length) : destinationHeader;
470
+ if (!isPathSafe(destWebdavPath, rootPath)) {
471
+ res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
472
+ res.end("Forbidden");
473
+ return true;
474
+ }
475
+ }
476
+ handleMove(res, filePath, destPath, overwrite);
477
+ return true;
478
+ }
479
+ case "COPY": {
480
+ const destPath = parseDestinationHeader(destinationHeader, prefix, rootPath);
481
+ if (destPath && destinationHeader) {
482
+ const destWebdavPath = destinationHeader.includes(prefix) ? destinationHeader.slice(destinationHeader.indexOf(prefix) + prefix.length) : destinationHeader;
483
+ if (!isPathSafe(destWebdavPath, rootPath)) {
484
+ res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
485
+ res.end("Forbidden");
486
+ return true;
487
+ }
488
+ }
489
+ handleCopy(res, filePath, destPath, overwrite);
490
+ return true;
491
+ }
492
+ default:
493
+ res.writeHead(405, {
494
+ "Allow": SUPPORTED_METHODS.join(", "),
495
+ "Content-Type": "text/plain",
496
+ "Access-Control-Allow-Origin": "*"
497
+ });
498
+ res.end("Method Not Allowed");
499
+ return true;
500
+ }
501
+ };
502
+ }
503
+
504
+ export {
505
+ WEBDAV_PREFIX,
506
+ isPathSafe,
507
+ resolveWebDAVPath,
508
+ checkAuth,
509
+ generatePropfindResponse,
510
+ handleOptions,
511
+ handleHead,
512
+ handleGet,
513
+ handlePut,
514
+ handleDelete,
515
+ handleMkcol,
516
+ handlePropfind,
517
+ handleMove,
518
+ handleCopy,
519
+ createWebDAVHandler
520
+ };
@@ -0,0 +1,93 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-U67V476Y.js";
4
+
5
+ // src/workgraph/ledger.ts
6
+ var ledger_exports = {};
7
+ __export(ledger_exports, {
8
+ activityOf: () => activityOf,
9
+ allClaims: () => allClaims,
10
+ append: () => append,
11
+ currentOwner: () => currentOwner,
12
+ historyOf: () => historyOf,
13
+ isClaimed: () => isClaimed,
14
+ ledgerPath: () => ledgerPath,
15
+ readAll: () => readAll,
16
+ readSince: () => readSince,
17
+ recent: () => recent
18
+ });
19
+ import fs from "fs";
20
+ import path from "path";
21
+ var LEDGER_FILE = ".clawvault/ledger.jsonl";
22
+ function ledgerPath(vaultPath) {
23
+ return path.join(vaultPath, LEDGER_FILE);
24
+ }
25
+ function append(vaultPath, actor, op, target, type, data) {
26
+ const entry = {
27
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
28
+ actor,
29
+ op,
30
+ target,
31
+ ...type ? { type } : {},
32
+ ...data && Object.keys(data).length > 0 ? { data } : {}
33
+ };
34
+ const lPath = ledgerPath(vaultPath);
35
+ const dir = path.dirname(lPath);
36
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
37
+ fs.appendFileSync(lPath, JSON.stringify(entry) + "\n", "utf-8");
38
+ return entry;
39
+ }
40
+ function readAll(vaultPath) {
41
+ const lPath = ledgerPath(vaultPath);
42
+ if (!fs.existsSync(lPath)) return [];
43
+ const lines = fs.readFileSync(lPath, "utf-8").split("\n").filter(Boolean);
44
+ return lines.map((line) => JSON.parse(line));
45
+ }
46
+ function readSince(vaultPath, since) {
47
+ return readAll(vaultPath).filter((e) => e.ts >= since);
48
+ }
49
+ function currentOwner(vaultPath, target) {
50
+ const entries = readAll(vaultPath).filter((e) => e.target === target);
51
+ let owner = null;
52
+ for (const e of entries) {
53
+ if (e.op === "claim") owner = e.actor;
54
+ if (e.op === "release" || e.op === "done" || e.op === "cancel") owner = null;
55
+ }
56
+ return owner;
57
+ }
58
+ function isClaimed(vaultPath, target) {
59
+ return currentOwner(vaultPath, target) !== null;
60
+ }
61
+ function historyOf(vaultPath, target) {
62
+ return readAll(vaultPath).filter((e) => e.target === target);
63
+ }
64
+ function activityOf(vaultPath, actor) {
65
+ return readAll(vaultPath).filter((e) => e.actor === actor);
66
+ }
67
+ function allClaims(vaultPath) {
68
+ const claims = /* @__PURE__ */ new Map();
69
+ const entries = readAll(vaultPath);
70
+ for (const e of entries) {
71
+ if (e.op === "claim") claims.set(e.target, e.actor);
72
+ if (e.op === "release" || e.op === "done" || e.op === "cancel") claims.delete(e.target);
73
+ }
74
+ return claims;
75
+ }
76
+ function recent(vaultPath, count = 20) {
77
+ const all = readAll(vaultPath);
78
+ return all.slice(-count);
79
+ }
80
+
81
+ export {
82
+ ledgerPath,
83
+ append,
84
+ readAll,
85
+ readSince,
86
+ currentOwner,
87
+ isClaimed,
88
+ historyOf,
89
+ activityOf,
90
+ allClaims,
91
+ recent,
92
+ ledger_exports
93
+ };