@kaban-board/cli 0.2.0 → 0.2.4
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/index.js +68 -22
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { Command } from "commander";
|
|
|
12
12
|
import { existsSync, readFileSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { BoardService, createDb, TaskService } from "@kaban-board/core";
|
|
15
|
-
function getContext() {
|
|
15
|
+
async function getContext() {
|
|
16
16
|
const kabanDir = join(process.cwd(), ".kaban");
|
|
17
17
|
const dbPath = join(kabanDir, "board.db");
|
|
18
18
|
const configPath = join(kabanDir, "config.json");
|
|
@@ -20,7 +20,7 @@ function getContext() {
|
|
|
20
20
|
console.error("Error: No board found. Run 'kaban init' first");
|
|
21
21
|
process.exit(1);
|
|
22
22
|
}
|
|
23
|
-
const db = createDb(dbPath);
|
|
23
|
+
const db = await createDb(dbPath);
|
|
24
24
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
25
25
|
const boardService = new BoardService(db);
|
|
26
26
|
const taskService = new TaskService(db, boardService);
|
|
@@ -60,7 +60,7 @@ function outputError(code, message) {
|
|
|
60
60
|
var addCommand = new Command("add").description("Add a new task").argument("<title>", "Task title").option("-c, --column <column>", "Column to add task to").option("-a, --agent <agent>", "Agent creating the task").option("-D, --description <text>", "Task description").option("-d, --depends-on <ids>", "Comma-separated task IDs this depends on").option("-j, --json", "Output as JSON").action(async (title, options) => {
|
|
61
61
|
const json = options.json;
|
|
62
62
|
try {
|
|
63
|
-
const { taskService, config } = getContext();
|
|
63
|
+
const { taskService, config } = await getContext();
|
|
64
64
|
const agent = options.agent ?? getAgent();
|
|
65
65
|
const columnId = options.column ?? config.defaults.column;
|
|
66
66
|
const dependsOn = options.dependsOn ? options.dependsOn.split(",").map((s) => s.trim()) : [];
|
|
@@ -95,7 +95,7 @@ import { Command as Command2 } from "commander";
|
|
|
95
95
|
var doneCommand = new Command2("done").description("Mark a task as done").argument("<id>", "Task ID (can be partial)").option("-j, --json", "Output as JSON").action(async (id, options) => {
|
|
96
96
|
const json = options.json;
|
|
97
97
|
try {
|
|
98
|
-
const { taskService, boardService } = getContext();
|
|
98
|
+
const { taskService, boardService } = await getContext();
|
|
99
99
|
const tasks = await taskService.listTasks();
|
|
100
100
|
const task = tasks.find((t) => t.id.startsWith(id));
|
|
101
101
|
if (!task) {
|
|
@@ -686,7 +686,12 @@ var hookCommand = new Command3("hook").description("Manage TodoWrite sync hook f
|
|
|
686
686
|
|
|
687
687
|
// src/commands/init.ts
|
|
688
688
|
import { existsSync as existsSync4, mkdirSync, writeFileSync } from "node:fs";
|
|
689
|
-
import {
|
|
689
|
+
import {
|
|
690
|
+
BoardService as BoardService2,
|
|
691
|
+
createDb as createDb2,
|
|
692
|
+
DEFAULT_CONFIG as DEFAULT_CONFIG2,
|
|
693
|
+
initializeSchema
|
|
694
|
+
} from "@kaban-board/core";
|
|
690
695
|
import { Command as Command4 } from "commander";
|
|
691
696
|
var initCommand = new Command4("init").description("Initialize a new Kaban board in the current directory").option("-n, --name <name>", "Board name", "Kaban Board").action(async (options) => {
|
|
692
697
|
const { kabanDir, dbPath, configPath } = getKabanPaths();
|
|
@@ -700,7 +705,7 @@ var initCommand = new Command4("init").description("Initialize a new Kaban board
|
|
|
700
705
|
board: { name: options.name }
|
|
701
706
|
};
|
|
702
707
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
703
|
-
const db = createDb2(dbPath);
|
|
708
|
+
const db = await createDb2(dbPath);
|
|
704
709
|
await initializeSchema(db);
|
|
705
710
|
const boardService = new BoardService2(db);
|
|
706
711
|
await boardService.initializeBoard(config);
|
|
@@ -730,7 +735,7 @@ function sortTasks(tasks, sortBy, reverse) {
|
|
|
730
735
|
var listCommand = new Command5("list").description("List tasks").option("-c, --column <column>", "Filter by column").option("-a, --agent <agent>", "Filter by creator agent").option("-u, --assignee <assignee>", "Filter by assigned agent").option("-b, --blocked", "Show only blocked tasks").option("-s, --sort <field>", "Sort by: name, date, updated").option("-r, --reverse", "Reverse sort order").option("-j, --json", "Output as JSON").action(async (options) => {
|
|
731
736
|
const json = options.json;
|
|
732
737
|
try {
|
|
733
|
-
const { taskService, boardService } = getContext();
|
|
738
|
+
const { taskService, boardService } = await getContext();
|
|
734
739
|
let tasks = await taskService.listTasks({
|
|
735
740
|
columnId: options.column,
|
|
736
741
|
agent: options.agent,
|
|
@@ -806,12 +811,12 @@ function getKabanPaths2(basePath) {
|
|
|
806
811
|
configPath: join4(kabanDir, "config.json")
|
|
807
812
|
};
|
|
808
813
|
}
|
|
809
|
-
function createContext(basePath) {
|
|
814
|
+
async function createContext(basePath) {
|
|
810
815
|
const { dbPath, configPath } = getKabanPaths2(basePath);
|
|
811
816
|
if (!existsSync5(dbPath)) {
|
|
812
817
|
throw new Error("No board found. Run 'kaban init' first");
|
|
813
818
|
}
|
|
814
|
-
const db = createDb3(dbPath);
|
|
819
|
+
const db = await createDb3(dbPath);
|
|
815
820
|
const config = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
816
821
|
const boardService = new BoardService3(db);
|
|
817
822
|
const taskService = new TaskService2(db, boardService);
|
|
@@ -964,7 +969,7 @@ async function startMcpServer(workingDirectory) {
|
|
|
964
969
|
board: { name: boardName }
|
|
965
970
|
};
|
|
966
971
|
writeFileSync2(configPath, JSON.stringify(config, null, 2));
|
|
967
|
-
const db = createDb3(dbPath);
|
|
972
|
+
const db = await createDb3(dbPath);
|
|
968
973
|
await initializeSchema2(db);
|
|
969
974
|
const boardService2 = new BoardService3(db);
|
|
970
975
|
await boardService2.initializeBoard(config);
|
|
@@ -981,7 +986,7 @@ async function startMcpServer(workingDirectory) {
|
|
|
981
986
|
]
|
|
982
987
|
};
|
|
983
988
|
}
|
|
984
|
-
const { taskService, boardService } = createContext(workingDirectory);
|
|
989
|
+
const { taskService, boardService } = await createContext(workingDirectory);
|
|
985
990
|
switch (name) {
|
|
986
991
|
case "kaban_add_task": {
|
|
987
992
|
const task = await taskService.addTask(args);
|
|
@@ -1091,7 +1096,7 @@ async function startMcpServer(workingDirectory) {
|
|
|
1091
1096
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1092
1097
|
const { uri } = request.params;
|
|
1093
1098
|
try {
|
|
1094
|
-
const { taskService, boardService } = createContext(workingDirectory);
|
|
1099
|
+
const { taskService, boardService } = await createContext(workingDirectory);
|
|
1095
1100
|
if (uri === "kaban://board/status") {
|
|
1096
1101
|
const board = await boardService.getBoard();
|
|
1097
1102
|
const columns = await boardService.getColumns();
|
|
@@ -1185,7 +1190,7 @@ import { Command as Command7 } from "commander";
|
|
|
1185
1190
|
var moveCommand = new Command7("move").description("Move a task to a different column").argument("<id>", "Task ID (can be partial)").argument("[column]", "Target column").option("-n, --next", "Move to next column").option("-f, --force", "Force move even if WIP limit exceeded").option("-j, --json", "Output as JSON").action(async (id, column, options) => {
|
|
1186
1191
|
const json = options.json;
|
|
1187
1192
|
try {
|
|
1188
|
-
const { taskService, boardService } = getContext();
|
|
1193
|
+
const { taskService, boardService } = await getContext();
|
|
1189
1194
|
const tasks = await taskService.listTasks();
|
|
1190
1195
|
const task = tasks.find((t) => t.id.startsWith(id));
|
|
1191
1196
|
if (!task) {
|
|
@@ -1262,7 +1267,7 @@ import { Command as Command9 } from "commander";
|
|
|
1262
1267
|
var statusCommand2 = new Command9("status").description("Show board status summary").option("-j, --json", "Output as JSON").action(async (options) => {
|
|
1263
1268
|
const json = options.json;
|
|
1264
1269
|
try {
|
|
1265
|
-
const { taskService, boardService } = getContext();
|
|
1270
|
+
const { taskService, boardService } = await getContext();
|
|
1266
1271
|
const board = await boardService.getBoard();
|
|
1267
1272
|
const columns = await boardService.getColumns();
|
|
1268
1273
|
const tasks = await taskService.listTasks();
|
|
@@ -1696,20 +1701,61 @@ var syncCommand = new Command10("sync").description("Sync TodoWrite input to Kab
|
|
|
1696
1701
|
});
|
|
1697
1702
|
|
|
1698
1703
|
// src/commands/tui.ts
|
|
1699
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
1704
|
+
import { spawn as spawn3, spawnSync } from "node:child_process";
|
|
1705
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
1700
1706
|
import { dirname as dirname3, join as join5 } from "node:path";
|
|
1701
|
-
import { fileURLToPath } from "node:url";
|
|
1702
1707
|
import { Command as Command11 } from "commander";
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1708
|
+
function findInPath(name) {
|
|
1709
|
+
const result = spawnSync("which", [name], { encoding: "utf-8" });
|
|
1710
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
1711
|
+
}
|
|
1712
|
+
function runBinary(path, args) {
|
|
1713
|
+
const child = spawn3(path, args, { stdio: "inherit", cwd: process.cwd() });
|
|
1714
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
1715
|
+
}
|
|
1716
|
+
function runBunx(bunPath, args) {
|
|
1717
|
+
let started = false;
|
|
1718
|
+
const child = spawn3(bunPath, ["x", "@kaban-board/tui", ...args], {
|
|
1707
1719
|
stdio: "inherit",
|
|
1708
1720
|
cwd: process.cwd()
|
|
1709
1721
|
});
|
|
1710
|
-
child.on("
|
|
1711
|
-
|
|
1722
|
+
child.on("spawn", () => {
|
|
1723
|
+
started = true;
|
|
1724
|
+
});
|
|
1725
|
+
child.on("error", () => {
|
|
1726
|
+
if (!started)
|
|
1727
|
+
showInstallError();
|
|
1712
1728
|
});
|
|
1729
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
1730
|
+
return true;
|
|
1731
|
+
}
|
|
1732
|
+
function showInstallError() {
|
|
1733
|
+
console.error(`
|
|
1734
|
+
Error: kaban-tui not found
|
|
1735
|
+
|
|
1736
|
+
The TUI requires Bun runtime. Install with one of:
|
|
1737
|
+
|
|
1738
|
+
# Homebrew (recommended)
|
|
1739
|
+
brew install beshkenadze/tap/kaban-tui
|
|
1740
|
+
|
|
1741
|
+
# Or install Bun, then run via bunx
|
|
1742
|
+
curl -fsSL https://bun.sh/install | bash
|
|
1743
|
+
bunx @kaban-board/tui
|
|
1744
|
+
`);
|
|
1745
|
+
process.exit(1);
|
|
1746
|
+
}
|
|
1747
|
+
var tuiCommand = new Command11("tui").description("Start interactive Terminal UI (requires Bun)").action(async () => {
|
|
1748
|
+
const args = process.argv.slice(3);
|
|
1749
|
+
const siblingBinary = join5(dirname3(process.execPath), "kaban-tui");
|
|
1750
|
+
if (existsSync7(siblingBinary))
|
|
1751
|
+
return runBinary(siblingBinary, args);
|
|
1752
|
+
const pathBinary = findInPath("kaban-tui");
|
|
1753
|
+
if (pathBinary)
|
|
1754
|
+
return runBinary(pathBinary, args);
|
|
1755
|
+
const bunPath = findInPath("bun");
|
|
1756
|
+
if (bunPath)
|
|
1757
|
+
return runBunx(bunPath, args);
|
|
1758
|
+
showInstallError();
|
|
1713
1759
|
});
|
|
1714
1760
|
|
|
1715
1761
|
// src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaban-board/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Terminal Kanban for AI Code Agents - CLI and MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@clack/prompts": "^0.11.0",
|
|
21
|
-
"@kaban-board/core": "0.
|
|
21
|
+
"@kaban-board/core": "0.1.3",
|
|
22
22
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
23
23
|
"chalk": "^5.6.2",
|
|
24
24
|
"commander": "^12.0.0",
|