vibe-coding-master 0.4.17 → 0.4.19
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/dist/backend/api/translation-routes.js +12 -0
- package/dist/backend/gateway/gateway-service.js +0 -1
- package/dist/backend/services/task-service.js +23 -10
- package/dist/backend/services/translation-service.js +64 -11
- package/dist/backend/services/translation-worker-service.js +19 -2
- package/dist/backend/templates/harness/gate-review.js +44 -6
- package/dist-frontend/assets/index-BrY-xd6U.js +95 -0
- package/dist-frontend/assets/{index-D0LBjl2L.css → index-D1LTJ-sY.css} +1 -1
- package/dist-frontend/index.html +2 -2
- package/docs/gateway-design.md +3 -3
- package/docs/product-design.md +3 -5
- package/package.json +1 -1
- package/dist-frontend/assets/index-B79szIZT.js +0 -95
|
@@ -29,6 +29,18 @@ export function registerTranslationRoutes(app, deps) {
|
|
|
29
29
|
...(request.body ?? { text: "" })
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
|
+
app.post("/api/tasks/:taskSlug/sessions/:role/translation/manual-output", async (request) => {
|
|
33
|
+
const project = await requireCurrentProject(deps.projectService);
|
|
34
|
+
const role = parseRole(request.params.role);
|
|
35
|
+
const task = await deps.taskService.loadTask(project.repoRoot, request.params.taskSlug);
|
|
36
|
+
return deps.translationService.translateManualOutput({
|
|
37
|
+
repoRoot: project.repoRoot,
|
|
38
|
+
taskRepoRoot: getTaskRuntimeRepoRoot(task),
|
|
39
|
+
taskSlug: request.params.taskSlug,
|
|
40
|
+
role,
|
|
41
|
+
text: request.body?.text ?? ""
|
|
42
|
+
});
|
|
43
|
+
});
|
|
32
44
|
app.post("/api/tasks/:taskSlug/sessions/:role/translation/send", async (request) => {
|
|
33
45
|
const project = await requireCurrentProject(deps.projectService);
|
|
34
46
|
const role = parseRole(request.params.role);
|
|
@@ -592,7 +592,6 @@ export function createGatewayService(deps) {
|
|
|
592
592
|
}
|
|
593
593
|
const enabled = await syncDesktopContext(await deps.settings.updateSettings({ enabled: true }));
|
|
594
594
|
await ensurePolling();
|
|
595
|
-
await deps.appSettings.updatePreferences({ flowPauseAlerts: false });
|
|
596
595
|
const lines = [
|
|
597
596
|
"Gateway started.",
|
|
598
597
|
"Full mobile commands and PM messages are now enabled.",
|
|
@@ -18,6 +18,16 @@ export function createTaskService(deps) {
|
|
|
18
18
|
statusCode: 409
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
+
const existingTasks = await readStoredTasks(deps.fs, taskStoreRoot);
|
|
22
|
+
const activeTask = existingTasks.find((task) => task.cleanupStatus !== "cleaned");
|
|
23
|
+
if (activeTask) {
|
|
24
|
+
throw new VcmError({
|
|
25
|
+
code: "ACTIVE_TASK_EXISTS",
|
|
26
|
+
message: `A task is already active for this project: ${activeTask.taskSlug}`,
|
|
27
|
+
statusCode: 409,
|
|
28
|
+
hint: "Close the current task before creating a new one."
|
|
29
|
+
});
|
|
30
|
+
}
|
|
21
31
|
if (await deps.git.branchExists(repoRoot, taskBranch)) {
|
|
22
32
|
throw new VcmError({
|
|
23
33
|
code: "TASK_BRANCH_EXISTS",
|
|
@@ -81,16 +91,7 @@ export function createTaskService(deps) {
|
|
|
81
91
|
return task;
|
|
82
92
|
},
|
|
83
93
|
async listTasks(repoRoot) {
|
|
84
|
-
|
|
85
|
-
if (!(await deps.fs.pathExists(tasksDir))) {
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
const entries = await deps.fs.readDir(tasksDir);
|
|
89
|
-
const tasks = [];
|
|
90
|
-
for (const entry of entries.filter((candidate) => candidate.endsWith(".json"))) {
|
|
91
|
-
tasks.push(await deps.fs.readJson(path.join(tasksDir, entry)));
|
|
92
|
-
}
|
|
93
|
-
return tasks.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
94
|
+
return readStoredTasks(deps.fs, deps.projectService.getProjectDataRoot(repoRoot));
|
|
94
95
|
},
|
|
95
96
|
async loadTask(repoRoot, taskSlug) {
|
|
96
97
|
assertValidTaskSlug(taskSlug);
|
|
@@ -149,6 +150,18 @@ export function createTaskService(deps) {
|
|
|
149
150
|
}
|
|
150
151
|
};
|
|
151
152
|
}
|
|
153
|
+
async function readStoredTasks(fs, taskStoreRoot) {
|
|
154
|
+
const tasksDir = path.join(taskStoreRoot, "tasks");
|
|
155
|
+
if (!(await fs.pathExists(tasksDir))) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
const entries = await fs.readDir(tasksDir);
|
|
159
|
+
const tasks = [];
|
|
160
|
+
for (const entry of entries.filter((candidate) => candidate.endsWith(".json"))) {
|
|
161
|
+
tasks.push(await fs.readJson(path.join(tasksDir, entry)));
|
|
162
|
+
}
|
|
163
|
+
return tasks.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
164
|
+
}
|
|
152
165
|
export function getTaskRuntimeRepoRoot(task) {
|
|
153
166
|
return task.worktreePath;
|
|
154
167
|
}
|
|
@@ -165,7 +165,7 @@ export function createTranslationService(deps) {
|
|
|
165
165
|
const replaySince = getTranscriptReplaySince(roleSession);
|
|
166
166
|
state.unsubscribeTranscript = deps.transcripts.subscribeToRoleSession(roleSession, (event) => {
|
|
167
167
|
void handleTranscriptEvent(roleSession.id, event).catch((error) => {
|
|
168
|
-
publishError(roleSession.id, error
|
|
168
|
+
publishError(roleSession.id, normalizeTranslationError(error, "Process Claude transcript event for translation failed."));
|
|
169
169
|
});
|
|
170
170
|
}, {
|
|
171
171
|
onError(error) {
|
|
@@ -277,13 +277,13 @@ export function createTranslationService(deps) {
|
|
|
277
277
|
}
|
|
278
278
|
if (delayMs <= 0) {
|
|
279
279
|
void flushClaudeOutputTranslations(sessionId).catch((error) => {
|
|
280
|
-
publishError(sessionId, error
|
|
280
|
+
publishError(sessionId, normalizeTranslationError(error, "Flush batched Claude output translations failed."));
|
|
281
281
|
});
|
|
282
282
|
return;
|
|
283
283
|
}
|
|
284
284
|
state.outputBatch.timer = setTimeout(() => {
|
|
285
285
|
void flushClaudeOutputTranslations(sessionId).catch((error) => {
|
|
286
|
-
publishError(sessionId, error
|
|
286
|
+
publishError(sessionId, normalizeTranslationError(error, "Flush delayed Claude output translations failed."));
|
|
287
287
|
});
|
|
288
288
|
}, delayMs);
|
|
289
289
|
}
|
|
@@ -355,14 +355,14 @@ export function createTranslationService(deps) {
|
|
|
355
355
|
}
|
|
356
356
|
publishStatus(sessionId, hasFailure ? "failed" : "ready");
|
|
357
357
|
}).catch((error) => {
|
|
358
|
-
publishError(sessionId, error
|
|
358
|
+
publishError(sessionId, normalizeTranslationError(error, "Run queued Claude output translation failed."));
|
|
359
359
|
});
|
|
360
360
|
}
|
|
361
361
|
function markOutputTranslationFailed(sessionId, entry, error) {
|
|
362
362
|
const failed = {
|
|
363
363
|
...entry,
|
|
364
364
|
status: "failed",
|
|
365
|
-
error: error
|
|
365
|
+
error: normalizeTranslationError(error, "Claude output translation failed."),
|
|
366
366
|
completedAt: now()
|
|
367
367
|
};
|
|
368
368
|
replaceEntry(sessionId, failed);
|
|
@@ -428,7 +428,7 @@ export function createTranslationService(deps) {
|
|
|
428
428
|
taskSlug: entry.taskSlug,
|
|
429
429
|
role: entry.role,
|
|
430
430
|
sourceText: entry.sourceText,
|
|
431
|
-
error: entry.error ?? "Translation
|
|
431
|
+
error: entry.error ?? "Translation failure reason was not recorded.",
|
|
432
432
|
failedAt: entry.completedAt ?? now(),
|
|
433
433
|
retryCount: existing?.retryCount ?? 0,
|
|
434
434
|
lastRetryAt: existing?.lastRetryAt
|
|
@@ -488,7 +488,7 @@ export function createTranslationService(deps) {
|
|
|
488
488
|
taskSlug: original.taskSlug,
|
|
489
489
|
role: original.role,
|
|
490
490
|
sourceText: original.sourceText,
|
|
491
|
-
error: original.error ?? "Translation
|
|
491
|
+
error: original.error ?? "Translation failure reason was not recorded.",
|
|
492
492
|
failedAt: original.completedAt ?? now(),
|
|
493
493
|
retryCount: 0
|
|
494
494
|
};
|
|
@@ -707,7 +707,7 @@ export function createTranslationService(deps) {
|
|
|
707
707
|
const failed = {
|
|
708
708
|
...entry,
|
|
709
709
|
status: "failed",
|
|
710
|
-
error: normalizeTranslationError(error),
|
|
710
|
+
error: normalizeTranslationError(error, "Composer input translation failed."),
|
|
711
711
|
completedAt: now()
|
|
712
712
|
};
|
|
713
713
|
if (roleSession) {
|
|
@@ -715,11 +715,50 @@ export function createTranslationService(deps) {
|
|
|
715
715
|
}
|
|
716
716
|
throw new VcmError({
|
|
717
717
|
code: "TRANSLATION_FAILED",
|
|
718
|
-
message: failed.error ?? "
|
|
718
|
+
message: failed.error ?? "Composer input translation failed.",
|
|
719
719
|
statusCode: 502
|
|
720
720
|
});
|
|
721
721
|
}
|
|
722
722
|
},
|
|
723
|
+
async translateManualOutput(input) {
|
|
724
|
+
const config = await loadConfig();
|
|
725
|
+
if (!input.text.trim()) {
|
|
726
|
+
throw new VcmError({
|
|
727
|
+
code: "TRANSLATION_INPUT_EMPTY",
|
|
728
|
+
message: "Manual translation input cannot be empty.",
|
|
729
|
+
statusCode: 400
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
const roleSession = await deps.sessionService.getRoleSession(input.repoRoot, input.taskSlug, input.role);
|
|
733
|
+
if (!roleSession || roleSession.status !== "running") {
|
|
734
|
+
throw new VcmError({
|
|
735
|
+
code: "SESSION_NOT_RUNNING",
|
|
736
|
+
message: `${input.role} session is not running.`,
|
|
737
|
+
statusCode: 409
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
await prepareCache({
|
|
741
|
+
repoRoot: input.taskRepoRoot ?? input.repoRoot,
|
|
742
|
+
baseRepoRoot: input.repoRoot,
|
|
743
|
+
taskSlug: input.taskSlug,
|
|
744
|
+
role: input.role,
|
|
745
|
+
sessionId: roleSession.id
|
|
746
|
+
});
|
|
747
|
+
startTranscriptTail(roleSession);
|
|
748
|
+
const entry = startClaudeOutputTranslation(roleSession.id, input.text, config, {
|
|
749
|
+
replaceExisting: false,
|
|
750
|
+
flushImmediately: true
|
|
751
|
+
});
|
|
752
|
+
if (!entry) {
|
|
753
|
+
throw new VcmError({
|
|
754
|
+
code: "TRANSLATION_NOT_STARTED",
|
|
755
|
+
message: "Manual translation could not be queued.",
|
|
756
|
+
statusCode: 409,
|
|
757
|
+
hint: "Check that the role session is still running and try again."
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
return entry;
|
|
761
|
+
},
|
|
723
762
|
async sendTranslatedInput(input) {
|
|
724
763
|
await writeToCurrentRole(input.repoRoot, input.taskSlug, input.role, input.englishText);
|
|
725
764
|
},
|
|
@@ -1098,6 +1137,20 @@ function upsertEntry(entries, entry) {
|
|
|
1098
1137
|
function getTranslationCachePath(repoRoot, stateRoot, taskSlug, role, sessionId) {
|
|
1099
1138
|
return path.join(repoRoot, stateRoot, "translation", taskSlug, role, `${sessionId}.jsonl`);
|
|
1100
1139
|
}
|
|
1101
|
-
function normalizeTranslationError(error) {
|
|
1102
|
-
|
|
1140
|
+
function normalizeTranslationError(error, fallback = "Translation failed before VCM could identify the failing stage.") {
|
|
1141
|
+
if (error instanceof Error) {
|
|
1142
|
+
return error.message || fallback;
|
|
1143
|
+
}
|
|
1144
|
+
if (typeof error === "string" && error.trim()) {
|
|
1145
|
+
return `${fallback} Reason: ${error}`;
|
|
1146
|
+
}
|
|
1147
|
+
if (error === undefined) {
|
|
1148
|
+
return fallback;
|
|
1149
|
+
}
|
|
1150
|
+
try {
|
|
1151
|
+
return `${fallback} Non-Error value: ${JSON.stringify(error)}`;
|
|
1152
|
+
}
|
|
1153
|
+
catch {
|
|
1154
|
+
return `${fallback} Non-Error value: ${String(error)}`;
|
|
1155
|
+
}
|
|
1103
1156
|
}
|
|
@@ -226,7 +226,7 @@ export function createTranslationWorkerService(deps) {
|
|
|
226
226
|
const failedAt = now();
|
|
227
227
|
for (const item of failedItems) {
|
|
228
228
|
item.status = "failed";
|
|
229
|
-
item.error = error
|
|
229
|
+
item.error = describeWorkerError(error, "Dispatch Translator task failed.");
|
|
230
230
|
item.updatedAt = failedAt;
|
|
231
231
|
}
|
|
232
232
|
queue.activeItemId = undefined;
|
|
@@ -437,7 +437,7 @@ export function createTranslationWorkerService(deps) {
|
|
|
437
437
|
}
|
|
438
438
|
catch (error) {
|
|
439
439
|
active.status = "failed";
|
|
440
|
-
active.error = error
|
|
440
|
+
active.error = describeWorkerError(error, "Finalize translation output failed.");
|
|
441
441
|
active.updatedAt = now();
|
|
442
442
|
queue.updatedAt = active.updatedAt;
|
|
443
443
|
await saveQueue(repoRoot, queue);
|
|
@@ -1847,3 +1847,20 @@ function invalidResult(message) {
|
|
|
1847
1847
|
statusCode: 422
|
|
1848
1848
|
});
|
|
1849
1849
|
}
|
|
1850
|
+
function describeWorkerError(error, fallback) {
|
|
1851
|
+
if (error instanceof Error) {
|
|
1852
|
+
return error.message || fallback;
|
|
1853
|
+
}
|
|
1854
|
+
if (typeof error === "string" && error.trim()) {
|
|
1855
|
+
return `${fallback} Reason: ${error}`;
|
|
1856
|
+
}
|
|
1857
|
+
if (error === undefined) {
|
|
1858
|
+
return fallback;
|
|
1859
|
+
}
|
|
1860
|
+
try {
|
|
1861
|
+
return `${fallback} Non-Error value: ${JSON.stringify(error)}`;
|
|
1862
|
+
}
|
|
1863
|
+
catch {
|
|
1864
|
+
return `${fallback} Non-Error value: ${String(error)}`;
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
@@ -10,11 +10,49 @@ Return only:
|
|
|
10
10
|
- \`approve\`: no gate-blocking finding.
|
|
11
11
|
- \`request_changes\`: evidence is missing, stale, contradictory, incomplete, or unsafe.
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
## Architecture Plan Gate
|
|
14
|
+
|
|
15
|
+
Read \`.claude/agents/architect.md\`; use coder/reviewer definitions only when
|
|
16
|
+
judging implementation or validation boundaries. Verify the required plan
|
|
17
|
+
structure, evidence, Scaffold Manifest, proof points, Replan triggers, and no
|
|
18
|
+
task-only source comments.
|
|
19
|
+
|
|
20
|
+
Focus on architectural soundness. Request changes when module boundaries,
|
|
21
|
+
public surface impact, dependency direction, state ownership, lifecycle,
|
|
22
|
+
failure paths, concurrency/restart behavior, docs/generated-context impact, or
|
|
23
|
+
key design decisions are missing, contradictory, unsafe, left for coder to
|
|
24
|
+
guess, or conflict with current project architecture.
|
|
25
|
+
|
|
26
|
+
## Validation Adequacy Gate
|
|
27
|
+
|
|
28
|
+
Read \`.claude/agents/reviewer.md\`; use architect/coder definitions to compare
|
|
29
|
+
validation against the plan and implementation test responsibilities. Verify
|
|
30
|
+
plan coverage, public contracts, validation level, commands/results,
|
|
31
|
+
skips/gaps/risks, final cleanup, and durable testing docs impact.
|
|
32
|
+
|
|
33
|
+
Focus on whether validation matches risk. Request changes when important user
|
|
34
|
+
or system paths lack integration or E2E case coverage, or when the review
|
|
35
|
+
report does not explain why such coverage is unnecessary or unavailable. Pay
|
|
36
|
+
special attention to module boundaries, public contracts, UI flows,
|
|
37
|
+
CLI/tooling, hooks, sessions, persistence, worktrees, and external process
|
|
38
|
+
behavior.
|
|
39
|
+
|
|
40
|
+
## Final Diff Gate
|
|
41
|
+
|
|
42
|
+
Read \`.claude/agents/coder.md\`; use architect/reviewer definitions to compare
|
|
43
|
+
the final diff against the approved plan and validation evidence. Check that
|
|
44
|
+
the diff matches plan, has no unapproved surface/dependency/docs changes, no
|
|
45
|
+
\`VCM:CODE\`, no task-process comments, meaningful tests, and fallible paths
|
|
46
|
+
handled.
|
|
47
|
+
|
|
48
|
+
Focus on code quality and boundary-condition robustness. Request changes when
|
|
49
|
+
the code violates project style, duplicates existing patterns unnecessarily,
|
|
50
|
+
adds avoidable abstraction, leaves debug/task-only artifacts, handles errors
|
|
51
|
+
inconsistently, changes files outside scope, weakens tests, or misses important
|
|
52
|
+
boundary conditions: empty/missing inputs, invalid data, permissions, external
|
|
53
|
+
command failure, partial writes, retries, concurrency, repeated UI actions,
|
|
54
|
+
stale state, restart recovery, cleanup, compatibility, or public API
|
|
55
|
+
validation.
|
|
18
56
|
|
|
19
57
|
## Output
|
|
20
58
|
|
|
@@ -29,7 +67,7 @@ Summary: <one or two sentences>
|
|
|
29
67
|
|
|
30
68
|
Findings must include severity, title, evidence, expected, gap, and risk.
|
|
31
69
|
|
|
32
|
-
Do not edit code, tests, durable docs, role files, route files, or handoff artifacts. Do not choose owners, fixes, Replan, or user-intervention needs.`;
|
|
70
|
+
Do not run tests. Review only code, architecture, and documents; do not perform validation. Do not edit code, tests, durable docs, role files, route files, or handoff artifacts. Do not choose owners, fixes, Replan, or user-intervention needs.`;
|
|
33
71
|
}
|
|
34
72
|
export function renderTranslatorAgentRules() {
|
|
35
73
|
return `## Role
|