Skip to content

Возможно полезные измненеия: #209

@skulidropek

Description

@skulidropek
meadav_david@meadav:~/docker-git$ git status
On branch main
Your branch is behind 'origin/main' by 31 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   .gitignore
	modified:   package.json
	modified:   packages/app/package.json
	modified:   packages/app/src/docker-git/main.ts
	modified:   packages/app/vite.config.ts
	modified:   packages/app/vite.docker-git.config.ts
	modified:   packages/lib/src/shell/clone.ts
	modified:   packages/lib/src/shell/docker-auth.ts
	modified:   packages/lib/src/shell/docker-compose-env.ts
	modified:   packages/lib/src/usecases/auth-sync-claude-seed.ts
	modified:   packages/lib/src/usecases/path-helpers.ts
	modified:   packages/lib/tests/usecases/path-helpers.test.ts
	modified:   scripts/e2e/issue-61-auth-labels.sh
	modified:   scripts/e2e/local-package-cli.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	packages/app/dist-verify/
	packages/lib/src/shell/home-dir.ts

no changes added to commit (use "git add" and/or "git commit -a")
meadav_david@meadav:~/docker-git$ git diff | cat
diff --git a/.gitignore b/.gitignore
index ebc26f4..784a62b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,8 @@ dist/
 build/
 coverage/
 packages/*/dist/
+packages/*/dist-app/
+packages/*/dist-docker-git/
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
diff --git a/package.json b/package.json
index e5c7b67..c5c4166 100644
--- a/package.json
+++ b/package.json
@@ -21,14 +21,14 @@
     "changeset": "changeset",
     "changeset-publish": "node -e \"if (!process.env.NPM_TOKEN) { console.log('Skipping publish: NPM_TOKEN is not set'); process.exit(0); }\" && changeset publish",
     "changeset-version": "changeset version",
-    "clone": "pnpm --filter ./packages/app build && node packages/app/dist/main.js clone",
-    "open": "pnpm --filter ./packages/app build && node packages/app/dist/main.js open",
-    "docker-git": "pnpm --filter ./packages/app build:docker-git && node packages/app/dist/src/docker-git/main.js",
+    "clone": "pnpm --filter ./packages/app build && node packages/app/dist-app/main.js clone",
+    "open": "pnpm --filter ./packages/app build && node packages/app/dist-app/main.js open",
+    "docker-git": "pnpm --filter ./packages/app build:docker-git && node packages/app/dist-docker-git/src/docker-git/main.js",
     "e2e": "bash scripts/e2e/run-all.sh",
     "e2e:clone-cache": "bash scripts/e2e/clone-cache.sh",
     "e2e:login-context": "bash scripts/e2e/login-context.sh",
     "e2e:opencode-autoconnect": "bash scripts/e2e/opencode-autoconnect.sh",
-    "list": "pnpm --filter ./packages/app build && node packages/app/dist/main.js list",
+    "list": "pnpm --filter ./packages/app build && node packages/app/dist-app/main.js list",
     "dev": "pnpm --filter ./packages/app dev",
     "lint": "pnpm --filter ./packages/app lint && pnpm --filter ./packages/lib lint",
     "lint:tests": "pnpm --filter ./packages/app lint:tests",
diff --git a/packages/app/package.json b/packages/app/package.json
index d017359..c330649 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -2,12 +2,12 @@
   "name": "@prover-coder-ai/docker-git",
   "version": "1.0.73",
   "description": "Minimal Vite-powered TypeScript console starter using Effect",
-  "main": "dist/src/docker-git/main.js",
+  "main": "dist-docker-git/src/docker-git/main.js",
   "bin": {
-    "docker-git": "dist/src/docker-git/main.js"
+    "docker-git": "dist-docker-git/src/docker-git/main.js"
   },
   "files": [
-    "dist"
+    "dist-docker-git"
   ],
   "directories": {
     "doc": "doc"
@@ -27,10 +27,10 @@
     "check": "pnpm run typecheck",
     "clone": "pnpm -C ../.. run clone",
     "open": "pnpm -C ../.. run open",
-    "docker-git": "node dist/src/docker-git/main.js",
+    "docker-git": "node dist-docker-git/src/docker-git/main.js",
     "list": "pnpm -C ../.. run list",
     "prestart": "pnpm run build",
-    "start": "node dist/main.js",
+    "start": "node dist-app/main.js",
     "pretest": "pnpm -C ../lib build",
     "test": "pnpm run lint:tests && vitest run",
     "pretypecheck": "pnpm -C ../lib build",
diff --git a/packages/app/src/docker-git/main.ts b/packages/app/src/docker-git/main.ts
index b82e82e..8d6f466 100644
--- a/packages/app/src/docker-git/main.ts
+++ b/packages/app/src/docker-git/main.ts
@@ -1,6 +1,7 @@
 #!/usr/bin/env node

 import { NodeContext, NodeRuntime } from "@effect/platform-node"
+import { normalizeHomeEnvironmentForSudo } from "@effect-template/lib/shell/home-dir"
 import { Effect } from "effect"

 import { program } from "./program.js"
@@ -15,6 +16,8 @@ import { program } from "./program.js"
 // EFFECT: Effect<void, unknown, NodeContext>
 // INVARIANT: program runs with NodeContext.layer
 // COMPLEXITY: O(n)
+normalizeHomeEnvironmentForSudo()
+
 const main = Effect.provide(program, NodeContext.layer)

 NodeRuntime.runMain(main)
diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts
index cfd0bb5..d595d83 100644
--- a/packages/app/vite.config.ts
+++ b/packages/app/vite.config.ts
@@ -16,7 +16,7 @@ export default defineConfig({
   },
   build: {
     target: "node20",
-    outDir: "dist",
+    outDir: "dist-app",
     sourcemap: true,
     ssr: "src/app/main.ts",
     rollupOptions: {
diff --git a/packages/app/vite.docker-git.config.ts b/packages/app/vite.docker-git.config.ts
index 7605ac4..f39b2ae 100644
--- a/packages/app/vite.docker-git.config.ts
+++ b/packages/app/vite.docker-git.config.ts
@@ -17,7 +17,7 @@ export default defineConfig({
   },
   build: {
     target: "node20",
-    outDir: "dist",
+    outDir: "dist-docker-git",
     sourcemap: true,
     ssr: "src/docker-git/main.ts",
     rollupOptions: {
diff --git a/packages/lib/src/shell/clone.ts b/packages/lib/src/shell/clone.ts
index e59df91..8db08e0 100644
--- a/packages/lib/src/shell/clone.ts
+++ b/packages/lib/src/shell/clone.ts
@@ -36,7 +36,7 @@ const runDockerGitCommand = (
     const path = yield* _(Path.Path)
     const workspaceRoot = process.cwd()
     const appRoot = path.join(workspaceRoot, "packages", "app")
-    const dockerGitCli = path.join(appRoot, "dist", "src", "docker-git", "main.js")
+    const dockerGitCli = path.join(appRoot, "dist-docker-git", "src", "docker-git", "main.js")
     const buildLabel = `pnpm -C ${appRoot} build:docker-git`
     const runLabel = `node ${dockerGitCli} ${commandName}`

diff --git a/packages/lib/src/shell/docker-auth.ts b/packages/lib/src/shell/docker-auth.ts
index 5e739a6..7c75c91 100644
--- a/packages/lib/src/shell/docker-auth.ts
+++ b/packages/lib/src/shell/docker-auth.ts
@@ -3,6 +3,7 @@ import type { PlatformError } from "@effect/platform/Error"
 import { Effect } from "effect"

 import { runCommandCapture, runCommandExitCode, runCommandWithExitCodes } from "./command-runner.js"
+import { resolveEffectiveHomeDir } from "./home-dir.js"

 export type DockerVolume = {
   readonly hostPath: string
@@ -56,7 +57,7 @@ const resolveContainerProjectsRoot = (): string | null => {
     return explicit
   }

-  const home = resolveDockerEnvValue("HOME") ?? resolveDockerEnvValue("USERPROFILE")
+  const home = resolveEffectiveHomeDir() ?? resolveDockerEnvValue("HOME") ?? resolveDockerEnvValue("USERPROFILE")
   return home === null ? null : `${trimDockerPathTrailingSlash(home)}/.docker-git`
 }

diff --git a/packages/lib/src/shell/docker-compose-env.ts b/packages/lib/src/shell/docker-compose-env.ts
index a2743ad..63ebf34 100644
--- a/packages/lib/src/shell/docker-compose-env.ts
+++ b/packages/lib/src/shell/docker-compose-env.ts
@@ -2,6 +2,7 @@ import type * as CommandExecutor from "@effect/platform/CommandExecutor"
 import { Effect } from "effect"

 import { resolveDockerEnvValue, resolveDockerVolumeHostPath, trimDockerPathTrailingSlash } from "./docker-auth.js"
+import { resolveEffectiveHomeDir } from "./home-dir.js"

 export const composeSpec = (cwd: string, args: ReadonlyArray<string>) => ({
   cwd,
@@ -15,7 +16,7 @@ const resolveProjectsRootCandidate = (): string | null => {
     return explicit
   }

-  const home = resolveDockerEnvValue("HOME") ?? resolveDockerEnvValue("USERPROFILE")
+  const home = resolveEffectiveHomeDir() ?? resolveDockerEnvValue("HOME") ?? resolveDockerEnvValue("USERPROFILE")
   return home === null ? null : `${trimDockerPathTrailingSlash(home)}/.docker-git`
 }

diff --git a/packages/lib/src/usecases/auth-sync-claude-seed.ts b/packages/lib/src/usecases/auth-sync-claude-seed.ts
index 36314b4..2c61ff2 100644
--- a/packages/lib/src/usecases/auth-sync-claude-seed.ts
+++ b/packages/lib/src/usecases/auth-sync-claude-seed.ts
@@ -3,6 +3,7 @@ import type * as FileSystem from "@effect/platform/FileSystem"
 import type * as Path from "@effect/platform/Path"
 import { Effect } from "effect"

+import { resolveEffectiveHomeDir } from "../shell/home-dir.js"
 import {
   hasClaudeCredentials,
   hasClaudeOauthAccount,
@@ -112,8 +113,8 @@ export const ensureClaudeAuthSeedFromHome = (
 ): Effect.Effect<void, PlatformError, FileSystem.FileSystem | Path.Path> =>
   withFsPathContext(({ fs, path }) =>
     Effect.gen(function*(_) {
-      const homeDir = (process.env["HOME"] ?? "").trim()
-      if (homeDir.length === 0) {
+      const homeDir = resolveEffectiveHomeDir()
+      if (homeDir === null || homeDir.length === 0) {
         return
       }

diff --git a/packages/lib/src/usecases/path-helpers.ts b/packages/lib/src/usecases/path-helpers.ts
index a4e3349..7f67ada 100644
--- a/packages/lib/src/usecases/path-helpers.ts
+++ b/packages/lib/src/usecases/path-helpers.ts
@@ -3,6 +3,8 @@ import type * as FileSystem from "@effect/platform/FileSystem"
 import type * as Path from "@effect/platform/Path"
 import { Effect } from "effect"

+import { resolveEffectiveHomeDir } from "../shell/home-dir.js"
+
 export const resolveAuthorizedKeysPath = (
   path: Path.Path,
   baseDir: string,
@@ -13,9 +15,8 @@ export const resolveAuthorizedKeysPath = (
     : path.resolve(baseDir, authorizedKeysPath)

 const resolveHomeDir = (): string | null => {
-  const raw = process.env["HOME"] ?? process.env["USERPROFILE"]
-  const home = raw?.trim() ?? ""
-  return home.length > 0 ? home : null
+  const home = resolveEffectiveHomeDir()
+  return home === null ? null : home.trim()
 }

 const expandHome = (value: string, home: string | null): string => {
diff --git a/packages/lib/tests/usecases/path-helpers.test.ts b/packages/lib/tests/usecases/path-helpers.test.ts
index 157f822..614380f 100644
--- a/packages/lib/tests/usecases/path-helpers.test.ts
+++ b/packages/lib/tests/usecases/path-helpers.test.ts
@@ -5,6 +5,11 @@ import { describe, expect, it } from "@effect/vitest"
 import { Effect } from "effect"

 import { findAuthorizedKeysSource, findSshPrivateKey } from "../../src/usecases/path-helpers.js"
+import {
+  normalizeHomeEnvironmentForSudo,
+  resolveEffectiveHomeDir,
+  resolveHomeDirFromPasswdContents
+} from "../../src/shell/home-dir.js"

 const withTempDir = <A, E, R>(
   use: (tempDir: string) => Effect.Effect<A, E, R>
@@ -52,6 +57,34 @@ const withPatchedEnv = <A, E, R>(
   )

 describe("path helpers", () => {
+  it.effect("prefers SUDO_HOME over /root when docker-git runs under sudo", () =>
+    withPatchedEnv(
+      {
+        HOME: "/root",
+        SUDO_USER: "alice",
+        SUDO_HOME: "/home/alice",
+        USERPROFILE: undefined
+      },
+      Effect.sync(() => {
+        expect(resolveHomeDirFromPasswdContents("alice:x:1000:1000::/home/alice:/bin/bash\n", "alice")).toBe("/home/alice")
+        expect(resolveEffectiveHomeDir()).toBe("/home/alice")
+      })
+    ))
+
+  it.effect("normalizes HOME to the invoking user's home in sudo flows", () =>
+    withPatchedEnv(
+      {
+        HOME: "/root",
+        SUDO_USER: "alice",
+        SUDO_HOME: "/home/alice",
+        USERPROFILE: undefined
+      },
+      Effect.sync(() => {
+        expect(normalizeHomeEnvironmentForSudo()).toBe("/home/alice")
+        expect(process.env["HOME"]).toBe("/home/alice")
+      })
+    ))
+
   it.effect("prefers the docker-git projects root public key over generic ~/.ssh keys", () =>
     withTempDir((root) =>
       Effect.gen(function*(_) {
diff --git a/scripts/e2e/issue-61-auth-labels.sh b/scripts/e2e/issue-61-auth-labels.sh
index 17f42e2..2e13333 100755
--- a/scripts/e2e/issue-61-auth-labels.sh
+++ b/scripts/e2e/issue-61-auth-labels.sh
@@ -111,8 +111,8 @@ import { Effect } from "effect"
 import { mkdirSync, writeFileSync } from "node:fs"
 import { join } from "node:path"

-import { writeAuthFlow } from "./dist/src/docker-git/menu-auth-data.js"
-import { writeProjectAuthFlow } from "./dist/src/docker-git/menu-project-auth-data.js"
+import { writeAuthFlow } from "./dist-docker-git/src/docker-git/menu-auth-data.js"
+import { writeProjectAuthFlow } from "./dist-docker-git/src/docker-git/menu-project-auth-data.js"

 const projectDir = process.env.PROJECT_DIR ?? ""
 const envProjectPath = process.env.PROJECT_ENV_PATH ?? ""
diff --git a/scripts/e2e/local-package-cli.sh b/scripts/e2e/local-package-cli.sh
index 8b80bd0..87a778d 100755
--- a/scripts/e2e/local-package-cli.sh
+++ b/scripts/e2e/local-package-cli.sh
@@ -62,7 +62,7 @@ PACKED_TARBALL="$REPO_ROOT/packages/app/$tarball_name"
 tar -tf "$PACKED_TARBALL" >"$TAR_LIST"
 while IFS= read -r entry; do
   case "$entry" in
-    package/package.json|package/README*|package/LICENSE*|package/CHANGELOG*|package/dist/*)
+    package/package.json|package/README*|package/LICENSE*|package/CHANGELOG*|package/dist-docker-git/*)
       ;;
     *)
       fail "unexpected file in packed tarball: $entry"
@@ -70,11 +70,11 @@ while IFS= read -r entry; do
   esac
 done <"$TAR_LIST"

-grep -Fxq "package/dist/src/docker-git/main.js" "$TAR_LIST" \
-  || fail "packed tarball does not include dist/src/docker-git/main.js"
+grep -Fxq "package/dist-docker-git/src/docker-git/main.js" "$TAR_LIST" \
+  || fail "packed tarball does not include dist-docker-git/src/docker-git/main.js"

 main_entry_tmp="$ROOT/main-entry.js"
-tar -xOf "$PACKED_TARBALL" package/dist/src/docker-git/main.js >"$main_entry_tmp"
+tar -xOf "$PACKED_TARBALL" package/dist-docker-git/src/docker-git/main.js >"$main_entry_tmp"
 main_first_line="$(head -n 1 "$main_entry_tmp" | tr -d '\r')"
 [[ "$main_first_line" == "#!/usr/bin/env node" ]] \
   || fail "packed CLI entrypoint missing shebang: expected '#!/usr/bin/env node', got '$main_first_line'"
meadav_david@meadav:~/docker-git$

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions