vibe-coding-master 0.7.41 → 0.7.43

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.
Files changed (33) hide show
  1. package/README.md +10 -5
  2. package/dist/backend/api/task-routes.js +31 -2
  3. package/dist/backend/api/workflow-control-routes.js +0 -31
  4. package/dist/backend/cli/install-vcm-harness.js +84 -9
  5. package/dist/backend/role-tool-policy.js +1 -2
  6. package/dist/backend/server.js +12 -5
  7. package/dist/backend/services/artifact-service.js +3 -2
  8. package/dist/backend/services/auto-memory-service.js +2 -2
  9. package/dist/backend/services/claude-hook-service.js +103 -4
  10. package/dist/backend/services/harness-feedback-service.js +105 -3
  11. package/dist/backend/services/harness-service.js +77 -10
  12. package/dist/backend/services/memory-review-paths.js +13 -0
  13. package/dist/backend/services/role-stall-detector-service.js +322 -0
  14. package/dist/backend/services/round-service.js +25 -0
  15. package/dist/backend/services/runtime-coordinator-service.js +10 -0
  16. package/dist/backend/services/session-service.js +76 -4
  17. package/dist/backend/services/workflow-control-service.js +439 -203
  18. package/dist/backend/templates/handoff.js +2 -3
  19. package/dist/backend/templates/harness/architect-agent.js +7 -4
  20. package/dist/backend/templates/harness/coder-agent.js +4 -5
  21. package/dist/backend/templates/harness/gate-review.js +7 -9
  22. package/dist/backend/templates/harness/harness-engineer-agent.js +18 -8
  23. package/dist/backend/templates/harness/project-manager-agent.js +5 -5
  24. package/dist/backend/templates/harness/vcm-code-navigation-skill.js +6 -7
  25. package/dist/backend/templates/harness/vcm-workflow-review-skill.js +7 -9
  26. package/dist/shared/types/role-stall.js +1 -0
  27. package/dist/shared/types/workflow.js +14 -0
  28. package/dist/shared/validation/artifact-registry.js +1 -1
  29. package/dist-frontend/assets/{index-C_XHGNBD.css → index-B0d4Z6ny.css} +1 -1
  30. package/dist-frontend/assets/{index-Bocc2DWF.js → index-VW9tYPP5.js} +38 -38
  31. package/dist-frontend/index.html +2 -2
  32. package/package.json +1 -1
  33. package/scripts/harness-tools/vcm-bash-guard +203 -13
@@ -280,6 +280,31 @@ export function createRoundService(deps) {
280
280
  return toSessionRoundState(next, timestamp);
281
281
  });
282
282
  },
283
+ async recordRoleRecoveryFailure(input) {
284
+ return withTaskLock(input, async () => {
285
+ const timestamp = now();
286
+ const state = await load(input);
287
+ const stopped = applyTerminalExit({
288
+ state,
289
+ taskSlug: input.taskSlug,
290
+ role: input.recovery.role,
291
+ timestamp
292
+ });
293
+ const next = {
294
+ ...stopped,
295
+ roleRecovery: normalizeRoleRecovery({
296
+ ...input.recovery,
297
+ status: "failed",
298
+ failedAt: input.recovery.failedAt ?? timestamp
299
+ }),
300
+ updatedAt: timestamp
301
+ };
302
+ await save(input, next);
303
+ clearSettleTimer(input);
304
+ await updateSessionStatus(input, next.currentRound?.status === "running" ? "running" : "stopped");
305
+ return toSessionRoundState(next, timestamp);
306
+ });
307
+ },
283
308
  async setRoleRecovery(input) {
284
309
  return withTaskLock(input, async () => {
285
310
  const timestamp = now();
@@ -42,9 +42,17 @@ export function createRuntimeCoordinatorService(deps) {
42
42
  ]);
43
43
  const preferences = await deps.appSettings.getPreferences();
44
44
  if (!activeTask) {
45
+ deps.roleStallDetector.clearProject(repoRoot);
45
46
  return { activeTask: null, gatewayStatus };
46
47
  }
47
48
  const taskRepoRoot = getTaskRuntimeRepoRoot(activeTask);
49
+ const stateRoot = await deps.getStateRoot(repoRoot);
50
+ await deps.roleStallDetector.reconcileTask({
51
+ repoRoot,
52
+ taskRepoRoot,
53
+ stateRoot,
54
+ taskSlug: activeTask.taskSlug
55
+ });
48
56
  const harnessInitialized = await deps.harnessService.getHarnessStatus(taskRepoRoot)
49
57
  .then((status) => status.initialized)
50
58
  .catch(() => false);
@@ -77,6 +85,7 @@ export function createRuntimeCoordinatorService(deps) {
77
85
  void reconcileCurrentProject().catch(() => undefined);
78
86
  },
79
87
  stop() {
88
+ deps.roleStallDetector.stop();
80
89
  if (reconcileTimer === undefined) {
81
90
  return;
82
91
  }
@@ -88,6 +97,7 @@ export function createRuntimeCoordinatorService(deps) {
88
97
  async function reconcileCurrentProject() {
89
98
  const project = await deps.projectService.getCurrentProject();
90
99
  if (!project) {
100
+ deps.roleStallDetector.stop();
91
101
  return;
92
102
  }
93
103
  await reconcileProject(project.repoRoot);
@@ -104,7 +104,12 @@ export function createSessionService(deps) {
104
104
  VCM_RUNTIME_SESSION_TOKEN: runtimeSessionToken
105
105
  }, modelEnvironment, {
106
106
  ...buildUsageTelemetryEnvironment(deps.apiUrl, role, model),
107
- ...(roleUsesLsp(role) ? { ENABLE_LSP_TOOL: "true" } : {})
107
+ ...(roleUsesLsp(role)
108
+ ? {
109
+ ENABLE_LSP_TOOL: "true",
110
+ ENABLE_TOOL_SEARCH: "false"
111
+ }
112
+ : {})
108
113
  }),
109
114
  cols: input.cols,
110
115
  rows: input.rows
@@ -716,7 +721,8 @@ export function createSessionService(deps) {
716
721
  return undefined;
717
722
  }
718
723
  const timestamp = now();
719
- const turnWasRunning = current.activityStatus === "running";
724
+ const turnWasRunning = current.activityStatus === "running"
725
+ && current.expectedRuntimeExitReason !== "role-stall-recovery";
720
726
  const updated = {
721
727
  ...current,
722
728
  status: input.status,
@@ -732,6 +738,71 @@ export function createSessionService(deps) {
732
738
  await persistRoleSessionRecord(deps.fs, repoRoot, getTaskRuntimeRepoRoot(task), config.stateRoot, updated);
733
739
  return { record: updated, turnWasRunning };
734
740
  }
741
+ async function persistTaskRoleRecord(repoRoot, taskSlug, record) {
742
+ deps.registry.upsert(record);
743
+ const config = await deps.projectService.loadConfig(repoRoot);
744
+ const task = await deps.taskService.loadTask(repoRoot, taskSlug);
745
+ await persistRoleSessionRecord(deps.fs, repoRoot, getTaskRuntimeRepoRoot(task), config.stateRoot, record);
746
+ return record;
747
+ }
748
+ async function recoverRoleSession(repoRoot, taskSlug, input) {
749
+ const current = await getTaskRoleSessionView(repoRoot, taskSlug, input.role);
750
+ if (!current
751
+ || current.id !== input.expectedSessionId
752
+ || current.runtimeSessionToken !== input.expectedRuntimeSessionToken
753
+ || current.status !== "running"
754
+ || current.activityStatus !== "running") {
755
+ throw new VcmError({
756
+ code: "ROLE_STALL_SESSION_CHANGED",
757
+ message: `${input.role} session changed before recovery could begin.`,
758
+ statusCode: 409
759
+ });
760
+ }
761
+ if (!current.claudeSessionId) {
762
+ throw new VcmError({
763
+ code: "CLAUDE_SESSION_MISSING",
764
+ message: `${input.role} does not have a confirmed Claude session id to resume.`,
765
+ statusCode: 409
766
+ });
767
+ }
768
+ const prepared = await persistTaskRoleRecord(repoRoot, taskSlug, {
769
+ ...current,
770
+ expectedRuntimeExitReason: "role-stall-recovery",
771
+ updatedAt: now()
772
+ });
773
+ if (deps.runtime.getSession(prepared.id)) {
774
+ await deps.runtime.stop(prepared.id);
775
+ }
776
+ await persistTaskRoleRecord(repoRoot, taskSlug, {
777
+ ...prepared,
778
+ status: "exited",
779
+ activityStatus: "idle",
780
+ pid: undefined,
781
+ expectedRuntimeExitReason: undefined,
782
+ updatedAt: now()
783
+ });
784
+ const resumed = await launchRoleSession(repoRoot, taskSlug, input.role, {
785
+ permissionMode: prepared.permissionMode,
786
+ model: prepared.model,
787
+ effort: prepared.effort
788
+ }, "resume");
789
+ if ((await waitForSessionInputReady(resumed.id)) === "exited") {
790
+ throw new VcmError({
791
+ code: "ROLE_STALL_RESUME_FAILED",
792
+ message: `${input.role} session exited before recovery input could be submitted.`,
793
+ statusCode: 409
794
+ });
795
+ }
796
+ await submitTerminalInput(deps.runtime, resumed.id, input.recoveryPrompt);
797
+ return persistTaskRoleRecord(repoRoot, taskSlug, {
798
+ ...resumed,
799
+ activityStatus: "running",
800
+ lastTurnStartedAt: now(),
801
+ lastHookEventAt: now(),
802
+ expectedRuntimeExitReason: undefined,
803
+ updatedAt: now()
804
+ });
805
+ }
735
806
  return {
736
807
  async assertModelLaunchReady(model = "default") {
737
808
  await getModelLaunchEnvironment(normalizeClaudeModel(model));
@@ -1199,7 +1270,8 @@ export function createSessionService(deps) {
1199
1270
  : undefined;
1200
1271
  }
1201
1272
  return markTaskRoleActivityIdle(repoRoot, taskSlug, role);
1202
- }
1273
+ },
1274
+ recoverRoleSession
1203
1275
  };
1204
1276
  }
1205
1277
  function toRoleSessionRecordView(record, runtime) {
@@ -1289,7 +1361,7 @@ function isSessionMissingError(error) {
1289
1361
  error.code === "SESSION_MISSING";
1290
1362
  }
1291
1363
  function withoutRuntimeOnlySessionFields(session) {
1292
- const { pid: _pid, runtimeSessionToken: _runtimeSessionToken, ...persisted } = session;
1364
+ const { pid: _pid, runtimeSessionToken: _runtimeSessionToken, expectedRuntimeExitReason: _expectedRuntimeExitReason, ...persisted } = session;
1293
1365
  return persisted;
1294
1366
  }
1295
1367
  function defaultIsProcessAlive(pid) {