-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathconfig.ts
More file actions
93 lines (85 loc) · 3.36 KB
/
config.ts
File metadata and controls
93 lines (85 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import type { PlatformError } from "@effect/platform/Error"
import type * as FileSystem from "@effect/platform/FileSystem"
import type * as Path from "@effect/platform/Path"
import * as ParseResult from "@effect/schema/ParseResult"
import * as Schema from "@effect/schema/Schema"
import * as TreeFormatter from "@effect/schema/TreeFormatter"
import { Effect, Either } from "effect"
import { defaultTemplateConfig, type ProjectConfig } from "../core/domain.js"
import { ConfigDecodeError, ConfigNotFoundError } from "./errors.js"
import { resolveBaseDir } from "./paths.js"
const TemplateConfigSchema = Schema.Struct({
containerName: Schema.String,
serviceName: Schema.String,
sshUser: Schema.String,
sshPort: Schema.Number.pipe(Schema.int()),
repoUrl: Schema.String,
repoRef: Schema.String,
targetDir: Schema.String,
volumeName: Schema.String,
dockerGitPath: Schema.optionalWith(Schema.String, {
default: () => defaultTemplateConfig.dockerGitPath
}),
authorizedKeysPath: Schema.String,
envGlobalPath: Schema.optionalWith(Schema.String, {
default: () => defaultTemplateConfig.envGlobalPath
}),
envProjectPath: Schema.optionalWith(Schema.String, {
default: () => defaultTemplateConfig.envProjectPath
}),
codexAuthPath: Schema.String,
codexSharedAuthPath: Schema.optionalWith(Schema.String, {
default: () => defaultTemplateConfig.codexSharedAuthPath
}),
codexHome: Schema.String,
enableMcpPlaywright: Schema.optionalWith(Schema.Boolean, {
default: () => defaultTemplateConfig.enableMcpPlaywright
}),
pnpmVersion: Schema.String
})
const ProjectConfigSchema = Schema.Struct({
schemaVersion: Schema.Literal(1),
template: TemplateConfigSchema
})
const ProjectConfigJsonSchema = Schema.parseJson(ProjectConfigSchema)
const decodeProjectConfig = (
path: string,
input: string
): Effect.Effect<ProjectConfig, ConfigDecodeError> =>
Either.match(ParseResult.decodeUnknownEither(ProjectConfigJsonSchema)(input), {
onLeft: (issue) =>
Effect.fail(
new ConfigDecodeError({
path,
message: TreeFormatter.formatIssueSync(issue)
})
),
onRight: (value) => Effect.succeed(value)
})
// CHANGE: read and decode docker-git.json from disk
// WHY: keep unknown inputs at the boundary and validate with schema
// QUOTE(ТЗ): "интерфейс в котором можно авторизировать все что мы хотим иметь"
// REF: user-request-2026-01-07
// SOURCE: n/a
// FORMAT THEOREM: forall p: decode(read(p)) = cfg -> cfg.schemaVersion = 1
// PURITY: SHELL
// EFFECT: Effect<ProjectConfig, ConfigNotFoundError | ConfigDecodeError | PlatformError, FileSystem | Path>
// INVARIANT: unknown input never leaks past this boundary
// COMPLEXITY: O(n) where n = |file|
export const readProjectConfig = (
baseDir: string
): Effect.Effect<
ProjectConfig,
ConfigNotFoundError | ConfigDecodeError | PlatformError,
FileSystem.FileSystem | Path.Path
> =>
Effect.gen(function*(_) {
const { fs, path, resolved } = yield* _(resolveBaseDir(baseDir))
const configPath = path.join(resolved, "docker-git.json")
const exists = yield* _(fs.exists(configPath))
if (!exists) {
return yield* _(Effect.fail(new ConfigNotFoundError({ path: configPath })))
}
const contents = yield* _(fs.readFileString(configPath))
return yield* _(decodeProjectConfig(configPath, contents))
})