hzl-cli 0.1.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/dist/__tests__/integration/cli-integration.test.d.ts +2 -0
- package/dist/__tests__/integration/cli-integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/cli-integration.test.js +295 -0
- package/dist/__tests__/integration/cli-integration.test.js.map +1 -0
- package/dist/__tests__/integration/helpers.d.ts +14 -0
- package/dist/__tests__/integration/helpers.d.ts.map +1 -0
- package/dist/__tests__/integration/helpers.js +44 -0
- package/dist/__tests__/integration/helpers.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add-dep.d.ts +15 -0
- package/dist/commands/add-dep.d.ts.map +1 -0
- package/dist/commands/add-dep.js +86 -0
- package/dist/commands/add-dep.js.map +1 -0
- package/dist/commands/add-dep.test.d.ts +2 -0
- package/dist/commands/add-dep.test.d.ts.map +1 -0
- package/dist/commands/add-dep.test.js +47 -0
- package/dist/commands/add-dep.test.js.map +1 -0
- package/dist/commands/add.d.ts +23 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +65 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/add.test.d.ts +2 -0
- package/dist/commands/add.test.d.ts.map +1 -0
- package/dist/commands/add.test.js +60 -0
- package/dist/commands/add.test.js.map +1 -0
- package/dist/commands/archive.d.ts +16 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +51 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/archive.test.d.ts +2 -0
- package/dist/commands/archive.test.d.ts.map +1 -0
- package/dist/commands/archive.test.js +48 -0
- package/dist/commands/archive.test.js.map +1 -0
- package/dist/commands/checkpoint.d.ts +17 -0
- package/dist/commands/checkpoint.d.ts.map +1 -0
- package/dist/commands/checkpoint.js +64 -0
- package/dist/commands/checkpoint.js.map +1 -0
- package/dist/commands/checkpoint.test.d.ts +2 -0
- package/dist/commands/checkpoint.test.d.ts.map +1 -0
- package/dist/commands/checkpoint.test.js +47 -0
- package/dist/commands/checkpoint.test.js.map +1 -0
- package/dist/commands/claim.d.ts +20 -0
- package/dist/commands/claim.d.ts.map +1 -0
- package/dist/commands/claim.js +62 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/claim.test.d.ts +2 -0
- package/dist/commands/claim.test.d.ts.map +1 -0
- package/dist/commands/claim.test.js +48 -0
- package/dist/commands/claim.test.js.map +1 -0
- package/dist/commands/comment.d.ts +16 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +53 -0
- package/dist/commands/comment.js.map +1 -0
- package/dist/commands/comment.test.d.ts +2 -0
- package/dist/commands/comment.test.d.ts.map +1 -0
- package/dist/commands/comment.test.js +46 -0
- package/dist/commands/comment.test.js.map +1 -0
- package/dist/commands/complete.d.ts +15 -0
- package/dist/commands/complete.d.ts.map +1 -0
- package/dist/commands/complete.js +47 -0
- package/dist/commands/complete.js.map +1 -0
- package/dist/commands/complete.test.d.ts +2 -0
- package/dist/commands/complete.test.d.ts.map +1 -0
- package/dist/commands/complete.test.js +42 -0
- package/dist/commands/complete.test.js.map +1 -0
- package/dist/commands/export-events.d.ts +14 -0
- package/dist/commands/export-events.d.ts.map +1 -0
- package/dist/commands/export-events.js +64 -0
- package/dist/commands/export-events.js.map +1 -0
- package/dist/commands/export-events.test.d.ts +2 -0
- package/dist/commands/export-events.test.d.ts.map +1 -0
- package/dist/commands/export-events.test.js +36 -0
- package/dist/commands/export-events.test.js.map +1 -0
- package/dist/commands/history.d.ts +22 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +70 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/history.test.d.ts +2 -0
- package/dist/commands/history.test.d.ts.map +1 -0
- package/dist/commands/history.test.js +41 -0
- package/dist/commands/history.test.js.map +1 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +43 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +39 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/list.d.ts +26 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +85 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/list.test.d.ts +2 -0
- package/dist/commands/list.test.d.ts.map +1 -0
- package/dist/commands/list.test.js +55 -0
- package/dist/commands/list.test.js.map +1 -0
- package/dist/commands/move.d.ts +15 -0
- package/dist/commands/move.d.ts.map +1 -0
- package/dist/commands/move.js +62 -0
- package/dist/commands/move.js.map +1 -0
- package/dist/commands/move.test.d.ts +2 -0
- package/dist/commands/move.test.d.ts.map +1 -0
- package/dist/commands/move.test.js +55 -0
- package/dist/commands/move.test.js.map +1 -0
- package/dist/commands/next.d.ts +18 -0
- package/dist/commands/next.d.ts.map +1 -0
- package/dist/commands/next.js +64 -0
- package/dist/commands/next.js.map +1 -0
- package/dist/commands/next.test.d.ts +2 -0
- package/dist/commands/next.test.d.ts.map +1 -0
- package/dist/commands/next.test.js +52 -0
- package/dist/commands/next.test.js.map +1 -0
- package/dist/commands/projects.d.ts +16 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +64 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/projects.test.d.ts +2 -0
- package/dist/commands/projects.test.d.ts.map +1 -0
- package/dist/commands/projects.test.js +47 -0
- package/dist/commands/projects.test.js.map +1 -0
- package/dist/commands/release.d.ts +17 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.js +52 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/release.test.d.ts +2 -0
- package/dist/commands/release.test.d.ts.map +1 -0
- package/dist/commands/release.test.js +47 -0
- package/dist/commands/release.test.js.map +1 -0
- package/dist/commands/remove-dep.d.ts +15 -0
- package/dist/commands/remove-dep.d.ts.map +1 -0
- package/dist/commands/remove-dep.js +55 -0
- package/dist/commands/remove-dep.js.map +1 -0
- package/dist/commands/remove-dep.test.d.ts +2 -0
- package/dist/commands/remove-dep.test.d.ts.map +1 -0
- package/dist/commands/remove-dep.test.js +47 -0
- package/dist/commands/remove-dep.test.js.map +1 -0
- package/dist/commands/rename-project.d.ts +16 -0
- package/dist/commands/rename-project.d.ts.map +1 -0
- package/dist/commands/rename-project.js +70 -0
- package/dist/commands/rename-project.js.map +1 -0
- package/dist/commands/rename-project.test.d.ts +2 -0
- package/dist/commands/rename-project.test.d.ts.map +1 -0
- package/dist/commands/rename-project.test.js +75 -0
- package/dist/commands/rename-project.test.js.map +1 -0
- package/dist/commands/reopen.d.ts +18 -0
- package/dist/commands/reopen.d.ts.map +1 -0
- package/dist/commands/reopen.js +56 -0
- package/dist/commands/reopen.js.map +1 -0
- package/dist/commands/reopen.test.d.ts +2 -0
- package/dist/commands/reopen.test.d.ts.map +1 -0
- package/dist/commands/reopen.test.js +48 -0
- package/dist/commands/reopen.test.js.map +1 -0
- package/dist/commands/sample-project.d.ts +21 -0
- package/dist/commands/sample-project.d.ts.map +1 -0
- package/dist/commands/sample-project.js +168 -0
- package/dist/commands/sample-project.js.map +1 -0
- package/dist/commands/sample-project.test.d.ts +2 -0
- package/dist/commands/sample-project.test.d.ts.map +1 -0
- package/dist/commands/sample-project.test.js +96 -0
- package/dist/commands/sample-project.test.js.map +1 -0
- package/dist/commands/search.d.ts +23 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +89 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/search.test.d.ts +2 -0
- package/dist/commands/search.test.d.ts.map +1 -0
- package/dist/commands/search.test.js +41 -0
- package/dist/commands/search.test.js.map +1 -0
- package/dist/commands/set-status.d.ts +18 -0
- package/dist/commands/set-status.d.ts.map +1 -0
- package/dist/commands/set-status.js +60 -0
- package/dist/commands/set-status.js.map +1 -0
- package/dist/commands/set-status.test.d.ts +2 -0
- package/dist/commands/set-status.test.d.ts.map +1 -0
- package/dist/commands/set-status.test.js +45 -0
- package/dist/commands/set-status.test.js.map +1 -0
- package/dist/commands/show.d.ts +34 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +96 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/show.test.d.ts +2 -0
- package/dist/commands/show.test.d.ts.map +1 -0
- package/dist/commands/show.test.js +50 -0
- package/dist/commands/show.test.js.map +1 -0
- package/dist/commands/stats.d.ts +15 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +84 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/stats.test.d.ts +2 -0
- package/dist/commands/stats.test.d.ts.map +1 -0
- package/dist/commands/stats.test.js +43 -0
- package/dist/commands/stats.test.js.map +1 -0
- package/dist/commands/steal.d.ts +19 -0
- package/dist/commands/steal.d.ts.map +1 -0
- package/dist/commands/steal.js +90 -0
- package/dist/commands/steal.js.map +1 -0
- package/dist/commands/steal.test.d.ts +2 -0
- package/dist/commands/steal.test.d.ts.map +1 -0
- package/dist/commands/steal.test.js +66 -0
- package/dist/commands/steal.test.js.map +1 -0
- package/dist/commands/stuck.d.ts +22 -0
- package/dist/commands/stuck.d.ts.map +1 -0
- package/dist/commands/stuck.js +91 -0
- package/dist/commands/stuck.js.map +1 -0
- package/dist/commands/stuck.test.d.ts +2 -0
- package/dist/commands/stuck.test.d.ts.map +1 -0
- package/dist/commands/stuck.test.js +51 -0
- package/dist/commands/stuck.test.js.map +1 -0
- package/dist/commands/task.d.ts +32 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +72 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/update.d.ts +23 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +105 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/update.test.d.ts +2 -0
- package/dist/commands/update.test.d.ts.map +1 -0
- package/dist/commands/update.test.js +63 -0
- package/dist/commands/update.test.js.map +1 -0
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +60 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/validate.test.d.ts +2 -0
- package/dist/commands/validate.test.d.ts.map +1 -0
- package/dist/commands/validate.test.js +39 -0
- package/dist/commands/validate.test.js.map +1 -0
- package/dist/commands/which-db.d.ts +12 -0
- package/dist/commands/which-db.d.ts.map +1 -0
- package/dist/commands/which-db.js +55 -0
- package/dist/commands/which-db.js.map +1 -0
- package/dist/commands/which-db.test.d.ts +2 -0
- package/dist/commands/which-db.test.d.ts.map +1 -0
- package/dist/commands/which-db.test.js +38 -0
- package/dist/commands/which-db.test.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +58 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +38 -0
- package/dist/config.test.js.map +1 -0
- package/dist/db.d.ts +17 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +35 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.test.d.ts +2 -0
- package/dist/errors.test.d.ts.map +1 -0
- package/dist/errors.test.js +15 -0
- package/dist/errors.test.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +267 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +30 -0
- package/dist/index.test.js.map +1 -0
- package/dist/output.d.ts +13 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +56 -0
- package/dist/output.js.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/types.test.d.ts +2 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +23 -0
- package/dist/types.test.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/projects.ts
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveDbPath } from '../config.js';
|
|
4
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
5
|
+
export function runProjects(options) {
|
|
6
|
+
const { services, json } = options;
|
|
7
|
+
const db = services.db;
|
|
8
|
+
// Query for projects with task counts, excluding archived
|
|
9
|
+
const rows = db.prepare(`
|
|
10
|
+
SELECT
|
|
11
|
+
project as name,
|
|
12
|
+
COUNT(*) as task_count,
|
|
13
|
+
SUM(CASE WHEN status = 'backlog' THEN 1 ELSE 0 END) as backlog_count,
|
|
14
|
+
SUM(CASE WHEN status = 'ready' THEN 1 ELSE 0 END) as ready_count,
|
|
15
|
+
SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress_count,
|
|
16
|
+
SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) as done_count
|
|
17
|
+
FROM tasks_current
|
|
18
|
+
WHERE status != 'archived'
|
|
19
|
+
GROUP BY project
|
|
20
|
+
ORDER BY project
|
|
21
|
+
`).all();
|
|
22
|
+
const projects = rows.map(row => ({
|
|
23
|
+
name: row.name,
|
|
24
|
+
task_count: row.task_count,
|
|
25
|
+
statuses: {
|
|
26
|
+
backlog: row.backlog_count,
|
|
27
|
+
ready: row.ready_count,
|
|
28
|
+
in_progress: row.in_progress_count,
|
|
29
|
+
done: row.done_count,
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
const result = { projects };
|
|
33
|
+
if (json) {
|
|
34
|
+
console.log(JSON.stringify(result));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (projects.length === 0) {
|
|
38
|
+
console.log('No projects found');
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log('Projects:');
|
|
42
|
+
for (const p of projects) {
|
|
43
|
+
console.log(` ${p.name}: ${p.task_count} tasks`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
export function createProjectsCommand() {
|
|
50
|
+
return new Command('projects')
|
|
51
|
+
.description('List all projects with task counts')
|
|
52
|
+
.action(function () {
|
|
53
|
+
const globalOpts = this.optsWithGlobals();
|
|
54
|
+
const dbPath = resolveDbPath(globalOpts.db);
|
|
55
|
+
const services = initializeDb(dbPath);
|
|
56
|
+
try {
|
|
57
|
+
runProjects({ services, json: globalOpts.json ?? false });
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
closeDb(services);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAiB,MAAM,UAAU,CAAC;AAchE,MAAM,UAAU,WAAW,CAAC,OAA8C;IACxE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;IAEvB,0DAA0D;IAC1D,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;GAYvB,CAAC,CAAC,GAAG,EAAW,CAAC;IAElB,MAAM,QAAQ,GAAkB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,QAAQ,EAAE;YACR,OAAO,EAAE,GAAG,CAAC,aAAa;YAC1B,KAAK,EAAE,GAAG,CAAC,WAAW;YACtB,WAAW,EAAE,GAAG,CAAC,iBAAiB;YAClC,IAAI,EAAE,GAAG,CAAC,UAAU;SACrB;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,MAAM,GAAmB,EAAE,QAAQ,EAAE,CAAC;IAE5C,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACzB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,QAAQ,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;SAC3B,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC;QACN,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAmB,CAAC;QAC3D,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.test.d.ts","sourceRoot":"","sources":["../../src/commands/projects.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/projects.test.ts
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { runProjects } from './projects.js';
|
|
7
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
8
|
+
import { TaskStatus } from 'hzl-core/events/types.js';
|
|
9
|
+
describe('runProjects', () => {
|
|
10
|
+
let tempDir;
|
|
11
|
+
let dbPath;
|
|
12
|
+
let services;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hzl-projects-test-'));
|
|
15
|
+
dbPath = path.join(tempDir, 'test.db');
|
|
16
|
+
services = initializeDb(dbPath);
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
closeDb(services);
|
|
20
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
it('returns empty list when no tasks exist', () => {
|
|
23
|
+
const result = runProjects({ services, json: false });
|
|
24
|
+
expect(result.projects).toHaveLength(0);
|
|
25
|
+
});
|
|
26
|
+
it('lists projects with task counts', () => {
|
|
27
|
+
// Create some tasks in different projects
|
|
28
|
+
services.taskService.createTask({ title: 'Task 1', project: 'project-a' });
|
|
29
|
+
services.taskService.createTask({ title: 'Task 2', project: 'project-a' });
|
|
30
|
+
services.taskService.createTask({ title: 'Task 3', project: 'project-b' });
|
|
31
|
+
const result = runProjects({ services, json: false });
|
|
32
|
+
expect(result.projects).toHaveLength(2);
|
|
33
|
+
const projectA = result.projects.find(p => p.name === 'project-a');
|
|
34
|
+
const projectB = result.projects.find(p => p.name === 'project-b');
|
|
35
|
+
expect(projectA?.task_count).toBe(2);
|
|
36
|
+
expect(projectB?.task_count).toBe(1);
|
|
37
|
+
});
|
|
38
|
+
it('excludes archived tasks from count', () => {
|
|
39
|
+
const task = services.taskService.createTask({ title: 'Task 1', project: 'test-project' });
|
|
40
|
+
services.taskService.setStatus(task.task_id, TaskStatus.Ready);
|
|
41
|
+
services.taskService.setStatus(task.task_id, TaskStatus.Done);
|
|
42
|
+
services.taskService.setStatus(task.task_id, TaskStatus.Archived);
|
|
43
|
+
const result = runProjects({ services, json: false });
|
|
44
|
+
expect(result.projects).toHaveLength(0);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=projects.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.test.js","sourceRoot":"","sources":["../../src/commands/projects.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type Services } from '../db.js';
|
|
3
|
+
export interface ReleaseResult {
|
|
4
|
+
task_id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: string;
|
|
7
|
+
claimed_by_author: string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function runRelease(options: {
|
|
10
|
+
services: Services;
|
|
11
|
+
taskId: string;
|
|
12
|
+
reason?: string;
|
|
13
|
+
author?: string;
|
|
14
|
+
json: boolean;
|
|
15
|
+
}): ReleaseResult;
|
|
16
|
+
export declare function createReleaseCommand(): Command;
|
|
17
|
+
//# sourceMappingURL=release.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../src/commands/release.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIhE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,aAAa,CAoBhB;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAwB9C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/release.ts
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveDbPath } from '../config.js';
|
|
4
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
5
|
+
import { handleError } from '../errors.js';
|
|
6
|
+
export function runRelease(options) {
|
|
7
|
+
const { services, taskId, reason, author, json } = options;
|
|
8
|
+
const task = services.taskService.releaseTask(taskId, { reason, author });
|
|
9
|
+
const result = {
|
|
10
|
+
task_id: task.task_id,
|
|
11
|
+
title: task.title,
|
|
12
|
+
status: task.status,
|
|
13
|
+
claimed_by_author: task.claimed_by_author,
|
|
14
|
+
};
|
|
15
|
+
if (json) {
|
|
16
|
+
console.log(JSON.stringify(result));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.log(`✓ Released task ${task.task_id}: ${task.title}`);
|
|
20
|
+
if (reason)
|
|
21
|
+
console.log(` Reason: ${reason}`);
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
export function createReleaseCommand() {
|
|
26
|
+
return new Command('release')
|
|
27
|
+
.description('Release a claimed task')
|
|
28
|
+
.argument('<taskId>', 'Task ID')
|
|
29
|
+
.option('--reason <reason>', 'Release reason')
|
|
30
|
+
.option('--author <name>', 'Author name')
|
|
31
|
+
.action(function (taskId, opts) {
|
|
32
|
+
const globalOpts = this.optsWithGlobals();
|
|
33
|
+
const dbPath = resolveDbPath(globalOpts.db);
|
|
34
|
+
const services = initializeDb(dbPath);
|
|
35
|
+
try {
|
|
36
|
+
runRelease({
|
|
37
|
+
services,
|
|
38
|
+
taskId,
|
|
39
|
+
reason: opts.reason,
|
|
40
|
+
author: opts.author,
|
|
41
|
+
json: globalOpts.json ?? false,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
handleError(e, globalOpts.json);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
closeDb(services);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.js","sourceRoot":"","sources":["../../src/commands/release.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAiB,MAAM,UAAU,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAU3C,MAAM,UAAU,UAAU,CAAC,OAM1B;IACC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAE3D,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1E,MAAM,MAAM,GAAkB;QAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;KAC1C,CAAC;IAEF,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9D,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;SAC1B,WAAW,CAAC,wBAAwB,CAAC;SACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;SAC/B,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;SAC7C,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC;SACxC,MAAM,CAAC,UAAyB,MAAc,EAAE,IAAS;QACxD,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAmB,CAAC;QAC3D,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,UAAU,CAAC;gBACT,QAAQ;gBACR,MAAM;gBACN,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,KAAK;aAC/B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.test.d.ts","sourceRoot":"","sources":["../../src/commands/release.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/release.test.ts
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { runRelease } from './release.js';
|
|
7
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
8
|
+
import { TaskStatus } from 'hzl-core/events/types.js';
|
|
9
|
+
describe('runRelease', () => {
|
|
10
|
+
let tempDir;
|
|
11
|
+
let dbPath;
|
|
12
|
+
let services;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hzl-release-test-'));
|
|
15
|
+
dbPath = path.join(tempDir, 'test.db');
|
|
16
|
+
services = initializeDb(dbPath);
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
closeDb(services);
|
|
20
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
it('releases a claimed task', () => {
|
|
23
|
+
const task = services.taskService.createTask({ title: 'Test', project: 'inbox' });
|
|
24
|
+
services.taskService.setStatus(task.task_id, TaskStatus.Ready);
|
|
25
|
+
services.taskService.claimTask(task.task_id);
|
|
26
|
+
const result = runRelease({
|
|
27
|
+
services,
|
|
28
|
+
taskId: task.task_id,
|
|
29
|
+
json: false,
|
|
30
|
+
});
|
|
31
|
+
expect(result.status).toBe(TaskStatus.Ready);
|
|
32
|
+
expect(result.claimed_by_author).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
it('accepts a reason', () => {
|
|
35
|
+
const task = services.taskService.createTask({ title: 'Test', project: 'inbox' });
|
|
36
|
+
services.taskService.setStatus(task.task_id, TaskStatus.Ready);
|
|
37
|
+
services.taskService.claimTask(task.task_id);
|
|
38
|
+
const result = runRelease({
|
|
39
|
+
services,
|
|
40
|
+
taskId: task.task_id,
|
|
41
|
+
reason: 'blocked on external dependency',
|
|
42
|
+
json: false,
|
|
43
|
+
});
|
|
44
|
+
expect(result.status).toBe(TaskStatus.Ready);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=release.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.test.js","sourceRoot":"","sources":["../../src/commands/release.test.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAiB,MAAM,UAAU,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAI,OAAe,CAAC;IACpB,IAAI,MAAc,CAAC;IACnB,IAAI,QAAkB,CAAC;IAEvB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;QACtE,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvC,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClB,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAClF,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/D,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE7C,MAAM,MAAM,GAAG,UAAU,CAAC;YACxB,QAAQ;YACR,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAClF,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/D,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE7C,MAAM,MAAM,GAAG,UAAU,CAAC;YACxB,QAAQ;YACR,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,MAAM,EAAE,gCAAgC;YACxC,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type Services } from '../db.js';
|
|
3
|
+
export interface RemoveDepResult {
|
|
4
|
+
task_id: string;
|
|
5
|
+
depends_on_id: string;
|
|
6
|
+
removed: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function runRemoveDep(options: {
|
|
9
|
+
services: Services;
|
|
10
|
+
taskId: string;
|
|
11
|
+
dependsOnId: string;
|
|
12
|
+
json: boolean;
|
|
13
|
+
}): RemoveDepResult;
|
|
14
|
+
export declare function createRemoveDepCommand(): Command;
|
|
15
|
+
//# sourceMappingURL=remove-dep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-dep.d.ts","sourceRoot":"","sources":["../../src/commands/remove-dep.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKhE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,eAAe,CA+BlB;AAED,wBAAgB,sBAAsB,IAAI,OAAO,CAiBhD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/remove-dep.ts
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveDbPath } from '../config.js';
|
|
4
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
5
|
+
import { handleError, CLIError, ExitCode } from '../errors.js';
|
|
6
|
+
import { EventType } from 'hzl-core/events/types.js';
|
|
7
|
+
export function runRemoveDep(options) {
|
|
8
|
+
const { services, taskId, dependsOnId, json } = options;
|
|
9
|
+
const { eventStore, projectionEngine } = services;
|
|
10
|
+
// Check task exists
|
|
11
|
+
const task = services.taskService.getTaskById(taskId);
|
|
12
|
+
if (!task) {
|
|
13
|
+
throw new CLIError(`Task not found: ${taskId}`, ExitCode.NotFound);
|
|
14
|
+
}
|
|
15
|
+
// Remove the dependency via event (idempotent)
|
|
16
|
+
const event = eventStore.append({
|
|
17
|
+
task_id: taskId,
|
|
18
|
+
type: EventType.DependencyRemoved,
|
|
19
|
+
data: { depends_on_id: dependsOnId },
|
|
20
|
+
});
|
|
21
|
+
projectionEngine.applyEvent(event);
|
|
22
|
+
const result = {
|
|
23
|
+
task_id: taskId,
|
|
24
|
+
depends_on_id: dependsOnId,
|
|
25
|
+
removed: true,
|
|
26
|
+
};
|
|
27
|
+
if (json) {
|
|
28
|
+
console.log(JSON.stringify(result));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.log(`✓ Removed dependency: ${taskId} → ${dependsOnId}`);
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
export function createRemoveDepCommand() {
|
|
36
|
+
return new Command('remove-dep')
|
|
37
|
+
.description('Remove a dependency between tasks')
|
|
38
|
+
.argument('<taskId>', 'Task ID that has the dependency')
|
|
39
|
+
.argument('<dependsOnId>', 'Task ID to remove as dependency')
|
|
40
|
+
.action(function (taskId, dependsOnId) {
|
|
41
|
+
const globalOpts = this.optsWithGlobals();
|
|
42
|
+
const dbPath = resolveDbPath(globalOpts.db);
|
|
43
|
+
const services = initializeDb(dbPath);
|
|
44
|
+
try {
|
|
45
|
+
runRemoveDep({ services, taskId, dependsOnId, json: globalOpts.json ?? false });
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
handleError(e, globalOpts.json);
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
closeDb(services);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=remove-dep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-dep.js","sourceRoot":"","sources":["../../src/commands/remove-dep.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAiB,MAAM,UAAU,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AASrD,MAAM,UAAU,YAAY,CAAC,OAK5B;IACC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,GAAG,QAAQ,CAAC;IAElD,oBAAoB;IACpB,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,QAAQ,CAAC,mBAAmB,MAAM,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrE,CAAC;IAED,+CAA+C;IAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC;QAC9B,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,SAAS,CAAC,iBAAiB;QACjC,IAAI,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE;KACrC,CAAC,CAAC;IACH,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAoB;QAC9B,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,WAAW;QAC1B,OAAO,EAAE,IAAI;KACd,CAAC;IAEF,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,yBAAyB,MAAM,MAAM,WAAW,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;SAC7B,WAAW,CAAC,mCAAmC,CAAC;SAChD,QAAQ,CAAC,UAAU,EAAE,iCAAiC,CAAC;SACvD,QAAQ,CAAC,eAAe,EAAE,iCAAiC,CAAC;SAC5D,MAAM,CAAC,UAAyB,MAAc,EAAE,WAAmB;QAClE,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAmB,CAAC;QAC3D,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;QAClF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-dep.test.d.ts","sourceRoot":"","sources":["../../src/commands/remove-dep.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/remove-dep.test.ts
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { runRemoveDep } from './remove-dep.js';
|
|
7
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
8
|
+
describe('runRemoveDep', () => {
|
|
9
|
+
let tempDir;
|
|
10
|
+
let dbPath;
|
|
11
|
+
let services;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hzl-remove-dep-test-'));
|
|
14
|
+
dbPath = path.join(tempDir, 'test.db');
|
|
15
|
+
services = initializeDb(dbPath);
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
closeDb(services);
|
|
19
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
it('removes a dependency between two tasks', () => {
|
|
22
|
+
const task1 = services.taskService.createTask({ title: 'Task 1', project: 'inbox' });
|
|
23
|
+
const task2 = services.taskService.createTask({ title: 'Task 2', project: 'inbox', depends_on: [task1.task_id] });
|
|
24
|
+
const result = runRemoveDep({
|
|
25
|
+
services,
|
|
26
|
+
taskId: task2.task_id,
|
|
27
|
+
dependsOnId: task1.task_id,
|
|
28
|
+
json: false,
|
|
29
|
+
});
|
|
30
|
+
expect(result.task_id).toBe(task2.task_id);
|
|
31
|
+
expect(result.depends_on_id).toBe(task1.task_id);
|
|
32
|
+
expect(result.removed).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('succeeds even if dependency does not exist', () => {
|
|
35
|
+
const task1 = services.taskService.createTask({ title: 'Task 1', project: 'inbox' });
|
|
36
|
+
const task2 = services.taskService.createTask({ title: 'Task 2', project: 'inbox' });
|
|
37
|
+
// Remove non-existent dependency - should still return removed: true (idempotent)
|
|
38
|
+
const result = runRemoveDep({
|
|
39
|
+
services,
|
|
40
|
+
taskId: task1.task_id,
|
|
41
|
+
dependsOnId: task2.task_id,
|
|
42
|
+
json: false,
|
|
43
|
+
});
|
|
44
|
+
expect(result.removed).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=remove-dep.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-dep.test.js","sourceRoot":"","sources":["../../src/commands/remove-dep.test.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAiB,MAAM,UAAU,CAAC;AAEhE,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,OAAe,CAAC;IACpB,IAAI,MAAc,CAAC;IACnB,IAAI,QAAkB,CAAC;IAEvB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;QACzE,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvC,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClB,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACrF,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAElH,MAAM,MAAM,GAAG,YAAY,CAAC;YAC1B,QAAQ;YACR,MAAM,EAAE,KAAK,CAAC,OAAO;YACrB,WAAW,EAAE,KAAK,CAAC,OAAO;YAC1B,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACrF,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAErF,kFAAkF;QAClF,MAAM,MAAM,GAAG,YAAY,CAAC;YAC1B,QAAQ;YACR,MAAM,EAAE,KAAK,CAAC,OAAO;YACrB,WAAW,EAAE,KAAK,CAAC,OAAO;YAC1B,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type Services } from '../db.js';
|
|
3
|
+
export interface RenameProjectResult {
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
moved_count: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function runRenameProject(options: {
|
|
9
|
+
services: Services;
|
|
10
|
+
from: string;
|
|
11
|
+
to: string;
|
|
12
|
+
force: boolean;
|
|
13
|
+
json: boolean;
|
|
14
|
+
}): RenameProjectResult;
|
|
15
|
+
export declare function createRenameProjectCommand(): Command;
|
|
16
|
+
//# sourceMappingURL=rename-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-project.d.ts","sourceRoot":"","sources":["../../src/commands/rename-project.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIhE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,mBAAmB,CA6CtB;AAED,wBAAgB,0BAA0B,IAAI,OAAO,CAsBpD"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/rename-project.ts
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveDbPath } from '../config.js';
|
|
4
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
5
|
+
import { EventType } from 'hzl-core/events/types.js';
|
|
6
|
+
export function runRenameProject(options) {
|
|
7
|
+
const { services, from, to, force, json } = options;
|
|
8
|
+
const { db, eventStore, projectionEngine } = services;
|
|
9
|
+
// Get all tasks in source project via direct DB query
|
|
10
|
+
const sourceTasks = db.prepare('SELECT task_id, project FROM tasks_current WHERE project = ?').all(from);
|
|
11
|
+
if (sourceTasks.length === 0) {
|
|
12
|
+
const result = { from, to, moved_count: 0 };
|
|
13
|
+
if (json) {
|
|
14
|
+
console.log(JSON.stringify(result));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
console.log(`No tasks found in project '${from}'`);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
// Check if target project already exists (has tasks)
|
|
22
|
+
const targetTasks = db.prepare('SELECT task_id FROM tasks_current WHERE project = ? LIMIT 1').all(to);
|
|
23
|
+
if (targetTasks.length > 0 && !force) {
|
|
24
|
+
throw new Error(`Project '${to}' already exists. Use --force to merge projects.`);
|
|
25
|
+
}
|
|
26
|
+
// Move all tasks from source to target by emitting task_moved events
|
|
27
|
+
let movedCount = 0;
|
|
28
|
+
for (const task of sourceTasks) {
|
|
29
|
+
const event = eventStore.append({
|
|
30
|
+
task_id: task.task_id,
|
|
31
|
+
type: EventType.TaskMoved,
|
|
32
|
+
data: { from_project: from, to_project: to },
|
|
33
|
+
});
|
|
34
|
+
projectionEngine.applyEvent(event);
|
|
35
|
+
movedCount++;
|
|
36
|
+
}
|
|
37
|
+
const result = { from, to, moved_count: movedCount };
|
|
38
|
+
if (json) {
|
|
39
|
+
console.log(JSON.stringify(result));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.log(`✓ Renamed project '${from}' to '${to}' (${movedCount} tasks moved)`);
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
export function createRenameProjectCommand() {
|
|
47
|
+
return new Command('rename-project')
|
|
48
|
+
.description('Rename a project (moves all tasks)')
|
|
49
|
+
.argument('<from>', 'Current project name')
|
|
50
|
+
.argument('<to>', 'New project name')
|
|
51
|
+
.option('-f, --force', 'Force merge if target project exists', false)
|
|
52
|
+
.action(function (from, to, opts) {
|
|
53
|
+
const globalOpts = this.optsWithGlobals();
|
|
54
|
+
const dbPath = resolveDbPath(globalOpts.db);
|
|
55
|
+
const services = initializeDb(dbPath);
|
|
56
|
+
try {
|
|
57
|
+
runRenameProject({
|
|
58
|
+
services,
|
|
59
|
+
from,
|
|
60
|
+
to,
|
|
61
|
+
force: opts.force,
|
|
62
|
+
json: globalOpts.json ?? false,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
closeDb(services);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=rename-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-project.js","sourceRoot":"","sources":["../../src/commands/rename-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-project.test.d.ts","sourceRoot":"","sources":["../../src/commands/rename-project.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// packages/hzl-cli/src/commands/rename-project.test.ts
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { runRenameProject } from './rename-project.js';
|
|
7
|
+
import { initializeDb, closeDb } from '../db.js';
|
|
8
|
+
describe('runRenameProject', () => {
|
|
9
|
+
let tempDir;
|
|
10
|
+
let dbPath;
|
|
11
|
+
let services;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hzl-rename-project-test-'));
|
|
14
|
+
dbPath = path.join(tempDir, 'test.db');
|
|
15
|
+
services = initializeDb(dbPath);
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
closeDb(services);
|
|
19
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
it('renames project by moving all tasks', () => {
|
|
22
|
+
services.taskService.createTask({ title: 'Task 1', project: 'old-project' });
|
|
23
|
+
services.taskService.createTask({ title: 'Task 2', project: 'old-project' });
|
|
24
|
+
const result = runRenameProject({
|
|
25
|
+
services,
|
|
26
|
+
from: 'old-project',
|
|
27
|
+
to: 'new-project',
|
|
28
|
+
force: false,
|
|
29
|
+
json: false,
|
|
30
|
+
});
|
|
31
|
+
expect(result.moved_count).toBe(2);
|
|
32
|
+
// Verify tasks are in new project via direct DB query
|
|
33
|
+
const newTasks = services.db.prepare('SELECT * FROM tasks_current WHERE project = ?').all('new-project');
|
|
34
|
+
expect(newTasks).toHaveLength(2);
|
|
35
|
+
// Verify old project is empty
|
|
36
|
+
const oldTasks = services.db.prepare('SELECT * FROM tasks_current WHERE project = ?').all('old-project');
|
|
37
|
+
expect(oldTasks).toHaveLength(0);
|
|
38
|
+
});
|
|
39
|
+
it('throws when target project exists without force flag', () => {
|
|
40
|
+
services.taskService.createTask({ title: 'Task 1', project: 'project-a' });
|
|
41
|
+
services.taskService.createTask({ title: 'Task 2', project: 'project-b' });
|
|
42
|
+
expect(() => runRenameProject({
|
|
43
|
+
services,
|
|
44
|
+
from: 'project-a',
|
|
45
|
+
to: 'project-b',
|
|
46
|
+
force: false,
|
|
47
|
+
json: false,
|
|
48
|
+
})).toThrow(/already exists/);
|
|
49
|
+
});
|
|
50
|
+
it('merges projects when force flag is set', () => {
|
|
51
|
+
services.taskService.createTask({ title: 'Task 1', project: 'project-a' });
|
|
52
|
+
services.taskService.createTask({ title: 'Task 2', project: 'project-b' });
|
|
53
|
+
const result = runRenameProject({
|
|
54
|
+
services,
|
|
55
|
+
from: 'project-a',
|
|
56
|
+
to: 'project-b',
|
|
57
|
+
force: true,
|
|
58
|
+
json: false,
|
|
59
|
+
});
|
|
60
|
+
expect(result.moved_count).toBe(1);
|
|
61
|
+
const tasks = services.db.prepare('SELECT * FROM tasks_current WHERE project = ?').all('project-b');
|
|
62
|
+
expect(tasks).toHaveLength(2);
|
|
63
|
+
});
|
|
64
|
+
it('returns zero when source project has no tasks', () => {
|
|
65
|
+
const result = runRenameProject({
|
|
66
|
+
services,
|
|
67
|
+
from: 'nonexistent',
|
|
68
|
+
to: 'new-project',
|
|
69
|
+
force: false,
|
|
70
|
+
json: false,
|
|
71
|
+
});
|
|
72
|
+
expect(result.moved_count).toBe(0);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=rename-project.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-project.test.js","sourceRoot":"","sources":["../../src/commands/rename-project.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type Services } from '../db.js';
|
|
3
|
+
import { TaskStatus } from 'hzl-core/events/types.js';
|
|
4
|
+
export interface ReopenResult {
|
|
5
|
+
task_id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
status: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function runReopen(options: {
|
|
10
|
+
services: Services;
|
|
11
|
+
taskId: string;
|
|
12
|
+
toStatus?: TaskStatus.Ready | TaskStatus.Backlog;
|
|
13
|
+
reason?: string;
|
|
14
|
+
author?: string;
|
|
15
|
+
json: boolean;
|
|
16
|
+
}): ReopenResult;
|
|
17
|
+
export declare function createReopenCommand(): Command;
|
|
18
|
+
//# sourceMappingURL=reopen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reopen.d.ts","sourceRoot":"","sources":["../../src/commands/reopen.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,UAAU,CAAC,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,YAAY,CAoBf;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CA2B7C"}
|