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.
@@ -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-CkLxZCoo.js"></script>
15
- <link rel="stylesheet" crossorigin href="/assets/index-DYxG7JDE.css">
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>
@@ -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.5",
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",