beads-ui 0.4.2 → 0.4.3
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 +24 -1
- package/README.md +2 -2
- package/app/main.bundle.js +41 -41
- package/app/main.bundle.js.map +4 -4
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beads-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
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;
|