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.
@@ -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
- const tasksDir = path.join(deps.projectService.getProjectDataRoot(repoRoot), "tasks");
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 instanceof Error ? error.message : "Translation failed.");
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 instanceof Error ? error.message : "Translation failed.");
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 instanceof Error ? error.message : "Translation failed.");
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 instanceof Error ? error.message : "Translation failed.");
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 instanceof Error ? error.message : "Translation failed.",
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 failed.",
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 failed.",
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 ?? "Translation failed.",
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
- return error instanceof Error ? error.message : "Translation failed.";
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 instanceof Error ? error.message : "Failed to dispatch Translator task.";
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 instanceof Error ? error.message : "Failed to finalize translation output.";
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
- ## Checks
14
-
15
- - \`architecture-plan\`: scope, affected files/contracts, Scaffold Manifest, dependencies, docs/generated context, proof points, Replan triggers, no task-only source comments.
16
- - \`validation-adequacy\`: review report covers the plan, public contracts, validation level, commands/results, skips/gaps/risks, final cleanup, durable testing docs impact.
17
- - \`final-diff\`: diff matches plan, no unapproved surface/dependency/docs, no \`VCM:CODE\`, no task-process comments, meaningful tests, fallible paths handled.
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