@prover-coder-ai/docker-git 1.0.45 → 1.0.47

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.
@@ -286,7 +286,7 @@ var runCommandWithExitCodes = (spec, okExitCodes, onFailure) => Effect.gen(funct
286
286
  const exitCode = yield* _(Command.exitCode(buildCommand(spec, "inherit", "inherit", "inherit")));
287
287
  yield* _(ensureExitCode(Number(exitCode), okExitCodes, onFailure));
288
288
  });
289
- var runCommandExitCode = (spec) => Effect.map(Command.exitCode(buildCommand(spec, "pipe", "pipe", "inherit")), Number);
289
+ var runCommandExitCode = (spec) => Effect.map(Command.exitCode(buildCommand(spec, "pipe", "pipe", "pipe")), Number);
290
290
  var collectUint8Array$1 = (chunks) => Chunk.reduce(chunks, new Uint8Array(), (acc, curr) => {
291
291
  const next = new Uint8Array(acc.length + curr.length);
292
292
  next.set(acc);
@@ -1394,7 +1394,7 @@ var readProjectConfig = (baseDir) => Effect.gen(function* (_) {
1394
1394
  //#endregion
1395
1395
  //#region ../lib/src/usecases/docker-git-config-search.ts
1396
1396
  var isDockerGitConfig = (entry) => entry.endsWith("docker-git.json");
1397
- var shouldSkipDir = (entry) => entry === ".git" || entry === ".orch" || entry === ".docker-git" || entry === ".cache";
1397
+ var shouldSkipDir = (entry) => entry === ".git" || entry === ".orch" || entry === ".docker-git" || entry === ".cache" || entry === "node_modules";
1398
1398
  var isNotFoundStatError = (error) => error._tag === "SystemError" && error.reason === "NotFound";
1399
1399
  var processDockerGitEntry = (fs, path, dir, entry, state) => Effect.gen(function* (_) {
1400
1400
  if (shouldSkipDir(entry)) return;
@@ -1426,7 +1426,15 @@ var findDockerGitConfigPaths = (fs, path, rootDir) => Effect.gen(function* (_) {
1426
1426
  //#endregion
1427
1427
  //#region ../lib/src/usecases/projects-core.ts
1428
1428
  var sshOptions = "-tt -Y -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
1429
- var buildSshCommand = (config, sshKey) => sshKey === null ? `ssh ${sshOptions} -p ${config.sshPort} ${config.sshUser}@localhost` : `ssh -i ${sshKey} ${sshOptions} -p ${config.sshPort} ${config.sshUser}@localhost`;
1429
+ var buildSshCommand = (config, sshKey, ipAddress) => {
1430
+ const host = ipAddress ?? "localhost";
1431
+ const port = ipAddress ? 22 : config.sshPort;
1432
+ return sshKey === null ? `ssh ${sshOptions} -p ${port} ${config.sshUser}@${host}` : `ssh -i ${sshKey} ${sshOptions} -p ${port} ${config.sshUser}@${host}`;
1433
+ };
1434
+ var getContainerIpIfInsideContainer = (fs, projectDir, containerName) => Effect.gen(function* (_) {
1435
+ if (!(yield* _(fs.exists("/.dockerenv")))) return;
1436
+ return yield* _(runDockerInspectContainerIp(projectDir, containerName).pipe(Effect.orElse(() => Effect.succeed("")), Effect.map((ip) => ip.length > 0 ? ip : void 0)));
1437
+ });
1430
1438
  var loadProjectBase = (configPath) => Effect.gen(function* (_) {
1431
1439
  const { fs, path, resolved } = yield* _(resolveBaseDir(configPath));
1432
1440
  const projectDir = path.dirname(resolved);
@@ -1440,12 +1448,14 @@ var loadProjectBase = (configPath) => Effect.gen(function* (_) {
1440
1448
  var findProjectConfigPaths = (projectsRoot) => withFsPathContext(({ fs, path }) => findDockerGitConfigPaths(fs, path, path.resolve(projectsRoot)));
1441
1449
  var loadProjectSummary = (configPath, sshKey) => Effect.gen(function* (_) {
1442
1450
  const { config, fs, path, projectDir } = yield* _(loadProjectBase(configPath));
1451
+ const ipAddress = yield* _(getContainerIpIfInsideContainer(fs, projectDir, config.template.containerName));
1443
1452
  const resolvedAuthorizedKeys = resolveAuthorizedKeysPath(path, projectDir, config.template.authorizedKeysPath);
1444
1453
  const authExists = yield* _(fs.exists(resolvedAuthorizedKeys));
1445
1454
  return {
1446
1455
  projectDir,
1447
1456
  config,
1448
- sshCommand: buildSshCommand(config.template, sshKey),
1457
+ sshCommand: buildSshCommand(config.template, sshKey, ipAddress),
1458
+ ipAddress,
1449
1459
  authorizedKeysPath: resolvedAuthorizedKeys,
1450
1460
  authorizedKeysExists: authExists
1451
1461
  };
@@ -1466,9 +1476,10 @@ var formatDisplayName = (repoUrl) => {
1466
1476
  var loadProjectItem = (configPath, sshKey) => Effect.gen(function* (_) {
1467
1477
  const { config, fs, path, projectDir } = yield* _(loadProjectBase(configPath));
1468
1478
  const template = config.template;
1479
+ const ipAddress = yield* _(getContainerIpIfInsideContainer(fs, projectDir, template.containerName));
1469
1480
  const resolvedAuthorizedKeys = resolveAuthorizedKeysPath(path, projectDir, template.authorizedKeysPath);
1470
1481
  const authExists = yield* _(fs.exists(resolvedAuthorizedKeys));
1471
- const sshCommand = buildSshCommand(template, sshKey);
1482
+ const sshCommand = buildSshCommand(template, sshKey, ipAddress);
1472
1483
  return {
1473
1484
  projectDir,
1474
1485
  displayName: formatDisplayName(template.repoUrl),
@@ -1480,6 +1491,7 @@ var loadProjectItem = (configPath, sshKey) => Effect.gen(function* (_) {
1480
1491
  sshPort: template.sshPort,
1481
1492
  targetDir: template.targetDir,
1482
1493
  sshCommand,
1494
+ ipAddress,
1483
1495
  sshKeyPath: sshKey,
1484
1496
  authorizedKeysPath: resolvedAuthorizedKeys,
1485
1497
  authorizedKeysExists: authExists,
@@ -1620,6 +1632,7 @@ var resolveTemplateResourceLimits = (template) => Effect.succeed(withDefaultReso
1620
1632
  var successExitCode = Number(ExitCode(0));
1621
1633
  var gitBaseEnv$1 = {
1622
1634
  GIT_TERMINAL_PROMPT: "0",
1635
+ GIT_SSH_COMMAND: "ssh -o BatchMode=yes",
1623
1636
  GIT_AUTHOR_NAME: "docker-git",
1624
1637
  GIT_AUTHOR_EMAIL: "docker-git@users.noreply.github.com",
1625
1638
  GIT_COMMITTER_NAME: "docker-git",
@@ -3063,6 +3076,62 @@ docker_git_refresh_gemini_env() {
3063
3076
 
3064
3077
  docker_git_refresh_gemini_env`;
3065
3078
  var renderGeminiAuthConfig = (config) => geminiAuthConfigTemplate.replaceAll("__GEMINI_AUTH_ROOT__", geminiAuthRootContainerPath(config.sshUser)).replaceAll("__GEMINI_HOME_DIR__", config.geminiHome);
3079
+ var geminiSettingsJsonTemplate = `{
3080
+ "model": {
3081
+ "name": "gemini-3.1-pro-preview-yolo",
3082
+ "compressionThreshold": 0.9,
3083
+ "disableLoopDetection": true
3084
+ },
3085
+ "modelConfigs": {
3086
+ "customAliases": {
3087
+ "yolo-ultra": {
3088
+ "modelConfig": {
3089
+ "model": "gemini-3.1-pro-preview-yolo",
3090
+ "generateContentConfig": {
3091
+ "tools": [
3092
+ {
3093
+ "googleSearch": {}
3094
+ },
3095
+ {
3096
+ "urlContext": {}
3097
+ }
3098
+ ]
3099
+ }
3100
+ }
3101
+ }
3102
+ }
3103
+ },
3104
+ "general": {
3105
+ "defaultApprovalMode": "auto_edit"
3106
+ },
3107
+ "tools": {
3108
+ "allowed": [
3109
+ "run_shell_command",
3110
+ "write_file",
3111
+ "googleSearch",
3112
+ "urlContext"
3113
+ ]
3114
+ },
3115
+ "sandbox": {
3116
+ "enabled": false
3117
+ },
3118
+ "security": {
3119
+ "folderTrust": {
3120
+ "enabled": false
3121
+ },
3122
+ "auth": {
3123
+ "selectedType": "oauth-personal"
3124
+ },
3125
+ "disableYoloMode": false
3126
+ },
3127
+ "mcpServers": {
3128
+ "playwright": {
3129
+ "command": "docker-git-playwright-mcp",
3130
+ "args": [],
3131
+ "trust": true
3132
+ }
3133
+ }
3134
+ }`;
3066
3135
  var renderGeminiPermissionSettingsConfig = (config) => String.raw`# Gemini CLI: keep trust settings in sync with docker-git defaults
3067
3136
  GEMINI_SETTINGS_DIR="${config.geminiHome}"
3068
3137
  GEMINI_TRUST_SETTINGS_FILE="$GEMINI_SETTINGS_DIR/trustedFolders.json"
@@ -3074,14 +3143,7 @@ mkdir -p "$GEMINI_SETTINGS_DIR" || true
3074
3143
  # Disable folder trust prompt and enable auto-approval in settings.json
3075
3144
  if [[ ! -f "$GEMINI_CONFIG_SETTINGS_FILE" ]]; then
3076
3145
  cat <<'EOF' > "$GEMINI_CONFIG_SETTINGS_FILE"
3077
- {
3078
- "security": {
3079
- "folderTrust": {
3080
- "enabled": false
3081
- },
3082
- "approvalPolicy": "never"
3083
- }
3084
- }
3146
+ ${geminiSettingsJsonTemplate}
3085
3147
  EOF
3086
3148
  fi
3087
3149
 
@@ -5520,18 +5582,24 @@ var runDockerComposeUpWithPortCheck = (projectDir) => Effect.gen(function* (_) {
5520
5582
  //#endregion
5521
5583
  //#region ../lib/src/usecases/projects-ssh.ts
5522
5584
  var buildSshArgs$1 = (item) => {
5585
+ const host = item.ipAddress ?? "localhost";
5586
+ const port = item.ipAddress ? 22 : item.sshPort;
5523
5587
  const args = [];
5524
5588
  if (item.sshKeyPath !== null) args.push("-i", item.sshKeyPath);
5525
- args.push("-tt", "-Y", "-o", "LogLevel=ERROR", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", String(item.sshPort), `${item.sshUser}@localhost`);
5589
+ args.push("-tt", "-Y", "-o", "LogLevel=ERROR", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", String(port), `${item.sshUser}@${host}`);
5526
5590
  return args;
5527
5591
  };
5528
5592
  var buildSshProbeArgs = (item) => {
5593
+ const host = item.ipAddress ?? "localhost";
5594
+ const port = item.ipAddress ? 22 : item.sshPort;
5529
5595
  const args = [];
5530
5596
  if (item.sshKeyPath !== null) args.push("-i", item.sshKeyPath);
5531
- args.push("-T", "-o", "BatchMode=yes", "-o", "ConnectTimeout=2", "-o", "ConnectionAttempts=1", "-o", "LogLevel=ERROR", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", String(item.sshPort), `${item.sshUser}@localhost`, "true");
5597
+ args.push("-T", "-o", "BatchMode=yes", "-o", "ConnectTimeout=2", "-o", "ConnectionAttempts=1", "-o", "LogLevel=ERROR", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", String(port), `${item.sshUser}@${host}`, "true");
5532
5598
  return args;
5533
5599
  };
5534
5600
  var waitForSshReady = (item) => {
5601
+ const host = item.ipAddress ?? "localhost";
5602
+ const port = item.ipAddress ? 22 : item.sshPort;
5535
5603
  const probe = Effect.gen(function* (_) {
5536
5604
  const exitCode = yield* _(runCommandExitCode({
5537
5605
  cwd: process.cwd(),
@@ -5543,7 +5611,7 @@ var waitForSshReady = (item) => {
5543
5611
  exitCode
5544
5612
  })));
5545
5613
  });
5546
- return pipe(Effect.log(`Waiting for SSH on localhost:${item.sshPort} ...`), Effect.zipRight(Effect.retry(probe, pipe(Schedule.spaced(Duration.seconds(2)), Schedule.intersect(Schedule.recurs(30))))), Effect.tap(() => Effect.log("SSH is ready.")));
5614
+ return pipe(Effect.log(`Waiting for SSH on ${host}:${port} ...`), Effect.zipRight(Effect.retry(probe, pipe(Schedule.spaced(Duration.seconds(2)), Schedule.intersect(Schedule.recurs(30))))), Effect.tap(() => Effect.log("SSH is ready.")));
5547
5615
  };
5548
5616
  var connectProjectSsh = (item) => pipe(ensureTerminalCursorVisible(), Effect.zipRight(runCommandWithExitCodes({
5549
5617
  cwd: process.cwd(),
@@ -5553,14 +5621,34 @@ var connectProjectSsh = (item) => pipe(ensureTerminalCursorVisible(), Effect.zip
5553
5621
  command: "ssh",
5554
5622
  exitCode
5555
5623
  }))), Effect.ensuring(ensureTerminalCursorVisible()));
5556
- var connectProjectSshWithUp = (item) => pipe(Effect.log(`Starting docker compose for ${item.displayName} ...`), Effect.zipRight(runDockerComposeUpWithPortCheck(item.projectDir)), Effect.map((template) => ({
5557
- ...item,
5558
- sshPort: template.sshPort
5559
- })), Effect.tap((updated) => waitForSshReady(updated)), Effect.flatMap((updated) => connectProjectSsh(updated)));
5560
- var listProjectStatus = Effect.asVoid(withProjectIndexAndSsh((index, sshKey) => forEachProjectStatus(index.configPaths, (status) => pipe(Effect.log(renderProjectStatusHeader(status)), Effect.zipRight(Effect.log(`SSH access: ${buildSshCommand(status.config.template, sshKey)}`)), Effect.zipRight(runDockerComposePsFormatted(status.projectDir).pipe(Effect.map((raw) => parseComposePsOutput(raw)), Effect.map((rows) => formatComposeRows(rows)), Effect.flatMap((text) => Effect.log(text)), Effect.matchEffect({
5624
+ var connectProjectSshWithUp = (item) => Effect.gen(function* (_) {
5625
+ const fs = yield* _(FileSystem.FileSystem);
5626
+ yield* _(Effect.log(`Starting docker compose for ${item.displayName} ...`));
5627
+ const template = yield* _(runDockerComposeUpWithPortCheck(item.projectDir));
5628
+ const isInsideContainer = yield* _(fs.exists("/.dockerenv"));
5629
+ let ipAddress;
5630
+ if (isInsideContainer) {
5631
+ const containerIp = yield* _(runDockerInspectContainerIp(item.projectDir, template.containerName).pipe(Effect.orElse(() => Effect.succeed(""))));
5632
+ if (containerIp.length > 0) ipAddress = containerIp;
5633
+ }
5634
+ const updated = {
5635
+ ...item,
5636
+ sshPort: template.sshPort,
5637
+ ipAddress
5638
+ };
5639
+ yield* _(waitForSshReady(updated));
5640
+ yield* _(connectProjectSsh(updated));
5641
+ });
5642
+ var listProjectStatus = withProjectIndexAndSsh((index, sshKey) => forEachProjectStatus(index.configPaths, (status) => Effect.gen(function* (_) {
5643
+ const ipAddress = yield* _(getContainerIpIfInsideContainer(yield* _(FileSystem.FileSystem), status.projectDir, status.config.template.containerName));
5644
+ yield* _(Effect.log(renderProjectStatusHeader(status)));
5645
+ yield* _(Effect.log(`SSH access: ${buildSshCommand(status.config.template, sshKey, ipAddress)}`));
5646
+ const text = formatComposeRows(parseComposePsOutput(yield* _(runDockerComposePsFormatted(status.projectDir))));
5647
+ yield* _(Effect.log(text));
5648
+ }).pipe(Effect.matchEffect({
5561
5649
  onFailure: (error) => Effect.logWarning(`docker compose ps failed for ${status.projectDir}: ${renderError(error)}`),
5562
5650
  onSuccess: () => Effect.void
5563
- })))))));
5651
+ })))).pipe(Effect.asVoid);
5564
5652
  //#endregion
5565
5653
  //#region ../lib/src/usecases/actions/docker-up.ts
5566
5654
  var clonePollInterval = Duration.seconds(1);
@@ -5572,9 +5660,15 @@ var agentFailPath = "/run/docker-git/agent.failed";
5572
5660
  var logSshAccess = (baseDir, config) => Effect.gen(function* (_) {
5573
5661
  const fs = yield* _(FileSystem.FileSystem);
5574
5662
  const path = yield* _(Path.Path);
5663
+ const isInsideContainer = yield* _(fs.exists("/.dockerenv"));
5664
+ let ipAddress;
5665
+ if (isInsideContainer) {
5666
+ const containerIp = yield* _(runDockerInspectContainerIp(baseDir, config.containerName).pipe(Effect.orElse(() => Effect.succeed(""))));
5667
+ if (containerIp.length > 0) ipAddress = containerIp;
5668
+ }
5575
5669
  const resolvedAuthorizedKeys = resolveAuthorizedKeysPath(path, baseDir, config.authorizedKeysPath);
5576
5670
  const authExists = yield* _(fs.exists(resolvedAuthorizedKeys));
5577
- const sshCommand = buildSshCommand(config, yield* _(findSshPrivateKey(fs, path, process.cwd())));
5671
+ const sshCommand = buildSshCommand(config, yield* _(findSshPrivateKey(fs, path, process.cwd())), ipAddress);
5578
5672
  yield* _(Effect.log(`SSH access: ${sshCommand}`));
5579
5673
  if (!authExists) yield* _(Effect.logWarning(`Authorized keys file missing: ${resolvedAuthorizedKeys} (SSH may fail without a matching key).`));
5580
5674
  });
@@ -5817,23 +5911,28 @@ var formatStateSyncLabel = (repoUrl) => {
5817
5911
  return repoPath.length > 0 ? repoPath : repoUrl;
5818
5912
  };
5819
5913
  var isInteractiveTty = () => process.stdin.isTTY && process.stdout.isTTY;
5820
- var buildSshArgs = (config, sshKeyPath, remoteCommand) => {
5914
+ var buildSshArgs = (config, sshKeyPath, remoteCommand, ipAddress) => {
5915
+ const host = ipAddress ?? "localhost";
5916
+ const port = ipAddress ? 22 : config.sshPort;
5821
5917
  const args = [];
5822
5918
  if (sshKeyPath !== null) args.push("-i", sshKeyPath);
5823
- args.push("-tt", "-Y", "-o", "LogLevel=ERROR", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", String(config.sshPort), `${config.sshUser}@localhost`);
5919
+ args.push("-tt", "-Y", "-o", "LogLevel=ERROR", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", String(port), `${config.sshUser}@${host}`);
5824
5920
  if (remoteCommand !== void 0) args.push(remoteCommand);
5825
5921
  return args;
5826
5922
  };
5827
5923
  var openSshBestEffort = (template, remoteCommand) => Effect.gen(function* (_) {
5828
- const sshKey = yield* _(findSshPrivateKey(yield* _(FileSystem.FileSystem), yield* _(Path.Path), process.cwd()));
5829
- const sshCommand = buildSshCommand(template, sshKey);
5924
+ const fs = yield* _(FileSystem.FileSystem);
5925
+ const path = yield* _(Path.Path);
5926
+ const ipAddress = yield* _(getContainerIpIfInsideContainer(fs, process.cwd(), template.containerName).pipe(Effect.orElse(() => Effect.succeed(""))));
5927
+ const sshKey = yield* _(findSshPrivateKey(fs, path, process.cwd()));
5928
+ const sshCommand = buildSshCommand(template, sshKey, ipAddress);
5830
5929
  const remoteCommandLabel = remoteCommand === void 0 ? "" : ` (${remoteCommand})`;
5831
5930
  yield* _(Effect.log(`Opening SSH: ${sshCommand}${remoteCommandLabel}`));
5832
5931
  yield* _(ensureTerminalCursorVisible());
5833
5932
  yield* _(runCommandWithExitCodes({
5834
5933
  cwd: process.cwd(),
5835
5934
  command: "ssh",
5836
- args: buildSshArgs(template, sshKey, remoteCommand)
5935
+ args: buildSshArgs(template, sshKey, remoteCommand, ipAddress)
5837
5936
  }, [0, 130], (exitCode) => new CommandFailedError({
5838
5937
  command: "ssh",
5839
5938
  exitCode
@@ -6565,6 +6664,165 @@ var authCodexStatus = (command) => withCodexAuth(command, ({ accountPath, cwd })
6565
6664
  }));
6566
6665
  var authCodexLogout = (command) => withCodexAuth(command, ({ accountPath, cwd }) => runCodexLogout(cwd, accountPath)).pipe(Effect.zipRight(autoSyncState(`chore(state): auth codex logout ${normalizeAccountLabel(command.label, "default")}`)));
6567
6666
  //#endregion
6667
+ //#region ../lib/src/usecases/auth-gemini-helpers.ts
6668
+ var geminiImageName = "docker-git-auth-gemini:latest";
6669
+ var geminiImageDir = ".docker-git/.orch/auth/gemini/.image";
6670
+ var geminiContainerHomeDir = "/gemini-home";
6671
+ var geminiCredentialsDir$1 = ".gemini";
6672
+ var geminiAuthRoot = ".docker-git/.orch/auth/gemini";
6673
+ var geminiApiKeyFileName = ".api-key";
6674
+ var geminiEnvFileName = ".env";
6675
+ var geminiApiKeyPath = (accountPath) => `${accountPath}/${geminiApiKeyFileName}`;
6676
+ var geminiEnvFilePath = (accountPath) => `${accountPath}/${geminiEnvFileName}`;
6677
+ var geminiCredentialsPath = (accountPath) => `${accountPath}/${geminiCredentialsDir$1}`;
6678
+ var renderGeminiDockerfile = () => String.raw`FROM ubuntu:24.04
6679
+ ENV DEBIAN_FRONTEND=noninteractive
6680
+ RUN apt-get update \
6681
+ && apt-get install -y --no-install-recommends ca-certificates curl bsdutils \
6682
+ && rm -rf /var/lib/apt/lists/*
6683
+ RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
6684
+ && apt-get install -y --no-install-recommends nodejs \
6685
+ && rm -rf /var/lib/apt/lists/*
6686
+ RUN npm install -g @google/gemini-cli@0.33.2
6687
+ `;
6688
+ var ensureGeminiOrchLayout = (cwd) => migrateLegacyOrchLayout(cwd, {
6689
+ envGlobalPath: defaultTemplateConfig.envGlobalPath,
6690
+ envProjectPath: defaultTemplateConfig.envProjectPath,
6691
+ codexAuthPath: defaultTemplateConfig.codexAuthPath,
6692
+ ghAuthPath: ".docker-git/.orch/auth/gh",
6693
+ claudeAuthPath: ".docker-git/.orch/auth/claude",
6694
+ geminiAuthPath: ".docker-git/.orch/auth/gemini"
6695
+ });
6696
+ var resolveGeminiAccountPath = (path, rootPath, label) => {
6697
+ const accountLabel = normalizeAccountLabel(label, "default");
6698
+ return {
6699
+ accountLabel,
6700
+ accountPath: path.join(rootPath, accountLabel)
6701
+ };
6702
+ };
6703
+ var withGeminiAuth = (command, run, options = {}) => withFsPathContext(({ cwd, fs, path }) => Effect.gen(function* (_) {
6704
+ yield* _(ensureGeminiOrchLayout(cwd));
6705
+ const { accountLabel, accountPath } = resolveGeminiAccountPath(path, resolvePathFromCwd(path, cwd, command.geminiAuthPath), command.label);
6706
+ yield* _(fs.makeDirectory(accountPath, { recursive: true }));
6707
+ if (options.buildImage === true) yield* _(ensureDockerImage(fs, path, cwd, {
6708
+ imageName: geminiImageName,
6709
+ imageDir: geminiImageDir,
6710
+ dockerfile: renderGeminiDockerfile(),
6711
+ buildLabel: "gemini auth"
6712
+ }));
6713
+ return yield* _(run({
6714
+ accountLabel,
6715
+ accountPath,
6716
+ cwd,
6717
+ fs
6718
+ }));
6719
+ }));
6720
+ var readApiKey = (fs, accountPath) => Effect.gen(function* (_) {
6721
+ const apiKeyFilePath = geminiApiKeyPath(accountPath);
6722
+ if (yield* _(isRegularFile$1(fs, apiKeyFilePath))) {
6723
+ const trimmed = (yield* _(fs.readFileString(apiKeyFilePath), Effect.orElseSucceed(() => ""))).trim();
6724
+ if (trimmed.length > 0) return trimmed;
6725
+ }
6726
+ const envFilePath = geminiEnvFilePath(accountPath);
6727
+ if (yield* _(isRegularFile$1(fs, envFilePath))) {
6728
+ const lines = (yield* _(fs.readFileString(envFilePath), Effect.orElseSucceed(() => ""))).split("\n");
6729
+ for (const line of lines) {
6730
+ const trimmed = line.trim();
6731
+ if (trimmed.startsWith("GEMINI_API_KEY=")) {
6732
+ const value = trimmed.slice(15).replaceAll(/^['"]|['"]$/g, "").trim();
6733
+ if (value.length > 0) return value;
6734
+ }
6735
+ }
6736
+ }
6737
+ return null;
6738
+ });
6739
+ var hasOauthCredentials$1 = (fs, accountPath) => Effect.gen(function* (_) {
6740
+ const credentialsDir = geminiCredentialsPath(accountPath);
6741
+ if (!(yield* _(fs.exists(credentialsDir)))) return false;
6742
+ const possibleFiles = [
6743
+ `${credentialsDir}/oauth-tokens.json`,
6744
+ `${credentialsDir}/credentials.json`,
6745
+ `${credentialsDir}/application_default_credentials.json`
6746
+ ];
6747
+ for (const filePath of possibleFiles) if (yield* _(isRegularFile$1(fs, filePath))) return true;
6748
+ return false;
6749
+ });
6750
+ var resolveGeminiAuthMethod = (fs, accountPath) => Effect.gen(function* (_) {
6751
+ if ((yield* _(readApiKey(fs, accountPath))) !== null) return "api-key";
6752
+ return (yield* _(hasOauthCredentials$1(fs, accountPath))) ? "oauth" : "none";
6753
+ });
6754
+ var prepareGeminiCredentialsDir = (cwd, accountPath, fs) => Effect.gen(function* (_) {
6755
+ const credentialsDir = geminiCredentialsPath(accountPath);
6756
+ const removeFallback = pipe(runCommandExitCode({
6757
+ cwd,
6758
+ command: "docker",
6759
+ args: [
6760
+ "run",
6761
+ "--rm",
6762
+ "-v",
6763
+ `${accountPath}:/target`,
6764
+ "alpine",
6765
+ "rm",
6766
+ "-rf",
6767
+ "/target/.gemini"
6768
+ ]
6769
+ }), Effect.asVoid, Effect.orElse(() => Effect.void));
6770
+ yield* _(fs.remove(credentialsDir, {
6771
+ recursive: true,
6772
+ force: true
6773
+ }).pipe(Effect.orElse(() => removeFallback)));
6774
+ yield* _(fs.makeDirectory(credentialsDir, { recursive: true }));
6775
+ yield* _(runCommandExitCode({
6776
+ cwd,
6777
+ command: "chmod",
6778
+ args: [
6779
+ "-R",
6780
+ "777",
6781
+ credentialsDir
6782
+ ]
6783
+ }).pipe(Effect.orElse(() => Effect.succeed(0))));
6784
+ return credentialsDir;
6785
+ });
6786
+ var defaultGeminiSettings = {
6787
+ model: {
6788
+ name: "gemini-3.1-pro-preview-yolo",
6789
+ compressionThreshold: .9,
6790
+ disableLoopDetection: true
6791
+ },
6792
+ modelConfigs: { customAliases: { "yolo-ultra": { "modelConfig": {
6793
+ "model": "gemini-3.1-pro-preview-yolo",
6794
+ "generateContentConfig": { "tools": [{ "googleSearch": {} }, { "urlContext": {} }] }
6795
+ } } } },
6796
+ general: { defaultApprovalMode: "auto_edit" },
6797
+ tools: { allowed: [
6798
+ "run_shell_command",
6799
+ "write_file",
6800
+ "googleSearch",
6801
+ "urlContext"
6802
+ ] },
6803
+ sandbox: { enabled: false },
6804
+ security: {
6805
+ folderTrust: { enabled: false },
6806
+ auth: { selectedType: "oauth-personal" },
6807
+ disableYoloMode: false
6808
+ },
6809
+ mcpServers: { playwright: {
6810
+ command: "docker-git-playwright-mcp",
6811
+ args: [],
6812
+ trust: true
6813
+ } }
6814
+ };
6815
+ var writeInitialSettings = (credentialsDir, fs) => Effect.gen(function* (_) {
6816
+ const settingsPath = `${credentialsDir}/settings.json`;
6817
+ yield* _(fs.writeFileString(settingsPath, JSON.stringify(defaultGeminiSettings, null, 2) + "\n"));
6818
+ const trustedFoldersPath = `${credentialsDir}/trustedFolders.json`;
6819
+ yield* _(fs.writeFileString(trustedFoldersPath, JSON.stringify({
6820
+ "/": "TRUST_FOLDER",
6821
+ [geminiContainerHomeDir]: "TRUST_FOLDER"
6822
+ })));
6823
+ return settingsPath;
6824
+ });
6825
+ //#endregion
6568
6826
  //#region ../lib/src/usecases/auth-gemini-oauth.ts
6569
6827
  var outputWindowSize = 262144;
6570
6828
  var authSuccessPatterns = [
@@ -6572,8 +6830,7 @@ var authSuccessPatterns = [
6572
6830
  "Authentication successful",
6573
6831
  "Successfully authenticated",
6574
6832
  "Logged in as",
6575
- "You are now logged in",
6576
- "Logged in with Google"
6833
+ "You are now logged in"
6577
6834
  ];
6578
6835
  var authFailurePatterns = [
6579
6836
  "Authentication failed",
@@ -6605,6 +6862,7 @@ var buildDockerGeminiAuthSpec = (cwd, accountPath, image, containerPath, port) =
6605
6862
  "NO_BROWSER=true",
6606
6863
  "GEMINI_CLI_NONINTERACTIVE=true",
6607
6864
  "GEMINI_CLI_TRUST_ALL=true",
6865
+ "GEMINI_DISABLE_UPDATE_CHECK=true",
6608
6866
  `OAUTH_CALLBACK_PORT=${port}`,
6609
6867
  "OAUTH_CALLBACK_HOST=0.0.0.0"
6610
6868
  ]
@@ -6613,12 +6871,15 @@ var buildDockerGeminiAuthArgs = (spec) => {
6613
6871
  const base = [
6614
6872
  "run",
6615
6873
  "--rm",
6874
+ "--init",
6616
6875
  "-i",
6617
6876
  "-t",
6618
6877
  "-v",
6619
6878
  `${spec.hostPath}:${spec.containerPath}`,
6620
6879
  "-p",
6621
- `${spec.callbackPort}:${spec.callbackPort}`
6880
+ `${spec.callbackPort}:${spec.callbackPort}`,
6881
+ "-w",
6882
+ spec.containerPath
6622
6883
  ];
6623
6884
  for (const entry of spec.env) {
6624
6885
  const trimmed = entry.trim();
@@ -6629,7 +6890,8 @@ var buildDockerGeminiAuthArgs = (spec) => {
6629
6890
  ...base,
6630
6891
  spec.image,
6631
6892
  "gemini",
6632
- "login",
6893
+ "mcp",
6894
+ "list",
6633
6895
  "--debug"
6634
6896
  ];
6635
6897
  };
@@ -6726,109 +6988,48 @@ var runGeminiOauthLoginWithPrompt = (cwd, accountPath, options) => Effect.scoped
6726
6988
  const resultBox = { value: "pending" };
6727
6989
  const stdoutFiber = yield* _(Effect.forkScoped(pumpDockerOutput(proc.stdout, 1, resultBox, authDeferred)));
6728
6990
  const stderrFiber = yield* _(Effect.forkScoped(pumpDockerOutput(proc.stderr, 2, resultBox, authDeferred)));
6729
- const exitCode = yield* _(Effect.race(proc.exitCode.pipe(Effect.map(Number)), pipe(Deferred.await(authDeferred), Effect.flatMap(() => proc.kill()), Effect.map(() => 0))));
6730
- yield* _(Fiber$1.join(stdoutFiber));
6731
- yield* _(Fiber$1.join(stderrFiber));
6991
+ const exitCode = yield* _(Effect.race(proc.exitCode.pipe(Effect.map(Number)), pipe(Deferred.await(authDeferred), Effect.delay("500 millis"), Effect.flatMap(() => proc.kill()), Effect.map(() => 0))));
6992
+ yield* _(Fiber$1.interrupt(stdoutFiber));
6993
+ yield* _(Fiber$1.interrupt(stderrFiber));
6732
6994
  yield* _(fixGeminiAuthPermissions(hostPath, spec.containerPath));
6733
6995
  return yield* _(resolveGeminiLoginResult(resultBox.value, exitCode));
6734
6996
  }));
6735
6997
  //#endregion
6736
- //#region ../lib/src/usecases/auth-gemini.ts
6737
- var geminiImageName = "docker-git-auth-gemini:latest";
6738
- var geminiImageDir = ".docker-git/.orch/auth/gemini/.image";
6739
- var geminiContainerHomeDir = "/gemini-home";
6740
- var geminiCredentialsDir$1 = ".gemini";
6741
- var geminiAuthRoot = ".docker-git/.orch/auth/gemini";
6742
- var geminiApiKeyFileName = ".api-key";
6743
- var geminiEnvFileName = ".env";
6744
- var geminiApiKeyPath = (accountPath) => `${accountPath}/${geminiApiKeyFileName}`;
6745
- var geminiEnvFilePath = (accountPath) => `${accountPath}/${geminiEnvFileName}`;
6746
- var geminiCredentialsPath = (accountPath) => `${accountPath}/${geminiCredentialsDir$1}`;
6747
- var renderGeminiDockerfile = () => String.raw`FROM ubuntu:24.04
6748
- ENV DEBIAN_FRONTEND=noninteractive
6749
- RUN apt-get update \
6750
- && apt-get install -y --no-install-recommends ca-certificates curl bsdutils \
6751
- && rm -rf /var/lib/apt/lists/*
6752
- RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
6753
- && apt-get install -y --no-install-recommends nodejs \
6754
- && node -v \
6755
- && npm -v \
6756
- && rm -rf /var/lib/apt/lists/*
6757
- RUN npm install -g @google/gemini-cli@latest
6758
- ENTRYPOINT ["/bin/bash", "-c"]
6759
- `;
6760
- var ensureGeminiOrchLayout = (cwd) => migrateLegacyOrchLayout(cwd, {
6761
- envGlobalPath: defaultTemplateConfig.envGlobalPath,
6762
- envProjectPath: defaultTemplateConfig.envProjectPath,
6763
- codexAuthPath: defaultTemplateConfig.codexAuthPath,
6764
- ghAuthPath: ".docker-git/.orch/auth/gh",
6765
- claudeAuthPath: ".docker-git/.orch/auth/claude",
6766
- geminiAuthPath: ".docker-git/.orch/auth/gemini"
6767
- });
6768
- var resolveGeminiAccountPath = (path, rootPath, label) => {
6769
- const accountLabel = normalizeAccountLabel(label, "default");
6770
- return {
6771
- accountLabel,
6772
- accountPath: path.join(rootPath, accountLabel)
6773
- };
6774
- };
6775
- var withGeminiAuth = (command, run, options = {}) => withFsPathContext(({ cwd, fs, path }) => Effect.gen(function* (_) {
6776
- yield* _(ensureGeminiOrchLayout(cwd));
6777
- const { accountLabel, accountPath } = resolveGeminiAccountPath(path, resolvePathFromCwd(path, cwd, command.geminiAuthPath), command.label);
6778
- yield* _(fs.makeDirectory(accountPath, { recursive: true }));
6779
- if (options.buildImage === true) yield* _(ensureDockerImage(fs, path, cwd, {
6780
- imageName: geminiImageName,
6781
- imageDir: geminiImageDir,
6782
- dockerfile: renderGeminiDockerfile(),
6783
- buildLabel: "gemini auth"
6784
- }));
6785
- return yield* _(run({
6786
- accountLabel,
6787
- accountPath,
6788
- cwd,
6789
- fs
6790
- }));
6791
- }));
6792
- var readApiKey = (fs, accountPath) => Effect.gen(function* (_) {
6793
- const apiKeyFilePath = geminiApiKeyPath(accountPath);
6794
- if (yield* _(isRegularFile$1(fs, apiKeyFilePath))) {
6795
- const trimmed = (yield* _(fs.readFileString(apiKeyFilePath), Effect.orElseSucceed(() => ""))).trim();
6796
- if (trimmed.length > 0) return trimmed;
6797
- }
6798
- const envFilePath = geminiEnvFilePath(accountPath);
6799
- if (yield* _(isRegularFile$1(fs, envFilePath))) {
6800
- const lines = (yield* _(fs.readFileString(envFilePath), Effect.orElseSucceed(() => ""))).split("\n");
6801
- for (const line of lines) {
6802
- const trimmed = line.trim();
6803
- if (trimmed.startsWith("GEMINI_API_KEY=")) {
6804
- const value = trimmed.slice(15).replaceAll(/^['"]|['"]$/g, "").trim();
6805
- if (value.length > 0) return value;
6806
- }
6807
- }
6998
+ //#region ../lib/src/usecases/auth-gemini-logout.ts
6999
+ var authGeminiLogout = (command) => Effect.gen(function* (_) {
7000
+ const accountLabel = normalizeAccountLabel(command.label, "default");
7001
+ yield* _(withGeminiAuth(command, ({ accountPath, fs }) => Effect.gen(function* (_) {
7002
+ yield* _(fs.remove(geminiApiKeyPath(accountPath), { force: true }));
7003
+ yield* _(fs.remove(geminiEnvFilePath(accountPath), { force: true }));
7004
+ yield* _(fs.remove(geminiCredentialsPath(accountPath), {
7005
+ recursive: true,
7006
+ force: true
7007
+ }));
7008
+ })));
7009
+ yield* _(autoSyncState(`chore(state): auth gemini logout ${accountLabel}`));
7010
+ }).pipe(Effect.asVoid);
7011
+ //#endregion
7012
+ //#region ../lib/src/usecases/auth-gemini-status.ts
7013
+ var authGeminiStatus = (command) => withGeminiAuth(command, ({ accountLabel, accountPath, fs }) => Effect.gen(function* (_) {
7014
+ const authMethod = yield* _(resolveGeminiAuthMethod(fs, accountPath));
7015
+ if (authMethod === "none") {
7016
+ yield* _(Effect.log(`Gemini not connected (${accountLabel}).`));
7017
+ return;
6808
7018
  }
6809
- return null;
6810
- });
6811
- var hasOauthCredentials$1 = (fs, accountPath) => Effect.gen(function* (_) {
6812
- const credentialsDir = geminiCredentialsPath(accountPath);
6813
- if (!(yield* _(fs.exists(credentialsDir)))) return false;
6814
- const possibleFiles = [
6815
- `${credentialsDir}/oauth-tokens.json`,
6816
- `${credentialsDir}/credentials.json`,
6817
- `${credentialsDir}/application_default_credentials.json`
6818
- ];
6819
- for (const filePath of possibleFiles) if (yield* _(isRegularFile$1(fs, filePath))) return true;
6820
- return false;
6821
- });
6822
- var resolveGeminiAuthMethod = (fs, accountPath) => Effect.gen(function* (_) {
6823
- if ((yield* _(readApiKey(fs, accountPath))) !== null) return "api-key";
6824
- return (yield* _(hasOauthCredentials$1(fs, accountPath))) ? "oauth" : "none";
6825
- });
7019
+ yield* _(Effect.log(`Gemini connected (${accountLabel}, ${authMethod}).`));
7020
+ }));
7021
+ //#endregion
7022
+ //#region ../lib/src/usecases/auth-gemini.ts
6826
7023
  var authGeminiLogin = (command, apiKey) => {
6827
7024
  const accountLabel = normalizeAccountLabel(command.label, "default");
6828
7025
  return withGeminiAuth(command, ({ accountPath, fs }) => Effect.gen(function* (_) {
6829
7026
  const apiKeyFilePath = geminiApiKeyPath(accountPath);
6830
7027
  yield* _(fs.writeFileString(apiKeyFilePath, `${apiKey.trim()}\n`));
6831
7028
  yield* _(fs.chmod(apiKeyFilePath, 384), Effect.orElseSucceed(() => void 0));
7029
+ const credentialsDir = geminiCredentialsPath(accountPath);
7030
+ yield* _(fs.makeDirectory(credentialsDir, { recursive: true }));
7031
+ const settingsPath = `${credentialsDir}/settings.json`;
7032
+ yield* _(fs.writeFileString(settingsPath, JSON.stringify(defaultGeminiSettings, null, 2) + "\n"));
6832
7033
  })).pipe(Effect.zipRight(autoSyncState(`chore(state): auth gemini ${accountLabel}`)));
6833
7034
  };
6834
7035
  var authGeminiLoginCli = (_command) => Effect.gen(function* (_) {
@@ -6843,39 +7044,6 @@ var authGeminiLoginCli = (_command) => Effect.gen(function* (_) {
6843
7044
  yield* _(Effect.log(" - Use: docker-git menu -> Auth profiles -> Gemini CLI: login via OAuth"));
6844
7045
  yield* _(Effect.log(" - Follow the prompts to authenticate with your Google account"));
6845
7046
  });
6846
- var prepareGeminiCredentialsDir = (cwd, accountPath, fs) => Effect.gen(function* (_) {
6847
- const credentialsDir = geminiCredentialsPath(accountPath);
6848
- const removeFallback = pipe(runCommandExitCode({
6849
- cwd,
6850
- command: "docker",
6851
- args: [
6852
- "run",
6853
- "--rm",
6854
- "-v",
6855
- `${accountPath}:/target`,
6856
- "alpine",
6857
- "rm",
6858
- "-rf",
6859
- "/target/.gemini"
6860
- ]
6861
- }), Effect.asVoid, Effect.orElse(() => Effect.void));
6862
- yield* _(fs.remove(credentialsDir, {
6863
- recursive: true,
6864
- force: true
6865
- }).pipe(Effect.orElse(() => removeFallback)));
6866
- yield* _(fs.makeDirectory(credentialsDir, { recursive: true }));
6867
- return credentialsDir;
6868
- });
6869
- var writeInitialSettings = (credentialsDir, fs) => Effect.gen(function* (_) {
6870
- const settingsPath = `${credentialsDir}/settings.json`;
6871
- yield* _(fs.writeFileString(settingsPath, JSON.stringify({ security: { folderTrust: { enabled: false } } })));
6872
- const trustedFoldersPath = `${credentialsDir}/trustedFolders.json`;
6873
- yield* _(fs.writeFileString(trustedFoldersPath, JSON.stringify({
6874
- "/": "TRUST_FOLDER",
6875
- [geminiContainerHomeDir]: "TRUST_FOLDER"
6876
- })));
6877
- return settingsPath;
6878
- });
6879
7047
  var authGeminiLoginOauth = (command) => {
6880
7048
  const accountLabel = normalizeAccountLabel(command.label, "default");
6881
7049
  return withGeminiAuth(command, ({ accountPath, cwd, fs }) => Effect.gen(function* (_) {
@@ -6884,33 +7052,9 @@ var authGeminiLoginOauth = (command) => {
6884
7052
  image: geminiImageName,
6885
7053
  containerPath: geminiContainerHomeDir
6886
7054
  }));
6887
- yield* _(fs.writeFileString(settingsPath, JSON.stringify({ security: {
6888
- folderTrust: { enabled: false },
6889
- auth: { selectedType: "oauth-personal" },
6890
- approvalPolicy: "never"
6891
- } }, null, 2) + "\n"));
7055
+ yield* _(fs.writeFileString(settingsPath, JSON.stringify(defaultGeminiSettings, null, 2) + "\n"));
6892
7056
  }), { buildImage: true }).pipe(Effect.zipRight(autoSyncState(`chore(state): auth gemini oauth ${accountLabel}`)));
6893
7057
  };
6894
- var authGeminiStatus = (command) => withGeminiAuth(command, ({ accountLabel, accountPath, fs }) => Effect.gen(function* (_) {
6895
- const authMethod = yield* _(resolveGeminiAuthMethod(fs, accountPath));
6896
- if (authMethod === "none") {
6897
- yield* _(Effect.log(`Gemini not connected (${accountLabel}).`));
6898
- return;
6899
- }
6900
- yield* _(Effect.log(`Gemini connected (${accountLabel}, ${authMethod}).`));
6901
- }));
6902
- var authGeminiLogout = (command) => Effect.gen(function* (_) {
6903
- const accountLabel = normalizeAccountLabel(command.label, "default");
6904
- yield* _(withGeminiAuth(command, ({ accountPath, fs }) => Effect.gen(function* (_) {
6905
- yield* _(fs.remove(geminiApiKeyPath(accountPath), { force: true }));
6906
- yield* _(fs.remove(geminiEnvFilePath(accountPath), { force: true }));
6907
- yield* _(fs.remove(geminiCredentialsPath(accountPath), {
6908
- recursive: true,
6909
- force: true
6910
- }));
6911
- })));
6912
- yield* _(autoSyncState(`chore(state): auth gemini logout ${accountLabel}`));
6913
- }).pipe(Effect.asVoid);
6914
7058
  //#endregion
6915
7059
  //#region ../lib/src/usecases/state-repo-github.ts
6916
7060
  var dotDockerGitRepoName = ".docker-git";