@prover-coder-ai/docker-git 1.0.42 → 1.0.43

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.
@@ -1211,6 +1211,38 @@ var ensureGhAuthImage = (fs, path, cwd, buildLabel) => ensureDockerImage(fs, pat
1211
1211
  buildLabel
1212
1212
  });
1213
1213
  //#endregion
1214
+ //#region ../lib/src/usecases/github-api-helpers.ts
1215
+ /**
1216
+ * Run `gh api <args>` inside the auth Docker container and return trimmed stdout.
1217
+ *
1218
+ * @pure false
1219
+ * @effect CommandExecutor (Docker)
1220
+ * @invariant exits with CommandFailedError on non-zero exit code
1221
+ * @complexity O(1)
1222
+ */
1223
+ var runGhApiCapture = (cwd, hostPath, token, args) => runDockerAuthCapture(buildDockerAuthSpec({
1224
+ cwd,
1225
+ image: ghImageName,
1226
+ hostPath,
1227
+ containerPath: ghAuthDir,
1228
+ env: `GH_TOKEN=${token}`,
1229
+ args: ["api", ...args],
1230
+ interactive: false
1231
+ }), [0], (exitCode) => new CommandFailedError({
1232
+ command: `gh api ${args.join(" ")}`,
1233
+ exitCode
1234
+ })).pipe(Effect.map((raw) => raw.trim()));
1235
+ /**
1236
+ * Like `runGhApiCapture` but returns `null` instead of failing on API errors
1237
+ * (e.g. HTTP 404 / non-zero exit code).
1238
+ *
1239
+ * @pure false
1240
+ * @effect CommandExecutor (Docker)
1241
+ * @invariant never fails — errors become null
1242
+ * @complexity O(1)
1243
+ */
1244
+ var runGhApiNullable = (cwd, hostPath, token, args) => runGhApiCapture(cwd, hostPath, token, args).pipe(Effect.catchTag("CommandFailedError", () => Effect.succeed("")), Effect.map((raw) => raw.length === 0 ? null : raw));
1245
+ //#endregion
1214
1246
  //#region ../lib/src/usecases/runtime.ts
1215
1247
  var withFsPathContext = (run) => Effect.gen(function* (_) {
1216
1248
  return yield* _(run({
@@ -1228,20 +1260,7 @@ var resolveGithubToken$1 = (envText) => {
1228
1260
  const labeled = entries.find((entry) => entry.key.startsWith("GITHUB_TOKEN__"));
1229
1261
  return labeled && labeled.value.trim().length > 0 ? labeled.value.trim() : null;
1230
1262
  };
1231
- var runGhApiCapture = (cwd, hostPath, token, args) => runDockerAuthCapture(buildDockerAuthSpec({
1232
- cwd,
1233
- image: ghImageName,
1234
- hostPath,
1235
- containerPath: ghAuthDir,
1236
- env: `GH_TOKEN=${token}`,
1237
- args: ["api", ...args],
1238
- interactive: false
1239
- }), [0], (exitCode) => new CommandFailedError({
1240
- command: `gh api ${args.join(" ")}`,
1241
- exitCode
1242
- })).pipe(Effect.map((raw) => raw.trim()));
1243
- var runGhApiCloneUrl = (cwd, hostPath, token, args) => runGhApiCapture(cwd, hostPath, token, args).pipe(Effect.catchTag("CommandFailedError", () => Effect.succeed("")), Effect.map((raw) => raw.length === 0 ? null : raw));
1244
- var resolveViewerLogin = (cwd, hostPath, token) => Effect.gen(function* (_) {
1263
+ var resolveViewerLogin$1 = (cwd, hostPath, token) => Effect.gen(function* (_) {
1245
1264
  const command = "gh api /user --jq .login";
1246
1265
  const raw = yield* _(runGhApiCapture(cwd, hostPath, token, [
1247
1266
  "/user",
@@ -1254,12 +1273,12 @@ var resolveViewerLogin = (cwd, hostPath, token) => Effect.gen(function* (_) {
1254
1273
  })));
1255
1274
  return raw;
1256
1275
  });
1257
- var resolveRepoCloneUrl = (cwd, hostPath, token, fullName) => runGhApiCloneUrl(cwd, hostPath, token, [
1276
+ var resolveRepoCloneUrl = (cwd, hostPath, token, fullName) => runGhApiNullable(cwd, hostPath, token, [
1258
1277
  `/repos/${fullName}`,
1259
1278
  "--jq",
1260
1279
  ".clone_url"
1261
1280
  ]);
1262
- var createFork = (cwd, hostPath, token, owner, repo) => runGhApiCloneUrl(cwd, hostPath, token, [
1281
+ var createFork = (cwd, hostPath, token, owner, repo) => runGhApiNullable(cwd, hostPath, token, [
1263
1282
  "-X",
1264
1283
  "POST",
1265
1284
  `/repos/${owner}/${repo}/forks`,
@@ -1277,7 +1296,7 @@ var resolveGithubForkUrl = (repoUrl, envGlobalPath) => withFsPathContext(({ cwd,
1277
1296
  const ghRoot = resolvePathFromCwd(path, cwd, ghAuthRoot);
1278
1297
  yield* _(fs.makeDirectory(ghRoot, { recursive: true }));
1279
1298
  yield* _(ensureGhAuthImage(fs, path, cwd, "gh api"));
1280
- const viewer = yield* _(resolveViewerLogin(cwd, ghRoot, token));
1299
+ const viewer = yield* _(resolveViewerLogin$1(cwd, ghRoot, token));
1281
1300
  if (viewer.toLowerCase() === repo.owner.toLowerCase()) return null;
1282
1301
  const existingFork = yield* _(resolveRepoCloneUrl(cwd, ghRoot, token, `${viewer}/${repo.repo}`));
1283
1302
  if (existingFork !== null) return existingFork;
@@ -1588,28 +1607,15 @@ var resolveComposeResourceLimits = (template, hostResources) => {
1588
1607
  //#region ../lib/src/usecases/resource-limits.ts
1589
1608
  var resolveTemplateResourceLimits = (template) => Effect.succeed(withDefaultResourceLimitIntent(template));
1590
1609
  //#endregion
1591
- //#region ../lib/src/usecases/state-repo/env.ts
1592
- var isTruthyEnv = (value) => {
1593
- const normalized = value.trim().toLowerCase();
1594
- return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
1595
- };
1596
- var isFalsyEnv = (value) => {
1597
- const normalized = value.trim().toLowerCase();
1598
- return normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off";
1599
- };
1600
- var autoSyncStrictEnvKey = "DOCKER_GIT_STATE_AUTO_SYNC_STRICT";
1601
- var defaultSyncMessage = "chore(state): sync";
1602
- var isAutoSyncEnabled = (envValue, hasRemote) => {
1603
- if (envValue === void 0) return hasRemote;
1604
- if (envValue.trim().length === 0) return hasRemote;
1605
- if (isFalsyEnv(envValue)) return false;
1606
- if (isTruthyEnv(envValue)) return true;
1607
- return true;
1608
- };
1609
- //#endregion
1610
1610
  //#region ../lib/src/usecases/state-repo/git-commands.ts
1611
1611
  var successExitCode = Number(ExitCode(0));
1612
- var gitBaseEnv$1 = { GIT_TERMINAL_PROMPT: "0" };
1612
+ var gitBaseEnv$1 = {
1613
+ GIT_TERMINAL_PROMPT: "0",
1614
+ GIT_AUTHOR_NAME: "docker-git",
1615
+ GIT_AUTHOR_EMAIL: "docker-git@users.noreply.github.com",
1616
+ GIT_COMMITTER_NAME: "docker-git",
1617
+ GIT_COMMITTER_EMAIL: "docker-git@users.noreply.github.com"
1618
+ };
1613
1619
  var git = (cwd, args, env = gitBaseEnv$1) => runCommandWithExitCodes({
1614
1620
  cwd,
1615
1621
  command: "git",
@@ -1641,6 +1647,68 @@ var hasOriginRemote = (root) => Effect.map(gitExitCode(root, [
1641
1647
  "origin"
1642
1648
  ]), (exit) => exit === successExitCode);
1643
1649
  //#endregion
1650
+ //#region ../lib/src/usecases/state-repo/adopt-remote.ts
1651
+ var adoptRemoteHistoryIfOrphan = (root, repoRef, env) => Effect.gen(function* (_) {
1652
+ const fetchExit = yield* _(gitExitCode(root, [
1653
+ "fetch",
1654
+ "origin",
1655
+ repoRef
1656
+ ], env));
1657
+ if (fetchExit !== successExitCode) {
1658
+ yield* _(Effect.logWarning(`git fetch origin ${repoRef} failed (exit ${fetchExit}); starting fresh history`));
1659
+ return;
1660
+ }
1661
+ const remoteRef = `origin/${repoRef}`;
1662
+ if ((yield* _(gitExitCode(root, [
1663
+ "show-ref",
1664
+ "--verify",
1665
+ "--quiet",
1666
+ `refs/remotes/${remoteRef}`
1667
+ ], env))) !== successExitCode) return;
1668
+ if ((yield* _(gitExitCode(root, ["rev-parse", "HEAD"], env))) !== successExitCode) {
1669
+ yield* _(git(root, ["reset", remoteRef], env));
1670
+ yield* _(gitExitCode(root, ["checkout-index", "--all"], env));
1671
+ yield* _(Effect.log(`Adopted remote history from ${remoteRef}`));
1672
+ return;
1673
+ }
1674
+ if ((yield* _(gitExitCode(root, [
1675
+ "merge-base",
1676
+ "HEAD",
1677
+ remoteRef
1678
+ ], env))) === successExitCode) return;
1679
+ yield* _(Effect.logWarning(`Local history has no common ancestor with ${remoteRef}; merging unrelated histories`));
1680
+ if ((yield* _(gitExitCode(root, [
1681
+ "merge",
1682
+ "--allow-unrelated-histories",
1683
+ "--no-edit",
1684
+ remoteRef
1685
+ ], env))) === successExitCode) {
1686
+ yield* _(Effect.log(`Merged unrelated histories from ${remoteRef}`));
1687
+ return;
1688
+ }
1689
+ yield* _(gitExitCode(root, ["merge", "--abort"], env));
1690
+ yield* _(Effect.logWarning(`Merge conflict with ${remoteRef}; sync will open a PR for manual resolution`));
1691
+ });
1692
+ //#endregion
1693
+ //#region ../lib/src/usecases/state-repo/env.ts
1694
+ var isTruthyEnv = (value) => {
1695
+ const normalized = value.trim().toLowerCase();
1696
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
1697
+ };
1698
+ var isFalsyEnv = (value) => {
1699
+ const normalized = value.trim().toLowerCase();
1700
+ return normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off";
1701
+ };
1702
+ var autoSyncStrictEnvKey = "DOCKER_GIT_STATE_AUTO_SYNC_STRICT";
1703
+ var defaultSyncMessage = "chore(state): sync";
1704
+ var isAutoSyncEnabled = (envValue, hasRemote) => {
1705
+ if (envValue === void 0) return hasRemote;
1706
+ if (envValue.trim().length === 0) return hasRemote;
1707
+ if (isFalsyEnv(envValue)) return false;
1708
+ if (isTruthyEnv(envValue)) return true;
1709
+ return true;
1710
+ };
1711
+ //#endregion
1644
1712
  //#region ../lib/src/usecases/state-repo/github-auth.ts
1645
1713
  var githubTokenKey = "GITHUB_TOKEN";
1646
1714
  var githubHttpsRemoteRe = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/;
@@ -4378,7 +4446,7 @@ var commitAllIfNeeded = (root, message, env) => Effect.gen(function* (_) {
4378
4446
  ], env));
4379
4447
  });
4380
4448
  var sanitizeBranchComponent = (value) => value.trim().replaceAll(" ", "-").replaceAll(":", "-").replaceAll("..", "-").replaceAll("@{", "-").replaceAll("\\", "-").replaceAll("^", "-").replaceAll("~", "-");
4381
- var rebaseOntoOriginIfPossible = (root, baseBranch, env) => Effect.gen(function* (_) {
4449
+ var pullRemoteAndRestoreLocal = (root, baseBranch, env) => Effect.gen(function* (_) {
4382
4450
  const fetchExit = yield* _(gitExitCode(root, [
4383
4451
  "fetch",
4384
4452
  "origin",
@@ -4393,10 +4461,26 @@ var rebaseOntoOriginIfPossible = (root, baseBranch, env) => Effect.gen(function*
4393
4461
  "--verify",
4394
4462
  "--quiet",
4395
4463
  `refs/remotes/origin/${baseBranch}`
4396
- ], env))) !== successExitCode) return "skipped";
4397
- if ((yield* _(gitExitCode(root, ["rebase", `origin/${baseBranch}`], env))) === successExitCode) return "ok";
4398
- yield* _(gitExitCode(root, ["rebase", "--abort"], env));
4399
- return "conflict";
4464
+ ], env))) !== successExitCode) return;
4465
+ yield* _(git(root, ["add", "-A"], env));
4466
+ const stashExit = yield* _(gitExitCode(root, ["stash", "--include-untracked"], env));
4467
+ yield* _(git(root, [
4468
+ "reset",
4469
+ "--hard",
4470
+ `origin/${baseBranch}`
4471
+ ], env));
4472
+ if (stashExit === successExitCode) {
4473
+ if ((yield* _(gitExitCode(root, ["stash", "pop"], env))) !== successExitCode) {
4474
+ yield* _(gitExitCode(root, [
4475
+ "checkout",
4476
+ "--theirs",
4477
+ "--",
4478
+ "."
4479
+ ], env));
4480
+ yield* _(git(root, ["add", "-A"], env));
4481
+ yield* _(gitExitCode(root, ["stash", "drop"], env));
4482
+ }
4483
+ }
4400
4484
  });
4401
4485
  var pushToNewBranch = (root, baseBranch, originPushTarget, env) => Effect.gen(function* (_) {
4402
4486
  const headShort = yield* _(gitCapture$1(root, [
@@ -4422,15 +4506,9 @@ var getCurrentBranch = (root, env) => gitCapture$1(root, [
4422
4506
  var runStateSyncOps = (root, originUrl, message, env, options) => Effect.gen(function* (_) {
4423
4507
  const originPushTarget = resolveOriginPushTarget(options?.originPushUrlOverride ?? null);
4424
4508
  yield* _(normalizeLegacyStateProjects(root));
4425
- yield* _(commitAllIfNeeded(root, resolveSyncMessage(message), env));
4426
4509
  const baseBranch = resolveBaseBranch(yield* _(getCurrentBranch(root, env)));
4427
- if ((yield* _(rebaseOntoOriginIfPossible(root, baseBranch, env))) === "conflict") {
4428
- const prBranch = yield* _(pushToNewBranch(root, baseBranch, originPushTarget, env));
4429
- const compareUrl = tryBuildGithubCompareUrl(originUrl, baseBranch, prBranch);
4430
- yield* _(Effect.logWarning(`State sync needs manual merge: pushed changes to branch '${prBranch}'.`));
4431
- yield* _(logOpenPr(originUrl, baseBranch, prBranch, compareUrl));
4432
- return;
4433
- }
4510
+ yield* _(pullRemoteAndRestoreLocal(root, baseBranch, env));
4511
+ yield* _(commitAllIfNeeded(root, resolveSyncMessage(message), env));
4434
4512
  const pushExit = yield* _(gitExitCode(root, [
4435
4513
  "push",
4436
4514
  "--no-verify",
@@ -4517,7 +4595,7 @@ var autoSyncState = (message) => Effect.gen(function* (_) {
4517
4595
  onFailure: (error) => Effect.logWarning(`State auto-sync failed: ${String(error)}`),
4518
4596
  onSuccess: () => Effect.void
4519
4597
  }), Effect.asVoid);
4520
- var cloneStateRepo = (root, input) => Effect.gen(function* (_) {
4598
+ var cloneStateRepo = (root, input, env) => Effect.gen(function* (_) {
4521
4599
  const cloneBranchExit = yield* _(runCommandExitCode({
4522
4600
  cwd: root,
4523
4601
  command: "git",
@@ -4528,7 +4606,7 @@ var cloneStateRepo = (root, input) => Effect.gen(function* (_) {
4528
4606
  input.repoUrl,
4529
4607
  root
4530
4608
  ],
4531
- env: gitBaseEnv$1
4609
+ env
4532
4610
  }));
4533
4611
  if (cloneBranchExit === successExitCode) return;
4534
4612
  yield* _(Effect.logWarning(`git clone --branch ${input.repoRef} failed (exit ${cloneBranchExit}); retrying without --branch`));
@@ -4540,58 +4618,63 @@ var cloneStateRepo = (root, input) => Effect.gen(function* (_) {
4540
4618
  input.repoUrl,
4541
4619
  root
4542
4620
  ],
4543
- env: gitBaseEnv$1
4621
+ env
4544
4622
  }));
4545
4623
  if (cloneDefaultExit !== successExitCode) return yield* _(Effect.fail(new CommandFailedError({
4546
4624
  command: "git clone",
4547
4625
  exitCode: cloneDefaultExit
4548
4626
  })));
4549
4627
  }).pipe(Effect.asVoid);
4550
- var initRepoIfNeeded = (fs, path, root, input) => Effect.gen(function* (_) {
4628
+ var initRepoIfNeeded = (fs, path, root, input, env) => Effect.gen(function* (_) {
4551
4629
  yield* _(fs.makeDirectory(root, { recursive: true }));
4552
4630
  const gitDir = path.join(root, ".git");
4553
4631
  if (yield* _(fs.exists(gitDir))) return;
4554
4632
  if ((yield* _(fs.readDirectory(root))).length === 0) {
4555
- yield* _(cloneStateRepo(root, input));
4633
+ yield* _(cloneStateRepo(root, input, env));
4556
4634
  yield* _(Effect.log(`State dir cloned: ${root}`));
4557
4635
  return;
4558
4636
  }
4559
- yield* _(git(root, ["init"], gitBaseEnv$1));
4637
+ yield* _(git(root, ["init", "--initial-branch=main"], env));
4560
4638
  }).pipe(Effect.asVoid);
4561
- var ensureOriginRemote = (root, repoUrl) => Effect.gen(function* (_) {
4639
+ var ensureOriginRemote = (root, repoUrl, env) => Effect.gen(function* (_) {
4562
4640
  if ((yield* _(gitExitCode(root, [
4563
4641
  "remote",
4564
4642
  "set-url",
4565
4643
  "origin",
4566
4644
  repoUrl
4567
- ], gitBaseEnv$1))) === successExitCode) return;
4645
+ ], env))) === successExitCode) return;
4568
4646
  yield* _(git(root, [
4569
4647
  "remote",
4570
4648
  "add",
4571
4649
  "origin",
4572
4650
  repoUrl
4573
- ], gitBaseEnv$1));
4651
+ ], env));
4574
4652
  });
4575
- var checkoutBranchBestEffort = (root, repoRef) => Effect.gen(function* (_) {
4653
+ var checkoutBranchBestEffort = (root, repoRef, env) => Effect.gen(function* (_) {
4576
4654
  const checkoutExit = yield* _(gitExitCode(root, [
4577
4655
  "checkout",
4578
4656
  "-B",
4579
4657
  repoRef
4580
- ], gitBaseEnv$1));
4658
+ ], env));
4581
4659
  if (checkoutExit === successExitCode) return;
4582
4660
  yield* _(Effect.logWarning(`git checkout -B ${repoRef} failed (exit ${checkoutExit})`));
4583
4661
  });
4584
- var stateInit = (input) => Effect.gen(function* (_) {
4585
- const fs = yield* _(FileSystem.FileSystem);
4586
- const path = yield* _(Path.Path);
4587
- const root = resolveStateRoot(path, process.cwd());
4588
- yield* _(initRepoIfNeeded(fs, path, root, input));
4589
- yield* _(ensureOriginRemote(root, input.repoUrl));
4590
- yield* _(checkoutBranchBestEffort(root, input.repoRef));
4591
- yield* _(ensureStateGitignore(fs, path, root));
4592
- yield* _(Effect.log(`State dir ready: ${root}`));
4593
- yield* _(Effect.log(`Remote: ${input.repoUrl}`));
4594
- }).pipe(Effect.asVoid);
4662
+ var stateInit = (input) => {
4663
+ const doInit = (env) => Effect.gen(function* (_) {
4664
+ const fs = yield* _(FileSystem.FileSystem);
4665
+ const path = yield* _(Path.Path);
4666
+ const root = resolveStateRoot(path, process.cwd());
4667
+ yield* _(initRepoIfNeeded(fs, path, root, input, env));
4668
+ yield* _(ensureOriginRemote(root, input.repoUrl, env));
4669
+ yield* _(adoptRemoteHistoryIfOrphan(root, input.repoRef, env));
4670
+ yield* _(checkoutBranchBestEffort(root, input.repoRef, env));
4671
+ yield* _(ensureStateGitignore(fs, path, root));
4672
+ yield* _(Effect.log(`State dir ready: ${root}`));
4673
+ yield* _(Effect.log(`Remote: ${input.repoUrl}`));
4674
+ }).pipe(Effect.asVoid);
4675
+ const token = input.token?.trim() ?? "";
4676
+ return token.length > 0 && isGithubHttpsRemote(input.repoUrl) ? withGithubAskpassEnv(token, doInit) : doInit(gitBaseEnv$1);
4677
+ };
4595
4678
  var stateStatus = Effect.gen(function* (_) {
4596
4679
  const output = yield* _(gitCapture$1(resolveStateRoot(yield* _(Path.Path), process.cwd()), [
4597
4680
  "status",
@@ -6266,6 +6349,87 @@ var authCodexStatus = (command) => withCodexAuth(command, ({ accountPath, cwd })
6266
6349
  }));
6267
6350
  var authCodexLogout = (command) => withCodexAuth(command, ({ accountPath, cwd }) => runCodexLogout(cwd, accountPath)).pipe(Effect.zipRight(autoSyncState(`chore(state): auth codex logout ${normalizeAccountLabel(command.label, "default")}`)));
6268
6351
  //#endregion
6352
+ //#region ../lib/src/usecases/state-repo-github.ts
6353
+ var dotDockerGitRepoName = ".docker-git";
6354
+ var defaultStateRef = "main";
6355
+ var resolveViewerLogin = (cwd, hostPath, token) => Effect.gen(function* (_) {
6356
+ const raw = yield* _(runGhApiCapture(cwd, hostPath, token, [
6357
+ "/user",
6358
+ "--jq",
6359
+ ".login"
6360
+ ]));
6361
+ if (raw.length === 0) return yield* _(Effect.fail(new CommandFailedError({
6362
+ command: "gh api /user --jq .login",
6363
+ exitCode: 1
6364
+ })));
6365
+ return raw;
6366
+ });
6367
+ var getRepoCloneUrl = (cwd, hostPath, token, login) => runGhApiNullable(cwd, hostPath, token, [
6368
+ `/repos/${login}/${dotDockerGitRepoName}`,
6369
+ "--jq",
6370
+ ".clone_url"
6371
+ ]);
6372
+ var createStateRepo = (cwd, hostPath, token) => runGhApiNullable(cwd, hostPath, token, [
6373
+ "-X",
6374
+ "POST",
6375
+ "/user/repos",
6376
+ "-f",
6377
+ `name=${dotDockerGitRepoName}`,
6378
+ "-f",
6379
+ "private=false",
6380
+ "-f",
6381
+ "auto_init=true",
6382
+ "--jq",
6383
+ ".clone_url"
6384
+ ]);
6385
+ /**
6386
+ * Ensures the .docker-git state repository exists on GitHub and is initialised locally.
6387
+ *
6388
+ * On GitHub auth, immediately:
6389
+ * 1. Resolve the authenticated user's login via the GitHub API
6390
+ * 2. Check whether `<login>/.docker-git` exists on GitHub
6391
+ * 3. If missing, create the repository (public, auto-initialised with a README)
6392
+ * 4. Initialise the local `~/.docker-git` directory as a clone of that repository
6393
+ *
6394
+ * All failures are swallowed and logged as warnings so they never abort the auth
6395
+ * flow itself.
6396
+ *
6397
+ * @param token - A valid GitHub personal-access or OAuth token
6398
+ * @returns Effect<void, never, GithubStateRepoRuntime>
6399
+ *
6400
+ * @pure false
6401
+ * @effect FileSystem, CommandExecutor (Docker gh CLI, git)
6402
+ * @invariant ∀token ∈ ValidTokens: ensureStateDotDockerGitRepo(token) → cloned(~/.docker-git) ∨ warned
6403
+ * @precondition token.length > 0
6404
+ * @postcondition ~/.docker-git is a git repo with origin pointing to github.com/<login>/.docker-git
6405
+ * @complexity O(1) API calls
6406
+ * @throws Never - all errors are caught and logged
6407
+ */
6408
+ var ensureStateDotDockerGitRepo = (token) => withFsPathContext(({ cwd, fs, path }) => Effect.gen(function* (_) {
6409
+ const ghRoot = resolvePathFromCwd(path, cwd, ghAuthRoot);
6410
+ yield* _(fs.makeDirectory(ghRoot, { recursive: true }));
6411
+ yield* _(ensureGhAuthImage(fs, path, cwd, "gh api"));
6412
+ const login = yield* _(resolveViewerLogin(cwd, ghRoot, token));
6413
+ let cloneUrl = yield* _(getRepoCloneUrl(cwd, ghRoot, token, login));
6414
+ if (cloneUrl === null) {
6415
+ yield* _(Effect.log(`Creating .docker-git repository for ${login}...`));
6416
+ cloneUrl = yield* _(createStateRepo(cwd, ghRoot, token));
6417
+ }
6418
+ if (cloneUrl === null) {
6419
+ yield* _(Effect.logWarning(`Could not resolve or create .docker-git repository for ${login}`));
6420
+ return;
6421
+ }
6422
+ yield* _(Effect.log(`Initializing state repository: ${cloneUrl}`));
6423
+ yield* _(stateInit({
6424
+ repoUrl: cloneUrl,
6425
+ repoRef: defaultStateRef,
6426
+ token
6427
+ }));
6428
+ })).pipe(Effect.matchEffect({
6429
+ onFailure: (error) => Effect.logWarning(`State repo setup failed: ${error instanceof Error ? error.message : String(error)}`),
6430
+ onSuccess: () => Effect.void
6431
+ }));
6432
+ //#endregion
6269
6433
  //#region ../lib/src/usecases/auth-github.ts
6270
6434
  var ensureGithubOrchLayout = (cwd, envGlobalPath) => migrateLegacyOrchLayout(cwd, {
6271
6435
  envGlobalPath,
@@ -6363,6 +6527,7 @@ var runGithubInteractiveLogin = (cwd, fs, path, envPath, command) => Effect.gen(
6363
6527
  const resolved = yield* _(resolveGithubTokenFromGh(cwd, accountPath));
6364
6528
  yield* _(ensureEnvFile$1(fs, path, envPath));
6365
6529
  yield* _(persistGithubToken(fs, envPath, buildGithubTokenKey(command.label), resolved));
6530
+ return resolved;
6366
6531
  });
6367
6532
  var authGithubLogin = (command) => withFsPathContext(({ cwd, fs, path }) => Effect.gen(function* (_) {
6368
6533
  yield* _(ensureGithubOrchLayout(cwd, command.envGlobalPath));
@@ -6373,10 +6538,11 @@ var authGithubLogin = (command) => withFsPathContext(({ cwd, fs, path }) => Effe
6373
6538
  if (token.length > 0) {
6374
6539
  yield* _(ensureEnvFile$1(fs, path, envPath));
6375
6540
  yield* _(persistGithubToken(fs, envPath, key, token));
6541
+ yield* _(ensureStateDotDockerGitRepo(token));
6376
6542
  yield* _(autoSyncState(`chore(state): auth gh ${label}`));
6377
6543
  return;
6378
6544
  }
6379
- yield* _(runGithubInteractiveLogin(cwd, fs, path, envPath, command));
6545
+ yield* _(ensureStateDotDockerGitRepo(yield* _(runGithubInteractiveLogin(cwd, fs, path, envPath, command))));
6380
6546
  yield* _(autoSyncState(`chore(state): auth gh ${label}`));
6381
6547
  }));
6382
6548
  var authGithubStatus = (command) => withEnvContext(command.envGlobalPath, ({ current, envPath }) => Effect.gen(function* (_) {