beads-ui 0.4.2 → 0.4.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/CHANGES.md +34 -1
- package/README.md +2 -2
- package/app/main.bundle.js +83 -79
- package/app/main.bundle.js.map +4 -4
- package/app/styles.css +17 -26
- package/package.json +3 -2
- package/server/bd.js +27 -22
- package/server/list-adapters.js +13 -0
- package/server/ws.js +15 -8
package/app/styles.css
CHANGED
|
@@ -497,6 +497,9 @@ button:disabled {
|
|
|
497
497
|
vertical-align: middle;
|
|
498
498
|
user-select: none;
|
|
499
499
|
border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
|
|
500
|
+
text-wrap: nowrap;
|
|
501
|
+
overflow: hidden;
|
|
502
|
+
text-overflow: ellipsis;
|
|
500
503
|
}
|
|
501
504
|
.badge + .badge,
|
|
502
505
|
.status-badge + .status-badge,
|
|
@@ -1324,20 +1327,20 @@ html[data-theme='dark'] {
|
|
|
1324
1327
|
gap: 10px;
|
|
1325
1328
|
padding: 8px 0;
|
|
1326
1329
|
border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1330
|
+
&:first-of-type {
|
|
1331
|
+
border-top: none;
|
|
1332
|
+
}
|
|
1333
|
+
& .label {
|
|
1334
|
+
color: var(--muted);
|
|
1335
|
+
font-size: 12px;
|
|
1336
|
+
min-width: 80px;
|
|
1337
|
+
}
|
|
1338
|
+
& .value {
|
|
1339
|
+
font-size: 13px;
|
|
1340
|
+
display: flex;
|
|
1341
|
+
align-items: center;
|
|
1342
|
+
gap: 8px;
|
|
1343
|
+
}
|
|
1341
1344
|
}
|
|
1342
1345
|
|
|
1343
1346
|
/* --- Issue Details Dialog (UI-104) --- */
|
|
@@ -1437,18 +1440,6 @@ html[data-theme='dark'] {
|
|
|
1437
1440
|
line-height: 1.2;
|
|
1438
1441
|
}
|
|
1439
1442
|
|
|
1440
|
-
.prop.labels {
|
|
1441
|
-
align-items: start;
|
|
1442
|
-
}
|
|
1443
|
-
.prop.labels .value > div {
|
|
1444
|
-
display: flex;
|
|
1445
|
-
flex-wrap: wrap;
|
|
1446
|
-
gap: 6px;
|
|
1447
|
-
}
|
|
1448
|
-
.prop.labels .value > div input {
|
|
1449
|
-
flex: 1;
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
1443
|
/* Sidebar control aesthetics */
|
|
1453
1444
|
#detail-root .props-card input[type='text'] {
|
|
1454
1445
|
border: 1px solid var(--control-border);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beads-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Local UI for Beads — Collaborate on issues with your coding agent.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"ai-tools"
|
|
10
10
|
],
|
|
11
11
|
"homepage": "https://github.com/mantoni/beads-ui",
|
|
12
|
+
"author": "Maximilian Antoni <mail@maxantoni.de>",
|
|
12
13
|
"type": "module",
|
|
13
14
|
"bin": {
|
|
14
15
|
"bdui": "bin/bdui.js"
|
|
@@ -57,7 +58,7 @@
|
|
|
57
58
|
"jsdom": "^27.0.1",
|
|
58
59
|
"prettier": "^3.3.3",
|
|
59
60
|
"typescript": "^5.6.3",
|
|
60
|
-
"vitest": "^
|
|
61
|
+
"vitest": "^4.0.6"
|
|
61
62
|
},
|
|
62
63
|
"files": [
|
|
63
64
|
"app/index.html",
|
package/server/bd.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { resolveDbPath } from './db.js';
|
|
3
|
+
import { debug } from './logging.js';
|
|
4
|
+
|
|
5
|
+
const log = debug('bd');
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Resolve the bd executable path.
|
|
@@ -24,15 +27,25 @@ export function getBdBin() {
|
|
|
24
27
|
*/
|
|
25
28
|
export function runBd(args, options = {}) {
|
|
26
29
|
const bin = getBdBin();
|
|
30
|
+
|
|
31
|
+
// Ensure a consistent DB by setting BEADS_DB environment variable
|
|
32
|
+
const db_path = resolveDbPath({
|
|
33
|
+
cwd: options.cwd || process.cwd(),
|
|
34
|
+
env: options.env || process.env
|
|
35
|
+
});
|
|
36
|
+
const env_with_db = {
|
|
37
|
+
...(options.env || process.env),
|
|
38
|
+
BEADS_DB: db_path.path
|
|
39
|
+
};
|
|
40
|
+
|
|
27
41
|
const spawn_opts = {
|
|
28
42
|
cwd: options.cwd || process.cwd(),
|
|
29
|
-
env:
|
|
43
|
+
env: env_with_db,
|
|
30
44
|
shell: false
|
|
31
45
|
};
|
|
32
46
|
|
|
33
|
-
// Ensure a consistent DB by injecting --db if missing, following beads precedence.
|
|
34
47
|
/** @type {string[]} */
|
|
35
|
-
const final_args =
|
|
48
|
+
const final_args = args.slice();
|
|
36
49
|
|
|
37
50
|
return new Promise((resolve) => {
|
|
38
51
|
const child = spawn(bin, final_args, spawn_opts);
|
|
@@ -78,8 +91,9 @@ export function runBd(args, options = {}) {
|
|
|
78
91
|
});
|
|
79
92
|
};
|
|
80
93
|
|
|
81
|
-
child.on('error', () => {
|
|
82
|
-
// Treat spawn error as an immediate non-zero exit
|
|
94
|
+
child.on('error', (err) => {
|
|
95
|
+
// Treat spawn error as an immediate non-zero exit; log for diagnostics.
|
|
96
|
+
log('spawn error running %s %o', bin, err);
|
|
83
97
|
finish(127);
|
|
84
98
|
});
|
|
85
99
|
child.on('close', (code) => {
|
|
@@ -98,30 +112,21 @@ export function runBd(args, options = {}) {
|
|
|
98
112
|
export async function runBdJson(args, options = {}) {
|
|
99
113
|
const result = await runBd(args, options);
|
|
100
114
|
if (result.code !== 0) {
|
|
115
|
+
log(
|
|
116
|
+
'bd exited with code %d (args=%o) stderr=%s',
|
|
117
|
+
result.code,
|
|
118
|
+
args,
|
|
119
|
+
result.stderr
|
|
120
|
+
);
|
|
101
121
|
return { code: result.code, stderr: result.stderr };
|
|
102
122
|
}
|
|
103
123
|
/** @type {unknown} */
|
|
104
124
|
let parsed;
|
|
105
125
|
try {
|
|
106
126
|
parsed = JSON.parse(result.stdout || 'null');
|
|
107
|
-
} catch {
|
|
127
|
+
} catch (err) {
|
|
128
|
+
log('bd returned invalid JSON (args=%o): %o', args, err);
|
|
108
129
|
return { code: 0, stderr: 'Invalid JSON from bd' };
|
|
109
130
|
}
|
|
110
131
|
return { code: 0, stdoutJson: parsed };
|
|
111
132
|
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Add a resolved "--db <path>" pair to args when none present.
|
|
115
|
-
*
|
|
116
|
-
* @param {string[]} args
|
|
117
|
-
* @param {string} cwd
|
|
118
|
-
* @param {Record<string, string | undefined>} env
|
|
119
|
-
* @returns {string[]}
|
|
120
|
-
*/
|
|
121
|
-
function withDbArg(args, cwd, env) {
|
|
122
|
-
if (args.includes('--db')) {
|
|
123
|
-
return args.slice();
|
|
124
|
-
}
|
|
125
|
-
const resolved = resolveDbPath({ cwd, env });
|
|
126
|
-
return ['--db', resolved.path, ...args];
|
|
127
|
-
}
|
package/server/list-adapters.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { runBdJson } from './bd.js';
|
|
2
|
+
import { debug } from './logging.js';
|
|
3
|
+
|
|
4
|
+
const log = debug('list-adapters');
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Build concrete `bd` CLI args for a subscription type + params.
|
|
@@ -107,6 +110,8 @@ export async function fetchListForSubscription(spec) {
|
|
|
107
110
|
try {
|
|
108
111
|
args = mapSubscriptionToBdArgs(spec);
|
|
109
112
|
} catch (err) {
|
|
113
|
+
// Surface bad requests (e.g., missing params)
|
|
114
|
+
log('mapSubscriptionToBdArgs failed for %o: %o', spec, err);
|
|
110
115
|
const e = toErrorObject(err);
|
|
111
116
|
return { ok: false, error: e };
|
|
112
117
|
}
|
|
@@ -114,6 +119,13 @@ export async function fetchListForSubscription(spec) {
|
|
|
114
119
|
try {
|
|
115
120
|
const res = await runBdJson(args);
|
|
116
121
|
if (!res || res.code !== 0 || !('stdoutJson' in res)) {
|
|
122
|
+
log(
|
|
123
|
+
'bd failed for %o (args=%o) code=%s stderr=%s',
|
|
124
|
+
spec,
|
|
125
|
+
args,
|
|
126
|
+
res?.code,
|
|
127
|
+
res?.stderr || ''
|
|
128
|
+
);
|
|
117
129
|
return {
|
|
118
130
|
ok: false,
|
|
119
131
|
error: {
|
|
@@ -161,6 +173,7 @@ export async function fetchListForSubscription(spec) {
|
|
|
161
173
|
const items = normalizeIssueList(raw);
|
|
162
174
|
return { ok: true, items };
|
|
163
175
|
} catch (err) {
|
|
176
|
+
log('bd invocation failed for %o (args=%o): %o', spec, args, err);
|
|
164
177
|
return {
|
|
165
178
|
ok: false,
|
|
166
179
|
error: {
|
package/server/ws.js
CHANGED
|
@@ -250,8 +250,8 @@ function emitSubscriptionSnapshot(ws, client_id, key, issues) {
|
|
|
250
250
|
});
|
|
251
251
|
try {
|
|
252
252
|
ws.send(msg);
|
|
253
|
-
} catch {
|
|
254
|
-
|
|
253
|
+
} catch (err) {
|
|
254
|
+
log('emit snapshot send failed key=%s id=%s: %o', key, client_id, err);
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
|
|
@@ -277,8 +277,8 @@ function emitSubscriptionUpsert(ws, client_id, key, issue) {
|
|
|
277
277
|
});
|
|
278
278
|
try {
|
|
279
279
|
ws.send(msg);
|
|
280
|
-
} catch {
|
|
281
|
-
|
|
280
|
+
} catch (err) {
|
|
281
|
+
log('emit upsert send failed key=%s id=%s: %o', key, client_id, err);
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
|
|
@@ -304,8 +304,8 @@ function emitSubscriptionDelete(ws, client_id, key, issue_id) {
|
|
|
304
304
|
});
|
|
305
305
|
try {
|
|
306
306
|
ws.send(msg);
|
|
307
|
-
} catch {
|
|
308
|
-
|
|
307
|
+
} catch (err) {
|
|
308
|
+
log('emit delete send failed key=%s id=%s: %o', key, client_id, err);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
|
|
@@ -322,6 +322,7 @@ async function refreshAndPublish(spec) {
|
|
|
322
322
|
await registry.withKeyLock(key, async () => {
|
|
323
323
|
const res = await fetchListForSubscription(spec);
|
|
324
324
|
if (!res.ok) {
|
|
325
|
+
log('refresh failed for %s: %s %o', key, res.error.message, res.error);
|
|
325
326
|
return;
|
|
326
327
|
}
|
|
327
328
|
const items = applyClosedIssuesFilter(spec, res.items);
|
|
@@ -554,14 +555,20 @@ export async function handleMessage(ws, data) {
|
|
|
554
555
|
await registry.withKeyLock(key, async () => {
|
|
555
556
|
const res = await fetchListForSubscription(spec);
|
|
556
557
|
if (!res.ok) {
|
|
558
|
+
log(
|
|
559
|
+
'initial snapshot failed for %s: %s %o',
|
|
560
|
+
key,
|
|
561
|
+
res.error.message,
|
|
562
|
+
res.error
|
|
563
|
+
);
|
|
557
564
|
return;
|
|
558
565
|
}
|
|
559
566
|
const items = applyClosedIssuesFilter(spec, res.items);
|
|
560
567
|
void registry.applyItems(key, items);
|
|
561
568
|
emitSubscriptionSnapshot(ws, client_id, key, items);
|
|
562
569
|
});
|
|
563
|
-
} catch {
|
|
564
|
-
|
|
570
|
+
} catch (err) {
|
|
571
|
+
log('subscribe-list snapshot error for %s: %o', key, err);
|
|
565
572
|
}
|
|
566
573
|
ws.send(JSON.stringify(makeOk(req, { id: client_id, key })));
|
|
567
574
|
return;
|