clawvault 2.5.3 → 2.6.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 (95) hide show
  1. package/README.md +159 -159
  2. package/bin/clawvault.js +111 -111
  3. package/bin/command-registration.test.js +166 -166
  4. package/bin/command-runtime.js +93 -93
  5. package/bin/command-runtime.test.js +154 -154
  6. package/bin/help-contract.test.js +39 -39
  7. package/bin/register-config-commands.js +153 -153
  8. package/bin/register-config-route-commands.test.js +121 -121
  9. package/bin/register-core-commands.js +237 -237
  10. package/bin/register-kanban-commands.js +56 -56
  11. package/bin/register-kanban-commands.test.js +83 -83
  12. package/bin/register-maintenance-commands.js +282 -282
  13. package/bin/register-project-commands.js +209 -209
  14. package/bin/register-project-commands.test.js +206 -206
  15. package/bin/register-query-commands.js +317 -317
  16. package/bin/register-query-commands.test.js +65 -65
  17. package/bin/register-resilience-commands.js +182 -182
  18. package/bin/register-resilience-commands.test.js +81 -81
  19. package/bin/register-route-commands.js +114 -114
  20. package/bin/register-session-lifecycle-commands.js +206 -206
  21. package/bin/register-tailscale-commands.js +106 -106
  22. package/bin/register-task-commands.js +348 -348
  23. package/bin/register-task-commands.test.js +69 -69
  24. package/bin/register-template-commands.js +75 -72
  25. package/bin/register-template-commands.test.js +87 -0
  26. package/bin/register-vault-operations-commands.js +300 -300
  27. package/bin/test-helpers/cli-command-fixtures.js +119 -119
  28. package/dashboard/lib/graph-diff.js +104 -104
  29. package/dashboard/lib/graph-diff.test.js +75 -75
  30. package/dashboard/lib/vault-parser.js +556 -556
  31. package/dashboard/lib/vault-parser.test.js +254 -254
  32. package/dashboard/public/app.js +796 -796
  33. package/dashboard/public/index.html +52 -52
  34. package/dashboard/public/styles.css +221 -221
  35. package/dashboard/server.js +374 -374
  36. package/dist/{chunk-J5EMBUPK.js → chunk-4OXMU5S2.js} +1 -1
  37. package/dist/{chunk-3FP5BJ42.js → chunk-4QYGFWRM.js} +1 -1
  38. package/dist/{chunk-4IV3R2F5.js → chunk-4TE4JMLA.js} +1 -1
  39. package/dist/{chunk-5GZFTAL7.js → chunk-AZYOKJYC.js} +128 -42
  40. package/dist/{chunk-FG6RJMCN.js → chunk-HA5M6KJB.js} +4 -4
  41. package/dist/{chunk-IZEY5S74.js → chunk-IEVLHNLU.js} +1 -1
  42. package/dist/{chunk-CLE2HHNT.js → chunk-IVRIKYFE.js} +18 -11
  43. package/dist/{chunk-AY4PGUVL.js → chunk-KL4NAOMO.js} +1 -1
  44. package/dist/{chunk-O7XHXF7F.js → chunk-MAKNAHAW.js} +4 -4
  45. package/dist/{chunk-OSMS7QIG.js → chunk-ME37YNW3.js} +2 -2
  46. package/dist/chunk-MFAWT5O5.js +301 -0
  47. package/dist/{chunk-TPDH3JPP.js → chunk-PBEE567J.js} +1 -1
  48. package/dist/{chunk-S2IG7VNM.js → chunk-Q2J5YTUF.js} +2 -2
  49. package/dist/{chunk-IOALNTAN.js → chunk-QWQ3TIKS.js} +103 -29
  50. package/dist/{chunk-YCVDVI5B.js → chunk-R2MIW5G7.js} +1 -1
  51. package/dist/{chunk-M25QVSJM.js → chunk-RVYA52PY.js} +1 -1
  52. package/dist/{chunk-NZ4ZZNSR.js → chunk-THRJVD4L.js} +1 -1
  53. package/dist/{chunk-4GBPTBFJ.js → chunk-TIGW564L.js} +1 -1
  54. package/dist/{chunk-LMEMZGUV.js → chunk-UEOUADMO.js} +3 -3
  55. package/dist/{chunk-GFJ3LIIB.js → chunk-XAVB4GB4.js} +1 -1
  56. package/dist/cli/index.js +15 -13
  57. package/dist/commands/backlog.js +3 -1
  58. package/dist/commands/blocked.js +3 -1
  59. package/dist/commands/canvas.js +3 -1
  60. package/dist/commands/context.js +3 -3
  61. package/dist/commands/doctor.js +9 -7
  62. package/dist/commands/embed.js +2 -2
  63. package/dist/commands/kanban.js +4 -2
  64. package/dist/commands/observe.js +7 -5
  65. package/dist/commands/project.js +5 -3
  66. package/dist/commands/rebuild.js +6 -4
  67. package/dist/commands/replay.js +6 -4
  68. package/dist/commands/setup.js +2 -2
  69. package/dist/commands/sleep.js +7 -5
  70. package/dist/commands/status.js +8 -6
  71. package/dist/commands/tailscale.js +3 -3
  72. package/dist/commands/task.js +4 -2
  73. package/dist/commands/template.d.ts +10 -1
  74. package/dist/commands/template.js +47 -55
  75. package/dist/commands/wake.js +2 -2
  76. package/dist/index.js +23 -22
  77. package/dist/lib/project-utils.js +4 -2
  78. package/dist/lib/tailscale.js +2 -2
  79. package/dist/lib/task-utils.d.ts +14 -13
  80. package/dist/lib/task-utils.js +3 -1
  81. package/dist/lib/template-engine.d.ts +1 -0
  82. package/dist/lib/webdav.js +1 -1
  83. package/hooks/clawvault/HOOK.md +83 -83
  84. package/hooks/clawvault/handler.js +816 -816
  85. package/hooks/clawvault/handler.test.js +263 -263
  86. package/package.json +94 -94
  87. package/templates/checkpoint.md +34 -19
  88. package/templates/daily-note.md +34 -19
  89. package/templates/daily.md +34 -19
  90. package/templates/decision.md +39 -17
  91. package/templates/handoff.md +34 -19
  92. package/templates/lesson.md +31 -16
  93. package/templates/person.md +37 -19
  94. package/templates/project.md +84 -23
  95. package/templates/task.md +81 -0
@@ -1,348 +1,348 @@
1
- /**
2
- * Task tracking command registrations for ClawVault
3
- * Registers task, backlog, blocked, and canvas commands
4
- */
5
-
6
- function parseCsvList(value) {
7
- if (!value) return undefined;
8
- const items = String(value)
9
- .split(',')
10
- .map((item) => item.trim())
11
- .filter(Boolean);
12
- return items.length > 0 ? items : undefined;
13
- }
14
-
15
- function clearableValue(value, shouldClear) {
16
- if (shouldClear) return null;
17
- return value;
18
- }
19
-
20
- export function registerTaskCommands(
21
- program,
22
- { chalk, resolveVaultPath }
23
- ) {
24
- // === TASK ===
25
- const taskCmd = program
26
- .command('task')
27
- .description('Manage tasks');
28
-
29
- // task add
30
- taskCmd
31
- .command('add <title>')
32
- .description('Add a new task')
33
- .option('-v, --vault <path>', 'Vault path')
34
- .option('--owner <owner>', 'Task owner')
35
- .option('--project <project>', 'Project name')
36
- .option('--priority <priority>', 'Priority (critical, high, medium, low)')
37
- .option('--due <date>', 'Due date (YYYY-MM-DD)')
38
- .option('--tags <tags>', 'Comma-separated tags')
39
- .option('--description <description>', 'One-line task summary')
40
- .option('--estimate <estimate>', 'Estimate (for example: 2h, 1d, 1w)')
41
- .option('--parent <slug>', 'Parent task slug')
42
- .option('--depends-on <slugs>', 'Comma-separated dependency slugs')
43
- .action(async (title, options) => {
44
- try {
45
- const vaultPath = resolveVaultPath(options.vault);
46
- const { taskCommand } = await import('../dist/commands/task.js');
47
- await taskCommand(vaultPath, 'add', {
48
- title,
49
- options: {
50
- owner: options.owner,
51
- project: options.project,
52
- priority: options.priority,
53
- due: options.due,
54
- tags: parseCsvList(options.tags),
55
- description: options.description,
56
- estimate: options.estimate,
57
- parent: options.parent,
58
- dependsOn: parseCsvList(options.dependsOn)
59
- }
60
- });
61
- } catch (err) {
62
- console.error(chalk.red(`Error: ${err.message}`));
63
- process.exit(1);
64
- }
65
- });
66
-
67
- // task list
68
- taskCmd
69
- .command('list')
70
- .description('List tasks with optional filters')
71
- .option('-v, --vault <path>', 'Vault path')
72
- .option('--owner <owner>', 'Filter by owner')
73
- .option('--project <project>', 'Filter by project')
74
- .option('--status <status>', 'Filter by status (open, in-progress, blocked, done)')
75
- .option('--priority <priority>', 'Filter by priority')
76
- .option('--due', 'Show only tasks with due dates (sorted by due date)')
77
- .option('--tag <tag>', 'Filter by tag')
78
- .option('--overdue', 'Show overdue tasks that are not done')
79
- .option('--json', 'Output as JSON')
80
- .action(async (options) => {
81
- try {
82
- const vaultPath = resolveVaultPath(options.vault);
83
- const { taskCommand } = await import('../dist/commands/task.js');
84
- await taskCommand(vaultPath, 'list', {
85
- options: {
86
- owner: options.owner,
87
- project: options.project,
88
- status: options.status,
89
- priority: options.priority,
90
- due: options.due,
91
- tag: options.tag,
92
- overdue: options.overdue,
93
- json: options.json
94
- }
95
- });
96
- } catch (err) {
97
- console.error(chalk.red(`Error: ${err.message}`));
98
- process.exit(1);
99
- }
100
- });
101
-
102
- // task update
103
- taskCmd
104
- .command('update <slug>')
105
- .description('Update a task')
106
- .option('-v, --vault <path>', 'Vault path')
107
- .option('--status <status>', 'New status')
108
- .option('--owner <owner>', 'New owner')
109
- .option('--clear-owner', 'Clear owner')
110
- .option('--project <project>', 'New project')
111
- .option('--clear-project', 'Clear project')
112
- .option('--priority <priority>', 'New priority')
113
- .option('--clear-priority', 'Clear priority')
114
- .option('--blocked-by <blocker>', 'What is blocking this task')
115
- .option('--clear-blocked-by', 'Clear blocked-by field')
116
- .option('--due <date>', 'New due date')
117
- .option('--clear-due', 'Clear due date')
118
- .option('--tags <tags>', 'Comma-separated tags')
119
- .option('--clear-tags', 'Clear tags')
120
- .option('--description <description>', 'One-line task summary')
121
- .option('--clear-description', 'Clear description')
122
- .option('--estimate <estimate>', 'Estimate (for example: 2h, 1d, 1w)')
123
- .option('--clear-estimate', 'Clear estimate')
124
- .option('--parent <slug>', 'Parent task slug')
125
- .option('--clear-parent', 'Clear parent task')
126
- .option('--depends-on <slugs>', 'Comma-separated dependency slugs')
127
- .option('--clear-depends-on', 'Clear dependencies')
128
- .option('--confidence <value>', 'Transition confidence (0-1)', parseFloat)
129
- .option('--reason <reason>', 'Reason for status change')
130
- .option('--clear-reason', 'Clear reason')
131
- .action(async (slug, options) => {
132
- try {
133
- const vaultPath = resolveVaultPath(options.vault);
134
- const { taskCommand } = await import('../dist/commands/task.js');
135
- await taskCommand(vaultPath, 'update', {
136
- slug,
137
- options: {
138
- status: options.status,
139
- owner: clearableValue(options.owner, options.clearOwner),
140
- project: clearableValue(options.project, options.clearProject),
141
- priority: clearableValue(options.priority, options.clearPriority),
142
- blockedBy: clearableValue(options.blockedBy, options.clearBlockedBy),
143
- due: clearableValue(options.due, options.clearDue),
144
- tags: options.clearTags ? null : parseCsvList(options.tags),
145
- description: clearableValue(options.description, options.clearDescription),
146
- estimate: clearableValue(options.estimate, options.clearEstimate),
147
- parent: clearableValue(options.parent, options.clearParent),
148
- dependsOn: options.clearDependsOn ? null : parseCsvList(options.dependsOn),
149
- confidence: options.confidence,
150
- reason: clearableValue(options.reason, options.clearReason)
151
- }
152
- });
153
- } catch (err) {
154
- console.error(chalk.red(`Error: ${err.message}`));
155
- process.exit(1);
156
- }
157
- });
158
-
159
- // task done
160
- taskCmd
161
- .command('done <slug>')
162
- .description('Mark a task as done')
163
- .option('-v, --vault <path>', 'Vault path')
164
- .option('--confidence <value>', 'Transition confidence (0-1)', parseFloat)
165
- .option('--reason <reason>', 'Reason for completion')
166
- .action(async (slug, options) => {
167
- try {
168
- const vaultPath = resolveVaultPath(options.vault);
169
- const { taskCommand } = await import('../dist/commands/task.js');
170
- await taskCommand(vaultPath, 'done', {
171
- slug,
172
- options: {
173
- confidence: options.confidence,
174
- reason: options.reason
175
- }
176
- });
177
- } catch (err) {
178
- console.error(chalk.red(`Error: ${err.message}`));
179
- process.exit(1);
180
- }
181
- });
182
-
183
- // task transitions
184
- taskCmd
185
- .command('transitions [task_id]')
186
- .description('Show transition history')
187
- .option('-v, --vault <path>', 'Vault path')
188
- .option('--agent <id>', 'Filter by agent')
189
- .option('--failed', 'Show only regression transitions')
190
- .option('--json', 'Output as JSON')
191
- .action(async (taskId, options) => {
192
- try {
193
- const vaultPath = resolveVaultPath(options.vault);
194
- const { taskCommand } = await import('../dist/commands/task.js');
195
- await taskCommand(vaultPath, 'transitions', {
196
- slug: taskId,
197
- options: {
198
- agent: options.agent,
199
- failed: options.failed,
200
- json: options.json
201
- }
202
- });
203
- } catch (err) {
204
- console.error(chalk.red(`Error: ${err.message}`));
205
- process.exit(1);
206
- }
207
- });
208
-
209
- // task show
210
- taskCmd
211
- .command('show <slug>')
212
- .description('Show task details')
213
- .option('-v, --vault <path>', 'Vault path')
214
- .option('--json', 'Output as JSON')
215
- .action(async (slug, options) => {
216
- try {
217
- const vaultPath = resolveVaultPath(options.vault);
218
- const { taskCommand } = await import('../dist/commands/task.js');
219
- await taskCommand(vaultPath, 'show', {
220
- slug,
221
- options: { json: options.json }
222
- });
223
- } catch (err) {
224
- console.error(chalk.red(`Error: ${err.message}`));
225
- process.exit(1);
226
- }
227
- });
228
-
229
- // === BACKLOG ===
230
- const backlogCmd = program
231
- .command('backlog')
232
- .description('Manage backlog items');
233
-
234
- // backlog add (also supports "backlog <title>" shorthand)
235
- backlogCmd
236
- .command('add <title>')
237
- .description('Add item to backlog')
238
- .option('-v, --vault <path>', 'Vault path')
239
- .option('--source <source>', 'Source of the idea')
240
- .option('--project <project>', 'Project name')
241
- .action(async (title, options) => {
242
- try {
243
- const vaultPath = resolveVaultPath(options.vault);
244
- const { backlogCommand } = await import('../dist/commands/backlog.js');
245
- await backlogCommand(vaultPath, 'add', {
246
- title,
247
- options: {
248
- source: options.source,
249
- project: options.project
250
- }
251
- });
252
- } catch (err) {
253
- console.error(chalk.red(`Error: ${err.message}`));
254
- process.exit(1);
255
- }
256
- });
257
-
258
- // backlog list
259
- backlogCmd
260
- .command('list')
261
- .description('List backlog items')
262
- .option('-v, --vault <path>', 'Vault path')
263
- .option('--project <project>', 'Filter by project')
264
- .option('--json', 'Output as JSON')
265
- .action(async (options) => {
266
- try {
267
- const vaultPath = resolveVaultPath(options.vault);
268
- const { backlogCommand } = await import('../dist/commands/backlog.js');
269
- await backlogCommand(vaultPath, 'list', {
270
- options: {
271
- project: options.project,
272
- json: options.json
273
- }
274
- });
275
- } catch (err) {
276
- console.error(chalk.red(`Error: ${err.message}`));
277
- process.exit(1);
278
- }
279
- });
280
-
281
- // backlog promote
282
- backlogCmd
283
- .command('promote <slug>')
284
- .description('Promote backlog item to task')
285
- .option('-v, --vault <path>', 'Vault path')
286
- .option('--owner <owner>', 'Task owner')
287
- .option('--priority <priority>', 'Task priority')
288
- .option('--due <date>', 'Due date')
289
- .action(async (slug, options) => {
290
- try {
291
- const vaultPath = resolveVaultPath(options.vault);
292
- const { backlogCommand } = await import('../dist/commands/backlog.js');
293
- await backlogCommand(vaultPath, 'promote', {
294
- slug,
295
- options: {
296
- owner: options.owner,
297
- priority: options.priority,
298
- due: options.due
299
- }
300
- });
301
- } catch (err) {
302
- console.error(chalk.red(`Error: ${err.message}`));
303
- process.exit(1);
304
- }
305
- });
306
-
307
- // === BLOCKED ===
308
- program
309
- .command('blocked')
310
- .description('View blocked tasks')
311
- .option('-v, --vault <path>', 'Vault path')
312
- .option('--project <project>', 'Filter by project')
313
- .option('--escalated', 'Show only escalated tasks (3+ blocked transitions)')
314
- .option('--json', 'Output as JSON')
315
- .action(async (options) => {
316
- try {
317
- const vaultPath = resolveVaultPath(options.vault);
318
- const { blockedCommand } = await import('../dist/commands/blocked.js');
319
- await blockedCommand(vaultPath, {
320
- project: options.project,
321
- escalated: options.escalated,
322
- json: options.json
323
- });
324
- } catch (err) {
325
- console.error(chalk.red(`Error: ${err.message}`));
326
- process.exit(1);
327
- }
328
- });
329
-
330
- // === CANVAS ===
331
- program
332
- .command('canvas')
333
- .description('Generate an Obsidian canvas dashboard file')
334
- .option('-v, --vault <path>', 'Vault path (default: find nearest)')
335
- .option('--output <path>', 'Output file path (default: dashboard.canvas)')
336
- .action(async (options) => {
337
- try {
338
- const vaultPath = resolveVaultPath(options.vault);
339
- const { canvasCommand } = await import('../dist/commands/canvas.js');
340
- await canvasCommand(vaultPath, {
341
- output: options.output
342
- });
343
- } catch (err) {
344
- console.error(chalk.red(`Error: ${err.message}`));
345
- process.exit(1);
346
- }
347
- });
348
- }
1
+ /**
2
+ * Task tracking command registrations for ClawVault
3
+ * Registers task, backlog, blocked, and canvas commands
4
+ */
5
+
6
+ function parseCsvList(value) {
7
+ if (!value) return undefined;
8
+ const items = String(value)
9
+ .split(',')
10
+ .map((item) => item.trim())
11
+ .filter(Boolean);
12
+ return items.length > 0 ? items : undefined;
13
+ }
14
+
15
+ function clearableValue(value, shouldClear) {
16
+ if (shouldClear) return null;
17
+ return value;
18
+ }
19
+
20
+ export function registerTaskCommands(
21
+ program,
22
+ { chalk, resolveVaultPath }
23
+ ) {
24
+ // === TASK ===
25
+ const taskCmd = program
26
+ .command('task')
27
+ .description('Manage tasks');
28
+
29
+ // task add
30
+ taskCmd
31
+ .command('add <title>')
32
+ .description('Add a new task')
33
+ .option('-v, --vault <path>', 'Vault path')
34
+ .option('--owner <owner>', 'Task owner')
35
+ .option('--project <project>', 'Project name')
36
+ .option('--priority <priority>', 'Priority (critical, high, medium, low)')
37
+ .option('--due <date>', 'Due date (YYYY-MM-DD)')
38
+ .option('--tags <tags>', 'Comma-separated tags')
39
+ .option('--description <description>', 'One-line task summary')
40
+ .option('--estimate <estimate>', 'Estimate (for example: 2h, 1d, 1w)')
41
+ .option('--parent <slug>', 'Parent task slug')
42
+ .option('--depends-on <slugs>', 'Comma-separated dependency slugs')
43
+ .action(async (title, options) => {
44
+ try {
45
+ const vaultPath = resolveVaultPath(options.vault);
46
+ const { taskCommand } = await import('../dist/commands/task.js');
47
+ await taskCommand(vaultPath, 'add', {
48
+ title,
49
+ options: {
50
+ owner: options.owner,
51
+ project: options.project,
52
+ priority: options.priority,
53
+ due: options.due,
54
+ tags: parseCsvList(options.tags),
55
+ description: options.description,
56
+ estimate: options.estimate,
57
+ parent: options.parent,
58
+ dependsOn: parseCsvList(options.dependsOn)
59
+ }
60
+ });
61
+ } catch (err) {
62
+ console.error(chalk.red(`Error: ${err.message}`));
63
+ process.exit(1);
64
+ }
65
+ });
66
+
67
+ // task list
68
+ taskCmd
69
+ .command('list')
70
+ .description('List tasks with optional filters')
71
+ .option('-v, --vault <path>', 'Vault path')
72
+ .option('--owner <owner>', 'Filter by owner')
73
+ .option('--project <project>', 'Filter by project')
74
+ .option('--status <status>', 'Filter by status (open, in-progress, blocked, done)')
75
+ .option('--priority <priority>', 'Filter by priority')
76
+ .option('--due', 'Show only tasks with due dates (sorted by due date)')
77
+ .option('--tag <tag>', 'Filter by tag')
78
+ .option('--overdue', 'Show overdue tasks that are not done')
79
+ .option('--json', 'Output as JSON')
80
+ .action(async (options) => {
81
+ try {
82
+ const vaultPath = resolveVaultPath(options.vault);
83
+ const { taskCommand } = await import('../dist/commands/task.js');
84
+ await taskCommand(vaultPath, 'list', {
85
+ options: {
86
+ owner: options.owner,
87
+ project: options.project,
88
+ status: options.status,
89
+ priority: options.priority,
90
+ due: options.due,
91
+ tag: options.tag,
92
+ overdue: options.overdue,
93
+ json: options.json
94
+ }
95
+ });
96
+ } catch (err) {
97
+ console.error(chalk.red(`Error: ${err.message}`));
98
+ process.exit(1);
99
+ }
100
+ });
101
+
102
+ // task update
103
+ taskCmd
104
+ .command('update <slug>')
105
+ .description('Update a task')
106
+ .option('-v, --vault <path>', 'Vault path')
107
+ .option('--status <status>', 'New status')
108
+ .option('--owner <owner>', 'New owner')
109
+ .option('--clear-owner', 'Clear owner')
110
+ .option('--project <project>', 'New project')
111
+ .option('--clear-project', 'Clear project')
112
+ .option('--priority <priority>', 'New priority')
113
+ .option('--clear-priority', 'Clear priority')
114
+ .option('--blocked-by <blocker>', 'What is blocking this task')
115
+ .option('--clear-blocked-by', 'Clear blocked-by field')
116
+ .option('--due <date>', 'New due date')
117
+ .option('--clear-due', 'Clear due date')
118
+ .option('--tags <tags>', 'Comma-separated tags')
119
+ .option('--clear-tags', 'Clear tags')
120
+ .option('--description <description>', 'One-line task summary')
121
+ .option('--clear-description', 'Clear description')
122
+ .option('--estimate <estimate>', 'Estimate (for example: 2h, 1d, 1w)')
123
+ .option('--clear-estimate', 'Clear estimate')
124
+ .option('--parent <slug>', 'Parent task slug')
125
+ .option('--clear-parent', 'Clear parent task')
126
+ .option('--depends-on <slugs>', 'Comma-separated dependency slugs')
127
+ .option('--clear-depends-on', 'Clear dependencies')
128
+ .option('--confidence <value>', 'Transition confidence (0-1)', parseFloat)
129
+ .option('--reason <reason>', 'Reason for status change')
130
+ .option('--clear-reason', 'Clear reason')
131
+ .action(async (slug, options) => {
132
+ try {
133
+ const vaultPath = resolveVaultPath(options.vault);
134
+ const { taskCommand } = await import('../dist/commands/task.js');
135
+ await taskCommand(vaultPath, 'update', {
136
+ slug,
137
+ options: {
138
+ status: options.status,
139
+ owner: clearableValue(options.owner, options.clearOwner),
140
+ project: clearableValue(options.project, options.clearProject),
141
+ priority: clearableValue(options.priority, options.clearPriority),
142
+ blockedBy: clearableValue(options.blockedBy, options.clearBlockedBy),
143
+ due: clearableValue(options.due, options.clearDue),
144
+ tags: options.clearTags ? null : parseCsvList(options.tags),
145
+ description: clearableValue(options.description, options.clearDescription),
146
+ estimate: clearableValue(options.estimate, options.clearEstimate),
147
+ parent: clearableValue(options.parent, options.clearParent),
148
+ dependsOn: options.clearDependsOn ? null : parseCsvList(options.dependsOn),
149
+ confidence: options.confidence,
150
+ reason: clearableValue(options.reason, options.clearReason)
151
+ }
152
+ });
153
+ } catch (err) {
154
+ console.error(chalk.red(`Error: ${err.message}`));
155
+ process.exit(1);
156
+ }
157
+ });
158
+
159
+ // task done
160
+ taskCmd
161
+ .command('done <slug>')
162
+ .description('Mark a task as done')
163
+ .option('-v, --vault <path>', 'Vault path')
164
+ .option('--confidence <value>', 'Transition confidence (0-1)', parseFloat)
165
+ .option('--reason <reason>', 'Reason for completion')
166
+ .action(async (slug, options) => {
167
+ try {
168
+ const vaultPath = resolveVaultPath(options.vault);
169
+ const { taskCommand } = await import('../dist/commands/task.js');
170
+ await taskCommand(vaultPath, 'done', {
171
+ slug,
172
+ options: {
173
+ confidence: options.confidence,
174
+ reason: options.reason
175
+ }
176
+ });
177
+ } catch (err) {
178
+ console.error(chalk.red(`Error: ${err.message}`));
179
+ process.exit(1);
180
+ }
181
+ });
182
+
183
+ // task transitions
184
+ taskCmd
185
+ .command('transitions [task_id]')
186
+ .description('Show transition history')
187
+ .option('-v, --vault <path>', 'Vault path')
188
+ .option('--agent <id>', 'Filter by agent')
189
+ .option('--failed', 'Show only regression transitions')
190
+ .option('--json', 'Output as JSON')
191
+ .action(async (taskId, options) => {
192
+ try {
193
+ const vaultPath = resolveVaultPath(options.vault);
194
+ const { taskCommand } = await import('../dist/commands/task.js');
195
+ await taskCommand(vaultPath, 'transitions', {
196
+ slug: taskId,
197
+ options: {
198
+ agent: options.agent,
199
+ failed: options.failed,
200
+ json: options.json
201
+ }
202
+ });
203
+ } catch (err) {
204
+ console.error(chalk.red(`Error: ${err.message}`));
205
+ process.exit(1);
206
+ }
207
+ });
208
+
209
+ // task show
210
+ taskCmd
211
+ .command('show <slug>')
212
+ .description('Show task details')
213
+ .option('-v, --vault <path>', 'Vault path')
214
+ .option('--json', 'Output as JSON')
215
+ .action(async (slug, options) => {
216
+ try {
217
+ const vaultPath = resolveVaultPath(options.vault);
218
+ const { taskCommand } = await import('../dist/commands/task.js');
219
+ await taskCommand(vaultPath, 'show', {
220
+ slug,
221
+ options: { json: options.json }
222
+ });
223
+ } catch (err) {
224
+ console.error(chalk.red(`Error: ${err.message}`));
225
+ process.exit(1);
226
+ }
227
+ });
228
+
229
+ // === BACKLOG ===
230
+ const backlogCmd = program
231
+ .command('backlog')
232
+ .description('Manage backlog items');
233
+
234
+ // backlog add (also supports "backlog <title>" shorthand)
235
+ backlogCmd
236
+ .command('add <title>')
237
+ .description('Add item to backlog')
238
+ .option('-v, --vault <path>', 'Vault path')
239
+ .option('--source <source>', 'Source of the idea')
240
+ .option('--project <project>', 'Project name')
241
+ .action(async (title, options) => {
242
+ try {
243
+ const vaultPath = resolveVaultPath(options.vault);
244
+ const { backlogCommand } = await import('../dist/commands/backlog.js');
245
+ await backlogCommand(vaultPath, 'add', {
246
+ title,
247
+ options: {
248
+ source: options.source,
249
+ project: options.project
250
+ }
251
+ });
252
+ } catch (err) {
253
+ console.error(chalk.red(`Error: ${err.message}`));
254
+ process.exit(1);
255
+ }
256
+ });
257
+
258
+ // backlog list
259
+ backlogCmd
260
+ .command('list')
261
+ .description('List backlog items')
262
+ .option('-v, --vault <path>', 'Vault path')
263
+ .option('--project <project>', 'Filter by project')
264
+ .option('--json', 'Output as JSON')
265
+ .action(async (options) => {
266
+ try {
267
+ const vaultPath = resolveVaultPath(options.vault);
268
+ const { backlogCommand } = await import('../dist/commands/backlog.js');
269
+ await backlogCommand(vaultPath, 'list', {
270
+ options: {
271
+ project: options.project,
272
+ json: options.json
273
+ }
274
+ });
275
+ } catch (err) {
276
+ console.error(chalk.red(`Error: ${err.message}`));
277
+ process.exit(1);
278
+ }
279
+ });
280
+
281
+ // backlog promote
282
+ backlogCmd
283
+ .command('promote <slug>')
284
+ .description('Promote backlog item to task')
285
+ .option('-v, --vault <path>', 'Vault path')
286
+ .option('--owner <owner>', 'Task owner')
287
+ .option('--priority <priority>', 'Task priority')
288
+ .option('--due <date>', 'Due date')
289
+ .action(async (slug, options) => {
290
+ try {
291
+ const vaultPath = resolveVaultPath(options.vault);
292
+ const { backlogCommand } = await import('../dist/commands/backlog.js');
293
+ await backlogCommand(vaultPath, 'promote', {
294
+ slug,
295
+ options: {
296
+ owner: options.owner,
297
+ priority: options.priority,
298
+ due: options.due
299
+ }
300
+ });
301
+ } catch (err) {
302
+ console.error(chalk.red(`Error: ${err.message}`));
303
+ process.exit(1);
304
+ }
305
+ });
306
+
307
+ // === BLOCKED ===
308
+ program
309
+ .command('blocked')
310
+ .description('View blocked tasks')
311
+ .option('-v, --vault <path>', 'Vault path')
312
+ .option('--project <project>', 'Filter by project')
313
+ .option('--escalated', 'Show only escalated tasks (3+ blocked transitions)')
314
+ .option('--json', 'Output as JSON')
315
+ .action(async (options) => {
316
+ try {
317
+ const vaultPath = resolveVaultPath(options.vault);
318
+ const { blockedCommand } = await import('../dist/commands/blocked.js');
319
+ await blockedCommand(vaultPath, {
320
+ project: options.project,
321
+ escalated: options.escalated,
322
+ json: options.json
323
+ });
324
+ } catch (err) {
325
+ console.error(chalk.red(`Error: ${err.message}`));
326
+ process.exit(1);
327
+ }
328
+ });
329
+
330
+ // === CANVAS ===
331
+ program
332
+ .command('canvas')
333
+ .description('Generate an Obsidian canvas dashboard file')
334
+ .option('-v, --vault <path>', 'Vault path (default: find nearest)')
335
+ .option('--output <path>', 'Output file path (default: dashboard.canvas)')
336
+ .action(async (options) => {
337
+ try {
338
+ const vaultPath = resolveVaultPath(options.vault);
339
+ const { canvasCommand } = await import('../dist/commands/canvas.js');
340
+ await canvasCommand(vaultPath, {
341
+ output: options.output
342
+ });
343
+ } catch (err) {
344
+ console.error(chalk.red(`Error: ${err.message}`));
345
+ process.exit(1);
346
+ }
347
+ });
348
+ }