clawvault 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/README.md +352 -20
  2. package/bin/clawvault.js +8 -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 -10
  6. package/bin/register-maintenance-commands.js +39 -3
  7. package/bin/register-query-commands.js +58 -29
  8. package/bin/register-task-commands.js +18 -1
  9. package/bin/register-task-commands.test.js +16 -0
  10. package/bin/register-vault-operations-commands.js +29 -1
  11. package/bin/register-workgraph-commands.js +1368 -0
  12. package/dashboard/lib/graph-diff.js +104 -0
  13. package/dashboard/lib/graph-diff.test.js +75 -0
  14. package/dashboard/lib/vault-parser.js +556 -0
  15. package/dashboard/lib/vault-parser.test.js +254 -0
  16. package/dashboard/public/app.js +796 -0
  17. package/dashboard/public/index.html +52 -0
  18. package/dashboard/public/styles.css +221 -0
  19. package/dashboard/server.js +374 -0
  20. package/dist/{chunk-F2JEUD4J.js → chunk-23YDQ3QU.js} +6 -8
  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-2ZDO52B4.js +52 -0
  24. package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
  25. package/dist/chunk-33VSQP4J.js +37 -0
  26. package/dist/chunk-4BQTQMJP.js +93 -0
  27. package/dist/{chunk-GUKMRGM7.js → chunk-4OXMU5S2.js} +1 -1
  28. package/dist/{chunk-62YTUT6J.js → chunk-4PY655YM.js} +15 -3
  29. package/dist/chunk-6FH3IULF.js +352 -0
  30. package/dist/{chunk-3NSBOUT3.js → chunk-77Q5CSPJ.js} +404 -80
  31. package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
  32. package/dist/chunk-BSJ6RIT7.js +447 -0
  33. package/dist/chunk-BUEW6IIK.js +364 -0
  34. package/dist/{chunk-WGRQ6HDV.js → chunk-CLJTREDS.js} +74 -14
  35. package/dist/chunk-EK6S23ZB.js +469 -0
  36. package/dist/{chunk-LNJA2UGL.js → chunk-ESFLMDRB.js} +9 -86
  37. package/dist/{chunk-H34S76MB.js → chunk-ESVS6K2B.js} +6 -6
  38. package/dist/{chunk-WAZ3NLWL.js → chunk-F55HGNU4.js} +0 -47
  39. package/dist/{chunk-QK3UCXWL.js → chunk-FHFUXL6G.js} +2 -2
  40. package/dist/{chunk-YKTA5JOJ.js → chunk-GAOWA7GR.js} +212 -46
  41. package/dist/chunk-GGA32J2R.js +784 -0
  42. package/dist/chunk-GNJL4YGR.js +79 -0
  43. package/dist/chunk-MDIH26GC.js +183 -0
  44. package/dist/{chunk-LYHGEHXG.js → chunk-MFAWT5O5.js} +0 -1
  45. package/dist/chunk-MM6QGW3P.js +207 -0
  46. package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
  47. package/dist/chunk-NCKFNBHJ.js +257 -0
  48. package/dist/{chunk-QBLMXKF2.js → chunk-OIWVQYQF.js} +1 -1
  49. package/dist/{chunk-42MXU7A6.js → chunk-P62WHA27.js} +58 -47
  50. package/dist/chunk-PBACDKKP.js +66 -0
  51. package/dist/{chunk-VGLOTGAS.js → chunk-QSHD36LH.js} +2 -2
  52. package/dist/{chunk-OZ7RIXTO.js → chunk-QSRRMEYM.js} +2 -2
  53. package/dist/chunk-QVEERJSP.js +152 -0
  54. package/dist/{chunk-N2AXRYLC.js → chunk-QWQ3TIKS.js} +1 -1
  55. package/dist/{chunk-3DHXQHYG.js → chunk-R2MIW5G7.js} +1 -1
  56. package/dist/{chunk-SJSFRIYS.js → chunk-SLXOR3CC.js} +2 -2
  57. package/dist/chunk-SS4B7P7V.js +99 -0
  58. package/dist/{chunk-JY6FYXIT.js → chunk-STCQGCEQ.js} +6 -11
  59. package/dist/chunk-U4O6C46S.js +154 -0
  60. package/dist/{chunk-ITPEXLHA.js → chunk-URXDAUVH.js} +24 -5
  61. package/dist/chunk-VSL7KY3M.js +189 -0
  62. package/dist/{chunk-U55BGUAU.js → chunk-W4SPAEE7.js} +6 -6
  63. package/dist/chunk-WMGIIABP.js +15 -0
  64. package/dist/{chunk-3D6BCTP6.js → chunk-X3SPPUFG.js} +51 -39
  65. package/dist/{chunk-THRJVD4L.js → chunk-Y6VJKXGL.js} +1 -1
  66. package/dist/{chunk-ZVVFWOLW.js → chunk-ZN54U2OZ.js} +123 -10
  67. package/dist/cli/index.js +32 -25
  68. package/dist/commands/archive.js +3 -3
  69. package/dist/commands/backlog.js +3 -3
  70. package/dist/commands/blocked.js +3 -3
  71. package/dist/commands/canvas.d.ts +15 -0
  72. package/dist/commands/canvas.js +200 -0
  73. package/dist/commands/checkpoint.js +2 -2
  74. package/dist/commands/compat.js +2 -2
  75. package/dist/commands/context.js +8 -6
  76. package/dist/commands/doctor.d.ts +11 -7
  77. package/dist/commands/doctor.js +18 -16
  78. package/dist/commands/embed.js +5 -6
  79. package/dist/commands/entities.js +2 -2
  80. package/dist/commands/graph.js +4 -4
  81. package/dist/commands/inject.d.ts +1 -1
  82. package/dist/commands/inject.js +5 -6
  83. package/dist/commands/kanban.js +4 -4
  84. package/dist/commands/link.js +5 -5
  85. package/dist/commands/migrate-observations.js +4 -4
  86. package/dist/commands/observe.d.ts +0 -1
  87. package/dist/commands/observe.js +14 -13
  88. package/dist/commands/project.js +5 -5
  89. package/dist/commands/rebuild-embeddings.d.ts +21 -0
  90. package/dist/commands/rebuild-embeddings.js +91 -0
  91. package/dist/commands/rebuild.js +12 -11
  92. package/dist/commands/recover.js +3 -3
  93. package/dist/commands/reflect.js +6 -7
  94. package/dist/commands/repair-session.js +1 -1
  95. package/dist/commands/replay.js +14 -14
  96. package/dist/commands/session-recap.js +1 -1
  97. package/dist/commands/setup.d.ts +2 -90
  98. package/dist/commands/setup.js +3 -21
  99. package/dist/commands/shell-init.js +1 -1
  100. package/dist/commands/sleep.d.ts +1 -1
  101. package/dist/commands/sleep.js +20 -19
  102. package/dist/commands/status.d.ts +2 -0
  103. package/dist/commands/status.js +57 -35
  104. package/dist/commands/sync-bd.d.ts +10 -0
  105. package/dist/commands/sync-bd.js +10 -0
  106. package/dist/commands/tailscale.js +3 -3
  107. package/dist/commands/task.js +4 -4
  108. package/dist/commands/template.js +2 -2
  109. package/dist/commands/wake.d.ts +1 -1
  110. package/dist/commands/wake.js +11 -10
  111. package/dist/commands/workgraph.d.ts +124 -0
  112. package/dist/commands/workgraph.js +38 -0
  113. package/dist/index.d.ts +337 -191
  114. package/dist/index.js +387 -118
  115. package/dist/{inject-Bzi5E-By.d.cts → inject-DYUrDqQO.d.ts} +3 -3
  116. package/dist/ledger-B7g7jhqG.d.ts +44 -0
  117. package/dist/lib/auto-linker.js +2 -2
  118. package/dist/lib/canvas-layout.d.ts +100 -16
  119. package/dist/lib/canvas-layout.js +21 -78
  120. package/dist/lib/config.d.ts +27 -3
  121. package/dist/lib/config.js +4 -2
  122. package/dist/lib/entity-index.js +1 -1
  123. package/dist/lib/project-utils.js +4 -4
  124. package/dist/lib/session-repair.js +1 -1
  125. package/dist/lib/session-utils.js +1 -1
  126. package/dist/lib/tailscale.js +1 -1
  127. package/dist/lib/task-utils.js +3 -3
  128. package/dist/lib/template-engine.js +1 -1
  129. package/dist/lib/webdav.js +1 -1
  130. package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
  131. package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
  132. package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
  133. package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
  134. package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
  135. package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
  136. package/dist/openclaw-plugin.d.ts +8 -0
  137. package/dist/openclaw-plugin.js +14 -0
  138. package/dist/registry-BR4326o0.d.ts +30 -0
  139. package/dist/store-CA-6sKCJ.d.ts +34 -0
  140. package/dist/thread-B9LhXNU0.d.ts +41 -0
  141. package/dist/transformers.node-A2ZRORSQ.js +46775 -0
  142. package/dist/{types-Y2_Um2Ls.d.cts → types-BbWJoC1c.d.ts} +1 -44
  143. package/dist/workgraph/index.d.ts +5 -0
  144. package/dist/workgraph/index.js +23 -0
  145. package/dist/workgraph/ledger.d.ts +2 -0
  146. package/dist/workgraph/ledger.js +25 -0
  147. package/dist/workgraph/registry.d.ts +2 -0
  148. package/dist/workgraph/registry.js +19 -0
  149. package/dist/workgraph/store.d.ts +2 -0
  150. package/dist/workgraph/store.js +25 -0
  151. package/dist/workgraph/thread.d.ts +2 -0
  152. package/dist/workgraph/thread.js +25 -0
  153. package/dist/workgraph/types.d.ts +54 -0
  154. package/dist/workgraph/types.js +7 -0
  155. package/hooks/clawvault/HOOK.md +34 -4
  156. package/hooks/clawvault/handler.js +760 -78
  157. package/hooks/clawvault/handler.test.js +235 -79
  158. package/hooks/clawvault/openclaw.plugin.json +72 -0
  159. package/openclaw.plugin.json +65 -38
  160. package/package.json +15 -18
  161. package/dist/chunk-3RG5ZIWI.js +0 -10
  162. package/dist/chunk-6U6MK36V.js +0 -205
  163. package/dist/chunk-7R7O6STJ.js +0 -88
  164. package/dist/chunk-CMB7UL7C.js +0 -327
  165. package/dist/chunk-DEFFDRVP.js +0 -938
  166. package/dist/chunk-E7MFQB6D.js +0 -163
  167. package/dist/chunk-GAJV4IGR.js +0 -82
  168. package/dist/chunk-GQSLDZTS.js +0 -560
  169. package/dist/chunk-K234IDRJ.js +0 -1073
  170. package/dist/chunk-MFM6K7PU.js +0 -374
  171. package/dist/chunk-MXSSG3QU.js +0 -42
  172. package/dist/chunk-PAH27GSN.js +0 -108
  173. package/dist/cli/index.cjs +0 -10033
  174. package/dist/cli/index.d.cts +0 -5
  175. package/dist/commands/archive.cjs +0 -287
  176. package/dist/commands/archive.d.cts +0 -11
  177. package/dist/commands/backlog.cjs +0 -721
  178. package/dist/commands/backlog.d.cts +0 -53
  179. package/dist/commands/blocked.cjs +0 -204
  180. package/dist/commands/blocked.d.cts +0 -26
  181. package/dist/commands/checkpoint.cjs +0 -244
  182. package/dist/commands/checkpoint.d.cts +0 -41
  183. package/dist/commands/compat.cjs +0 -369
  184. package/dist/commands/compat.d.cts +0 -28
  185. package/dist/commands/context.cjs +0 -2989
  186. package/dist/commands/context.d.cts +0 -2
  187. package/dist/commands/doctor.cjs +0 -3062
  188. package/dist/commands/doctor.d.cts +0 -21
  189. package/dist/commands/embed.cjs +0 -232
  190. package/dist/commands/embed.d.cts +0 -17
  191. package/dist/commands/entities.cjs +0 -141
  192. package/dist/commands/entities.d.cts +0 -7
  193. package/dist/commands/graph.cjs +0 -501
  194. package/dist/commands/graph.d.cts +0 -21
  195. package/dist/commands/inject.cjs +0 -1636
  196. package/dist/commands/inject.d.cts +0 -2
  197. package/dist/commands/kanban.cjs +0 -884
  198. package/dist/commands/kanban.d.cts +0 -63
  199. package/dist/commands/link.cjs +0 -965
  200. package/dist/commands/link.d.cts +0 -11
  201. package/dist/commands/migrate-observations.cjs +0 -362
  202. package/dist/commands/migrate-observations.d.cts +0 -19
  203. package/dist/commands/observe.cjs +0 -4099
  204. package/dist/commands/observe.d.cts +0 -23
  205. package/dist/commands/project.cjs +0 -1341
  206. package/dist/commands/project.d.cts +0 -85
  207. package/dist/commands/rebuild.cjs +0 -3136
  208. package/dist/commands/rebuild.d.cts +0 -11
  209. package/dist/commands/recover.cjs +0 -361
  210. package/dist/commands/recover.d.cts +0 -38
  211. package/dist/commands/reflect.cjs +0 -1008
  212. package/dist/commands/reflect.d.cts +0 -11
  213. package/dist/commands/repair-session.cjs +0 -457
  214. package/dist/commands/repair-session.d.cts +0 -38
  215. package/dist/commands/replay.cjs +0 -4103
  216. package/dist/commands/replay.d.cts +0 -16
  217. package/dist/commands/session-recap.cjs +0 -353
  218. package/dist/commands/session-recap.d.cts +0 -27
  219. package/dist/commands/setup.cjs +0 -1345
  220. package/dist/commands/setup.d.cts +0 -100
  221. package/dist/commands/shell-init.cjs +0 -75
  222. package/dist/commands/shell-init.d.cts +0 -7
  223. package/dist/commands/sleep.cjs +0 -6028
  224. package/dist/commands/sleep.d.cts +0 -36
  225. package/dist/commands/status.cjs +0 -2736
  226. package/dist/commands/status.d.cts +0 -52
  227. package/dist/commands/tailscale.cjs +0 -1532
  228. package/dist/commands/tailscale.d.cts +0 -52
  229. package/dist/commands/task.cjs +0 -1236
  230. package/dist/commands/task.d.cts +0 -97
  231. package/dist/commands/template.cjs +0 -457
  232. package/dist/commands/template.d.cts +0 -36
  233. package/dist/commands/wake.cjs +0 -2626
  234. package/dist/commands/wake.d.cts +0 -22
  235. package/dist/context-BUGaWpyL.d.cts +0 -46
  236. package/dist/index.cjs +0 -14526
  237. package/dist/index.d.cts +0 -858
  238. package/dist/inject-Bzi5E-By.d.ts +0 -137
  239. package/dist/lib/auto-linker.cjs +0 -176
  240. package/dist/lib/auto-linker.d.cts +0 -26
  241. package/dist/lib/canvas-layout.cjs +0 -136
  242. package/dist/lib/canvas-layout.d.cts +0 -31
  243. package/dist/lib/config.cjs +0 -78
  244. package/dist/lib/config.d.cts +0 -11
  245. package/dist/lib/entity-index.cjs +0 -84
  246. package/dist/lib/entity-index.d.cts +0 -26
  247. package/dist/lib/project-utils.cjs +0 -864
  248. package/dist/lib/project-utils.d.cts +0 -97
  249. package/dist/lib/session-repair.cjs +0 -239
  250. package/dist/lib/session-repair.d.cts +0 -110
  251. package/dist/lib/session-utils.cjs +0 -209
  252. package/dist/lib/session-utils.d.cts +0 -63
  253. package/dist/lib/tailscale.cjs +0 -1183
  254. package/dist/lib/tailscale.d.cts +0 -225
  255. package/dist/lib/task-utils.cjs +0 -1137
  256. package/dist/lib/task-utils.d.cts +0 -208
  257. package/dist/lib/template-engine.cjs +0 -47
  258. package/dist/lib/template-engine.d.cts +0 -11
  259. package/dist/lib/webdav.cjs +0 -568
  260. package/dist/lib/webdav.d.cts +0 -109
  261. package/dist/plugin/index.cjs +0 -1907
  262. package/dist/plugin/index.d.cts +0 -36
  263. package/dist/plugin/index.d.ts +0 -36
  264. package/dist/plugin/index.js +0 -572
  265. package/dist/plugin/inject.cjs +0 -356
  266. package/dist/plugin/inject.d.cts +0 -54
  267. package/dist/plugin/inject.d.ts +0 -54
  268. package/dist/plugin/inject.js +0 -17
  269. package/dist/plugin/observe.cjs +0 -631
  270. package/dist/plugin/observe.d.cts +0 -39
  271. package/dist/plugin/observe.d.ts +0 -39
  272. package/dist/plugin/observe.js +0 -18
  273. package/dist/plugin/templates.cjs +0 -593
  274. package/dist/plugin/templates.d.cts +0 -52
  275. package/dist/plugin/templates.d.ts +0 -52
  276. package/dist/plugin/templates.js +0 -25
  277. package/dist/plugin/types.cjs +0 -18
  278. package/dist/plugin/types.d.cts +0 -209
  279. package/dist/plugin/types.d.ts +0 -209
  280. package/dist/plugin/types.js +0 -0
  281. package/dist/plugin/vault.cjs +0 -927
  282. package/dist/plugin/vault.d.cts +0 -68
  283. package/dist/plugin/vault.d.ts +0 -68
  284. package/dist/plugin/vault.js +0 -22
  285. package/dist/types-Y2_Um2Ls.d.ts +0 -205
  286. package/templates/memory-event.md +0 -67
  287. package/templates/party.md +0 -63
  288. package/templates/primitive-registry.yaml +0 -551
  289. package/templates/run.md +0 -68
  290. package/templates/trigger.md +0 -68
  291. package/templates/workspace.md +0 -50
@@ -0,0 +1,784 @@
1
+ import {
2
+ block,
3
+ claim,
4
+ createThread,
5
+ decompose,
6
+ done,
7
+ release
8
+ } from "./chunk-VSL7KY3M.js";
9
+ import {
10
+ create,
11
+ list,
12
+ read
13
+ } from "./chunk-QVEERJSP.js";
14
+ import {
15
+ allClaims,
16
+ readAll,
17
+ recent
18
+ } from "./chunk-4BQTQMJP.js";
19
+ import {
20
+ defineType,
21
+ listTypes
22
+ } from "./chunk-MM6QGW3P.js";
23
+
24
+ // src/commands/workgraph.ts
25
+ import os from "os";
26
+ import path from "path";
27
+ import chalk from "chalk";
28
+ var BOX = {
29
+ topLeft: "\u256D",
30
+ topRight: "\u256E",
31
+ bottomLeft: "\u2570",
32
+ bottomRight: "\u256F",
33
+ horizontal: "\u2500",
34
+ vertical: "\u2502",
35
+ teeRight: "\u251C",
36
+ teeLeft: "\u2524",
37
+ teeDown: "\u252C",
38
+ teeUp: "\u2534",
39
+ cross: "\u253C"
40
+ };
41
+ var PRIORITY_CONFIG = {
42
+ urgent: { color: chalk.red, symbol: "\u{1F534}", label: "URGENT" },
43
+ high: { color: chalk.yellow, symbol: "\u{1F7E0}", label: "HIGH" },
44
+ medium: { color: chalk.blue, symbol: "\u{1F535}", label: "MEDIUM" },
45
+ low: { color: chalk.gray, symbol: "\u26AA", label: "LOW" }
46
+ };
47
+ var STATUS_CONFIG = {
48
+ open: { color: chalk.cyan, symbol: "\u25CB", label: "Open" },
49
+ active: { color: chalk.green, symbol: "\u25CF", label: "Active" },
50
+ blocked: { color: chalk.red, symbol: "\u2298", label: "Blocked" },
51
+ done: { color: chalk.gray, symbol: "\u2713", label: "Done" },
52
+ cancelled: { color: chalk.dim, symbol: "\u2717", label: "Cancelled" }
53
+ };
54
+ var OP_COLORS = {
55
+ create: chalk.green,
56
+ update: chalk.blue,
57
+ delete: chalk.red,
58
+ claim: chalk.yellow,
59
+ release: chalk.cyan,
60
+ block: chalk.red,
61
+ unblock: chalk.green,
62
+ done: chalk.greenBright,
63
+ cancel: chalk.gray,
64
+ define: chalk.magenta,
65
+ decompose: chalk.cyan
66
+ };
67
+ function getAgentName() {
68
+ return process.env.CLAWVAULT_AGENT ?? os.hostname();
69
+ }
70
+ function resolveVaultPath(optionPath) {
71
+ return path.resolve(optionPath ?? process.env.CLAWVAULT_PATH ?? process.cwd());
72
+ }
73
+ function formatRelativeTime(isoTimestamp) {
74
+ const now = Date.now();
75
+ const then = new Date(isoTimestamp).getTime();
76
+ const diffMs = now - then;
77
+ if (diffMs < 0) return "just now";
78
+ const seconds = Math.floor(diffMs / 1e3);
79
+ const minutes = Math.floor(seconds / 60);
80
+ const hours = Math.floor(minutes / 60);
81
+ const days = Math.floor(hours / 24);
82
+ const weeks = Math.floor(days / 7);
83
+ if (weeks > 0) return `${weeks}w ago`;
84
+ if (days > 0) return `${days}d ago`;
85
+ if (hours > 0) return `${hours}h ago`;
86
+ if (minutes > 0) return `${minutes}m ago`;
87
+ if (seconds > 0) return `${seconds}s ago`;
88
+ return "just now";
89
+ }
90
+ function drawLine(width, title) {
91
+ if (!title) {
92
+ return BOX.horizontal.repeat(width);
93
+ }
94
+ const titlePadded = ` ${title} `;
95
+ const remaining = width - titlePadded.length - 2;
96
+ const left = Math.floor(remaining / 2);
97
+ const right = remaining - left;
98
+ return BOX.horizontal.repeat(left) + chalk.bold(titlePadded) + BOX.horizontal.repeat(right);
99
+ }
100
+ function drawBox(title, lines, width = 60) {
101
+ const innerWidth = width - 2;
102
+ const output = [];
103
+ output.push(BOX.topLeft + drawLine(innerWidth, title) + BOX.topRight);
104
+ for (const line of lines) {
105
+ const stripped = stripAnsi(line);
106
+ const padding = innerWidth - stripped.length;
107
+ output.push(BOX.vertical + line + " ".repeat(Math.max(0, padding)) + BOX.vertical);
108
+ }
109
+ output.push(BOX.bottomLeft + BOX.horizontal.repeat(innerWidth) + BOX.bottomRight);
110
+ return output.join("\n");
111
+ }
112
+ function stripAnsi(str) {
113
+ return str.replace(/\x1B\[[0-9;]*m/g, "");
114
+ }
115
+ function truncate(str, maxLen) {
116
+ if (str.length <= maxLen) return str;
117
+ return str.slice(0, maxLen - 1) + "\u2026";
118
+ }
119
+ function formatThreadLine(inst, showOwner = true) {
120
+ const status = inst.fields.status;
121
+ const priority = inst.fields.priority ?? "medium";
122
+ const title = truncate(String(inst.fields.title ?? inst.path), 40);
123
+ const owner = inst.fields.owner;
124
+ const statusCfg = STATUS_CONFIG[status] ?? STATUS_CONFIG.open;
125
+ const priorityCfg = PRIORITY_CONFIG[priority] ?? PRIORITY_CONFIG.medium;
126
+ let line = `${statusCfg.color(statusCfg.symbol)} ${priorityCfg.symbol} ${chalk.white(title)}`;
127
+ if (showOwner && owner) {
128
+ line += chalk.dim(` @${owner}`);
129
+ }
130
+ return line;
131
+ }
132
+ function parseList(value) {
133
+ if (!value) return [];
134
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
135
+ }
136
+ function formatError(what, why, fix) {
137
+ return [
138
+ "",
139
+ chalk.red.bold("\u2717 Error: ") + chalk.red(what),
140
+ "",
141
+ chalk.dim("Why: ") + why,
142
+ chalk.dim("Fix: ") + chalk.cyan(fix),
143
+ ""
144
+ ].join("\n");
145
+ }
146
+ async function statusCommand(vaultPath) {
147
+ const agentName = getAgentName();
148
+ const now = /* @__PURE__ */ new Date();
149
+ const greeting = getGreeting(now.getHours());
150
+ console.log("");
151
+ console.log(chalk.bold.cyan(`${greeting}, ${agentName}!`));
152
+ console.log(chalk.dim(`${now.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })}`));
153
+ console.log("");
154
+ const allThreads = list(vaultPath, "thread");
155
+ const activeThreads = allThreads.filter((t) => t.fields.status === "active");
156
+ const openThreads = allThreads.filter((t) => t.fields.status === "open");
157
+ const blockedThreads = allThreads.filter((t) => t.fields.status === "blocked");
158
+ const myActiveThreads = activeThreads.filter((t) => t.fields.owner === agentName);
159
+ if (myActiveThreads.length > 0) {
160
+ const activeLines = myActiveThreads.map((t) => formatThreadLine(t, false));
161
+ console.log(drawBox("\u{1F525} Your Active Work", activeLines, 65));
162
+ console.log("");
163
+ }
164
+ if (openThreads.length > 0) {
165
+ const sorted = sortByPriority(openThreads);
166
+ const availableLines = sorted.slice(0, 5).map((t) => formatThreadLine(t, false));
167
+ if (sorted.length > 5) {
168
+ availableLines.push(chalk.dim(` ... and ${sorted.length - 5} more`));
169
+ }
170
+ console.log(drawBox("\u{1F4CB} Available Work", availableLines, 65));
171
+ console.log("");
172
+ }
173
+ if (blockedThreads.length > 0) {
174
+ const blockedLines = blockedThreads.slice(0, 3).map((t) => {
175
+ const title = truncate(String(t.fields.title ?? t.path), 35);
176
+ const deps = t.fields.deps ?? [];
177
+ const depStr = deps.length > 0 ? chalk.dim(` \u2192 ${deps[0]}`) : "";
178
+ return `${STATUS_CONFIG.blocked.color(STATUS_CONFIG.blocked.symbol)} ${title}${depStr}`;
179
+ });
180
+ console.log(drawBox("\u26D4 Blocked", blockedLines, 65));
181
+ console.log("");
182
+ }
183
+ const recentEntries = recent(vaultPath, 8);
184
+ if (recentEntries.length > 0) {
185
+ const activityLines = recentEntries.reverse().map((e) => {
186
+ const opColor = OP_COLORS[e.op] ?? chalk.white;
187
+ const target = truncate(path.basename(e.target, ".md"), 25);
188
+ const time = formatRelativeTime(e.ts);
189
+ return `${opColor(e.op.padEnd(8))} ${chalk.white(target)} ${chalk.dim(time)}`;
190
+ });
191
+ console.log(drawBox("\u{1F4DC} Recent Activity", activityLines, 65));
192
+ console.log("");
193
+ }
194
+ const claims = allClaims(vaultPath);
195
+ const teamMembers = /* @__PURE__ */ new Map();
196
+ for (const [target, owner] of claims) {
197
+ const current = teamMembers.get(owner) ?? [];
198
+ current.push(target);
199
+ teamMembers.set(owner, current);
200
+ }
201
+ if (teamMembers.size > 0) {
202
+ const teamLines = [];
203
+ for (const [member, threads] of teamMembers) {
204
+ const isYou = member === agentName;
205
+ const name = isYou ? chalk.green(`${member} (you)`) : chalk.white(member);
206
+ teamLines.push(`${chalk.cyan("\u25CF")} ${name}: ${chalk.dim(`${threads.length} active`)}`);
207
+ }
208
+ console.log(drawBox("\u{1F465} Team Status", teamLines, 65));
209
+ console.log("");
210
+ }
211
+ const summaryParts = [
212
+ chalk.green(`${activeThreads.length} active`),
213
+ chalk.cyan(`${openThreads.length} open`),
214
+ chalk.red(`${blockedThreads.length} blocked`)
215
+ ];
216
+ console.log(chalk.dim("Summary: ") + summaryParts.join(chalk.dim(" \xB7 ")));
217
+ console.log("");
218
+ }
219
+ function getGreeting(hour) {
220
+ if (hour < 12) return "\u2600\uFE0F Good morning";
221
+ if (hour < 17) return "\u{1F324}\uFE0F Good afternoon";
222
+ return "\u{1F319} Good evening";
223
+ }
224
+ function sortByPriority(threads) {
225
+ const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 };
226
+ return [...threads].sort((a, b) => {
227
+ const priorityA = String(a.fields.priority ?? "medium");
228
+ const priorityB = String(b.fields.priority ?? "medium");
229
+ const pa = priorityOrder[priorityA] ?? 2;
230
+ const pb = priorityOrder[priorityB] ?? 2;
231
+ return pa - pb;
232
+ });
233
+ }
234
+ async function threadCreateCommand(vaultPath, title, options) {
235
+ const agentName = getAgentName();
236
+ const goal = options.goal ?? `Complete: ${title}`;
237
+ const priority = options.priority ?? "medium";
238
+ const deps = parseList(options.deps);
239
+ const tags = parseList(options.tags);
240
+ try {
241
+ const inst = createThread(vaultPath, title, goal, agentName, {
242
+ priority,
243
+ deps,
244
+ tags
245
+ });
246
+ console.log("");
247
+ console.log(chalk.green.bold("\u2713 Thread created"));
248
+ console.log("");
249
+ console.log(chalk.dim(" Path: ") + chalk.white(inst.path));
250
+ console.log(chalk.dim(" Title: ") + chalk.white(inst.fields.title));
251
+ console.log(chalk.dim(" Goal: ") + chalk.white(inst.fields.goal));
252
+ console.log(chalk.dim(" Priority: ") + formatPriority(priority));
253
+ if (deps.length > 0) {
254
+ console.log(chalk.dim(" Deps: ") + chalk.cyan(deps.join(", ")));
255
+ }
256
+ if (tags.length > 0) {
257
+ console.log(chalk.dim(" Tags: ") + chalk.magenta(tags.join(", ")));
258
+ }
259
+ console.log("");
260
+ console.log(chalk.dim(`Claim it: ${chalk.cyan(`clawvault wg thread claim ${inst.path}`)}`));
261
+ console.log("");
262
+ } catch (err) {
263
+ const message = err instanceof Error ? err.message : String(err);
264
+ console.error(formatError(
265
+ "Failed to create thread",
266
+ message,
267
+ "Check the title is unique and vault path is correct"
268
+ ));
269
+ process.exitCode = 1;
270
+ }
271
+ }
272
+ function formatPriority(priority) {
273
+ const cfg = PRIORITY_CONFIG[priority] ?? PRIORITY_CONFIG.medium;
274
+ return cfg.color(`${cfg.symbol} ${cfg.label}`);
275
+ }
276
+ async function threadListCommand(vaultPath, options) {
277
+ let threads = list(vaultPath, "thread");
278
+ if (options.status) {
279
+ threads = threads.filter((t) => t.fields.status === options.status);
280
+ }
281
+ if (options.owner) {
282
+ const ownerFilter = options.owner === "me" ? getAgentName() : options.owner;
283
+ threads = threads.filter((t) => t.fields.owner === ownerFilter);
284
+ }
285
+ if (options.json) {
286
+ console.log(JSON.stringify(threads, null, 2));
287
+ return;
288
+ }
289
+ if (threads.length === 0) {
290
+ console.log("");
291
+ console.log(chalk.dim("No threads found matching filters."));
292
+ console.log("");
293
+ return;
294
+ }
295
+ console.log("");
296
+ console.log(chalk.bold(`Threads (${threads.length})`));
297
+ console.log(chalk.dim("\u2500".repeat(70)));
298
+ const sorted = sortByPriority(threads);
299
+ for (const t of sorted) {
300
+ const status = t.fields.status;
301
+ const priority = t.fields.priority ?? "medium";
302
+ const title = truncate(String(t.fields.title ?? t.path), 35);
303
+ const owner = t.fields.owner;
304
+ const updated = formatRelativeTime(String(t.fields.updated));
305
+ const statusCfg = STATUS_CONFIG[status] ?? STATUS_CONFIG.open;
306
+ const priorityCfg = PRIORITY_CONFIG[priority] ?? PRIORITY_CONFIG.medium;
307
+ let line = `${statusCfg.color(statusCfg.symbol.padEnd(2))}`;
308
+ line += `${priorityCfg.symbol} `;
309
+ line += chalk.white(title.padEnd(37));
310
+ line += owner ? chalk.cyan(`@${owner}`.padEnd(15)) : " ".repeat(15);
311
+ line += chalk.dim(updated);
312
+ console.log(line);
313
+ }
314
+ console.log(chalk.dim("\u2500".repeat(70)));
315
+ console.log("");
316
+ }
317
+ async function threadClaimCommand(vaultPath, threadPath) {
318
+ const agentName = getAgentName();
319
+ const normalizedPath = normalizeThreadPath(threadPath);
320
+ try {
321
+ const inst = claim(vaultPath, normalizedPath, agentName);
322
+ console.log("");
323
+ console.log(chalk.green.bold("\u2713 Thread claimed"));
324
+ console.log("");
325
+ const briefLines = [
326
+ chalk.dim("Title: ") + chalk.white.bold(inst.fields.title),
327
+ chalk.dim("Goal: ") + chalk.white(inst.fields.goal),
328
+ chalk.dim("Priority: ") + formatPriority(String(inst.fields.priority ?? "medium"))
329
+ ];
330
+ const deps = inst.fields.deps ?? [];
331
+ if (deps.length > 0) {
332
+ briefLines.push(chalk.dim("Deps: ") + chalk.cyan(deps.join(", ")));
333
+ }
334
+ const contextRefs = inst.fields.context_refs ?? [];
335
+ if (contextRefs.length > 0) {
336
+ briefLines.push(chalk.dim("Context: ") + chalk.magenta(contextRefs.join(", ")));
337
+ }
338
+ console.log(drawBox("\u{1F4CB} Work Brief", briefLines, 65));
339
+ console.log("");
340
+ if (inst.body && inst.body.trim()) {
341
+ console.log(chalk.dim("\u2500".repeat(65)));
342
+ console.log(chalk.dim("Notes:"));
343
+ console.log(inst.body.trim().split("\n").slice(0, 10).join("\n"));
344
+ console.log(chalk.dim("\u2500".repeat(65)));
345
+ console.log("");
346
+ }
347
+ console.log(chalk.dim(`When done: ${chalk.cyan(`clawvault wg thread done ${normalizedPath}`)}`));
348
+ console.log("");
349
+ } catch (err) {
350
+ const message = err instanceof Error ? err.message : String(err);
351
+ console.error(formatError(
352
+ "Failed to claim thread",
353
+ message,
354
+ 'Ensure the thread exists and is in "open" status'
355
+ ));
356
+ process.exitCode = 1;
357
+ }
358
+ }
359
+ function normalizeThreadPath(input) {
360
+ if (input.startsWith("threads/")) return input;
361
+ if (input.endsWith(".md")) return `threads/${input}`;
362
+ return `threads/${input}.md`;
363
+ }
364
+ async function threadDoneCommand(vaultPath, threadPath, options) {
365
+ const agentName = getAgentName();
366
+ const normalizedPath = normalizeThreadPath(threadPath);
367
+ try {
368
+ const inst = done(vaultPath, normalizedPath, agentName, options.output);
369
+ console.log("");
370
+ console.log(chalk.green.bold("\u2713 Thread completed!"));
371
+ console.log("");
372
+ console.log(chalk.dim(" Title: ") + chalk.white(inst.fields.title));
373
+ console.log(chalk.dim(" Status: ") + chalk.green("done"));
374
+ if (options.output) {
375
+ console.log(chalk.dim(" Output: ") + chalk.white(truncate(options.output, 50)));
376
+ }
377
+ console.log("");
378
+ console.log(chalk.dim("Great work! \u{1F389}"));
379
+ console.log("");
380
+ } catch (err) {
381
+ const message = err instanceof Error ? err.message : String(err);
382
+ console.error(formatError(
383
+ "Failed to complete thread",
384
+ message,
385
+ 'Ensure you own the thread and it is in "active" status'
386
+ ));
387
+ process.exitCode = 1;
388
+ }
389
+ }
390
+ async function threadBlockCommand(vaultPath, threadPath, options) {
391
+ const agentName = getAgentName();
392
+ const normalizedPath = normalizeThreadPath(threadPath);
393
+ if (!options.by) {
394
+ console.error(formatError(
395
+ "Missing --by option",
396
+ "You must specify what is blocking this thread",
397
+ 'clawvault wg thread block <path> --by "reason or dependency"'
398
+ ));
399
+ process.exitCode = 1;
400
+ return;
401
+ }
402
+ try {
403
+ const inst = block(vaultPath, normalizedPath, agentName, options.by, options.reason);
404
+ console.log("");
405
+ console.log(chalk.yellow.bold("\u2298 Thread blocked"));
406
+ console.log("");
407
+ console.log(chalk.dim(" Title: ") + chalk.white(inst.fields.title));
408
+ console.log(chalk.dim(" Blocked by: ") + chalk.red(options.by));
409
+ if (options.reason) {
410
+ console.log(chalk.dim(" Reason: ") + chalk.white(options.reason));
411
+ }
412
+ console.log("");
413
+ } catch (err) {
414
+ const message = err instanceof Error ? err.message : String(err);
415
+ console.error(formatError(
416
+ "Failed to block thread",
417
+ message,
418
+ 'Ensure the thread exists and is in "active" status'
419
+ ));
420
+ process.exitCode = 1;
421
+ }
422
+ }
423
+ async function threadReleaseCommand(vaultPath, threadPath, options) {
424
+ const agentName = getAgentName();
425
+ const normalizedPath = normalizeThreadPath(threadPath);
426
+ try {
427
+ const inst = release(vaultPath, normalizedPath, agentName, options.reason);
428
+ console.log("");
429
+ console.log(chalk.cyan.bold("\u21A9 Thread released"));
430
+ console.log("");
431
+ console.log(chalk.dim(" Title: ") + chalk.white(inst.fields.title));
432
+ console.log(chalk.dim(" Status: ") + chalk.cyan("open"));
433
+ if (options.reason) {
434
+ console.log(chalk.dim(" Reason: ") + chalk.white(options.reason));
435
+ }
436
+ console.log("");
437
+ console.log(chalk.dim("Thread is now available for others to claim."));
438
+ console.log("");
439
+ } catch (err) {
440
+ const message = err instanceof Error ? err.message : String(err);
441
+ console.error(formatError(
442
+ "Failed to release thread",
443
+ message,
444
+ "Ensure you own the thread"
445
+ ));
446
+ process.exitCode = 1;
447
+ }
448
+ }
449
+ async function threadDecomposeCommand(vaultPath, threadPath, options) {
450
+ const agentName = getAgentName();
451
+ const normalizedPath = normalizeThreadPath(threadPath);
452
+ if (!options.into || options.into.length === 0) {
453
+ console.error(formatError(
454
+ "Missing --into option",
455
+ "You must specify sub-thread titles",
456
+ 'clawvault wg thread decompose <path> --into "sub1" --into "sub2"'
457
+ ));
458
+ process.exitCode = 1;
459
+ return;
460
+ }
461
+ try {
462
+ const parent = read(vaultPath, normalizedPath);
463
+ if (!parent) {
464
+ throw new Error(`Thread not found: ${normalizedPath}`);
465
+ }
466
+ const subthreads = options.into.map((title) => ({
467
+ title,
468
+ goal: `Sub-task of: ${parent.fields.title}`
469
+ }));
470
+ const created = decompose(vaultPath, normalizedPath, subthreads, agentName);
471
+ console.log("");
472
+ console.log(chalk.green.bold("\u2713 Thread decomposed"));
473
+ console.log("");
474
+ console.log(chalk.dim(" Parent: ") + chalk.white(parent.fields.title));
475
+ console.log(chalk.dim(" Created sub-threads:"));
476
+ for (const sub of created) {
477
+ console.log(chalk.cyan(` \u2192 ${sub.fields.title}`));
478
+ }
479
+ console.log("");
480
+ } catch (err) {
481
+ const message = err instanceof Error ? err.message : String(err);
482
+ console.error(formatError(
483
+ "Failed to decompose thread",
484
+ message,
485
+ "Ensure the thread exists"
486
+ ));
487
+ process.exitCode = 1;
488
+ }
489
+ }
490
+ async function ledgerCommand(vaultPath, options) {
491
+ let entries = readAll(vaultPath);
492
+ if (options.actor) {
493
+ const actorFilter = options.actor === "me" ? getAgentName() : options.actor;
494
+ entries = entries.filter((e) => e.actor === actorFilter);
495
+ }
496
+ if (options.target) {
497
+ entries = entries.filter((e) => e.target.includes(options.target));
498
+ }
499
+ const limit = options.last ?? 20;
500
+ entries = entries.slice(-limit);
501
+ if (options.json) {
502
+ console.log(JSON.stringify(entries, null, 2));
503
+ return;
504
+ }
505
+ if (entries.length === 0) {
506
+ console.log("");
507
+ console.log(chalk.dim("No ledger entries found."));
508
+ console.log("");
509
+ return;
510
+ }
511
+ console.log("");
512
+ console.log(chalk.bold(`Ledger (last ${entries.length} entries)`));
513
+ console.log(chalk.dim("\u2500".repeat(80)));
514
+ for (const entry of entries.reverse()) {
515
+ const opColor = OP_COLORS[entry.op] ?? chalk.white;
516
+ const time = formatRelativeTime(entry.ts);
517
+ const target = truncate(entry.target, 30);
518
+ const actor = entry.actor;
519
+ let line = chalk.dim(time.padEnd(10));
520
+ line += opColor(entry.op.toUpperCase().padEnd(10));
521
+ line += chalk.white(target.padEnd(32));
522
+ line += chalk.cyan(`@${actor}`);
523
+ console.log(line);
524
+ if (entry.data && Object.keys(entry.data).length > 0) {
525
+ const dataStr = JSON.stringify(entry.data);
526
+ console.log(chalk.dim(` ${truncate(dataStr, 68)}`));
527
+ }
528
+ }
529
+ console.log(chalk.dim("\u2500".repeat(80)));
530
+ console.log("");
531
+ }
532
+ async function defineCommand(vaultPath, typeName, options) {
533
+ const agentName = getAgentName();
534
+ const description = options.description ?? `Custom type: ${typeName}`;
535
+ const fields = {};
536
+ if (options.fields) {
537
+ const fieldPairs = options.fields.split(",");
538
+ for (const pair of fieldPairs) {
539
+ const [name, type] = pair.split(":").map((s) => s.trim());
540
+ if (name && type) {
541
+ fields[name] = { type };
542
+ }
543
+ }
544
+ }
545
+ try {
546
+ const typeDef = defineType(
547
+ vaultPath,
548
+ typeName,
549
+ description,
550
+ fields,
551
+ agentName,
552
+ options.dir
553
+ );
554
+ console.log("");
555
+ console.log(chalk.green.bold("\u2713 Type defined"));
556
+ console.log("");
557
+ console.log(chalk.dim(" Name: ") + chalk.magenta(typeDef.name));
558
+ console.log(chalk.dim(" Directory: ") + chalk.white(typeDef.directory));
559
+ console.log(chalk.dim(" Fields:"));
560
+ for (const [fieldName, fieldDef] of Object.entries(typeDef.fields)) {
561
+ const required = fieldDef.required ? chalk.red("*") : " ";
562
+ console.log(chalk.dim(` ${required} ${fieldName}: ${fieldDef.type}`));
563
+ }
564
+ console.log("");
565
+ console.log(chalk.dim(`Create instances: ${chalk.cyan(`clawvault wg create ${typeDef.name} "title"`)}`));
566
+ console.log("");
567
+ } catch (err) {
568
+ const message = err instanceof Error ? err.message : String(err);
569
+ console.error(formatError(
570
+ "Failed to define type",
571
+ message,
572
+ "Ensure the type name is unique and not a built-in type"
573
+ ));
574
+ process.exitCode = 1;
575
+ }
576
+ }
577
+ async function typesCommand(vaultPath, options) {
578
+ const types = listTypes(vaultPath);
579
+ if (options.json) {
580
+ console.log(JSON.stringify(types, null, 2));
581
+ return;
582
+ }
583
+ console.log("");
584
+ console.log(chalk.bold(`Primitive Types (${types.length})`));
585
+ console.log(chalk.dim("\u2500".repeat(70)));
586
+ for (const typeDef of types) {
587
+ const builtInBadge = typeDef.builtIn ? chalk.cyan(" [built-in]") : chalk.magenta(" [custom]");
588
+ console.log("");
589
+ console.log(chalk.white.bold(typeDef.name) + builtInBadge);
590
+ console.log(chalk.dim(` ${typeDef.description}`));
591
+ console.log(chalk.dim(` Directory: ${typeDef.directory}/`));
592
+ console.log(chalk.dim(" Fields:"));
593
+ const fieldEntries = Object.entries(typeDef.fields);
594
+ for (const [fieldName, fieldDef] of fieldEntries) {
595
+ const required = fieldDef.required ? chalk.red("*") : " ";
596
+ const defaultVal = fieldDef.default !== void 0 ? chalk.dim(` = ${JSON.stringify(fieldDef.default)}`) : "";
597
+ const desc = fieldDef.description ? chalk.dim(` \u2014 ${fieldDef.description}`) : "";
598
+ console.log(` ${required} ${chalk.cyan(fieldName)}: ${fieldDef.type}${defaultVal}${desc}`);
599
+ }
600
+ }
601
+ console.log("");
602
+ console.log(chalk.dim("\u2500".repeat(70)));
603
+ console.log("");
604
+ }
605
+ async function createCommand(vaultPath, typeName, title, options) {
606
+ const agentName = getAgentName();
607
+ const body = options.body ?? "";
608
+ const fields = { title };
609
+ const knownOptions = /* @__PURE__ */ new Set(["body", "vault"]);
610
+ for (const [key, value] of Object.entries(options)) {
611
+ if (!knownOptions.has(key) && value !== void 0) {
612
+ fields[key] = value;
613
+ }
614
+ }
615
+ try {
616
+ const inst = create(vaultPath, typeName, fields, body, agentName);
617
+ console.log("");
618
+ console.log(chalk.green.bold(`\u2713 ${typeName} created`));
619
+ console.log("");
620
+ console.log(chalk.dim(" Path: ") + chalk.white(inst.path));
621
+ console.log(chalk.dim(" Title: ") + chalk.white(inst.fields.title));
622
+ console.log("");
623
+ } catch (err) {
624
+ const message = err instanceof Error ? err.message : String(err);
625
+ console.error(formatError(
626
+ `Failed to create ${typeName}`,
627
+ message,
628
+ `Ensure the type "${typeName}" exists. Run: clawvault wg types`
629
+ ));
630
+ process.exitCode = 1;
631
+ }
632
+ }
633
+ async function boardCommand(vaultPath, options) {
634
+ const threads = list(vaultPath, "thread");
635
+ const termWidth = options.width ?? process.stdout.columns ?? 120;
636
+ const columns = {
637
+ open: [],
638
+ active: [],
639
+ blocked: [],
640
+ done: [],
641
+ cancelled: []
642
+ };
643
+ for (const t of threads) {
644
+ const status = t.fields.status;
645
+ if (columns[status]) {
646
+ columns[status].push(t);
647
+ }
648
+ }
649
+ for (const status of Object.keys(columns)) {
650
+ columns[status] = sortByPriority(columns[status]);
651
+ }
652
+ const visibleStatuses = ["open", "active", "blocked", "done"];
653
+ const colWidth = Math.floor((termWidth - visibleStatuses.length - 1) / visibleStatuses.length);
654
+ const cardWidth = colWidth - 4;
655
+ console.log("");
656
+ console.log(chalk.bold.cyan("\u2554" + "\u2550".repeat(termWidth - 2) + "\u2557"));
657
+ console.log(chalk.bold.cyan("\u2551") + chalk.bold(" WORKGRAPH BOARD").padEnd(termWidth - 2) + chalk.bold.cyan("\u2551"));
658
+ console.log(chalk.bold.cyan("\u255A" + "\u2550".repeat(termWidth - 2) + "\u255D"));
659
+ console.log("");
660
+ let headerLine = "";
661
+ for (const status of visibleStatuses) {
662
+ const cfg = STATUS_CONFIG[status];
663
+ const header = `${cfg.symbol} ${cfg.label} (${columns[status].length})`;
664
+ const padded = header.padEnd(colWidth);
665
+ headerLine += cfg.color(padded);
666
+ }
667
+ console.log(headerLine);
668
+ console.log(chalk.dim("\u2500".repeat(termWidth)));
669
+ const maxRows = Math.max(...visibleStatuses.map((s) => columns[s].length), 1);
670
+ for (let row = 0; row < Math.min(maxRows, 15); row++) {
671
+ let line = "";
672
+ for (const status of visibleStatuses) {
673
+ const t = columns[status][row];
674
+ if (t) {
675
+ const card = formatBoardCard(t, cardWidth);
676
+ line += card.padEnd(colWidth);
677
+ } else {
678
+ line += " ".repeat(colWidth);
679
+ }
680
+ }
681
+ console.log(line);
682
+ }
683
+ if (maxRows > 15) {
684
+ console.log(chalk.dim(`... and ${maxRows - 15} more rows`));
685
+ }
686
+ console.log("");
687
+ console.log(chalk.dim("\u2500".repeat(termWidth)));
688
+ const legendParts = Object.entries(PRIORITY_CONFIG).map(
689
+ ([, cfg]) => `${cfg.symbol} ${cfg.label}`
690
+ );
691
+ console.log(chalk.dim("Priority: ") + legendParts.join(chalk.dim(" \xB7 ")));
692
+ console.log("");
693
+ }
694
+ function formatBoardCard(t, width) {
695
+ const priority = t.fields.priority ?? "medium";
696
+ const title = truncate(String(t.fields.title ?? t.path), width - 4);
697
+ const owner = t.fields.owner;
698
+ const priorityCfg = PRIORITY_CONFIG[priority] ?? PRIORITY_CONFIG.medium;
699
+ let card = `${priorityCfg.symbol} ${title}`;
700
+ if (owner) {
701
+ card += chalk.dim(` @${truncate(owner, 8)}`);
702
+ }
703
+ return card;
704
+ }
705
+ function registerWorkgraphCommands(program) {
706
+ const wg = program.command("wg").description("Workgraph \u2014 multi-agent coordination primitives");
707
+ wg.command("status").description("Agent morning briefing with active work, available tasks, and team status").option("-v, --vault <path>", "Vault path").action(async (options) => {
708
+ const vaultPath = resolveVaultPath(options.vault);
709
+ await statusCommand(vaultPath);
710
+ });
711
+ const threadCmd = wg.command("thread").description("Thread lifecycle operations");
712
+ threadCmd.command("create <title>").description("Create a new thread").option("--goal <goal>", "What success looks like").option("--priority <priority>", "urgent | high | medium | low", "medium").option("--deps <deps>", "Comma-separated dependency paths").option("--tags <tags>", "Comma-separated tags").option("-v, --vault <path>", "Vault path").action(async (title, options) => {
713
+ const vaultPath = resolveVaultPath(options.vault);
714
+ await threadCreateCommand(vaultPath, title, options);
715
+ });
716
+ threadCmd.command("list").description("List threads with optional filters").option("--status <status>", "Filter by status: open | active | blocked | done | cancelled").option("--owner <owner>", 'Filter by owner (use "me" for current agent)').option("--json", "Output as JSON").option("-v, --vault <path>", "Vault path").action(async (options) => {
717
+ const vaultPath = resolveVaultPath(options.vault);
718
+ await threadListCommand(vaultPath, options);
719
+ });
720
+ threadCmd.command("claim <path>").description("Claim a thread and show work brief").option("-v, --vault <path>", "Vault path").action(async (threadPath, options) => {
721
+ const vaultPath = resolveVaultPath(options.vault);
722
+ await threadClaimCommand(vaultPath, threadPath);
723
+ });
724
+ threadCmd.command("done <path>").description("Mark thread as complete").option("--output <output>", "Completion summary or output").option("-v, --vault <path>", "Vault path").action(async (threadPath, options) => {
725
+ const vaultPath = resolveVaultPath(options.vault);
726
+ await threadDoneCommand(vaultPath, threadPath, options);
727
+ });
728
+ threadCmd.command("block <path>").description("Block thread on a dependency").requiredOption("--by <blocker>", "What is blocking this thread").option("--reason <reason>", "Additional context").option("-v, --vault <path>", "Vault path").action(async (threadPath, options) => {
729
+ const vaultPath = resolveVaultPath(options.vault);
730
+ await threadBlockCommand(vaultPath, threadPath, options);
731
+ });
732
+ threadCmd.command("release <path>").description("Release thread back to the pool").option("--reason <reason>", "Why releasing").option("-v, --vault <path>", "Vault path").action(async (threadPath, options) => {
733
+ const vaultPath = resolveVaultPath(options.vault);
734
+ await threadReleaseCommand(vaultPath, threadPath, options);
735
+ });
736
+ threadCmd.command("decompose <path>").description("Break thread into sub-threads").option("--into <titles...>", "Sub-thread titles").option("-v, --vault <path>", "Vault path").action(async (threadPath, options) => {
737
+ const vaultPath = resolveVaultPath(options.vault);
738
+ await threadDecomposeCommand(vaultPath, threadPath, { into: options.into ?? [] });
739
+ });
740
+ wg.command("ledger").description("View coordination history").option("--last <n>", "Number of entries to show", "20").option("--actor <actor>", 'Filter by actor (use "me" for current agent)').option("--target <target>", "Filter by target path substring").option("--json", "Output as JSON").option("-v, --vault <path>", "Vault path").action(async (options) => {
741
+ const vaultPath = resolveVaultPath(options.vault);
742
+ await ledgerCommand(vaultPath, {
743
+ last: options.last ? parseInt(options.last, 10) : 20,
744
+ actor: options.actor,
745
+ target: options.target,
746
+ json: options.json
747
+ });
748
+ });
749
+ wg.command("define <type>").description("Define a new primitive type").option("--fields <fields>", "Comma-separated field definitions (name:type)").option("--dir <directory>", "Custom directory for instances").option("--description <desc>", "Type description").option("-v, --vault <path>", "Vault path").action(async (typeName, options) => {
750
+ const vaultPath = resolveVaultPath(options.vault);
751
+ await defineCommand(vaultPath, typeName, options);
752
+ });
753
+ wg.command("types").description("List all primitive types with their fields").option("--json", "Output as JSON").option("-v, --vault <path>", "Vault path").action(async (options) => {
754
+ const vaultPath = resolveVaultPath(options.vault);
755
+ await typesCommand(vaultPath, options);
756
+ });
757
+ wg.command("create <type> <title>").description("Create any primitive instance").option("--body <body>", "Markdown body content").option("-v, --vault <path>", "Vault path").allowUnknownOption(true).action(async (typeName, title, options) => {
758
+ const vaultPath = resolveVaultPath(options.vault);
759
+ await createCommand(vaultPath, typeName, title, options);
760
+ });
761
+ wg.command("board").description("Terminal kanban board view").option("--width <width>", "Terminal width override").option("-v, --vault <path>", "Vault path").action(async (options) => {
762
+ const vaultPath = resolveVaultPath(options.vault);
763
+ await boardCommand(vaultPath, {
764
+ width: options.width ? parseInt(options.width, 10) : void 0
765
+ });
766
+ });
767
+ }
768
+
769
+ export {
770
+ statusCommand,
771
+ threadCreateCommand,
772
+ threadListCommand,
773
+ threadClaimCommand,
774
+ threadDoneCommand,
775
+ threadBlockCommand,
776
+ threadReleaseCommand,
777
+ threadDecomposeCommand,
778
+ ledgerCommand,
779
+ defineCommand,
780
+ typesCommand,
781
+ createCommand,
782
+ boardCommand,
783
+ registerWorkgraphCommands
784
+ };