Skip to content

Commit 91327fa

Browse files
committed
fix(lib): split auth sync copy helpers for lint
1 parent f0302c5 commit 91327fa

2 files changed

Lines changed: 85 additions & 100 deletions

File tree

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import type { PlatformError } from "@effect/platform/Error"
2+
import type * as FileSystem from "@effect/platform/FileSystem"
3+
import type * as Path from "@effect/platform/Path"
4+
import { Effect } from "effect"
5+
6+
const copyDirRecursive = (
7+
fs: FileSystem.FileSystem,
8+
path: Path.Path,
9+
sourcePath: string,
10+
targetPath: string
11+
): Effect.Effect<void, PlatformError> =>
12+
Effect.gen(function*(_) {
13+
const sourceInfo = yield* _(fs.stat(sourcePath))
14+
if (sourceInfo.type !== "Directory") {
15+
return
16+
}
17+
yield* _(fs.makeDirectory(targetPath, { recursive: true }))
18+
const entries = yield* _(fs.readDirectory(sourcePath))
19+
for (const entry of entries) {
20+
const sourceEntry = path.join(sourcePath, entry)
21+
const targetEntry = path.join(targetPath, entry)
22+
const entryInfo = yield* _(fs.stat(sourceEntry))
23+
if (entryInfo.type === "Directory") {
24+
yield* _(copyDirRecursive(fs, path, sourceEntry, targetEntry))
25+
} else if (entryInfo.type === "File") {
26+
yield* _(fs.copyFile(sourceEntry, targetEntry))
27+
}
28+
}
29+
})
30+
31+
type CodexFileCopySpec = {
32+
readonly sourceDir: string
33+
readonly targetDir: string
34+
readonly fileName: string
35+
readonly label: string
36+
}
37+
38+
export const copyCodexFile = (
39+
fs: FileSystem.FileSystem,
40+
path: Path.Path,
41+
spec: CodexFileCopySpec
42+
): Effect.Effect<void, PlatformError> =>
43+
Effect.gen(function*(_) {
44+
const sourceFile = path.join(spec.sourceDir, spec.fileName)
45+
const targetFile = path.join(spec.targetDir, spec.fileName)
46+
const sourceExists = yield* _(fs.exists(sourceFile))
47+
if (!sourceExists) {
48+
return
49+
}
50+
const targetExists = yield* _(fs.exists(targetFile))
51+
if (targetExists) {
52+
return
53+
}
54+
yield* _(fs.copyFile(sourceFile, targetFile))
55+
yield* _(Effect.log(`Copied Codex ${spec.label} from ${sourceFile} to ${targetFile}`))
56+
})
57+
58+
export const copyDirIfEmpty = (
59+
fs: FileSystem.FileSystem,
60+
path: Path.Path,
61+
sourceDir: string,
62+
targetDir: string,
63+
label: string
64+
): Effect.Effect<void, PlatformError> =>
65+
Effect.gen(function*(_) {
66+
if (sourceDir === targetDir) {
67+
return
68+
}
69+
const sourceExists = yield* _(fs.exists(sourceDir))
70+
if (!sourceExists) {
71+
return
72+
}
73+
const sourceInfo = yield* _(fs.stat(sourceDir))
74+
if (sourceInfo.type !== "Directory") {
75+
return
76+
}
77+
yield* _(fs.makeDirectory(targetDir, { recursive: true }))
78+
const targetEntries = yield* _(fs.readDirectory(targetDir))
79+
if (targetEntries.length > 0) {
80+
return
81+
}
82+
yield* _(copyDirRecursive(fs, path, sourceDir, targetDir))
83+
yield* _(Effect.log(`Copied ${label} from ${sourceDir} to ${targetDir}`))
84+
})

packages/lib/src/usecases/auth-sync.ts

Lines changed: 1 addition & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type * as FileSystem from "@effect/platform/FileSystem"
33
import type * as Path from "@effect/platform/Path"
44
import { Effect } from "effect"
55

6+
import { copyCodexFile, copyDirIfEmpty } from "./auth-copy.js"
67
import { parseEnvEntries, removeEnvKey, upsertEnvKey } from "./env-file.js"
78
import { withFsPathContext } from "./runtime.js"
89

@@ -163,58 +164,6 @@ const copyFileIfNeeded = (
163164
})
164165
)
165166

166-
const copyDirRecursive = (
167-
fs: FileSystem.FileSystem,
168-
path: Path.Path,
169-
sourcePath: string,
170-
targetPath: string
171-
): Effect.Effect<void, PlatformError> =>
172-
Effect.gen(function*(_) {
173-
const sourceInfo = yield* _(fs.stat(sourcePath))
174-
if (sourceInfo.type !== "Directory") {
175-
return
176-
}
177-
yield* _(fs.makeDirectory(targetPath, { recursive: true }))
178-
const entries = yield* _(fs.readDirectory(sourcePath))
179-
for (const entry of entries) {
180-
const sourceEntry = path.join(sourcePath, entry)
181-
const targetEntry = path.join(targetPath, entry)
182-
const entryInfo = yield* _(fs.stat(sourceEntry))
183-
if (entryInfo.type === "Directory") {
184-
yield* _(copyDirRecursive(fs, path, sourceEntry, targetEntry))
185-
} else if (entryInfo.type === "File") {
186-
yield* _(fs.copyFile(sourceEntry, targetEntry))
187-
}
188-
}
189-
})
190-
191-
type CodexFileCopySpec = {
192-
readonly sourceDir: string
193-
readonly targetDir: string
194-
readonly fileName: string
195-
readonly label: string
196-
}
197-
198-
const copyCodexFile = (
199-
fs: FileSystem.FileSystem,
200-
path: Path.Path,
201-
spec: CodexFileCopySpec
202-
): Effect.Effect<void, PlatformError> =>
203-
Effect.gen(function*(_) {
204-
const sourceFile = path.join(spec.sourceDir, spec.fileName)
205-
const targetFile = path.join(spec.targetDir, spec.fileName)
206-
const sourceExists = yield* _(fs.exists(sourceFile))
207-
if (!sourceExists) {
208-
return
209-
}
210-
const targetExists = yield* _(fs.exists(targetFile))
211-
if (targetExists) {
212-
return
213-
}
214-
yield* _(fs.copyFile(sourceFile, targetFile))
215-
yield* _(Effect.log(`Copied Codex ${spec.label} from ${sourceFile} to ${targetFile}`))
216-
})
217-
218167
// CHANGE: ensure Codex config exists with full-access defaults
219168
// WHY: enable all codex commands without extra prompts inside containers
220169
// QUOTE(ТЗ): "сразу настраивал полностью весь доступ ко всем командам"
@@ -249,44 +198,6 @@ export const ensureCodexConfigFile = (
249198
})
250199
)
251200

252-
const copyDirIfEmpty = (
253-
fs: FileSystem.FileSystem,
254-
path: Path.Path,
255-
sourceDir: string,
256-
targetDir: string,
257-
label: string
258-
): Effect.Effect<void, PlatformError> =>
259-
Effect.gen(function*(_) {
260-
if (sourceDir === targetDir) {
261-
return
262-
}
263-
const sourceExists = yield* _(fs.exists(sourceDir))
264-
if (!sourceExists) {
265-
return
266-
}
267-
const sourceInfo = yield* _(fs.stat(sourceDir))
268-
if (sourceInfo.type !== "Directory") {
269-
return
270-
}
271-
yield* _(fs.makeDirectory(targetDir, { recursive: true }))
272-
const targetEntries = yield* _(fs.readDirectory(targetDir))
273-
if (targetEntries.length > 0) {
274-
return
275-
}
276-
yield* _(copyDirRecursive(fs, path, sourceDir, targetDir))
277-
yield* _(Effect.log(`Copied ${label} from ${sourceDir} to ${targetDir}`))
278-
})
279-
280-
// CHANGE: sync shared auth artifacts into new project directory
281-
// WHY: reuse global GH/Codex auth across containers automatically
282-
// QUOTE(ТЗ): "автоматически всё копировали на наш контейнер? и gh тоже"
283-
// REF: user-request-2026-01-29-auth-sync
284-
// SOURCE: n/a
285-
// FORMAT THEOREM: forall p: sync(p) -> env,codex_auth available(p)
286-
// PURITY: SHELL
287-
// EFFECT: Effect<void, PlatformError, FileSystem | Path>
288-
// INVARIANT: only copies when target is empty or placeholder
289-
// COMPLEXITY: O(n) where n = |files|
290201
type AuthPaths = {
291202
readonly envGlobalPath: string
292203
readonly envProjectPath: string
@@ -341,16 +252,6 @@ export const syncAuthArtifacts = (
341252
})
342253
)
343254

344-
// CHANGE: migrate legacy .orch layout into the new .docker-git/.orch location
345-
// WHY: keep all shared auth/config files under .docker-git by default
346-
// QUOTE(ТЗ): "по умолчанию все конфиги хранились вместе ... .docker-git"
347-
// REF: user-request-2026-01-29-orch-layout
348-
// SOURCE: n/a
349-
// FORMAT THEOREM: forall s: legacy(s) -> migrated(s)
350-
// PURITY: SHELL
351-
// EFFECT: Effect<void, PlatformError, FileSystem | Path>
352-
// INVARIANT: never overwrites existing non-empty targets
353-
// COMPLEXITY: O(n) where n = |files|
354255
export const migrateLegacyOrchLayout = (
355256
baseDir: string,
356257
envGlobalPath: string,

0 commit comments

Comments
 (0)