claude-remote-cli 2.3.5 → 2.4.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/dist/frontend/assets/{index-DYxG7JDE.css → index-B71YYqJ5.css} +1 -1
- package/dist/frontend/assets/index-DgUrQn-w.js +47 -0
- package/dist/frontend/index.html +2 -2
- package/dist/server/index.js +77 -0
- package/dist/test/pull-requests.test.js +64 -0
- package/package.json +2 -1
- package/dist/frontend/assets/index-CkLxZCoo.js +0 -47
package/dist/frontend/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
12
12
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
13
13
|
<meta name="theme-color" content="#1a1a1a" />
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-DgUrQn-w.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B71YYqJ5.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="app"></div>
|
package/dist/server/index.js
CHANGED
|
@@ -306,6 +306,83 @@ async function main() {
|
|
|
306
306
|
}
|
|
307
307
|
res.json({ prState, additions, deletions });
|
|
308
308
|
});
|
|
309
|
+
// GET /pull-requests?repo=<path>
|
|
310
|
+
app.get('/pull-requests', requireAuth, async (req, res) => {
|
|
311
|
+
const repoPath = typeof req.query.repo === 'string' ? req.query.repo : undefined;
|
|
312
|
+
if (!repoPath) {
|
|
313
|
+
res.status(400).json({ prs: [], error: 'repo query parameter is required' });
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const fields = 'number,title,url,headRefName,state,author,updatedAt,additions,deletions,reviewDecision';
|
|
317
|
+
// Get current GitHub user
|
|
318
|
+
let currentUser = '';
|
|
319
|
+
try {
|
|
320
|
+
const { stdout: whoami } = await execFileAsync('gh', ['api', 'user', '--jq', '.login'], { cwd: repoPath });
|
|
321
|
+
currentUser = whoami.trim();
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
const response = { prs: [], error: 'gh_not_authenticated' };
|
|
325
|
+
res.json(response);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
// Fetch authored PRs
|
|
329
|
+
const authored = [];
|
|
330
|
+
try {
|
|
331
|
+
const { stdout } = await execFileAsync('gh', [
|
|
332
|
+
'pr', 'list', '--author', currentUser, '--state', 'open', '--limit', '30',
|
|
333
|
+
'--json', fields,
|
|
334
|
+
], { cwd: repoPath });
|
|
335
|
+
const raw = JSON.parse(stdout);
|
|
336
|
+
for (const pr of raw) {
|
|
337
|
+
authored.push({
|
|
338
|
+
number: pr.number,
|
|
339
|
+
title: pr.title,
|
|
340
|
+
url: pr.url,
|
|
341
|
+
headRefName: pr.headRefName,
|
|
342
|
+
state: pr.state,
|
|
343
|
+
author: pr.author?.login ?? currentUser,
|
|
344
|
+
role: 'author',
|
|
345
|
+
updatedAt: pr.updatedAt,
|
|
346
|
+
additions: pr.additions ?? 0,
|
|
347
|
+
deletions: pr.deletions ?? 0,
|
|
348
|
+
reviewDecision: pr.reviewDecision ?? null,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
catch { /* no authored PRs or gh error */ }
|
|
353
|
+
// Fetch review-requested PRs
|
|
354
|
+
const reviewing = [];
|
|
355
|
+
try {
|
|
356
|
+
const { stdout } = await execFileAsync('gh', [
|
|
357
|
+
'pr', 'list', '--search', `review-requested:${currentUser}`, '--state', 'open', '--limit', '30',
|
|
358
|
+
'--json', fields,
|
|
359
|
+
], { cwd: repoPath });
|
|
360
|
+
const raw = JSON.parse(stdout);
|
|
361
|
+
for (const pr of raw) {
|
|
362
|
+
reviewing.push({
|
|
363
|
+
number: pr.number,
|
|
364
|
+
title: pr.title,
|
|
365
|
+
url: pr.url,
|
|
366
|
+
headRefName: pr.headRefName,
|
|
367
|
+
state: pr.state,
|
|
368
|
+
author: pr.author?.login ?? '',
|
|
369
|
+
role: 'reviewer',
|
|
370
|
+
updatedAt: pr.updatedAt,
|
|
371
|
+
additions: pr.additions ?? 0,
|
|
372
|
+
deletions: pr.deletions ?? 0,
|
|
373
|
+
reviewDecision: pr.reviewDecision ?? null,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
catch { /* no review-requested PRs or gh error */ }
|
|
378
|
+
// Deduplicate: if a PR appears in both (user is author AND reviewer), keep as 'author'
|
|
379
|
+
const seen = new Set(authored.map(pr => pr.number));
|
|
380
|
+
const combined = [...authored, ...reviewing.filter(pr => !seen.has(pr.number))];
|
|
381
|
+
// Sort by updatedAt descending
|
|
382
|
+
combined.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
383
|
+
const response = { prs: combined };
|
|
384
|
+
res.json(response);
|
|
385
|
+
});
|
|
309
386
|
// GET /worktrees?repo=<path> — list worktrees; omit repo to scan all repos in all rootDirs
|
|
310
387
|
app.get('/worktrees', requireAuth, (req, res) => {
|
|
311
388
|
const repoParam = typeof req.query.repo === 'string' ? req.query.repo : undefined;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
describe('PullRequest types', () => {
|
|
4
|
+
it('constructs a valid author PR', () => {
|
|
5
|
+
const pr = {
|
|
6
|
+
number: 42,
|
|
7
|
+
title: 'Fix bug',
|
|
8
|
+
url: 'https://github.com/owner/repo/pull/42',
|
|
9
|
+
headRefName: 'fix/bug',
|
|
10
|
+
state: 'OPEN',
|
|
11
|
+
author: 'testuser',
|
|
12
|
+
role: 'author',
|
|
13
|
+
updatedAt: '2026-02-24T00:00:00Z',
|
|
14
|
+
additions: 10,
|
|
15
|
+
deletions: 5,
|
|
16
|
+
reviewDecision: 'APPROVED',
|
|
17
|
+
};
|
|
18
|
+
assert.equal(pr.role, 'author');
|
|
19
|
+
assert.equal(pr.state, 'OPEN');
|
|
20
|
+
});
|
|
21
|
+
it('constructs a valid reviewer PR', () => {
|
|
22
|
+
const pr = {
|
|
23
|
+
number: 43,
|
|
24
|
+
title: 'Add feature',
|
|
25
|
+
url: 'https://github.com/owner/repo/pull/43',
|
|
26
|
+
headRefName: 'feat/new',
|
|
27
|
+
state: 'OPEN',
|
|
28
|
+
author: 'otheruser',
|
|
29
|
+
role: 'reviewer',
|
|
30
|
+
updatedAt: '2026-02-24T00:00:00Z',
|
|
31
|
+
additions: 50,
|
|
32
|
+
deletions: 20,
|
|
33
|
+
reviewDecision: null,
|
|
34
|
+
};
|
|
35
|
+
assert.equal(pr.role, 'reviewer');
|
|
36
|
+
});
|
|
37
|
+
it('constructs a valid response with error', () => {
|
|
38
|
+
const response = {
|
|
39
|
+
prs: [],
|
|
40
|
+
error: 'gh_not_authenticated',
|
|
41
|
+
};
|
|
42
|
+
assert.equal(response.prs.length, 0);
|
|
43
|
+
assert.equal(response.error, 'gh_not_authenticated');
|
|
44
|
+
});
|
|
45
|
+
it('constructs a valid response without error', () => {
|
|
46
|
+
const response = {
|
|
47
|
+
prs: [{
|
|
48
|
+
number: 1,
|
|
49
|
+
title: 'Test',
|
|
50
|
+
url: 'https://github.com/o/r/pull/1',
|
|
51
|
+
headRefName: 'test',
|
|
52
|
+
state: 'OPEN',
|
|
53
|
+
author: 'user',
|
|
54
|
+
role: 'author',
|
|
55
|
+
updatedAt: '2026-02-24T00:00:00Z',
|
|
56
|
+
additions: 0,
|
|
57
|
+
deletions: 0,
|
|
58
|
+
reviewDecision: null,
|
|
59
|
+
}],
|
|
60
|
+
};
|
|
61
|
+
assert.equal(response.prs.length, 1);
|
|
62
|
+
assert.equal(response.error, undefined);
|
|
63
|
+
});
|
|
64
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-remote-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Remote web interface for Claude Code CLI sessions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/server/index.js",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"author": "Donovan Yohan",
|
|
44
44
|
"dependencies": {
|
|
45
|
+
"@tanstack/svelte-query": "^6.0.18",
|
|
45
46
|
"@xterm/addon-fit": "^0.11.0",
|
|
46
47
|
"@xterm/xterm": "^6.0.0",
|
|
47
48
|
"bcrypt": "^5.1.1",
|