forked from ProverCoderAI/docker-git
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdomain.ts
More file actions
399 lines (347 loc) · 11.4 KB
/
domain.ts
File metadata and controls
399 lines (347 loc) · 11.4 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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
import type { SessionGistCommand } from "./session-gist-domain.js"
export type { MenuAction, ParseError } from "./menu.js"
export { parseMenuSelection } from "./menu.js"
export { deriveRepoPathParts, deriveRepoSlug, resolveRepoInput } from "./repo.js"
export type AgentMode = "claude" | "codex" | "gemini"
export type DockerNetworkMode = "shared" | "project"
export const defaultDockerNetworkMode: DockerNetworkMode = "shared"
export const defaultDockerSharedNetworkName = "docker-git-shared"
export const defaultCpuLimit = "30%"
export const defaultRamLimit = "30%"
export interface TemplateConfig {
readonly containerName: string
readonly serviceName: string
readonly sshUser: string
readonly sshPort: number
readonly repoUrl: string
readonly repoRef: string
readonly forkRepoUrl?: string
readonly gitTokenLabel?: string | undefined
readonly codexAuthLabel?: string | undefined
readonly claudeAuthLabel?: string | undefined
readonly targetDir: string
readonly volumeName: string
readonly dockerGitPath: string
readonly authorizedKeysPath: string
readonly envGlobalPath: string
readonly envProjectPath: string
readonly codexAuthPath: string
readonly codexSharedAuthPath: string
readonly codexHome: string
readonly geminiAuthLabel?: string | undefined
readonly geminiAuthPath: string
readonly geminiHome: string
readonly cpuLimit?: string | undefined
readonly ramLimit?: string | undefined
readonly dockerNetworkMode: DockerNetworkMode
readonly dockerSharedNetworkName: string
readonly enableMcpPlaywright: boolean
readonly pnpmVersion: string
readonly agentMode?: AgentMode | undefined
readonly agentAuto?: boolean | undefined
}
export interface ProjectConfig {
readonly schemaVersion: 1
readonly template: TemplateConfig
}
export interface CreateCommand {
readonly _tag: "Create"
readonly config: TemplateConfig
readonly outDir: string
readonly runUp: boolean
readonly force: boolean
readonly forceEnv: boolean
readonly waitForClone: boolean
readonly openSsh: boolean
}
export interface MenuCommand {
readonly _tag: "Menu"
}
export interface AttachCommand {
readonly _tag: "Attach"
readonly projectDir: string
}
export interface PanesCommand {
readonly _tag: "Panes"
readonly projectDir: string
}
export interface SessionsListCommand {
readonly _tag: "SessionsList"
readonly projectDir: string
readonly includeDefault: boolean
}
export interface SessionsKillCommand {
readonly _tag: "SessionsKill"
readonly projectDir: string
readonly pid: number
}
export interface SessionsLogsCommand {
readonly _tag: "SessionsLogs"
readonly projectDir: string
readonly pid: number
readonly lines: number
}
// CHANGE: remove scrap cache mode and keep only the reproducible session snapshot.
// WHY: cache archives include large, easily-rebuildable artifacts (e.g. node_modules) that should not be stored in git.
// QUOTE(ТЗ): "не должно быть старого режима где он качает весь шлак типо node_modules"
// REF: user-request-2026-02-15
// SOURCE: n/a
// FORMAT THEOREM: forall m: ScrapMode, m = "session"
// PURITY: CORE
// EFFECT: Effect<never>
// INVARIANT: scrap exports/imports are always recipe-like (git state + small secrets), never full workspace caches
// COMPLEXITY: O(1)
export type ScrapMode = "session"
export interface ScrapExportCommand {
readonly _tag: "ScrapExport"
readonly projectDir: string
readonly archivePath: string
readonly mode: ScrapMode
}
export interface ScrapImportCommand {
readonly _tag: "ScrapImport"
readonly projectDir: string
readonly archivePath: string
readonly wipe: boolean
readonly mode: ScrapMode
}
export interface McpPlaywrightUpCommand {
readonly _tag: "McpPlaywrightUp"
readonly projectDir: string
readonly runUp: boolean
}
export interface ApplyCommand {
readonly _tag: "Apply"
readonly projectDir: string
readonly runUp: boolean
readonly gitTokenLabel?: string | undefined
readonly codexTokenLabel?: string | undefined
readonly claudeTokenLabel?: string | undefined
readonly geminiTokenLabel?: string | undefined
readonly cpuLimit?: string | undefined
readonly ramLimit?: string | undefined
readonly enableMcpPlaywright?: boolean | undefined
}
// CHANGE: add apply-all command to apply docker-git config to every known project; support --active flag
// WHY: allow bulk-updating all containers in one command; --active restricts to currently running containers only
// QUOTE(ТЗ): "Сделать команду которая сама на все контейнеры применит новые настройки"
// QUOTE(ТЗ): "сделать это возможным через атрибут --active применять только к активным контейнерам, а не ко всем"
// REF: issue-164, issue-185
// PURITY: CORE
// EFFECT: n/a
// INVARIANT: when activeOnly=false applies to all discovered projects; when activeOnly=true applies only to running containers; individual failures do not abort the batch
// COMPLEXITY: O(1)
export interface ApplyAllCommand {
readonly _tag: "ApplyAll"
readonly activeOnly: boolean
}
export interface HelpCommand {
readonly _tag: "Help"
readonly message: string
}
export interface StatusCommand {
readonly _tag: "Status"
}
export interface DownAllCommand {
readonly _tag: "DownAll"
}
export interface StatePathCommand {
readonly _tag: "StatePath"
}
export interface StateInitCommand {
readonly _tag: "StateInit"
readonly repoUrl: string
readonly repoRef: string
}
export interface StatePullCommand {
readonly _tag: "StatePull"
}
export interface StatePushCommand {
readonly _tag: "StatePush"
}
export interface StateStatusCommand {
readonly _tag: "StateStatus"
}
export interface StateCommitCommand {
readonly _tag: "StateCommit"
readonly message: string
}
export interface StateSyncCommand {
readonly _tag: "StateSync"
readonly message: string | null
}
export interface AuthGithubLoginCommand {
readonly _tag: "AuthGithubLogin"
readonly label: string | null
readonly token: string | null
readonly scopes: string | null
readonly envGlobalPath: string
}
export interface AuthGithubStatusCommand {
readonly _tag: "AuthGithubStatus"
readonly envGlobalPath: string
}
export interface AuthGithubLogoutCommand {
readonly _tag: "AuthGithubLogout"
readonly label: string | null
readonly envGlobalPath: string
}
export interface AuthCodexLoginCommand {
readonly _tag: "AuthCodexLogin"
readonly label: string | null
readonly codexAuthPath: string
}
export interface AuthCodexStatusCommand {
readonly _tag: "AuthCodexStatus"
readonly label: string | null
readonly codexAuthPath: string
}
export interface AuthCodexLogoutCommand {
readonly _tag: "AuthCodexLogout"
readonly label: string | null
readonly codexAuthPath: string
}
export interface AuthClaudeLoginCommand {
readonly _tag: "AuthClaudeLogin"
readonly label: string | null
readonly claudeAuthPath: string
}
export interface AuthClaudeStatusCommand {
readonly _tag: "AuthClaudeStatus"
readonly label: string | null
readonly claudeAuthPath: string
}
export interface AuthClaudeLogoutCommand {
readonly _tag: "AuthClaudeLogout"
readonly label: string | null
readonly claudeAuthPath: string
}
// CHANGE: add Gemini CLI auth commands
// WHY: enable Gemini CLI authentication management similar to Claude/Codex
// QUOTE(ТЗ): "Добавь поддержку gemini CLI"
// REF: issue-146
// SOURCE: https://geminicli.com/docs/get-started/authentication/
// FORMAT THEOREM: forall cmd ∈ AuthGeminiCommand: cmd.geminiAuthPath is valid path
// PURITY: CORE
// EFFECT: n/a
// INVARIANT: authentication state is isolated by label
// COMPLEXITY: O(1)
export interface AuthGeminiLoginCommand {
readonly _tag: "AuthGeminiLogin"
readonly label: string | null
readonly geminiAuthPath: string
readonly isWeb: boolean
}
export interface AuthGeminiStatusCommand {
readonly _tag: "AuthGeminiStatus"
readonly label: string | null
readonly geminiAuthPath: string
}
export interface AuthGeminiLogoutCommand {
readonly _tag: "AuthGeminiLogout"
readonly label: string | null
readonly geminiAuthPath: string
}
export type {
SessionGistBackupCommand,
SessionGistCommand,
SessionGistDownloadCommand,
SessionGistListCommand,
SessionGistViewCommand
} from "./session-gist-domain.js"
export type SessionsCommand =
| SessionsListCommand
| SessionsKillCommand
| SessionsLogsCommand
| SessionGistCommand
export type ScrapCommand =
| ScrapExportCommand
| ScrapImportCommand
export type AuthCommand =
| AuthGithubLoginCommand
| AuthGithubStatusCommand
| AuthGithubLogoutCommand
| AuthCodexLoginCommand
| AuthCodexStatusCommand
| AuthCodexLogoutCommand
| AuthClaudeLoginCommand
| AuthClaudeStatusCommand
| AuthClaudeLogoutCommand
| AuthGeminiLoginCommand
| AuthGeminiStatusCommand
| AuthGeminiLogoutCommand
export type StateCommand =
| StatePathCommand
| StateInitCommand
| StatePullCommand
| StatePushCommand
| StateStatusCommand
| StateCommitCommand
| StateSyncCommand
export type Command =
| CreateCommand
| MenuCommand
| AttachCommand
| PanesCommand
| SessionsCommand
| ScrapCommand
| McpPlaywrightUpCommand
| ApplyCommand
| ApplyAllCommand
| HelpCommand
| StatusCommand
| DownAllCommand
| StateCommand
| AuthCommand
// CHANGE: validate docker network mode values at the CLI/config boundary
// WHY: keep compose network behavior explicit and type-safe
// QUOTE(ТЗ): "Что бы среды были изолированы?"
// REF: user-request-2026-02-20-networks
// SOURCE: n/a
// FORMAT THEOREM: ∀x: isDockerNetworkMode(x) -> x ∈ {"shared","project"}
// PURITY: CORE
// EFFECT: n/a
// INVARIANT: returns true only for known modes
// COMPLEXITY: O(1)
export const isDockerNetworkMode = (value: string): value is DockerNetworkMode =>
value === "shared" || value === "project"
// CHANGE: derive compose network name from typed template config
// WHY: keep network naming deterministic across template generation and runtime checks
// QUOTE(ТЗ): "Если я хочу уникальную сеть на каждый контейнер?"
// REF: user-request-2026-02-20-networks
// SOURCE: n/a
// FORMAT THEOREM: ∀cfg: resolveComposeNetworkName(cfg) = n -> deterministic(n)
// PURITY: CORE
// EFFECT: n/a
// INVARIANT: shared mode always resolves to dockerSharedNetworkName; project mode to "<service>-net"
// COMPLEXITY: O(1)
export const resolveComposeNetworkName = (
config: Pick<TemplateConfig, "serviceName" | "dockerNetworkMode" | "dockerSharedNetworkName">
): string =>
config.dockerNetworkMode === "shared"
? config.dockerSharedNetworkName
: `${config.serviceName}-net`
export const defaultTemplateConfig = {
containerName: "dev-ssh",
serviceName: "dev",
sshUser: "dev",
sshPort: 2222,
repoRef: "main",
targetDir: "/home/dev/app",
volumeName: "dev_home",
dockerGitPath: "./.docker-git",
authorizedKeysPath: "./.docker-git/authorized_keys",
envGlobalPath: "./.docker-git/.orch/env/global.env",
envProjectPath: "./.orch/env/project.env",
codexAuthPath: "./.docker-git/.orch/auth/codex",
codexSharedAuthPath: "./.docker-git/.orch/auth/codex",
codexHome: "/home/dev/.codex",
geminiAuthPath: "./.docker-git/.orch/auth/gemini",
geminiHome: "/home/dev/.gemini",
cpuLimit: defaultCpuLimit,
ramLimit: defaultRamLimit,
dockerNetworkMode: defaultDockerNetworkMode,
dockerSharedNetworkName: defaultDockerSharedNetworkName,
enableMcpPlaywright: false,
pnpmVersion: "10.27.0"
}