vibe-coding-master 0.3.21 → 0.3.23

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
@@ -237,7 +237,7 @@ the base repo has uncommitted changes, when the current branch has no upstream,
237
237
  or when the active task is an inline task using the base repo directly. It does
238
238
  not stash, merge, or mutate task worktrees.
239
239
 
240
- When VCM is connected to an active task, the bottom of the sidebar shows a task status dock. It stays outside the collapsible groups and shows the active VCM Session title, task status, start time, total elapsed time, total Round count, and role active runtime. If a Round is currently running, the dock also shows the Current Round start time, total elapsed time, role active runtime, and Turn count.
240
+ When VCM is connected to an active task, the bottom of the sidebar shows a task status dock. It stays outside the collapsible groups and shows the active VCM Session title, task status, start time, total elapsed time, total Round count, and role active runtime. The dock also shows the Current Round while it is running, or the Last Round after a flow pause, including start time, total elapsed time, role active runtime, Turn count, and Round status.
241
241
 
242
242
  ## Mobile Gateway
243
243
 
@@ -586,7 +586,7 @@ The normal path is timer-driven: `Stop` starts a backend timer, and `UserPromptS
586
586
 
587
587
  When `Flow pause alert` is enabled, the frontend polls the task Round state and deduplicates each stopped Round so the same stopped state does not alert on every poll. Flow duration is measured from the first `UserPromptSubmit` to `stoppedAt`, falling back to the last `Stop` when needed. If the flow lasted less than 2 minutes, it plays the local chime 3 times at 1.4 second intervals. If the flow lasted 2 minutes or longer, it shows a modal alert and repeats the local chime until the user clicks `Confirm`. A stopped Round can mean normal completion, user decision needed, dispatch failure, or another workflow interruption; the point is to get the user to look with the right amount of urgency.
588
588
 
589
- The Current Round dock separates wall-clock Round duration from role active runtime. `Total` is `now - Round.startedAt`; `Role runtime` is only the accumulated time between each Turn's `UserPromptSubmit` and `Stop`; `Turn count` is the number of accepted prompts inside the current Round.
589
+ The Round dock separates wall-clock Round duration from role active runtime. For a running Round, `Total` is `now - Round.startedAt`; for a stopped Round, it is `stoppedAt - Round.startedAt`. `Role runtime` is only the accumulated time between each Turn's `UserPromptSubmit` and `Stop`; `Turn count` is the number of accepted prompts inside the Round.
590
590
 
591
591
  ## Resume Behavior
592
592
 
@@ -64,11 +64,18 @@ export function registerArtifactRoutes(app, deps) {
64
64
  const task = await deps.taskService.loadTask(project.repoRoot, request.params.taskSlug);
65
65
  const taskRepoRoot = getTaskRuntimeRepoRoot(task);
66
66
  const paths = deps.artifactService.getHandoffPaths(taskRepoRoot, task.handoffDir);
67
+ const artifactPath = paths.roleLogPaths[request.params.role];
68
+ if (!artifactPath) {
69
+ return {
70
+ role: request.params.role,
71
+ content: ""
72
+ };
73
+ }
67
74
  return {
68
75
  role: request.params.role,
69
76
  content: await deps.artifactService.readArtifact({
70
77
  repoRoot: taskRepoRoot,
71
- artifactPath: paths.roleLogPaths[request.params.role]
78
+ artifactPath
72
79
  })
73
80
  };
74
81
  });
@@ -4,6 +4,30 @@ export function registerCodexTranslationRoutes(app, deps) {
4
4
  const project = await requireCurrentProject(deps.projectService);
5
5
  return deps.codexTranslationService.getState(project.repoRoot);
6
6
  });
7
+ app.get("/api/translation/codex/session", async () => {
8
+ const project = await requireCurrentProject(deps.projectService);
9
+ return (await deps.sessionService.getProjectTranslatorSession(project.repoRoot)) ?? null;
10
+ });
11
+ app.post("/api/translation/codex/session/ensure", async (request) => {
12
+ const project = await requireCurrentProject(deps.projectService);
13
+ return deps.sessionService.ensureProjectTranslatorSession(project.repoRoot, request.body);
14
+ });
15
+ app.post("/api/translation/codex/session/start", async (request) => {
16
+ const project = await requireCurrentProject(deps.projectService);
17
+ return deps.sessionService.startProjectTranslatorSession(project.repoRoot, request.body);
18
+ });
19
+ app.post("/api/translation/codex/session/resume", async (request) => {
20
+ const project = await requireCurrentProject(deps.projectService);
21
+ return deps.sessionService.resumeProjectTranslatorSession(project.repoRoot, request.body);
22
+ });
23
+ app.post("/api/translation/codex/session/restart", async (request) => {
24
+ const project = await requireCurrentProject(deps.projectService);
25
+ return deps.sessionService.restartProjectTranslatorSession(project.repoRoot, request.body);
26
+ });
27
+ app.post("/api/translation/codex/session/stop", async () => {
28
+ const project = await requireCurrentProject(deps.projectService);
29
+ return deps.sessionService.stopProjectTranslatorSession(project.repoRoot);
30
+ });
7
31
  app.get("/api/translation/codex/source-files", async (request) => {
8
32
  const project = await requireCurrentProject(deps.projectService);
9
33
  return deps.codexTranslationService.browseSourceFiles(project.repoRoot, {
@@ -4,7 +4,9 @@ export function registerProjectRoutes(app, deps) {
4
4
  return deps.projectService.getRecentRepositoryPaths();
5
5
  });
6
6
  app.post("/api/projects/connect", async (request) => {
7
- return deps.projectService.connectProject(request.body);
7
+ const project = await deps.projectService.connectProject(request.body);
8
+ await deps.codexTranslationService?.cleanupStartupRuntime(project.repoRoot);
9
+ return project;
8
10
  });
9
11
  app.get("/api/projects/current", async () => {
10
12
  return deps.projectService.getCurrentProject();
@@ -88,7 +88,9 @@ function degradedArtifactSummary(handoffDir) {
88
88
  logsDir,
89
89
  messagesDir,
90
90
  roleCommandPaths: Object.fromEntries(DISPATCHABLE_ROLES.map((role) => [role, `${roleCommandsDir}/${role}.md`])),
91
- roleLogPaths: Object.fromEntries(ROLE_NAMES.map((role) => [role, `${logsDir}/${role}.log`])),
91
+ roleLogPaths: Object.fromEntries(ROLE_NAMES
92
+ .filter((role) => role !== "codex-translator")
93
+ .map((role) => [role, `${logsDir}/${role}.log`])),
92
94
  messageRoutePaths: {},
93
95
  architecturePlanPath: `${handoffDir}/architecture-plan.md`,
94
96
  knownIssuesPath: `${handoffDir}/known-issues.md`,
@@ -72,10 +72,14 @@ export async function createServer(deps, options = {}) {
72
72
  codexReviewService: deps.codexReviewService
73
73
  });
74
74
  registerCodexTranslationRoutes(app, {
75
+ projectService: deps.projectService,
76
+ codexTranslationService: deps.codexTranslationService,
77
+ sessionService: deps.sessionService
78
+ });
79
+ registerProjectRoutes(app, {
75
80
  projectService: deps.projectService,
76
81
  codexTranslationService: deps.codexTranslationService
77
82
  });
78
- registerProjectRoutes(app, { projectService: deps.projectService });
79
83
  registerHarnessRoutes(app, {
80
84
  projectService: deps.projectService,
81
85
  harnessService: deps.harnessService
@@ -118,6 +122,7 @@ export async function createServer(deps, options = {}) {
118
122
  registerGatewayRoutes(app, { gatewayService: deps.gatewayService });
119
123
  registerTerminalWs(app, { runtime: deps.runtime });
120
124
  app.addHook("onReady", async () => {
125
+ await cleanupRecentTranslationRuntime(deps);
121
126
  await deps.gatewayService.start();
122
127
  });
123
128
  app.addHook("onClose", async () => {
@@ -134,6 +139,10 @@ export async function createServer(deps, options = {}) {
134
139
  }
135
140
  return app;
136
141
  }
142
+ async function cleanupRecentTranslationRuntime(deps) {
143
+ const repoRoots = await deps.projectService.getRecentRepositoryPaths();
144
+ await Promise.all(repoRoots.map((repoRoot) => deps.codexTranslationService.cleanupStartupRuntime(repoRoot)));
145
+ }
137
146
  export async function startServer(options = {}) {
138
147
  const host = options.host ?? "127.0.0.1";
139
148
  const port = options.port ?? 4173;
@@ -42,8 +42,7 @@ 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"),
46
- "codex-translator": path.posix.join(logsDir, "codex-translator.log")
45
+ "codex-reviewer": path.posix.join(logsDir, "codex-reviewer.log")
47
46
  },
48
47
  messageRoutePaths: getDefaultMessageRoutePaths(messagesDir),
49
48
  architecturePlanPath: path.posix.join(handoffDir, "architecture-plan.md"),
@@ -179,7 +178,15 @@ export function createArtifactService(fs) {
179
178
  });
180
179
  }
181
180
  const paths = this.getHandoffPaths(input.repoRoot, input.handoffDir);
182
- await fs.appendText(resolveRepoPath(input.repoRoot, paths.roleLogPaths[input.role]), input.content);
181
+ const roleLogPath = paths.roleLogPaths[input.role];
182
+ if (!roleLogPath) {
183
+ throw new VcmError({
184
+ code: "ROLE_LOG_UNAVAILABLE",
185
+ message: `${input.role} does not write a handoff log.`,
186
+ statusCode: 409
187
+ });
188
+ }
189
+ await fs.appendText(resolveRepoPath(input.repoRoot, roleLogPath), input.content);
183
190
  }
184
191
  };
185
192
  }
@@ -18,6 +18,13 @@ export function createCodexHookService(deps) {
18
18
  statusCode: 409
19
19
  });
20
20
  }
21
+ if (input.role === "codex-translator") {
22
+ return {
23
+ project,
24
+ config: undefined,
25
+ taskRepoRoot: undefined
26
+ };
27
+ }
21
28
  const config = await deps.projectService.loadConfig(project.repoRoot);
22
29
  const task = await deps.taskService.loadTask(project.repoRoot, input.taskSlug);
23
30
  const taskRepoRoot = getTaskRuntimeRepoRoot(task);
@@ -37,16 +44,30 @@ export function createCodexHookService(deps) {
37
44
  });
38
45
  }
39
46
  const context = await getHookContext(input);
40
- const session = await deps.sessionService.recordRoleHookEvent(context.project.repoRoot, {
41
- taskSlug: input.taskSlug,
42
- role: input.role,
43
- eventName,
44
- sessionId: stringOrUndefined(input.event.session_id),
45
- transcriptPath: stringOrUndefined(input.event.transcript_path),
46
- cwd: stringOrUndefined(input.event.cwd),
47
- allowSessionMismatch: true
48
- });
47
+ const session = input.role === "codex-translator"
48
+ ? await deps.sessionService.recordProjectTranslatorHookEvent(context.project.repoRoot, {
49
+ eventName,
50
+ sessionId: stringOrUndefined(input.event.session_id),
51
+ transcriptPath: stringOrUndefined(input.event.transcript_path),
52
+ cwd: stringOrUndefined(input.event.cwd)
53
+ })
54
+ : await deps.sessionService.recordRoleHookEvent(context.project.repoRoot, {
55
+ taskSlug: input.taskSlug,
56
+ role: input.role,
57
+ eventName,
58
+ sessionId: stringOrUndefined(input.event.session_id),
59
+ transcriptPath: stringOrUndefined(input.event.transcript_path),
60
+ cwd: stringOrUndefined(input.event.cwd),
61
+ allowSessionMismatch: true
62
+ });
49
63
  if (input.role === "codex-reviewer") {
64
+ if (!context.config || !context.taskRepoRoot) {
65
+ throw new VcmError({
66
+ code: "CODEX_HOOK_TASK_CONTEXT_MISSING",
67
+ message: "Codex Reviewer hook is missing task context.",
68
+ statusCode: 500
69
+ });
70
+ }
50
71
  await deps.roundService.recordRoleTurnEvent({
51
72
  repoRoot: context.project.repoRoot,
52
73
  stateRepoRoot: context.taskRepoRoot,