Skip to content

Commit 109be65

Browse files
committed
merge main into Windows support PR
2 parents ff1bc75 + d2884b1 commit 109be65

211 files changed

Lines changed: 10187 additions & 2423 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ bun run docker-git --help
2525
docker-git auth github login --web
2626
docker-git auth codex login --web
2727
docker-git auth claude login --web
28+
docker-git auth grok login --web
2829
```
2930

31+
Grok support uses the official xAI CLI installer from `https://x.ai/cli/install.sh`
32+
and the CLI device-code login flow. API-key auth can also be stored under the
33+
selected Grok account label via `GROK_DEPLOYMENT_KEY`, `GROK_API_KEY`, or
34+
`XAI_API_KEY`.
35+
3036
## CLI пример
3137

3238
Можно передавать ссылку на репозиторий, ветку (`/tree/...`), issue или PR.
@@ -44,8 +50,8 @@ docker-git clone https://github.com/ProverCoderAI/docker-git/issues/122 --force
4450
docker-git clone https://github.com/ProverCoderAI/docker-git/issues/122 --force --auto
4551
```
4652

47-
- `--auto` сам выбирает Claude или Codex по доступной авторизации. Если доступны оба, выбор случайный.
48-
- `--auto=claude` или `--auto=codex` принудительно выбирает агента.
53+
- `--auto` сам выбирает Claude, Codex, Gemini или Grok по доступной авторизации. Если доступно несколько, выбор случайный.
54+
- `--auto=claude`, `--auto=codex`, `--auto=gemini` или `--auto=grok` принудительно выбирает агента.
4955
- В auto-режиме агент сам выполняет задачу, создаёт PR и после завершения контейнер очищается.
5056

5157
Применение конфигурации:

bun.lock

Lines changed: 68 additions & 94 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/api/Dockerfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,17 @@ RUN set -eu; \
3535
libnss3 libpango-1.0-0 libx11-xcb1 libxcb-dri3-0 libxcomposite1 libxdamage1 libxfixes3 \
3636
libxkbcommon0 libxrandr2 libxshmfence1 \
3737
&& mkdir -p /usr/share/keyrings \
38+
&& curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
39+
| gpg --dearmor -o /usr/share/keyrings/cloudflare-main.gpg \
40+
&& echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
41+
> /etc/apt/sources.list.d/cloudflared.list \
3842
&& curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
3943
| gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
4044
&& curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
4145
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
4246
> /etc/apt/sources.list.d/nvidia-container-toolkit.list \
4347
&& apt-get -o Acquire::Retries=3 update \
44-
&& apt-get -o Acquire::Retries=3 install -y --no-install-recommends nvidia-container-toolkit \
48+
&& apt-get -o Acquire::Retries=3 install -y --no-install-recommends cloudflared nvidia-container-toolkit \
4549
&& nvidia-ctk runtime configure --runtime=docker \
4650
&& rm -rf /var/lib/apt/lists/*
4751

packages/api/README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ Diagnostic classification + remediation messages live in
3636
`packages/app/src/docker-git/controller-docker-diagnostics.ts` and are
3737
covered by `packages/app/tests/docker-git/controller-docker-diagnostics.test.ts`.
3838

39-
## UI wrapper
40-
41-
After API startup open:
42-
43-
- `http://localhost:3334/`
44-
45-
This page is a built-in UI shell for manual API checks without CLI.
46-
4739
## Run (local)
4840

4941
```bash

packages/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"@types/ws": "^8.18.1",
4444
"@typescript-eslint/eslint-plugin": "^8.59.3",
4545
"@typescript-eslint/parser": "^8.59.3",
46-
"eslint": "^10.3.0",
46+
"eslint": "^10.4.0",
4747
"fast-check": "4.8.0",
4848
"globals": "^17.6.0",
4949
"typescript": "^6.0.3",

packages/api/src/api/contracts.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type ProjectStatus = "running" | "stopped" | "unknown"
22

3-
export type AgentProvider = "codex" | "opencode" | "claude" | "custom"
3+
export type AgentProvider = "codex" | "opencode" | "claude" | "grok" | "custom"
44

55
export type AgentStatus = "starting" | "running" | "stopping" | "stopped" | "exited" | "failed"
66

@@ -74,6 +74,23 @@ export type ProjectPortForwardRequest = {
7474
readonly hostPort?: number | undefined
7575
}
7676

77+
export type PanelCloudflareTunnelStatus = "starting" | "running" | "stopped" | "failed"
78+
79+
export type PanelCloudflareTunnelSession = {
80+
readonly error: string | null
81+
readonly id: string
82+
readonly logTail: ReadonlyArray<string>
83+
readonly panelUrl: string
84+
readonly publicUrl: string | null
85+
readonly startedAt: string
86+
readonly status: PanelCloudflareTunnelStatus
87+
readonly stoppedAt: string | null
88+
}
89+
90+
export type StartPanelCloudflareTunnelRequest = {
91+
readonly panelUrl: string
92+
}
93+
7794
export type ProjectBrowserStatus = "running" | "stopped" | "missing" | "unknown"
7895

7996
export type ProjectBrowserSession = {
@@ -183,19 +200,23 @@ export type AuthMenuFlow =
183200
| "ClaudeLogout"
184201
| "GeminiApiKey"
185202
| "GeminiLogout"
203+
| "GrokApiKey"
204+
| "GrokLogout"
186205

187-
export type AuthTerminalFlow = "ClaudeOauth" | "GeminiOauth"
206+
export type AuthTerminalFlow = "ClaudeOauth" | "GeminiOauth" | "GrokOauth"
188207

189208
export type AuthSnapshot = {
190209
readonly globalEnvPath: string
191210
readonly claudeAuthPath: string
192211
readonly geminiAuthPath: string
212+
readonly grokAuthPath: string
193213
readonly totalEntries: number
194214
readonly githubTokenEntries: number
195215
readonly gitTokenEntries: number
196216
readonly gitUserEntries: number
197217
readonly claudeAuthEntries: number
198218
readonly geminiAuthEntries: number
219+
readonly grokAuthEntries: number
199220
}
200221

201222
export type AuthMenuRequest = {
@@ -249,6 +270,8 @@ export type ProjectAuthFlow =
249270
| "ProjectClaudeDisconnect"
250271
| "ProjectGeminiConnect"
251272
| "ProjectGeminiDisconnect"
273+
| "ProjectGrokConnect"
274+
| "ProjectGrokDisconnect"
252275

253276
export type ProjectAuthSnapshot = {
254277
readonly projectDir: string
@@ -257,22 +280,25 @@ export type ProjectAuthSnapshot = {
257280
readonly envProjectPath: string
258281
readonly claudeAuthPath: string
259282
readonly geminiAuthPath: string
283+
readonly grokAuthPath: string
260284
readonly githubTokenEntries: number
261285
readonly gitTokenEntries: number
262286
readonly claudeAuthEntries: number
263287
readonly geminiAuthEntries: number
288+
readonly grokAuthEntries: number
264289
readonly activeGithubLabel: string | null
265290
readonly activeGitLabel: string | null
266291
readonly activeClaudeLabel: string | null
267292
readonly activeGeminiLabel: string | null
293+
readonly activeGrokLabel: string | null
268294
}
269295

270296
export type ProjectAuthRequest = {
271297
readonly flow: ProjectAuthFlow
272298
readonly label?: string | null | undefined
273299
}
274300

275-
export type ProjectPromptKind = "claude" | "codex" | "gemini"
301+
export type ProjectPromptKind = "claude" | "codex" | "gemini" | "grok"
276302

277303
export type ProjectPromptFile = {
278304
readonly kind: ProjectPromptKind
@@ -302,6 +328,7 @@ export type ProjectSkillScope =
302328
| "claude/skills"
303329
| "codex/skills"
304330
| "gemini/skills"
331+
| "grok/skills"
305332

306333
export type ProjectSkillFile = {
307334
readonly id: string
@@ -357,6 +384,10 @@ export type UpProjectRequest = {
357384
}
358385

359386
export type ApplyProjectRequest = {
387+
readonly cpuLimit?: string | undefined
388+
readonly ramLimit?: string | undefined
389+
readonly playwrightCpuLimit?: string | undefined
390+
readonly playwrightRamLimit?: string | undefined
360391
readonly gpu?: "none" | "all" | undefined
361392
}
362393

@@ -385,6 +416,8 @@ export type CreateProjectRequest = {
385416
readonly codexHome?: string | undefined
386417
readonly cpuLimit?: string | undefined
387418
readonly ramLimit?: string | undefined
419+
readonly playwrightCpuLimit?: string | undefined
420+
readonly playwrightRamLimit?: string | undefined
388421
readonly gpu?: "none" | "all" | undefined
389422
readonly dockerNetworkMode?: string | undefined
390423
readonly dockerSharedNetworkName?: string | undefined
@@ -394,6 +427,8 @@ export type CreateProjectRequest = {
394427
readonly skipGithubAuth?: boolean | undefined
395428
readonly codexTokenLabel?: string | undefined
396429
readonly claudeTokenLabel?: string | undefined
430+
readonly geminiTokenLabel?: string | undefined
431+
readonly grokTokenLabel?: string | undefined
397432
readonly agentAutoMode?: string | undefined
398433
readonly up?: boolean | undefined
399434
readonly openSsh?: boolean | undefined

packages/api/src/api/schema.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export const CreateProjectRequestSchema = Schema.Struct({
2323
codexHome: OptionalString,
2424
cpuLimit: OptionalString,
2525
ramLimit: OptionalString,
26+
playwrightCpuLimit: OptionalString,
27+
playwrightRamLimit: OptionalString,
2628
gpu: Schema.optional(Schema.Literal("none", "all")),
2729
dockerNetworkMode: OptionalString,
2830
dockerSharedNetworkName: OptionalString,
@@ -32,6 +34,8 @@ export const CreateProjectRequestSchema = Schema.Struct({
3234
skipGithubAuth: OptionalBoolean,
3335
codexTokenLabel: OptionalString,
3436
claudeTokenLabel: OptionalString,
37+
geminiTokenLabel: OptionalString,
38+
grokTokenLabel: OptionalString,
3539
agentAutoMode: OptionalString,
3640
up: OptionalBoolean,
3741
openSsh: OptionalBoolean,
@@ -58,10 +62,12 @@ export const AuthMenuFlowSchema = Schema.Literal(
5862
"GitRemove",
5963
"ClaudeLogout",
6064
"GeminiApiKey",
61-
"GeminiLogout"
65+
"GeminiLogout",
66+
"GrokApiKey",
67+
"GrokLogout"
6268
)
6369

64-
export const AuthTerminalFlowSchema = Schema.Literal("ClaudeOauth", "GeminiOauth")
70+
export const AuthTerminalFlowSchema = Schema.Literal("ClaudeOauth", "GeminiOauth", "GrokOauth")
6571

6672
export const AuthMenuRequestSchema = Schema.Struct({
6773
flow: AuthMenuFlowSchema,
@@ -105,15 +111,17 @@ export const ProjectAuthFlowSchema = Schema.Literal(
105111
"ProjectClaudeConnect",
106112
"ProjectClaudeDisconnect",
107113
"ProjectGeminiConnect",
108-
"ProjectGeminiDisconnect"
114+
"ProjectGeminiDisconnect",
115+
"ProjectGrokConnect",
116+
"ProjectGrokDisconnect"
109117
)
110118

111119
export const ProjectAuthRequestSchema = Schema.Struct({
112120
flow: ProjectAuthFlowSchema,
113121
label: OptionalNullableString
114122
})
115123

116-
export const ProjectPromptKindSchema = Schema.Literal("claude", "codex", "gemini")
124+
export const ProjectPromptKindSchema = Schema.Literal("claude", "codex", "gemini", "grok")
117125

118126
export const ProjectPromptUpdateRequestSchema = Schema.Struct({
119127
content: Schema.String
@@ -125,7 +133,8 @@ export const ProjectSkillScopeSchema = Schema.Literal(
125133
"agents/.skills",
126134
"claude/skills",
127135
"codex/skills",
128-
"gemini/skills"
136+
"gemini/skills",
137+
"grok/skills"
129138
)
130139

131140
export const ProjectSkillUpdateRequestSchema = Schema.Struct({
@@ -152,6 +161,10 @@ export const ApplyAllRequestSchema = Schema.Struct({
152161
})
153162

154163
export const ApplyProjectRequestSchema = Schema.Struct({
164+
cpuLimit: OptionalString,
165+
ramLimit: OptionalString,
166+
playwrightCpuLimit: OptionalString,
167+
playwrightRamLimit: OptionalString,
155168
gpu: Schema.optional(Schema.Literal("none", "all"))
156169
})
157170

@@ -161,14 +174,22 @@ export const UpProjectRequestSchema = Schema.Struct({
161174
})
162175

163176
export const StartProjectTerminalSessionRequestSchema = Schema.Struct({
164-
requestId: Schema.String
177+
requestId: Schema.UUID
178+
})
179+
180+
export const ActiveProjectTerminalSessionRequestSchema = Schema.Struct({
181+
sessionId: Schema.String
165182
})
166183

167184
export const ProjectPortForwardRequestSchema = Schema.Struct({
168185
hostPort: Schema.optional(Schema.Number),
169186
targetPort: Schema.Number
170187
})
171188

189+
export const StartPanelCloudflareTunnelRequestSchema = Schema.Struct({
190+
panelUrl: Schema.String
191+
})
192+
172193
export const ProjectBrowserStatusSchema = Schema.Literal("running", "stopped", "missing", "unknown")
173194

174195
export const ProjectBrowserSessionSchema = Schema.Struct({
@@ -236,7 +257,7 @@ export const ProjectDatabaseForwardSchema = Schema.Struct({
236257
targetPort: Schema.Number
237258
})
238259

239-
export const AgentProviderSchema = Schema.Literal("codex", "opencode", "claude", "custom")
260+
export const AgentProviderSchema = Schema.Literal("codex", "opencode", "claude", "grok", "custom")
240261

241262
export const AgentEnvVarSchema = Schema.Struct({
242263
key: Schema.String,

packages/api/src/auth-terminal-runner.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import { NodeContext, NodeRuntime } from "@effect/platform-node"
2-
import { authClaudeLogin, authGeminiLoginOauth } from "@effect-template/lib"
2+
import { authClaudeLogin, authGeminiLoginOauth, authGrokLoginOauth } from "@effect-template/lib"
33
import { Effect, Match } from "effect"
44

5-
type AuthTerminalRunnerFlow = "ClaudeOauth" | "GeminiOauth"
5+
type AuthTerminalRunnerFlow = "ClaudeOauth" | "GeminiOauth" | "GrokOauth"
66

7-
const parseFlow = (value: string | undefined): AuthTerminalRunnerFlow =>
8-
value === "ClaudeOauth" || value === "GeminiOauth" ? value : "ClaudeOauth"
7+
const parseFlow = (value: string | undefined): AuthTerminalRunnerFlow => {
8+
if (value === "ClaudeOauth" || value === "GeminiOauth" || value === "GrokOauth") {
9+
return value
10+
}
11+
process.stderr.write(`Unsupported auth terminal flow: ${value ?? "<empty>"}\n`)
12+
process.exit(2)
13+
}
914

1015
const parseLabel = (value: string | undefined): string | null => {
1116
const trimmed = value?.trim() ?? ""
@@ -29,6 +34,13 @@ const program = Match.value(flow).pipe(
2934
geminiAuthPath: ".docker-git/.orch/auth/gemini",
3035
isWeb: false
3136
})),
37+
Match.when("GrokOauth", () =>
38+
authGrokLoginOauth({
39+
_tag: "AuthGrokLogin",
40+
label,
41+
grokAuthPath: ".docker-git/.orch/auth/grok",
42+
isWeb: false
43+
})),
3244
Match.exhaustive
3345
)
3446

0 commit comments

Comments
 (0)