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.
- package/README.md +159 -159
- package/bin/clawvault.js +111 -111
- package/bin/command-registration.test.js +166 -166
- package/bin/command-runtime.js +93 -93
- package/bin/command-runtime.test.js +154 -154
- package/bin/help-contract.test.js +39 -39
- package/bin/register-config-commands.js +153 -153
- package/bin/register-config-route-commands.test.js +121 -121
- package/bin/register-core-commands.js +237 -237
- package/bin/register-kanban-commands.js +56 -56
- package/bin/register-kanban-commands.test.js +83 -83
- package/bin/register-maintenance-commands.js +282 -282
- package/bin/register-project-commands.js +209 -209
- package/bin/register-project-commands.test.js +206 -206
- package/bin/register-query-commands.js +317 -317
- package/bin/register-query-commands.test.js +65 -65
- package/bin/register-resilience-commands.js +182 -182
- package/bin/register-resilience-commands.test.js +81 -81
- package/bin/register-route-commands.js +114 -114
- package/bin/register-session-lifecycle-commands.js +206 -206
- package/bin/register-tailscale-commands.js +106 -106
- package/bin/register-task-commands.js +348 -348
- package/bin/register-task-commands.test.js +69 -69
- package/bin/register-template-commands.js +75 -72
- package/bin/register-template-commands.test.js +87 -0
- package/bin/register-vault-operations-commands.js +300 -300
- package/bin/test-helpers/cli-command-fixtures.js +119 -119
- package/dashboard/lib/graph-diff.js +104 -104
- package/dashboard/lib/graph-diff.test.js +75 -75
- package/dashboard/lib/vault-parser.js +556 -556
- package/dashboard/lib/vault-parser.test.js +254 -254
- package/dashboard/public/app.js +796 -796
- package/dashboard/public/index.html +52 -52
- package/dashboard/public/styles.css +221 -221
- package/dashboard/server.js +374 -374
- package/dist/{chunk-J5EMBUPK.js → chunk-4OXMU5S2.js} +1 -1
- package/dist/{chunk-3FP5BJ42.js → chunk-4QYGFWRM.js} +1 -1
- package/dist/{chunk-4IV3R2F5.js → chunk-4TE4JMLA.js} +1 -1
- package/dist/{chunk-5GZFTAL7.js → chunk-AZYOKJYC.js} +128 -42
- package/dist/{chunk-FG6RJMCN.js → chunk-HA5M6KJB.js} +4 -4
- package/dist/{chunk-IZEY5S74.js → chunk-IEVLHNLU.js} +1 -1
- package/dist/{chunk-CLE2HHNT.js → chunk-IVRIKYFE.js} +18 -11
- package/dist/{chunk-AY4PGUVL.js → chunk-KL4NAOMO.js} +1 -1
- package/dist/{chunk-O7XHXF7F.js → chunk-MAKNAHAW.js} +4 -4
- package/dist/{chunk-OSMS7QIG.js → chunk-ME37YNW3.js} +2 -2
- package/dist/chunk-MFAWT5O5.js +301 -0
- package/dist/{chunk-TPDH3JPP.js → chunk-PBEE567J.js} +1 -1
- package/dist/{chunk-S2IG7VNM.js → chunk-Q2J5YTUF.js} +2 -2
- package/dist/{chunk-IOALNTAN.js → chunk-QWQ3TIKS.js} +103 -29
- package/dist/{chunk-YCVDVI5B.js → chunk-R2MIW5G7.js} +1 -1
- package/dist/{chunk-M25QVSJM.js → chunk-RVYA52PY.js} +1 -1
- package/dist/{chunk-NZ4ZZNSR.js → chunk-THRJVD4L.js} +1 -1
- package/dist/{chunk-4GBPTBFJ.js → chunk-TIGW564L.js} +1 -1
- package/dist/{chunk-LMEMZGUV.js → chunk-UEOUADMO.js} +3 -3
- package/dist/{chunk-GFJ3LIIB.js → chunk-XAVB4GB4.js} +1 -1
- package/dist/cli/index.js +15 -13
- package/dist/commands/backlog.js +3 -1
- package/dist/commands/blocked.js +3 -1
- package/dist/commands/canvas.js +3 -1
- package/dist/commands/context.js +3 -3
- package/dist/commands/doctor.js +9 -7
- package/dist/commands/embed.js +2 -2
- package/dist/commands/kanban.js +4 -2
- package/dist/commands/observe.js +7 -5
- package/dist/commands/project.js +5 -3
- package/dist/commands/rebuild.js +6 -4
- package/dist/commands/replay.js +6 -4
- package/dist/commands/setup.js +2 -2
- package/dist/commands/sleep.js +7 -5
- package/dist/commands/status.js +8 -6
- package/dist/commands/tailscale.js +3 -3
- package/dist/commands/task.js +4 -2
- package/dist/commands/template.d.ts +10 -1
- package/dist/commands/template.js +47 -55
- package/dist/commands/wake.js +2 -2
- package/dist/index.js +23 -22
- package/dist/lib/project-utils.js +4 -2
- package/dist/lib/tailscale.js +2 -2
- package/dist/lib/task-utils.d.ts +14 -13
- package/dist/lib/task-utils.js +3 -1
- package/dist/lib/template-engine.d.ts +1 -0
- package/dist/lib/webdav.js +1 -1
- package/hooks/clawvault/HOOK.md +83 -83
- package/hooks/clawvault/handler.js +816 -816
- package/hooks/clawvault/handler.test.js +263 -263
- package/package.json +94 -94
- package/templates/checkpoint.md +34 -19
- package/templates/daily-note.md +34 -19
- package/templates/daily.md +34 -19
- package/templates/decision.md +39 -17
- package/templates/handoff.md +34 -19
- package/templates/lesson.md +31 -16
- package/templates/person.md +37 -19
- package/templates/project.md +84 -23
- 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
|
+
}
|