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.
- package/README.md +10 -5
- package/dist/backend/api/task-routes.js +31 -2
- package/dist/backend/api/workflow-control-routes.js +0 -31
- package/dist/backend/cli/install-vcm-harness.js +84 -9
- package/dist/backend/role-tool-policy.js +1 -2
- package/dist/backend/server.js +12 -5
- package/dist/backend/services/artifact-service.js +3 -2
- package/dist/backend/services/auto-memory-service.js +2 -2
- package/dist/backend/services/claude-hook-service.js +103 -4
- package/dist/backend/services/harness-feedback-service.js +105 -3
- package/dist/backend/services/harness-service.js +77 -10
- package/dist/backend/services/memory-review-paths.js +13 -0
- package/dist/backend/services/role-stall-detector-service.js +322 -0
- package/dist/backend/services/round-service.js +25 -0
- package/dist/backend/services/runtime-coordinator-service.js +10 -0
- package/dist/backend/services/session-service.js +76 -4
- package/dist/backend/services/workflow-control-service.js +439 -203
- package/dist/backend/templates/handoff.js +2 -3
- package/dist/backend/templates/harness/architect-agent.js +7 -4
- package/dist/backend/templates/harness/coder-agent.js +4 -5
- package/dist/backend/templates/harness/gate-review.js +7 -9
- package/dist/backend/templates/harness/harness-engineer-agent.js +18 -8
- package/dist/backend/templates/harness/project-manager-agent.js +5 -5
- package/dist/backend/templates/harness/vcm-code-navigation-skill.js +6 -7
- package/dist/backend/templates/harness/vcm-workflow-review-skill.js +7 -9
- package/dist/shared/types/role-stall.js +1 -0
- package/dist/shared/types/workflow.js +14 -0
- package/dist/shared/validation/artifact-registry.js +1 -1
- package/dist-frontend/assets/{index-C_XHGNBD.css → index-B0d4Z6ny.css} +1 -1
- package/dist-frontend/assets/{index-Bocc2DWF.js → index-VW9tYPP5.js} +38 -38
- package/dist-frontend/index.html +2 -2
- package/package.json +1 -1
- 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)
|
|
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) {
|