vibe-coding-master 0.3.16 → 0.3.18
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 +8 -7
- package/dist/backend/api/translation-routes.js +0 -13
- package/dist/backend/runtime/node-pty-runtime.js +13 -3
- package/dist/backend/server.js +1 -3
- package/dist/backend/services/app-settings-service.js +6 -31
- package/dist/backend/services/codex-translation-service.js +281 -130
- package/dist/backend/services/session-service.js +15 -8
- package/dist/backend/services/translation-service.js +198 -245
- package/dist/backend/templates/harness/codex-review.js +20 -8
- package/dist/shared/types/app-settings.js +5 -0
- package/dist/shared/types/session.js +5 -5
- package/dist/shared/types/translation.js +0 -5
- package/dist-frontend/assets/index-DOKW0Y5n.js +95 -0
- package/dist-frontend/assets/index-Dmefx9m7.css +32 -0
- package/dist-frontend/index.html +2 -2
- package/docs/codex-translation-plan.md +107 -63
- package/docs/gateway-design.md +2 -2
- package/docs/product-design.md +22 -22
- package/package.json +1 -1
- package/dist/backend/adapters/translation-provider.js +0 -145
- package/dist/backend/services/translation-prompts.js +0 -173
- package/dist-frontend/assets/index-BNJJ_Tcf.js +0 -92
- package/dist-frontend/assets/index-C1FPjOXU.css +0 -32
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ When Codex Review Gates are enabled for a task, or when a Codex Reviewer session
|
|
|
31
31
|
- Two-stage VCM harness setup: deterministic fixed install plus AI-assisted bootstrap.
|
|
32
32
|
- VCM-managed root rules, four role agents, repo-local VCM skills, Claude Code hooks, Codex Reviewer hooks, generated-context tools, and PR template.
|
|
33
33
|
- Rust generated context for module indexing and crate-external public surface indexing.
|
|
34
|
-
- Translation panel powered by
|
|
34
|
+
- Translation panel powered by the long-lived Codex Translator session.
|
|
35
35
|
- Mobile Gateway through Tencent iLink Bot API / Weixin DM, for talking to PM and managing tasks from Weixin.
|
|
36
36
|
- Durable task state, session state, raw terminal logs, handoff artifacts, and message history.
|
|
37
37
|
|
|
@@ -139,7 +139,7 @@ Important container notes:
|
|
|
139
139
|
|
|
140
140
|
- Install Claude Code inside the container, or make `claude` available in the container `PATH`.
|
|
141
141
|
- Make sure Claude Code authentication works inside the container.
|
|
142
|
-
- Make sure the container has network access to Claude services and
|
|
142
|
+
- Make sure the container has network access to Claude services and any configured Codex model endpoints 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
145
|
- Set `VCM_SANDBOX=devcontainer` so VCM-managed Codex Reviewer and Codex Translator sessions rely on the container boundary and do not start Codex's nested Linux sandbox.
|
|
@@ -388,7 +388,7 @@ Translation settings are local and stored in:
|
|
|
388
388
|
<vcmDataDir>/settings.json
|
|
389
389
|
```
|
|
390
390
|
|
|
391
|
-
The same file stores recent repository paths
|
|
391
|
+
The same file stores recent repository paths and global translation preferences such as enablement, auto-send, and target language.
|
|
392
392
|
|
|
393
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 and Codex Translator sessions do not run a nested Codex sandbox.
|
|
394
394
|
|
|
@@ -400,10 +400,11 @@ When Gateway is on, `Flow pause alert` is forced off because mobile notification
|
|
|
400
400
|
|
|
401
401
|
Translation behavior:
|
|
402
402
|
|
|
403
|
-
-
|
|
404
|
-
-
|
|
405
|
-
-
|
|
403
|
+
- Conversation translation is routed through the Codex Translator session and result files.
|
|
404
|
+
- Global translation controls live in the sidebar Translation section: enablement, auto-send, target language, bootstrap, memory update, and file translation.
|
|
405
|
+
- File and conversation translation share `<baseRepoRoot>/.ai/vcm/translations/`; conversation result files are temporary runtime artifacts.
|
|
406
406
|
- Claude Code output translation reads semantic Claude transcript JSONL files under `~/.claude/projects`, not raw PTY output.
|
|
407
|
+
- Claude Code prose output waits 10 seconds before dispatch so adjacent output can be translated in one Codex batch.
|
|
407
408
|
- VCM tails those transcript files in the backend. Closing the translation panel does not stop capture; the tailer stops only when the role session is stopped/restarted or the task is closed.
|
|
408
409
|
- Translation events are cached under the task runtime repo at `.ai/vcm/translation/<task>/<role>/<session-id>.jsonl` and delivered to the frontend through HTTP polling.
|
|
409
410
|
- The polling cursor is the next expected seq: `after=18` acknowledges seq `1..17` and returns seq `18+`; there is no snapshot mismatch error.
|
|
@@ -414,7 +415,7 @@ Translation behavior:
|
|
|
414
415
|
- Assistant prose renders Markdown in the panel, including headings, lists, code fences, tables, and links.
|
|
415
416
|
- Tool calls and tool results are preserved as dim one-line rows such as `● Bash({"command":"npm test"})`.
|
|
416
417
|
- User input uses one textarea. Press `Enter` to translate or send the current English draft; press `Shift+Enter` for a newline.
|
|
417
|
-
- After user input is translated, the
|
|
418
|
+
- After user input is translated, the translated draft is appended after the original text in the same textarea.
|
|
418
419
|
- `Send English` writes the current English draft to the active embedded terminal and submits it.
|
|
419
420
|
- Automatic terminal submission uses bracketed paste first, then sends Enter separately for Claude Code TUI reliability.
|
|
420
421
|
- The translation panel `Auto-send` toggle sends the translated draft automatically when translation succeeds without warnings.
|
|
@@ -2,19 +2,6 @@ import { isVcmRoleName } from "../../shared/constants.js";
|
|
|
2
2
|
import { VcmError } from "../errors.js";
|
|
3
3
|
import { getTaskRuntimeRepoRoot } from "../services/task-service.js";
|
|
4
4
|
export function registerTranslationRoutes(app, deps) {
|
|
5
|
-
app.get("/api/translation/settings", async () => {
|
|
6
|
-
return deps.translationService.getSettings();
|
|
7
|
-
});
|
|
8
|
-
app.put("/api/translation/settings", async (request) => {
|
|
9
|
-
const { apiKey, ...settings } = request.body ?? {};
|
|
10
|
-
return deps.translationService.updateSettings(settings, apiKey !== undefined ? { apiKey } : undefined);
|
|
11
|
-
});
|
|
12
|
-
app.get("/api/translation/prompts", async () => {
|
|
13
|
-
return deps.translationService.getPromptPreviews();
|
|
14
|
-
});
|
|
15
|
-
app.post("/api/translation/test", async () => {
|
|
16
|
-
return deps.translationService.testProvider();
|
|
17
|
-
});
|
|
18
5
|
app.post("/api/tasks/:taskSlug/sessions/:role/translation/start", async (request) => {
|
|
19
6
|
const project = await requireCurrentProject(deps.projectService);
|
|
20
7
|
const role = parseRole(request.params.role);
|
|
@@ -16,7 +16,9 @@ export function createNodePtyTerminalRuntime(deps) {
|
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
18
|
const create = async (input, sessionId = id()) => {
|
|
19
|
-
|
|
19
|
+
if (input.logPath) {
|
|
20
|
+
await deps.fs.ensureDir(input.logPath.replace(/[/\\][^/\\]+$/, ""));
|
|
21
|
+
}
|
|
20
22
|
const child = pty.spawn(input.command, input.args, {
|
|
21
23
|
cwd: input.cwd,
|
|
22
24
|
env: buildPtyEnvironment(process.env, input.env),
|
|
@@ -33,7 +35,9 @@ export function createNodePtyTerminalRuntime(deps) {
|
|
|
33
35
|
startedAt: now(),
|
|
34
36
|
exitCode: null
|
|
35
37
|
};
|
|
36
|
-
const logWriter =
|
|
38
|
+
const logWriter = input.logPath
|
|
39
|
+
? createTerminalLogWriter(deps.fs, input.logPath, deps.onLogWriteError ?? defaultLogWriteErrorHandler)
|
|
40
|
+
: createNoopTerminalLogWriter();
|
|
37
41
|
const entry = {
|
|
38
42
|
input,
|
|
39
43
|
session,
|
|
@@ -134,7 +138,7 @@ export function createNodePtyTerminalRuntime(deps) {
|
|
|
134
138
|
subscribe(sessionId, listener, options = {}) {
|
|
135
139
|
const entry = getEntry(entries, sessionId);
|
|
136
140
|
entry.listeners.add(listener);
|
|
137
|
-
if (options.replay !== false) {
|
|
141
|
+
if (options.replay !== false && entry.input.logPath) {
|
|
138
142
|
void readTerminalReplayText(deps.fs, entry.input.logPath)
|
|
139
143
|
.then((data) => {
|
|
140
144
|
if (!data || !entry.listeners.has(listener)) {
|
|
@@ -171,6 +175,12 @@ function disposeEntry(entries, entry, status, exitCode) {
|
|
|
171
175
|
entries.delete(entry.session.id);
|
|
172
176
|
return true;
|
|
173
177
|
}
|
|
178
|
+
function createNoopTerminalLogWriter() {
|
|
179
|
+
return {
|
|
180
|
+
append() { },
|
|
181
|
+
async close() { }
|
|
182
|
+
};
|
|
183
|
+
}
|
|
174
184
|
export function createTerminalLogWriter(fs, logPath, onError) {
|
|
175
185
|
let closed = false;
|
|
176
186
|
let pending = Promise.resolve();
|
package/dist/backend/server.js
CHANGED
|
@@ -16,7 +16,6 @@ import { createCodexTranslationService } from "./services/codex-translation-serv
|
|
|
16
16
|
import { createHarnessService, createScriptFixedHarnessInstaller } from "./services/harness-service.js";
|
|
17
17
|
import { createNodeFileSystemAdapter } from "./adapters/filesystem.js";
|
|
18
18
|
import { createNodePtyTerminalRuntime } from "./runtime/node-pty-runtime.js";
|
|
19
|
-
import { createOpenAiCompatibleTranslationProvider } from "./adapters/translation-provider.js";
|
|
20
19
|
import { registerGatewayRoutes } from "./api/gateway-routes.js";
|
|
21
20
|
import { registerDiagnosticsRoutes } from "./api/diagnostics-routes.js";
|
|
22
21
|
import { createWeixinIlinkChannel } from "./gateway/channels/weixin-ilink-channel.js";
|
|
@@ -227,8 +226,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
227
226
|
codexTranslationService,
|
|
228
227
|
fs,
|
|
229
228
|
projectService,
|
|
230
|
-
appSettings
|
|
231
|
-
provider: createOpenAiCompatibleTranslationProvider()
|
|
229
|
+
appSettings
|
|
232
230
|
});
|
|
233
231
|
const gatewaySettings = createGatewaySettingsService({ fs });
|
|
234
232
|
const gatewayAudit = createGatewayAuditLog({
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { VCM_ROLE_NAMES } from "../../shared/constants.js";
|
|
4
4
|
import { CODEX_REVIEW_GATES } from "../../shared/types/codex-review.js";
|
|
5
|
-
import { createDefaultLaunchTemplate, DEFAULT_TRANSLATION_TARGET_LANGUAGE, TRANSLATION_TARGET_LANGUAGE_OPTIONS } from "../../shared/types/app-settings.js";
|
|
5
|
+
import { createDefaultLaunchTemplate, DEFAULT_TRANSLATION_OUTPUT_MODE, DEFAULT_TRANSLATION_TARGET_LANGUAGE, TRANSLATION_OUTPUT_MODE_OPTIONS, TRANSLATION_TARGET_LANGUAGE_OPTIONS } from "../../shared/types/app-settings.js";
|
|
6
6
|
import { CLAUDE_MODEL_OPTIONS, SESSION_EFFORT_OPTIONS } from "../../shared/types/session.js";
|
|
7
7
|
import { resolveVcmDataDir } from "../vcm-data-dir.js";
|
|
8
8
|
const MAX_RECENT_REPOSITORIES = 5;
|
|
@@ -71,18 +71,6 @@ export function createAppSettingsService(deps) {
|
|
|
71
71
|
});
|
|
72
72
|
return preferences;
|
|
73
73
|
},
|
|
74
|
-
async updateTranslationConfig(config) {
|
|
75
|
-
const current = await loadSettings();
|
|
76
|
-
const translation = normalizeTranslationConfig(config) ?? { settings: {}, secrets: {} };
|
|
77
|
-
await saveSettings({
|
|
78
|
-
...current,
|
|
79
|
-
translation
|
|
80
|
-
});
|
|
81
|
-
return translation;
|
|
82
|
-
},
|
|
83
|
-
async getTranslationConfig() {
|
|
84
|
-
return (await loadSettings()).translation;
|
|
85
|
-
},
|
|
86
74
|
async getRecentRepositoryPaths() {
|
|
87
75
|
return (await loadSettings()).recentRepositoryPaths;
|
|
88
76
|
},
|
|
@@ -226,7 +214,6 @@ function normalizeSettingsFile(input) {
|
|
|
226
214
|
const settings = {
|
|
227
215
|
version: 1,
|
|
228
216
|
preferences: normalizePreferences(input.preferences),
|
|
229
|
-
translation: normalizeTranslationConfig(input.translation),
|
|
230
217
|
recentRepositoryPaths: normalizeRecentRepositoryPaths(input.recentRepositoryPaths)
|
|
231
218
|
};
|
|
232
219
|
const codexReview = normalizeCodexReviewSettingsState(input.codexReview);
|
|
@@ -247,6 +234,7 @@ function normalizePreferences(input) {
|
|
|
247
234
|
translationEnabled: candidate.translationEnabled === true,
|
|
248
235
|
translationAutoSendEnabled: candidate.translationAutoSendEnabled === true,
|
|
249
236
|
translationTargetLanguage: normalizeTranslationTargetLanguage(candidate.translationTargetLanguage),
|
|
237
|
+
translationOutputMode: normalizeTranslationOutputMode(candidate.translationOutputMode),
|
|
250
238
|
launchTemplate: normalizeLaunchTemplate(candidate.launchTemplate)
|
|
251
239
|
};
|
|
252
240
|
}
|
|
@@ -266,6 +254,10 @@ function normalizeTranslationTargetLanguage(input) {
|
|
|
266
254
|
const option = TRANSLATION_TARGET_LANGUAGE_OPTIONS.find((current) => current.value === input);
|
|
267
255
|
return option?.value ?? DEFAULT_TRANSLATION_TARGET_LANGUAGE;
|
|
268
256
|
}
|
|
257
|
+
function normalizeTranslationOutputMode(input) {
|
|
258
|
+
const option = TRANSLATION_OUTPUT_MODE_OPTIONS.find((current) => current.value === input);
|
|
259
|
+
return option?.value ?? DEFAULT_TRANSLATION_OUTPUT_MODE;
|
|
260
|
+
}
|
|
269
261
|
function normalizeLaunchTemplate(input) {
|
|
270
262
|
const defaults = createDefaultLaunchTemplate();
|
|
271
263
|
if (!isObject(input)) {
|
|
@@ -310,23 +302,6 @@ function normalizeSessionEffort(input, fallback) {
|
|
|
310
302
|
const effort = SESSION_EFFORT_OPTIONS.find((option) => option.value === input);
|
|
311
303
|
return effort?.value ?? fallback;
|
|
312
304
|
}
|
|
313
|
-
function normalizeTranslationConfig(input) {
|
|
314
|
-
if (!input || typeof input !== "object") {
|
|
315
|
-
return undefined;
|
|
316
|
-
}
|
|
317
|
-
const candidate = input;
|
|
318
|
-
const rawSettings = isObject(candidate.settings) ? candidate.settings : {};
|
|
319
|
-
const rawSecrets = isObject(candidate.secrets) ? candidate.secrets : {};
|
|
320
|
-
const { apiKey: settingsApiKey, ...settings } = rawSettings;
|
|
321
|
-
const apiKey = rawSecrets.apiKey ?? settingsApiKey;
|
|
322
|
-
return {
|
|
323
|
-
settings,
|
|
324
|
-
secrets: {
|
|
325
|
-
...rawSecrets,
|
|
326
|
-
...(apiKey !== undefined ? { apiKey } : {})
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
305
|
function normalizeRecentRepositoryPaths(input) {
|
|
331
306
|
const paths = Array.isArray(input) ? input : [];
|
|
332
307
|
const seen = new Set();
|