vibe-coding-master 0.3.10 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -142,6 +142,7 @@ Important container notes:
142
142
  - Make sure the container has network access to Claude services and to the translation provider if translation is enabled.
143
143
  - VCM accepts normal Git repositories by checking `.git` directly. It also supports `.git` files that point to worktree gitdirs.
144
144
  - VCM uses per-command `git -c safe.directory=...` for Git metadata reads and does not require global `git config --global --add safe.directory`.
145
+ - Set `VCM_SANDBOX=devcontainer` so VCM-managed Codex Reviewer sessions rely on the container boundary and do not start Codex's nested Linux sandbox.
145
146
  - Treat the container as the sandbox boundary, especially when using relaxed Claude Code permission modes.
146
147
 
147
148
  ## Basic Usage
@@ -389,7 +390,7 @@ Translation settings are local and stored in:
389
390
 
390
391
  The same file stores recent repository paths. The translation API key is stored locally under `translation.secrets.apiKey`; it is not written to the connected repository, `.ai/vcm/handoffs`, raw terminal logs, or git diffs.
391
392
 
392
- VCM resolves `vcmDataDir` from `VCM_DATA_DIR`. If `VCM_DATA_DIR` is unset or empty, VCM uses `~/.vcm`. In Dev Containers, set `VCM_DATA_DIR=/workspace/.ai/vcm` through `containerEnv` so VCM app state survives container rebuilds.
393
+ VCM resolves `vcmDataDir` from `VCM_DATA_DIR`. If `VCM_DATA_DIR` is unset or empty, VCM uses `~/.vcm`. In Dev Containers, set `VCM_DATA_DIR=/workspace/.ai/vcm` and `VCM_SANDBOX=devcontainer` through `containerEnv` so VCM app state survives container rebuilds and VCM-managed Codex Reviewer sessions do not run a nested Codex sandbox.
393
394
 
394
395
  The sidebar `Settings` section also stores the UI theme preference in this file. The default is `system`, which follows the OS/browser color-scheme preference; users can cycle between `System`, `Light`, and `Dark`.
395
396
 
@@ -6,4 +6,11 @@ export function registerCodexHookRoutes(app, deps) {
6
6
  await deps.codexHookService.handleStopHook(request.body);
7
7
  return {};
8
8
  });
9
+ app.post("/api/hooks/codex-translator", async (request) => {
10
+ return deps.codexHookService.handleHook(request.body);
11
+ });
12
+ app.post("/api/hooks/codex-translator/stop", async (request) => {
13
+ await deps.codexHookService.handleStopHook(request.body);
14
+ return {};
15
+ });
9
16
  }
@@ -0,0 +1,50 @@
1
+ import { VcmError } from "../errors.js";
2
+ export function registerCodexTranslationRoutes(app, deps) {
3
+ app.get("/api/translation/codex/state", async () => {
4
+ const project = await requireCurrentProject(deps.projectService);
5
+ return deps.codexTranslationService.getState(project.repoRoot);
6
+ });
7
+ app.get("/api/translation/codex/source-files", async (request) => {
8
+ const project = await requireCurrentProject(deps.projectService);
9
+ return deps.codexTranslationService.browseSourceFiles(project.repoRoot, {
10
+ path: request.query.path,
11
+ query: request.query.query,
12
+ limit: request.query.limit === undefined ? undefined : Number(request.query.limit)
13
+ });
14
+ });
15
+ app.post("/api/translation/codex/files", async (request) => {
16
+ const project = await requireCurrentProject(deps.projectService);
17
+ return deps.codexTranslationService.createFileJob(project.repoRoot, request.body);
18
+ });
19
+ app.post("/api/translation/codex/bootstrap", async (request) => {
20
+ const project = await requireCurrentProject(deps.projectService);
21
+ return deps.codexTranslationService.createBootstrapRun(project.repoRoot, request.body);
22
+ });
23
+ app.get("/api/translation/codex/files/:jobId", async (request) => {
24
+ const project = await requireCurrentProject(deps.projectService);
25
+ return deps.codexTranslationService.readFileJobOutput(project.repoRoot, request.params.jobId);
26
+ });
27
+ app.post("/api/translation/codex/files/:jobId/promote", async (request) => {
28
+ const project = await requireCurrentProject(deps.projectService);
29
+ const targetPath = request.body?.targetPath?.trim();
30
+ if (!targetPath) {
31
+ throw new VcmError({
32
+ code: "TRANSLATION_PROMOTE_TARGET_REQUIRED",
33
+ message: "Promote target path is required.",
34
+ statusCode: 400
35
+ });
36
+ }
37
+ return deps.codexTranslationService.promoteFileJob(project.repoRoot, request.params.jobId, targetPath);
38
+ });
39
+ }
40
+ async function requireCurrentProject(projectService) {
41
+ const project = await projectService.getCurrentProject();
42
+ if (!project) {
43
+ throw new VcmError({
44
+ code: "PROJECT_NOT_CONNECTED",
45
+ message: "Connect a repository first.",
46
+ statusCode: 409
47
+ });
48
+ }
49
+ return project;
50
+ }
@@ -6,7 +6,7 @@ import process from "node:process";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { renderArchitectHarnessRules } from "../templates/harness/architect-agent.js";
8
8
  import { renderCoderHarnessRules } from "../templates/harness/coder-agent.js";
9
- import { renderCodexAgentsHarnessRules, renderCodexArchitecturePlanPrompt, renderCodexCliConfigHarnessRules, renderCodexConfigHarnessRules, renderCodexFinalDiffPrompt, renderCodexHooksHarnessRules, renderCodexReviewResultSchema, renderCodexValidationAdequacyPrompt, renderRequestCodexReviewTool, renderVcmCodexReviewGateSkillRules } from "../templates/harness/codex-review.js";
9
+ import { renderCodexAgentsHarnessRules, renderCodexArchitecturePlanPrompt, renderCodexCliConfigHarnessRules, renderCodexConfigHarnessRules, renderCodexFinalDiffPrompt, renderCodexHooksHarnessRules, renderCodexReviewResultSchema, renderCodexTranslatorAgentsHarnessRules, renderCodexTranslatorConfigHarnessRules, renderCodexValidationAdequacyPrompt, renderRequestCodexReviewTool, renderVcmCodexReviewGateSkillRules } from "../templates/harness/codex-review.js";
10
10
  import { renderRootClaudeHarnessRules } from "../templates/harness/claude-root.js";
11
11
  import { renderGitignoreHarnessRules } from "../templates/harness/gitignore.js";
12
12
  import { renderProjectManagerHarnessRules } from "../templates/harness/project-manager-agent.js";
@@ -109,6 +109,13 @@ const MANAGED_FILES = [
109
109
  commentStyle: "html",
110
110
  category: "codex-reviewer-agent",
111
111
  content: renderCodexAgentsHarnessRules()
112
+ },
113
+ {
114
+ path: ".ai/codex-translator/AGENTS.md",
115
+ title: "VCM Codex Translator",
116
+ commentStyle: "html",
117
+ category: "codex-translator-agent",
118
+ content: renderCodexTranslatorAgentsHarnessRules()
112
119
  }
113
120
  ];
114
121
  const DURABLE_DOC_TEMPLATES = [
@@ -186,6 +193,24 @@ const WHOLE_FILES = [
186
193
  mode: 0o644,
187
194
  content: renderCodexHooksHarnessRules()
188
195
  },
196
+ {
197
+ path: ".ai/codex-translator/config.toml",
198
+ category: "codex-translator-config",
199
+ mode: 0o644,
200
+ content: renderCodexTranslatorConfigHarnessRules()
201
+ },
202
+ {
203
+ path: ".ai/codex-translator/.codex/config.toml",
204
+ category: "codex-translator-hooks",
205
+ mode: 0o644,
206
+ content: renderCodexCliConfigHarnessRules()
207
+ },
208
+ {
209
+ path: ".ai/codex-translator/.codex/hooks.json",
210
+ category: "codex-translator-hooks",
211
+ mode: 0o644,
212
+ content: renderCodexHooksHarnessRules("codex-translator")
213
+ },
189
214
  {
190
215
  path: ".ai/codex/prompts/architecture-plan-gate.md",
191
216
  category: "codex-review-prompt",
@@ -432,6 +457,9 @@ function fixedDirectories() {
432
457
  ".ai/codex/.codex/",
433
458
  ".ai/codex/prompts/",
434
459
  ".ai/codex/schemas/",
460
+ ".ai/codex-translator/",
461
+ ".ai/codex-translator/.codex/",
462
+ ".ai/vcm/translations/",
435
463
  ".ai/vcm/codex-reviews/",
436
464
  ".ai/tools/",
437
465
  ".ai/generated/"
@@ -12,6 +12,7 @@ import { createGitAdapter } from "./adapters/git-adapter.js";
12
12
  import { createAppSettingsService } from "./services/app-settings-service.js";
13
13
  import { createClaudeTranscriptService } from "./services/claude-transcript-service.js";
14
14
  import { createCodexReviewService } from "./services/codex-review-service.js";
15
+ import { createCodexTranslationService } from "./services/codex-translation-service.js";
15
16
  import { createHarnessService, createScriptFixedHarnessInstaller } from "./services/harness-service.js";
16
17
  import { createNodeFileSystemAdapter } from "./adapters/filesystem.js";
17
18
  import { createNodePtyTerminalRuntime } from "./runtime/node-pty-runtime.js";
@@ -37,6 +38,7 @@ import { registerArtifactRoutes } from "./api/artifact-routes.js";
37
38
  import { registerClaudeHookRoutes } from "./api/claude-hook-routes.js";
38
39
  import { registerCodexHookRoutes } from "./api/codex-hook-routes.js";
39
40
  import { registerCodexReviewRoutes } from "./api/codex-review-routes.js";
41
+ import { registerCodexTranslationRoutes } from "./api/codex-translation-routes.js";
40
42
  import { registerHarnessRoutes } from "./api/harness-routes.js";
41
43
  import { registerMessageRoutes } from "./api/message-routes.js";
42
44
  import { registerProjectRoutes } from "./api/project-routes.js";
@@ -69,6 +71,10 @@ export async function createServer(deps, options = {}) {
69
71
  projectService: deps.projectService,
70
72
  codexReviewService: deps.codexReviewService
71
73
  });
74
+ registerCodexTranslationRoutes(app, {
75
+ projectService: deps.projectService,
76
+ codexTranslationService: deps.codexTranslationService
77
+ });
72
78
  registerProjectRoutes(app, { projectService: deps.projectService });
73
79
  registerHarnessRoutes(app, {
74
80
  projectService: deps.projectService,
@@ -169,7 +175,8 @@ export function createDefaultServerDeps(options = {}) {
169
175
  artifactService,
170
176
  projectService,
171
177
  taskService,
172
- apiUrl: options.apiUrl
178
+ apiUrl: options.apiUrl,
179
+ sandboxMode: process.env.VCM_SANDBOX
173
180
  });
174
181
  const commandDispatcher = createCommandDispatcher({
175
182
  runtime,
@@ -205,12 +212,18 @@ export function createDefaultServerDeps(options = {}) {
205
212
  sessionService,
206
213
  roundService
207
214
  });
215
+ const codexTranslationService = createCodexTranslationService({
216
+ fs,
217
+ runtime,
218
+ sessionService
219
+ });
208
220
  const transcripts = createClaudeTranscriptService();
209
221
  const translationService = createTranslationService({
210
222
  runtime,
211
223
  sessionRegistry: registry,
212
224
  transcripts,
213
225
  sessionService,
226
+ codexTranslationService,
214
227
  fs,
215
228
  projectService,
216
229
  appSettings,
@@ -250,7 +263,8 @@ export function createDefaultServerDeps(options = {}) {
250
263
  projectService,
251
264
  taskService,
252
265
  sessionService,
253
- roundService
266
+ roundService,
267
+ codexTranslationService
254
268
  });
255
269
  const diagnosticsService = createDiagnosticsService({
256
270
  appRoot: getAppRoot(),
@@ -270,6 +284,7 @@ export function createDefaultServerDeps(options = {}) {
270
284
  codexHookService,
271
285
  messageService,
272
286
  codexReviewService,
287
+ codexTranslationService,
273
288
  roundService,
274
289
  statusService,
275
290
  translationService,
@@ -42,7 +42,8 @@ export function createArtifactService(fs) {
42
42
  architect: path.posix.join(logsDir, "architect.log"),
43
43
  coder: path.posix.join(logsDir, "coder.log"),
44
44
  reviewer: path.posix.join(logsDir, "reviewer.log"),
45
- "codex-reviewer": path.posix.join(logsDir, "codex-reviewer.log")
45
+ "codex-reviewer": path.posix.join(logsDir, "codex-reviewer.log"),
46
+ "codex-translator": path.posix.join(logsDir, "codex-translator.log")
46
47
  },
47
48
  messageRoutePaths: getDefaultMessageRoutePaths(messagesDir),
48
49
  architecturePlanPath: path.posix.join(handoffDir, "architecture-plan.md"),
@@ -1,9 +1,9 @@
1
+ import { isCodexRoleName } from "../../shared/constants.js";
1
2
  import { VcmError } from "../errors.js";
2
3
  import { getTaskRuntimeRepoRoot } from "./task-service.js";
3
- const CODEX_REVIEWER_ROLE = "codex-reviewer";
4
4
  export function createCodexHookService(deps) {
5
5
  async function getHookContext(input) {
6
- if (input.role !== CODEX_REVIEWER_ROLE) {
6
+ if (!isCodexRoleName(input.role)) {
7
7
  throw new VcmError({
8
8
  code: "CODEX_HOOK_ROLE_INVALID",
9
9
  message: `Unknown Codex hook role: ${input.role}`,
@@ -14,7 +14,7 @@ export function createCodexHookService(deps) {
14
14
  if (!project) {
15
15
  throw new VcmError({
16
16
  code: "PROJECT_NOT_CONNECTED",
17
- message: "Connect a repository before accepting Codex Reviewer hooks.",
17
+ message: "Connect a repository before accepting Codex hooks.",
18
18
  statusCode: 409
19
19
  });
20
20
  }
@@ -32,14 +32,14 @@ export function createCodexHookService(deps) {
32
32
  if (eventName !== expectedEventName) {
33
33
  throw new VcmError({
34
34
  code: "CODEX_HOOK_EVENT_UNSUPPORTED",
35
- message: `Unsupported Codex Reviewer hook event for this endpoint: ${eventName}`,
35
+ message: `Unsupported Codex hook event for this endpoint: ${eventName}`,
36
36
  statusCode: 400
37
37
  });
38
38
  }
39
39
  const context = await getHookContext(input);
40
40
  const session = await deps.sessionService.recordRoleHookEvent(context.project.repoRoot, {
41
41
  taskSlug: input.taskSlug,
42
- role: CODEX_REVIEWER_ROLE,
42
+ role: input.role,
43
43
  eventName,
44
44
  sessionId: stringOrUndefined(input.event.session_id),
45
45
  transcriptPath: stringOrUndefined(input.event.transcript_path),
@@ -51,14 +51,17 @@ export function createCodexHookService(deps) {
51
51
  stateRepoRoot: context.taskRepoRoot,
52
52
  stateRoot: context.config.stateRoot,
53
53
  taskSlug: input.taskSlug,
54
- role: CODEX_REVIEWER_ROLE,
54
+ role: input.role,
55
55
  eventName
56
56
  });
57
+ if (input.role === "codex-translator") {
58
+ await deps.codexTranslationService?.handleCodexHook(context.project.repoRoot, eventName, input.taskSlug);
59
+ }
57
60
  return {
58
61
  ok: true,
59
62
  eventName,
60
63
  taskSlug: input.taskSlug,
61
- role: CODEX_REVIEWER_ROLE,
64
+ role: input.role,
62
65
  sessionUpdated: Boolean(session)
63
66
  };
64
67
  }
@@ -77,9 +80,9 @@ function parseHookEvent(value) {
77
80
  }
78
81
  throw new VcmError({
79
82
  code: "CODEX_HOOK_EVENT_UNSUPPORTED",
80
- message: `Unsupported Codex Reviewer hook event: ${String(value)}`,
83
+ message: `Unsupported Codex hook event: ${String(value)}`,
81
84
  statusCode: 400,
82
- hint: "VCM accepts Codex Reviewer UserPromptSubmit and Stop hooks only."
85
+ hint: "VCM accepts Codex UserPromptSubmit and Stop hooks only."
83
86
  });
84
87
  }
85
88
  function stringOrUndefined(value) {