linear-grab-bridge 0.13.0 → 0.15.1
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/linear-grab-bridge.mjs +34 -1
- package/package.json +1 -1
package/linear-grab-bridge.mjs
CHANGED
|
@@ -28,7 +28,7 @@ const flag = (name, fallback) => {
|
|
|
28
28
|
const PORT = Number(flag('--port', '4577'));
|
|
29
29
|
const DIR = flag('--dir', process.cwd());
|
|
30
30
|
const CLAUDE_BIN = flag('--claude', 'claude');
|
|
31
|
-
const VERSION = '0.
|
|
31
|
+
const VERSION = '0.15.1';
|
|
32
32
|
|
|
33
33
|
/** Best-effort command runner (git/gh introspection). Never throws. */
|
|
34
34
|
function run(cmd, args, cwd = DIR) {
|
|
@@ -68,6 +68,9 @@ const tasks = new Map();
|
|
|
68
68
|
/** Linear Authorization header supplied by the panel (for the media proxy). */
|
|
69
69
|
let linearAuth = null;
|
|
70
70
|
|
|
71
|
+
/** PR state cache (gh pr view) — 60s TTL. */
|
|
72
|
+
const prStatusCache = new Map();
|
|
73
|
+
|
|
71
74
|
// ---- persistence -----------------------------------------------------------
|
|
72
75
|
|
|
73
76
|
const HISTORY_DIR = join(homedir(), '.linear-grab');
|
|
@@ -579,6 +582,35 @@ createServer(async (req, res) => {
|
|
|
579
582
|
});
|
|
580
583
|
return res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
581
584
|
}
|
|
585
|
+
// Real PR states (OPEN/MERGED/CLOSED) via gh — the panel can't know
|
|
586
|
+
// merge status from Linear attachments alone.
|
|
587
|
+
if (req.method === 'POST' && url.pathname === '/pr/status') {
|
|
588
|
+
const body = await readBody(req);
|
|
589
|
+
const urls = (Array.isArray(body.urls) ? body.urls : []).slice(0, 20);
|
|
590
|
+
const statuses = {};
|
|
591
|
+
await Promise.all(
|
|
592
|
+
urls.map(async (u) => {
|
|
593
|
+
const prUrl = String(u);
|
|
594
|
+
if (!/^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+$/.test(prUrl)) return;
|
|
595
|
+
const cached = prStatusCache.get(prUrl);
|
|
596
|
+
if (cached && Date.now() - cached.at < 60_000) {
|
|
597
|
+
statuses[prUrl] = cached.state;
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const out = await run('gh', ['pr', 'view', prUrl, '--json', 'state']);
|
|
601
|
+
try {
|
|
602
|
+
const state = JSON.parse(out ?? '').state;
|
|
603
|
+
if (state) {
|
|
604
|
+
prStatusCache.set(prUrl, { state, at: Date.now() });
|
|
605
|
+
statuses[prUrl] = state;
|
|
606
|
+
}
|
|
607
|
+
} catch {
|
|
608
|
+
/* gh missing / not accessible */
|
|
609
|
+
}
|
|
610
|
+
}),
|
|
611
|
+
);
|
|
612
|
+
return json(res, 200, { statuses });
|
|
613
|
+
}
|
|
582
614
|
// Fast-merge: after reviewing the demo, one click merges the PR via gh.
|
|
583
615
|
if (req.method === 'POST' && url.pathname === '/pr/merge') {
|
|
584
616
|
const body = await readBody(req);
|
|
@@ -587,6 +619,7 @@ createServer(async (req, res) => {
|
|
|
587
619
|
return json(res, 400, { error: 'invalid PR url' });
|
|
588
620
|
}
|
|
589
621
|
const out = await run('gh', ['pr', 'merge', prUrl, '--squash']);
|
|
622
|
+
prStatusCache.delete(prUrl);
|
|
590
623
|
if (out === null) {
|
|
591
624
|
return json(res, 502, { error: 'gh pr merge failed — check gh auth / merge conflicts / required checks' });
|
|
592
625
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linear-grab-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Local bridge for Linear Grab — delegate issues from the browser panel to headless Claude Code sessions running in your repo, with live status and an upload relay.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|