@citadel-labs/beads-ui 2.1.0 → 2.4.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/.claude/worktrees/agent-a7b97047/LICENSE +21 -0
- package/.claude/worktrees/agent-a7b97047/README.md +63 -0
- package/.claude/worktrees/agent-a7b97047/bin/beads-board.js +183 -0
- package/.claude/worktrees/agent-a7b97047/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/.claude/worktrees/agent-a7b97047/package-lock.json +1752 -0
- package/.claude/worktrees/agent-a7b97047/package.json +43 -0
- package/.claude/worktrees/agent-a7b97047/server/__tests__/api.test.js +206 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/angular-html-DA-rfuFy.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/angular-ts-BrjP3tb8.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/c-BIGW1oBm.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/cpp-BRuaLJcg.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/csharp-COcwbKMJ.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/css-CLj8gQPS.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/dockerfile-BcOcwvcX.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/dotenv-Da5cRb03.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/github-dark-DHJKELXO.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/go-C27-OAKa.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/graphql-ChdNCCLP.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/html-derivative-C6UeqQa8.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/html-pp8916En.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/http-l_GQhCeT.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/index-BBBYE21N.css +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/index-cZFE6wf9.js +231 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/ini-BEwlwnbL.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/java-CylS5w8V.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/json-Cp-IABpG.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/jsonc-Des-eS-w.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/jsonl-DcaNXYhu.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/jsx-g9-lgVsj.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/kusto-wEQ09or8.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/latex-DdMFrP5M.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/markdown-Cvjx9yec.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/mdc-Dz5ISc6g.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/mermaid-mWjccvbQ.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/php-R6g_5hLQ.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/powershell-Dpen1YoG.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/python-B6aJPvgy.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/ruby-AcS3PBV-.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/rust-B1yitclQ.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/sass-Cj5Yp3dK.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/scss-D5BDwBP9.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/shellscript-DfDnw5Jg.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/sql-BLtJtn59.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/svelte-DR4MIrkg.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/swift-D82vCrfD.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/toml-vGWfd6FD.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/tsx-COt5Ahok.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/vue-CJgBXYWu.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/xml-sdJ4AIDG.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/yaml-Buea-lGh.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/assets/zig-VOosw3JB.js +1 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/favicon.svg +103 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/index.html +14 -0
- package/.claude/worktrees/agent-a7b97047/server/dist/vite.svg +1 -0
- package/.claude/worktrees/agent-a7b97047/server/handlers.js +357 -0
- package/.claude/worktrees/agent-a7b97047/server/index.js +88 -0
- package/.claude/worktrees/agent-a7b97047/server/terminal.js +103 -0
- package/.claude/worktrees/agent-a7b97047/vitest.config.mjs +8 -0
- package/.claude/worktrees/agent-a952bde8/LICENSE +21 -0
- package/.claude/worktrees/agent-a952bde8/README.md +63 -0
- package/.claude/worktrees/agent-a952bde8/bin/beads-board.js +183 -0
- package/.claude/worktrees/agent-a952bde8/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/.claude/worktrees/agent-a952bde8/package-lock.json +1752 -0
- package/.claude/worktrees/agent-a952bde8/package.json +43 -0
- package/.claude/worktrees/agent-a952bde8/server/__tests__/api.test.js +122 -0
- package/.claude/worktrees/agent-a952bde8/server/dist/assets/index-BsWRmNbj.js +79 -0
- package/.claude/worktrees/agent-a952bde8/server/dist/assets/index-C7JKZkTD.css +1 -0
- package/.claude/worktrees/agent-a952bde8/server/dist/favicon.svg +103 -0
- package/.claude/worktrees/agent-a952bde8/server/dist/index.html +14 -0
- package/.claude/worktrees/agent-a952bde8/server/dist/vite.svg +1 -0
- package/.claude/worktrees/agent-a952bde8/server/handlers.js +269 -0
- package/.claude/worktrees/agent-a952bde8/server/index.js +88 -0
- package/.claude/worktrees/agent-a952bde8/server/terminal.js +103 -0
- package/.claude/worktrees/agent-a952bde8/vitest.config.mjs +8 -0
- package/README.md +2 -1
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +153 -0
- package/coverage/coverage-final.json +2 -0
- package/coverage/favicon.png +0 -0
- package/coverage/handlers.js.html +892 -0
- package/coverage/index.html +116 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/package.json +43 -34
- package/server/__tests__/api.test.js +261 -0
- package/server/dist/assets/angular-html-DA-rfuFy.js +1 -0
- package/server/dist/assets/angular-ts-BrjP3tb8.js +1 -0
- package/server/dist/assets/c-BIGW1oBm.js +1 -0
- package/server/dist/assets/cpp-BRuaLJcg.js +1 -0
- package/server/dist/assets/csharp-COcwbKMJ.js +1 -0
- package/server/dist/assets/css-CLj8gQPS.js +1 -0
- package/server/dist/assets/dockerfile-BcOcwvcX.js +1 -0
- package/server/dist/assets/dotenv-Da5cRb03.js +1 -0
- package/server/dist/assets/github-dark-DHJKELXO.js +1 -0
- package/server/dist/assets/go-C27-OAKa.js +1 -0
- package/server/dist/assets/graphql-ChdNCCLP.js +1 -0
- package/server/dist/assets/html-derivative-C6UeqQa8.js +1 -0
- package/server/dist/assets/html-pp8916En.js +1 -0
- package/server/dist/assets/http-l_GQhCeT.js +1 -0
- package/server/dist/assets/index-DOFQi_E1.js +231 -0
- package/server/dist/assets/index-DeppoR8O.css +1 -0
- package/server/dist/assets/ini-BEwlwnbL.js +1 -0
- package/server/dist/assets/java-CylS5w8V.js +1 -0
- package/server/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/server/dist/assets/json-Cp-IABpG.js +1 -0
- package/server/dist/assets/jsonc-Des-eS-w.js +1 -0
- package/server/dist/assets/jsonl-DcaNXYhu.js +1 -0
- package/server/dist/assets/jsx-g9-lgVsj.js +1 -0
- package/server/dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/server/dist/assets/kusto-wEQ09or8.js +1 -0
- package/server/dist/assets/latex-DdMFrP5M.js +1 -0
- package/server/dist/assets/markdown-Cvjx9yec.js +1 -0
- package/server/dist/assets/mdc-Dz5ISc6g.js +1 -0
- package/server/dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/server/dist/assets/mermaid-mWjccvbQ.js +1 -0
- package/server/dist/assets/php-R6g_5hLQ.js +1 -0
- package/server/dist/assets/powershell-Dpen1YoG.js +1 -0
- package/server/dist/assets/python-B6aJPvgy.js +1 -0
- package/server/dist/assets/ruby-AcS3PBV-.js +1 -0
- package/server/dist/assets/rust-B1yitclQ.js +1 -0
- package/server/dist/assets/sass-Cj5Yp3dK.js +1 -0
- package/server/dist/assets/scss-D5BDwBP9.js +1 -0
- package/server/dist/assets/shellscript-DfDnw5Jg.js +1 -0
- package/server/dist/assets/sql-BLtJtn59.js +1 -0
- package/server/dist/assets/svelte-DR4MIrkg.js +1 -0
- package/server/dist/assets/swift-D82vCrfD.js +1 -0
- package/server/dist/assets/toml-vGWfd6FD.js +1 -0
- package/server/dist/assets/tsx-COt5Ahok.js +1 -0
- package/server/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/server/dist/assets/vue-CJgBXYWu.js +1 -0
- package/server/dist/assets/xml-sdJ4AIDG.js +1 -0
- package/server/dist/assets/yaml-Buea-lGh.js +1 -0
- package/server/dist/assets/zig-VOosw3JB.js +1 -0
- package/server/dist/index.html +2 -2
- package/server/handlers.js +356 -0
- package/server/index.js +2 -242
- package/server/terminal.js +2 -4
- package/vitest.config.mjs +8 -0
- package/server/dist/assets/index-BNjM8bEC.css +0 -1
- package/server/dist/assets/index-BU8XOdEX.js +0 -75
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@citadel-labs/beads-ui",
|
|
3
|
+
"version": "2.3.0",
|
|
4
|
+
"description": "Kanban dashboard and git log viewer for Beads",
|
|
5
|
+
"bin": {
|
|
6
|
+
"bdui": "bin/beads-board.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "cd ui && npm run build",
|
|
10
|
+
"start": "node server/index.js",
|
|
11
|
+
"test": "vitest run && npm --prefix ui test",
|
|
12
|
+
"test:server": "vitest run",
|
|
13
|
+
"test:ui": "npm --prefix ui test",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"publish:patch": "npm version patch && git push && git push --tags && npm publish --access public",
|
|
17
|
+
"publish:minor": "npm version minor && git push && git push --tags && npm publish --access public",
|
|
18
|
+
"publish:major": "npm version major && git push && git push --tags && npm publish --access public"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"beads",
|
|
22
|
+
"kanban",
|
|
23
|
+
"dashboard",
|
|
24
|
+
"git",
|
|
25
|
+
"cli",
|
|
26
|
+
"bdui"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/srimel/beads-board.git"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/srimel/beads-board",
|
|
33
|
+
"author": "Stuart Rimel <stuart.rimel@gmail.com>",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"node-pty": "^1.1.0",
|
|
37
|
+
"ws": "^8.19.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
41
|
+
"vitest": "^4.0.18"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeAll, afterAll, afterEach } from 'vitest';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
import { createRequestHandler, setExecFile } from '../handlers.js';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const DIST_DIR = path.join(__dirname, '..', 'dist');
|
|
10
|
+
const PROJECT_DIR = path.join(__dirname, '..', '..');
|
|
11
|
+
|
|
12
|
+
let server;
|
|
13
|
+
let baseUrl;
|
|
14
|
+
const mockFn = vi.fn();
|
|
15
|
+
|
|
16
|
+
// Helper: mock execFile to return specific output for bd/git commands
|
|
17
|
+
function mockExecFile(fn) {
|
|
18
|
+
mockFn.mockImplementation((cmd, args, opts, cb) => {
|
|
19
|
+
const result = fn(cmd, args);
|
|
20
|
+
if (result instanceof Error) {
|
|
21
|
+
cb(result, '', result.message);
|
|
22
|
+
} else {
|
|
23
|
+
cb(null, result, '');
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
beforeAll(async () => {
|
|
29
|
+
// Replace the real execFile with our mock
|
|
30
|
+
setExecFile(mockFn);
|
|
31
|
+
const handler = createRequestHandler(PROJECT_DIR, DIST_DIR);
|
|
32
|
+
server = http.createServer(handler);
|
|
33
|
+
await new Promise((resolve) => {
|
|
34
|
+
server.listen(0, () => {
|
|
35
|
+
const addr = server.address();
|
|
36
|
+
baseUrl = `http://localhost:${addr.port}`;
|
|
37
|
+
resolve();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterAll(async () => {
|
|
43
|
+
await new Promise((resolve) => server.close(resolve));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
mockFn.mockReset();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
async function get(urlPath) {
|
|
51
|
+
const r = await fetch(`${baseUrl}${urlPath}`);
|
|
52
|
+
const text = await r.text();
|
|
53
|
+
let data = null;
|
|
54
|
+
try { data = JSON.parse(text); } catch {}
|
|
55
|
+
return { status: r.status, data, text };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('API endpoints', () => {
|
|
59
|
+
it('GET /api/issues returns JSON array', async () => {
|
|
60
|
+
mockExecFile((cmd, args) => {
|
|
61
|
+
return JSON.stringify([{ id: 'test-1', title: 'Test', issue_type: 'task' }]);
|
|
62
|
+
});
|
|
63
|
+
const res = await get('/api/issues');
|
|
64
|
+
expect(res.status).toBe(200);
|
|
65
|
+
expect(Array.isArray(res.data)).toBe(true);
|
|
66
|
+
expect(res.data[0]).toHaveProperty('id', 'test-1');
|
|
67
|
+
expect(res.data[0]).toHaveProperty('type', 'task'); // normalizeIssue applied
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('GET /api/issue/:id returns issue data for valid ID', async () => {
|
|
71
|
+
mockExecFile((cmd, args) => {
|
|
72
|
+
if (cmd === 'bd') return JSON.stringify({ id: 'beads-board-abc', title: 'Test Issue' });
|
|
73
|
+
return '';
|
|
74
|
+
});
|
|
75
|
+
const res = await get('/api/issue/beads-board-abc');
|
|
76
|
+
expect(res.status).toBe(200);
|
|
77
|
+
expect(res.data).toHaveProperty('title', 'Test Issue');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('GET /api/issue/:id accepts dotted IDs', async () => {
|
|
81
|
+
mockExecFile((cmd, args) => {
|
|
82
|
+
if (cmd === 'bd') return JSON.stringify({ id: 'beads-board-abc.1', title: 'Sub-task' });
|
|
83
|
+
return '';
|
|
84
|
+
});
|
|
85
|
+
const res = await get('/api/issue/beads-board-abc.1');
|
|
86
|
+
expect(res.status).toBe(200);
|
|
87
|
+
expect(res.data).toHaveProperty('id', 'beads-board-abc.1');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('GET /api/issue/:id returns 400 for invalid ID', async () => {
|
|
91
|
+
const res = await get('/api/issue/invalid;id');
|
|
92
|
+
expect(res.status).toBe(400);
|
|
93
|
+
expect(res.data).toHaveProperty('error', 'Invalid issue ID');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('GET /api/ready returns JSON array', async () => {
|
|
97
|
+
mockExecFile((cmd, args) => {
|
|
98
|
+
if (cmd === 'bd') return JSON.stringify([{ id: 'test-2', title: 'Ready', issue_type: 'bug' }]);
|
|
99
|
+
return '';
|
|
100
|
+
});
|
|
101
|
+
const res = await get('/api/ready');
|
|
102
|
+
expect(res.status).toBe(200);
|
|
103
|
+
expect(Array.isArray(res.data)).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('GET /api/blocked returns JSON array', async () => {
|
|
107
|
+
mockExecFile((cmd, args) => {
|
|
108
|
+
if (cmd === 'bd') return JSON.stringify([]);
|
|
109
|
+
return '';
|
|
110
|
+
});
|
|
111
|
+
const res = await get('/api/blocked');
|
|
112
|
+
expect(res.status).toBe(200);
|
|
113
|
+
expect(Array.isArray(res.data)).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('GET / serves index.html', async () => {
|
|
117
|
+
// No mock needed — this reads from dist/
|
|
118
|
+
const res = await fetch(`${baseUrl}/`);
|
|
119
|
+
expect(res.status).toBe(200);
|
|
120
|
+
expect(res.headers.get('content-type')).toContain('text/html');
|
|
121
|
+
});
|
|
122
|
+
});
|