@h-rig/server 0.0.6-alpha.10 → 0.0.6-alpha.11

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.
@@ -115,8 +115,13 @@ function upsertProjectRecord(projectRoot, input) {
115
115
  function linkProjectCheckout(projectRoot, repoSlug, checkout) {
116
116
  return upsertProjectRecord(projectRoot, { repoSlug, checkout });
117
117
  }
118
+ function projectRegistryContainsCheckout(projectRoot, checkoutPath) {
119
+ const target = resolve(checkoutPath);
120
+ return Object.values(readRegistry(projectRoot)).some((project) => project.checkouts.some((checkout) => checkout.path ? resolve(checkout.path) === target : false));
121
+ }
118
122
  export {
119
123
  upsertProjectRecord,
124
+ projectRegistryContainsCheckout,
120
125
  normalizeRepoSlug,
121
126
  linkProjectCheckout,
122
127
  getProjectRecord,
@@ -3,7 +3,7 @@
3
3
  import { spawn } from "child_process";
4
4
  import { loadConfig } from "@rig/core/load-config";
5
5
  import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
6
- import { dirname as dirname5, relative as relative2, resolve as resolve10 } from "path";
6
+ import { dirname as dirname6, relative as relative2, resolve as resolve10 } from "path";
7
7
  import {
8
8
  listAuthorityRuns as listAuthorityRuns7,
9
9
  readAuthorityRun as readAuthorityRun8,
@@ -99,7 +99,7 @@ function normalizeStatus(value) {
99
99
 
100
100
  // packages/server/src/server.ts
101
101
  import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
102
- import { dirname as dirname4, resolve as resolve8 } from "path";
102
+ import { dirname as dirname5, resolve as resolve8 } from "path";
103
103
  import {
104
104
  listAuthorityArtifactRoots,
105
105
  listAuthorityRuns as listAuthorityRuns6,
@@ -478,8 +478,8 @@ import {
478
478
 
479
479
  // packages/server/src/server-helpers/github-auth-store.ts
480
480
  import { randomBytes } from "crypto";
481
- import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
482
- import { resolve as resolve7 } from "path";
481
+ import { chmodSync, copyFileSync, existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
482
+ import { dirname as dirname4, resolve as resolve7 } from "path";
483
483
  function cleanString(value) {
484
484
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
485
485
  }
@@ -509,6 +509,26 @@ function parseApiSessions(value) {
509
509
  }];
510
510
  });
511
511
  }
512
+ function parsePendingDevice(value) {
513
+ if (!value || typeof value !== "object")
514
+ return null;
515
+ const record = value;
516
+ const pollId = cleanString(record.pollId);
517
+ const deviceCode = cleanString(record.deviceCode);
518
+ const expiresAt = cleanString(record.expiresAt);
519
+ const intervalSeconds = typeof record.intervalSeconds === "number" && Number.isFinite(record.intervalSeconds) ? Math.max(1, Math.floor(record.intervalSeconds)) : null;
520
+ if (!pollId || !deviceCode || !expiresAt || !intervalSeconds)
521
+ return null;
522
+ return { pollId, deviceCode, expiresAt, intervalSeconds };
523
+ }
524
+ function parsePendingDevices(value) {
525
+ if (!Array.isArray(value))
526
+ return [];
527
+ return value.flatMap((entry) => {
528
+ const pending = parsePendingDevice(entry);
529
+ return pending ? [pending] : [];
530
+ });
531
+ }
512
532
  function readStoredAuth(stateFile) {
513
533
  if (!existsSync4(stateFile))
514
534
  return {};
@@ -522,6 +542,7 @@ function readStoredAuth(stateFile) {
522
542
  selectedRepo: cleanString(parsed.selectedRepo),
523
543
  tokenSource: parsed.tokenSource === "oauth-device" || parsed.tokenSource === "manual-token" || parsed.tokenSource === "env" ? parsed.tokenSource : undefined,
524
544
  pendingDevice: parsePendingDevice(parsed.pendingDevice),
545
+ pendingDevices: parsePendingDevices(parsed.pendingDevices),
525
546
  apiSessions: parseApiSessions(parsed.apiSessions),
526
547
  updatedAt: cleanString(parsed.updatedAt) ?? undefined
527
548
  };
@@ -529,34 +550,36 @@ function readStoredAuth(stateFile) {
529
550
  return {};
530
551
  }
531
552
  }
532
- function parsePendingDevice(value) {
533
- if (!value || typeof value !== "object")
534
- return null;
535
- const record = value;
536
- const pollId = cleanString(record.pollId);
537
- const deviceCode = cleanString(record.deviceCode);
538
- const expiresAt = cleanString(record.expiresAt);
539
- const intervalSeconds = typeof record.intervalSeconds === "number" && Number.isFinite(record.intervalSeconds) ? Math.max(1, Math.floor(record.intervalSeconds)) : null;
540
- if (!pollId || !deviceCode || !expiresAt || !intervalSeconds)
541
- return null;
542
- return { pollId, deviceCode, expiresAt, intervalSeconds };
543
- }
544
553
  function newApiSessionToken() {
545
554
  return `rig_${randomBytes(32).toString("base64url")}`;
546
555
  }
547
556
  function writeStoredAuth(stateFile, payload) {
548
- mkdirSync4(resolve7(stateFile, ".."), { recursive: true });
557
+ mkdirSync4(dirname4(stateFile), { recursive: true });
549
558
  writeFileSync4(stateFile, `${JSON.stringify(payload, null, 2)}
550
559
  `, { encoding: "utf8", mode: 384 });
551
560
  try {
552
561
  chmodSync(stateFile, 384);
553
562
  } catch {}
554
563
  }
564
+ function localProjectAuthStateFile(projectRoot) {
565
+ return resolve7(projectRoot, ".rig", "state", "github-auth.json");
566
+ }
555
567
  function resolveGitHubAuthStateFile(projectRoot) {
556
568
  return resolve7(resolveServerAuthorityPaths(projectRoot).stateDir, "github-auth.json");
557
569
  }
558
- function createGitHubAuthStore(projectRoot) {
559
- const stateFile = resolveGitHubAuthStateFile(projectRoot);
570
+ function copyGitHubAuthStateToLocalProjectRoot(stateFile, projectRoot) {
571
+ const targetFile = localProjectAuthStateFile(projectRoot);
572
+ mkdirSync4(dirname4(targetFile), { recursive: true });
573
+ if (existsSync4(stateFile)) {
574
+ copyFileSync(stateFile, targetFile);
575
+ try {
576
+ chmodSync(targetFile, 384);
577
+ } catch {}
578
+ return;
579
+ }
580
+ writeStoredAuth(targetFile, {});
581
+ }
582
+ function createGitHubAuthStoreFromStateFile(stateFile) {
560
583
  return {
561
584
  stateFile,
562
585
  status(options) {
@@ -586,6 +609,7 @@ function createGitHubAuthStore(projectRoot) {
586
609
  scopes: input.scopes ?? [],
587
610
  selectedRepo: input.selectedRepo ?? previous.selectedRepo ?? null,
588
611
  pendingDevice: null,
612
+ pendingDevices: [],
589
613
  apiSessions: previous.apiSessions ?? [],
590
614
  updatedAt: new Date().toISOString()
591
615
  });
@@ -614,15 +638,24 @@ function createGitHubAuthStore(projectRoot) {
614
638
  const session = (previous.apiSessions ?? []).find((candidate) => candidate.token === clean);
615
639
  return session ? { login: cleanString(session.login), userId: cleanString(session.userId) } : null;
616
640
  },
617
- copyToProjectRoot(projectRoot2) {
618
- const targetFile = resolveGitHubAuthStateFile(projectRoot2);
641
+ copyToProjectRoot(projectRoot) {
642
+ const targetFile = resolveGitHubAuthStateFile(projectRoot);
619
643
  writeStoredAuth(targetFile, readStoredAuth(stateFile));
620
644
  },
645
+ copyToLocalProjectRoot(projectRoot) {
646
+ copyGitHubAuthStateToLocalProjectRoot(stateFile, projectRoot);
647
+ },
621
648
  savePendingDevice(input) {
622
649
  const previous = readStoredAuth(stateFile);
650
+ const pendingDevices = [
651
+ ...previous.pendingDevice ? [previous.pendingDevice] : [],
652
+ ...previous.pendingDevices ?? [],
653
+ input
654
+ ].filter((entry, index, entries) => entries.findIndex((candidate) => candidate.pollId === entry.pollId) === index);
623
655
  writeStoredAuth(stateFile, {
624
656
  ...previous,
625
- pendingDevice: input,
657
+ pendingDevice: null,
658
+ pendingDevices,
626
659
  updatedAt: new Date().toISOString()
627
660
  });
628
661
  },
@@ -635,23 +668,32 @@ function createGitHubAuthStore(projectRoot) {
635
668
  });
636
669
  },
637
670
  readPendingDevice(pollId) {
638
- const pending = readStoredAuth(stateFile).pendingDevice ?? null;
639
- if (!pending || pending.pollId !== pollId)
671
+ const previous = readStoredAuth(stateFile);
672
+ const pending = [
673
+ ...previous.pendingDevice ? [previous.pendingDevice] : [],
674
+ ...previous.pendingDevices ?? []
675
+ ].find((entry) => entry.pollId === pollId) ?? null;
676
+ if (!pending)
640
677
  return null;
641
678
  if (Date.parse(pending.expiresAt) <= Date.now())
642
679
  return null;
643
680
  return pending;
644
681
  },
645
- clearPendingDevice() {
682
+ clearPendingDevice(pollId) {
646
683
  const previous = readStoredAuth(stateFile);
684
+ const remaining = pollId ? (previous.pendingDevices ?? []).filter((entry) => entry.pollId !== pollId) : [];
647
685
  writeStoredAuth(stateFile, {
648
686
  ...previous,
649
687
  pendingDevice: null,
688
+ pendingDevices: remaining,
650
689
  updatedAt: new Date().toISOString()
651
690
  });
652
691
  }
653
692
  };
654
693
  }
694
+ function createGitHubAuthStore(projectRoot) {
695
+ return createGitHubAuthStoreFromStateFile(resolveGitHubAuthStateFile(projectRoot));
696
+ }
655
697
 
656
698
  // packages/server/src/server-helpers/github-projects.ts
657
699
  function asRecord(value) {
@@ -1665,7 +1707,7 @@ function resolveLocalRunCliProjectRoot(projectRoot) {
1665
1707
  }
1666
1708
  try {
1667
1709
  const monorepoRoot = resolveMonorepoRoot6(projectRoot);
1668
- const outerProjectRoot = dirname5(dirname5(monorepoRoot));
1710
+ const outerProjectRoot = dirname6(dirname6(monorepoRoot));
1669
1711
  if (existsSync7(resolve10(outerProjectRoot, "packages/cli/bin/rig.ts"))) {
1670
1712
  return outerProjectRoot;
1671
1713
  }