vibe-coding-master 0.6.23 → 0.7.1
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 +12 -10
- package/dist/backend/api/harness-routes.js +10 -4
- package/dist/backend/api/task-routes.js +2 -32
- package/dist/backend/cli/install-vcm-harness.js +9 -1
- package/dist/backend/gateway/gateway-service.js +4 -37
- package/dist/backend/server.js +35 -16
- package/dist/backend/services/auto-memory-service.js +57 -50
- package/dist/backend/services/claude-hook-service.js +42 -2
- package/dist/backend/services/claude-transcript-reply.js +81 -1
- package/dist/backend/services/harness-service.js +10 -1
- package/dist/backend/services/runtime-coordinator-service.js +43 -9
- package/dist/backend/services/runtime-recovery-service.js +6 -0
- package/dist/backend/services/task-close-service.js +88 -0
- package/dist/backend/services/task-service.js +152 -35
- package/dist/backend/services/turn-reconciler-service.js +122 -0
- package/dist/backend/templates/harness/claude-root.js +1 -0
- package/dist/backend/templates/harness/harness-engineer-agent.js +15 -17
- package/dist/backend/templates/harness/role-memory.js +11 -1
- package/dist/backend/templates/harness/vcm-propose-memory-skill.js +35 -0
- package/dist-frontend/assets/{index-9V9COJZy.js → index-e8Tqa8Qh.js} +26 -25
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { readTranscriptTurnEvidence } from "./claude-transcript-reply.js";
|
|
2
|
+
import { getTaskRuntimeRepoRoot } from "./task-service.js";
|
|
3
|
+
export const TURN_STALL_THRESHOLD_MS = 30 * 60_000;
|
|
4
|
+
export const TURN_INTERRUPT_GRACE_MS = 10_000;
|
|
5
|
+
export function createTurnReconcilerService(deps) {
|
|
6
|
+
const now = deps.now ?? (() => new Date().toISOString());
|
|
7
|
+
const stallThresholdMs = deps.stallThresholdMs ?? TURN_STALL_THRESHOLD_MS;
|
|
8
|
+
const interruptGraceMs = deps.interruptGraceMs ?? TURN_INTERRUPT_GRACE_MS;
|
|
9
|
+
const readEvidence = deps.readTranscriptEvidence ?? readTranscriptTurnEvidence;
|
|
10
|
+
const pendingInterrupts = new Map();
|
|
11
|
+
return {
|
|
12
|
+
async reconcileTask(repoRoot, task, stateRoot) {
|
|
13
|
+
const taskRepoRoot = getTaskRuntimeRepoRoot(task);
|
|
14
|
+
const round = await deps.roundService.getSessionRoundState({
|
|
15
|
+
repoRoot,
|
|
16
|
+
stateRepoRoot: taskRepoRoot,
|
|
17
|
+
stateRoot,
|
|
18
|
+
taskSlug: task.taskSlug
|
|
19
|
+
});
|
|
20
|
+
if (round.status !== "running"
|
|
21
|
+
|| !round.activeRole
|
|
22
|
+
|| !round.activeTurnStartedAt
|
|
23
|
+
|| round.roleRecovery) {
|
|
24
|
+
clearTaskInterrupts(repoRoot, task.taskSlug);
|
|
25
|
+
return { status: "inactive" };
|
|
26
|
+
}
|
|
27
|
+
const role = round.activeRole;
|
|
28
|
+
const interruptKey = `${repoRoot}:${task.taskSlug}:${role}`;
|
|
29
|
+
const session = await deps.sessionService.getRoleSession(repoRoot, task.taskSlug, role);
|
|
30
|
+
const evidence = session
|
|
31
|
+
? await readEvidence({ ...session, lastTurnStartedAt: round.activeTurnStartedAt })
|
|
32
|
+
: {};
|
|
33
|
+
if (evidence.completion) {
|
|
34
|
+
pendingInterrupts.delete(interruptKey);
|
|
35
|
+
await deps.claudeHookService.handleReconciledTurnEnd(buildReconciledHook(task.taskSlug, role, session, "Stop", {
|
|
36
|
+
vcm_reconcile_reason: "transcript-end-turn",
|
|
37
|
+
vcm_completion_id: evidence.completion.id,
|
|
38
|
+
vcm_completion_at: evidence.completion.timestamp
|
|
39
|
+
}));
|
|
40
|
+
return { status: "completed", role, reason: "transcript-end-turn" };
|
|
41
|
+
}
|
|
42
|
+
if (!session || session.status !== "running") {
|
|
43
|
+
pendingInterrupts.delete(interruptKey);
|
|
44
|
+
const reason = session ? "terminal-session-exited" : "terminal-session-missing";
|
|
45
|
+
await deps.claudeHookService.handleReconciledTurnEnd(buildReconciledHook(task.taskSlug, role, session, "StopFailure", {
|
|
46
|
+
error: reason.replaceAll("-", "_"),
|
|
47
|
+
error_details: `VCM reconciled an active turn because its ${reason.replaceAll("-", " ")}.`
|
|
48
|
+
}));
|
|
49
|
+
return { status: "failed", role, reason };
|
|
50
|
+
}
|
|
51
|
+
const lastActivityAt = latestTimestamp([
|
|
52
|
+
round.activeTurnStartedAt,
|
|
53
|
+
session.lastHookEventAt,
|
|
54
|
+
session.lastOutputAt,
|
|
55
|
+
evidence.lastActivityAt
|
|
56
|
+
]);
|
|
57
|
+
const currentTime = now();
|
|
58
|
+
if (!isStale(lastActivityAt, currentTime, stallThresholdMs)) {
|
|
59
|
+
pendingInterrupts.delete(interruptKey);
|
|
60
|
+
return { status: "active" };
|
|
61
|
+
}
|
|
62
|
+
const pendingInterrupt = pendingInterrupts.get(interruptKey);
|
|
63
|
+
if (!pendingInterrupt || pendingInterrupt.turnStartedAt !== round.activeTurnStartedAt) {
|
|
64
|
+
deps.runtime.write(session.id, "\u0003");
|
|
65
|
+
pendingInterrupts.set(interruptKey, {
|
|
66
|
+
turnStartedAt: round.activeTurnStartedAt,
|
|
67
|
+
requestedAt: currentTime
|
|
68
|
+
});
|
|
69
|
+
return { status: "active" };
|
|
70
|
+
}
|
|
71
|
+
if (!isStale(pendingInterrupt.requestedAt, currentTime, interruptGraceMs)) {
|
|
72
|
+
return { status: "active" };
|
|
73
|
+
}
|
|
74
|
+
pendingInterrupts.delete(interruptKey);
|
|
75
|
+
await deps.claudeHookService.handleReconciledTurnEnd(buildReconciledHook(task.taskSlug, role, session, "StopFailure", {
|
|
76
|
+
error: "turn_stalled",
|
|
77
|
+
error_details: `No hook, terminal output, or transcript activity was observed for ${stallThresholdMs}ms.`
|
|
78
|
+
}));
|
|
79
|
+
return { status: "failed", role, reason: "turn-stalled" };
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
function clearTaskInterrupts(repoRoot, taskSlug) {
|
|
83
|
+
for (const key of pendingInterrupts.keys()) {
|
|
84
|
+
if (key.startsWith(`${repoRoot}:${taskSlug}:`)) {
|
|
85
|
+
pendingInterrupts.delete(key);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function buildReconciledHook(taskSlug, role, session, eventName, evidence) {
|
|
91
|
+
return {
|
|
92
|
+
taskSlug,
|
|
93
|
+
role,
|
|
94
|
+
event: {
|
|
95
|
+
hook_event_name: eventName,
|
|
96
|
+
...(session?.claudeSessionId ? { session_id: session.claudeSessionId } : {}),
|
|
97
|
+
...(session?.transcriptPath ? { transcript_path: session.transcriptPath } : {}),
|
|
98
|
+
...(session?.cwd ? { cwd: session.cwd } : {}),
|
|
99
|
+
vcm_reconciled: true,
|
|
100
|
+
...evidence
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function latestTimestamp(values) {
|
|
105
|
+
return values.reduce((latest, value) => {
|
|
106
|
+
if (!value) {
|
|
107
|
+
return latest;
|
|
108
|
+
}
|
|
109
|
+
const valueMs = Date.parse(value);
|
|
110
|
+
const latestMs = latest ? Date.parse(latest) : Number.NaN;
|
|
111
|
+
return Number.isFinite(valueMs) && (!Number.isFinite(latestMs) || valueMs > latestMs)
|
|
112
|
+
? value
|
|
113
|
+
: latest;
|
|
114
|
+
}, undefined);
|
|
115
|
+
}
|
|
116
|
+
function isStale(lastActivityAt, currentTime, thresholdMs) {
|
|
117
|
+
const activityMs = lastActivityAt ? Date.parse(lastActivityAt) : Number.NaN;
|
|
118
|
+
const currentMs = Date.parse(currentTime);
|
|
119
|
+
return Number.isFinite(activityMs)
|
|
120
|
+
&& Number.isFinite(currentMs)
|
|
121
|
+
&& currentMs - activityMs >= thresholdMs;
|
|
122
|
+
}
|
|
@@ -8,6 +8,7 @@ export function renderRootClaudeHarnessRules() {
|
|
|
8
8
|
- \`vcm-route-message\` is the only channel for PM-hub dispatch and reporting among project-manager, architect, coder, and tester. Gate Review and tool-role work use their dedicated VCM skills and controllers. Follow the route skill's write-then-stop rule.
|
|
9
9
|
- Use \`vcm-long-running-validation\` for long-running validation. Follow the background job limits below.
|
|
10
10
|
- Use \`vcm-report-harness-issue\` when you notice a reusable VCM harness problem. Record feedback; do not contact Harness Engineer directly.
|
|
11
|
+
- Treat \`.ai/vcm/memory/**\` as read-only. Use \`vcm-propose-memory\` only when VCM assigns a memory proposal during Task Harness Review.
|
|
11
12
|
- Project-manager runs \`vcm-gate-review\` unconditionally at every Gate Review trigger point and on VCM Gate Review callbacks; the tool reports the authoritative enable state.
|
|
12
13
|
|
|
13
14
|
## VCM Harness Scope
|
|
@@ -38,9 +38,10 @@ You are not part of the task workflow round state.
|
|
|
38
38
|
permitted bootstrap edits directly in the active task worktree and commit them
|
|
39
39
|
yourself.
|
|
40
40
|
- Retrospective Mode: analyze a completed task for reusable harness problems.
|
|
41
|
-
Do not edit harness
|
|
42
|
-
- Memory Review Mode:
|
|
43
|
-
|
|
41
|
+
Do not edit harness or memory files.
|
|
42
|
+
- Memory Review Mode: when Auto Memory is enabled and VCM starts the memory
|
|
43
|
+
phase of Task Harness Review, review role proposals and write only the review
|
|
44
|
+
output files assigned by VCM.
|
|
44
45
|
- VCM Feedback Mode: draft VCM product, installer, UI, or fixed-template issue
|
|
45
46
|
feedback. Do not submit without explicit in-session user authorization.
|
|
46
47
|
|
|
@@ -50,8 +51,7 @@ You are not part of the task workflow round state.
|
|
|
50
51
|
explicitly asks you to apply an approved harness change.
|
|
51
52
|
- When applying edits, work only in the active task worktree named by VCM. Do not
|
|
52
53
|
edit the base repository root unless VCM explicitly says so.
|
|
53
|
-
- In Proposal Mode
|
|
54
|
-
harness files; only the memory exception above may write files.
|
|
54
|
+
- In Proposal Mode and Retrospective Mode, do not edit files.
|
|
55
55
|
- Commit every applied harness change yourself before ending your turn.
|
|
56
56
|
- Do not overwrite VCM fixed managed blocks.
|
|
57
57
|
- Keep project-specific customization outside VCM managed blocks.
|
|
@@ -64,18 +64,16 @@ You are not part of the task workflow round state.
|
|
|
64
64
|
## Memory Management
|
|
65
65
|
|
|
66
66
|
- Own VCM-managed project memory under \`.ai/vcm/memory/**\`.
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- When VCM assigns review output paths, edit only those paths. VCM applies the
|
|
78
|
-
reviewed memory and records the diff.
|
|
67
|
+
- When Auto Memory is disabled, do not request proposals, start Memory Review
|
|
68
|
+
Mode, or update memory.
|
|
69
|
+
- During VCM-assigned Memory Review, verify every role proposal against task
|
|
70
|
+
evidence, merge duplicates, remove stale entries, and keep role-specific
|
|
71
|
+
knowledge in the matching role memory file.
|
|
72
|
+
- Do not record task narrative, temporary state, unverified conclusions, or
|
|
73
|
+
Harness rules in memory.
|
|
74
|
+
- Edit only the review output paths assigned by VCM. Do not edit
|
|
75
|
+
\`.ai/vcm/memory/**\` directly. VCM applies the reviewed output and records the
|
|
76
|
+
diff.
|
|
79
77
|
|
|
80
78
|
## Task Harness Retrospective
|
|
81
79
|
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
export function renderRoleMemoryRules(role) {
|
|
2
|
+
const proposalRule = role === "harness-engineer"
|
|
3
|
+
? `Treat \`.ai/vcm/memory/**\` as read-only during role turns. Update memory
|
|
4
|
+
only through VCM-assigned Memory Review output paths or explicit user edits in
|
|
5
|
+
Harness Studio. When Auto Memory is disabled, do not initiate memory proposals,
|
|
6
|
+
reviews, or updates.`
|
|
7
|
+
: `Treat \`.ai/vcm/memory/**\` as read-only. Do not create, edit, or delete
|
|
8
|
+
memory files. Only when VCM explicitly requests a proposal during Task Harness
|
|
9
|
+
Review, use \`vcm-propose-memory\` and write the exact assigned draft path.`;
|
|
2
10
|
return `### Role Memory
|
|
3
11
|
|
|
4
12
|
Before handling work in a session, read \`.ai/vcm/memory/roles/${role}.md\`.
|
|
5
13
|
Read it again after context compaction before continuing.
|
|
6
14
|
|
|
7
15
|
Treat memory as accumulated project context, not authority. Verify it against
|
|
8
|
-
current code, documentation, and task evidence
|
|
16
|
+
current code, documentation, and task evidence.
|
|
17
|
+
|
|
18
|
+
${proposalRule}`;
|
|
9
19
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function renderVcmProposeMemorySkillRules() {
|
|
2
|
+
return `Use this skill only when VCM explicitly requests a memory proposal during Task
|
|
3
|
+
Harness Review and provides an exact draft path.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
- Treat \`.ai/vcm/memory/**\` as read-only. This skill creates a proposal; it
|
|
8
|
+
never edits active memory.
|
|
9
|
+
- Write only to the exact draft path assigned by VCM. The path must be under
|
|
10
|
+
\`.ai/vcm/memory-review/runs/<run-id>/drafts/\` in the active task worktree.
|
|
11
|
+
- If VCM did not provide a draft path, do not create a proposal.
|
|
12
|
+
- Propose only verified, durable, reusable project knowledge supported by task
|
|
13
|
+
evidence.
|
|
14
|
+
- Do not record task narrative, temporary state, unverified conclusions, or
|
|
15
|
+
Harness rules.
|
|
16
|
+
- Do not edit handoff artifacts or route messages from this skill.
|
|
17
|
+
|
|
18
|
+
## Draft Format
|
|
19
|
+
|
|
20
|
+
\`\`\`markdown
|
|
21
|
+
# Memory Proposal
|
|
22
|
+
Decision: update | no-change
|
|
23
|
+
|
|
24
|
+
## Add
|
|
25
|
+
|
|
26
|
+
## Update
|
|
27
|
+
|
|
28
|
+
## Remove
|
|
29
|
+
|
|
30
|
+
## Evidence
|
|
31
|
+
\`\`\`
|
|
32
|
+
|
|
33
|
+
Use \`Decision: no-change\` when the completed task produced no qualifying
|
|
34
|
+
memory. End the turn after writing the assigned draft.`;
|
|
35
|
+
}
|