vibe-coding-master 0.0.13 → 0.0.14
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 +16 -12
- package/dist/backend/api/claude-hook-routes.js +5 -0
- package/dist/backend/api/message-routes.js +4 -0
- package/dist/backend/server.js +11 -3
- package/dist/backend/services/claude-hook-service.js +70 -0
- package/dist/backend/services/harness-service.js +95 -0
- package/dist/backend/services/message-service.js +76 -6
- package/dist/backend/services/round-service.js +17 -127
- package/dist/backend/services/session-service.js +39 -0
- package/dist/backend/services/status-service.js +0 -76
- package/dist/backend/templates/harness/architect-agent.js +4 -0
- package/dist/backend/templates/harness/claude-root.js +3 -0
- package/dist/backend/templates/harness/coder-agent.js +4 -0
- package/dist/backend/templates/harness/project-manager-agent.js +4 -0
- package/dist/backend/templates/harness/reviewer-agent.js +4 -0
- package/dist/backend/templates/message-envelope.js +3 -1
- package/dist/cli/vcmctl.js +30 -0
- package/dist/shared/types/claude-hook.js +1 -0
- package/dist-frontend/assets/{index-CyJrJge9.js → index-DVhkEVnA.js} +36 -35
- package/dist-frontend/assets/index-jEkUTnIY.css +32 -0
- package/dist-frontend/index.html +2 -2
- package/docs/cc-best-practices.md +8 -0
- package/docs/product-design.md +24 -25
- package/docs/v1-architecture-design.md +36 -36
- package/docs/v1-implementation-plan.md +44 -31
- package/package.json +1 -1
- package/dist-frontend/assets/index-N5DA0uE9.css +0 -32
|
@@ -57,6 +57,7 @@ export function createSessionService(deps) {
|
|
|
57
57
|
taskSlug,
|
|
58
58
|
role,
|
|
59
59
|
status: runtimeSession.status,
|
|
60
|
+
activityStatus: "idle",
|
|
60
61
|
command: startCommand.display,
|
|
61
62
|
permissionMode,
|
|
62
63
|
cwd: taskRepoRoot,
|
|
@@ -99,6 +100,7 @@ export function createSessionService(deps) {
|
|
|
99
100
|
const updated = {
|
|
100
101
|
...existing,
|
|
101
102
|
status: "exited",
|
|
103
|
+
activityStatus: "idle",
|
|
102
104
|
updatedAt: now()
|
|
103
105
|
};
|
|
104
106
|
deps.registry.upsert(updated);
|
|
@@ -139,6 +141,7 @@ export function createSessionService(deps) {
|
|
|
139
141
|
return {
|
|
140
142
|
...record,
|
|
141
143
|
status: runtimeSession.status,
|
|
144
|
+
activityStatus: record.activityStatus ?? "idle",
|
|
142
145
|
pid: runtimeSession.pid,
|
|
143
146
|
lastOutputAt: runtimeSession.lastOutputAt,
|
|
144
147
|
exitCode: runtimeSession.exitCode
|
|
@@ -153,9 +156,45 @@ export function createSessionService(deps) {
|
|
|
153
156
|
}
|
|
154
157
|
}
|
|
155
158
|
return sessions;
|
|
159
|
+
},
|
|
160
|
+
async recordClaudeHookEvent(repoRoot, input) {
|
|
161
|
+
const current = await this.getRoleSession(repoRoot, input.taskSlug, input.role);
|
|
162
|
+
if (!current || !matchesClaudeHookSession(current, input)) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
const timestamp = now();
|
|
166
|
+
const updated = {
|
|
167
|
+
...current,
|
|
168
|
+
activityStatus: input.eventName === "UserPromptSubmit" ? "running" : "idle",
|
|
169
|
+
lastHookEventAt: timestamp,
|
|
170
|
+
lastPromptSubmittedAt: input.eventName === "UserPromptSubmit"
|
|
171
|
+
? timestamp
|
|
172
|
+
: current.lastPromptSubmittedAt,
|
|
173
|
+
lastStopAt: input.eventName === "Stop"
|
|
174
|
+
? timestamp
|
|
175
|
+
: current.lastStopAt,
|
|
176
|
+
updatedAt: timestamp
|
|
177
|
+
};
|
|
178
|
+
deps.registry.upsert(updated);
|
|
179
|
+
const config = await deps.projectService.loadConfig(repoRoot);
|
|
180
|
+
const task = await deps.taskService.loadTask(repoRoot, input.taskSlug);
|
|
181
|
+
await persistTaskSession(deps.fs, getTaskRuntimeRepoRoot(task), config.stateRoot, updated);
|
|
182
|
+
return updated;
|
|
156
183
|
}
|
|
157
184
|
};
|
|
158
185
|
}
|
|
186
|
+
function matchesClaudeHookSession(record, input) {
|
|
187
|
+
if (input.claudeSessionId && record.claudeSessionId === input.claudeSessionId) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
if (input.transcriptPath && record.transcriptPath === input.transcriptPath) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (!input.claudeSessionId && !input.transcriptPath) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
159
198
|
function getRecoverableStatus(record) {
|
|
160
199
|
if (!record.claudeSessionId) {
|
|
161
200
|
return record.status === "running" ? "missing" : record.status;
|
|
@@ -16,84 +16,8 @@ export function createStatusService(deps) {
|
|
|
16
16
|
task,
|
|
17
17
|
sessions,
|
|
18
18
|
artifacts,
|
|
19
|
-
workflow: buildWorkflowReport(artifacts, sessions),
|
|
20
19
|
warnings
|
|
21
20
|
};
|
|
22
21
|
}
|
|
23
22
|
};
|
|
24
23
|
}
|
|
25
|
-
function buildWorkflowReport(artifacts, sessions) {
|
|
26
|
-
const isComplete = (kind) => artifacts.checks.find((check) => check.kind === kind)?.status === "ok";
|
|
27
|
-
const roleIsRunning = (role) => sessions.some((session) => session.role === role && session.status === "running");
|
|
28
|
-
const architectureComplete = isComplete("architecture-plan");
|
|
29
|
-
const implementationComplete = isComplete("implementation-log") && isComplete("validation-log");
|
|
30
|
-
const reviewComplete = isComplete("review-report");
|
|
31
|
-
const docsSyncComplete = isComplete("docs-sync-report");
|
|
32
|
-
const steps = [
|
|
33
|
-
{
|
|
34
|
-
id: "architecture-plan",
|
|
35
|
-
label: "Architecture",
|
|
36
|
-
role: "architect",
|
|
37
|
-
artifactPaths: [artifacts.paths.architecturePlanPath],
|
|
38
|
-
status: architectureComplete ? "complete" : "ready",
|
|
39
|
-
detail: architectureComplete
|
|
40
|
-
? "architecture-plan.md is ready."
|
|
41
|
-
: roleIsRunning("architect")
|
|
42
|
-
? "Architect is running; produce architecture-plan.md before coder work."
|
|
43
|
-
: "Start architect and produce architecture-plan.md before coder work."
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
id: "implementation",
|
|
47
|
-
label: "Implementation",
|
|
48
|
-
role: "coder",
|
|
49
|
-
artifactPaths: [artifacts.paths.implementationLogPath, artifacts.paths.validationLogPath],
|
|
50
|
-
status: implementationComplete ? "complete" : architectureComplete ? "ready" : "blocked",
|
|
51
|
-
detail: implementationComplete
|
|
52
|
-
? "implementation-log.md and validation-log.md are ready."
|
|
53
|
-
: architectureComplete
|
|
54
|
-
? "Start coder, then update implementation-log.md and validation-log.md."
|
|
55
|
-
: "Blocked until architecture-plan.md is complete."
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
id: "review",
|
|
59
|
-
label: "Review",
|
|
60
|
-
role: "reviewer",
|
|
61
|
-
artifactPaths: [artifacts.paths.reviewReportPath],
|
|
62
|
-
status: reviewComplete ? "complete" : implementationComplete ? "ready" : "blocked",
|
|
63
|
-
detail: reviewComplete
|
|
64
|
-
? "review-report.md is ready."
|
|
65
|
-
: implementationComplete
|
|
66
|
-
? "Start reviewer for independent review and final test adequacy."
|
|
67
|
-
: "Blocked until implementation-log.md and validation-log.md are complete."
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
id: "docs-sync",
|
|
71
|
-
label: "Docs Sync",
|
|
72
|
-
role: "architect",
|
|
73
|
-
artifactPaths: [artifacts.paths.docsSyncReportPath],
|
|
74
|
-
status: docsSyncComplete ? "complete" : reviewComplete ? "ready" : "blocked",
|
|
75
|
-
detail: docsSyncComplete
|
|
76
|
-
? "docs-sync-report.md is ready."
|
|
77
|
-
: reviewComplete
|
|
78
|
-
? "Send architect a docs-sync / architecture drift check task."
|
|
79
|
-
: "Blocked until review-report.md is complete."
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
id: "final-acceptance",
|
|
83
|
-
label: "PM Final",
|
|
84
|
-
role: "project-manager",
|
|
85
|
-
artifactPaths: [],
|
|
86
|
-
status: docsSyncComplete ? "ready" : "blocked",
|
|
87
|
-
detail: docsSyncComplete
|
|
88
|
-
? "Project Manager can prepare final acceptance, commit, and PR."
|
|
89
|
-
: "Blocked until architect docs sync is complete."
|
|
90
|
-
}
|
|
91
|
-
];
|
|
92
|
-
const current = steps.find((step) => step.status !== "complete") ?? steps[steps.length - 1];
|
|
93
|
-
return {
|
|
94
|
-
currentStepId: current.id,
|
|
95
|
-
nextAction: current.detail,
|
|
96
|
-
blocked: current.status === "blocked",
|
|
97
|
-
steps
|
|
98
|
-
};
|
|
99
|
-
}
|
|
@@ -9,5 +9,9 @@ export function renderArchitectHarnessRules() {
|
|
|
9
9
|
- Write docs-sync-report.md with docs changed, docs intentionally left unchanged, remaining documentation risks, and decision.
|
|
10
10
|
- Stop and reply to project-manager if implementation drift changes architecture, public contracts, dependency direction, schema, auth, permission, payment, or design assumptions.
|
|
11
11
|
- Reply to project-manager once per received VCM message when complete, blocked, or unclear; do not send fragmented progress updates unless project-manager explicitly requested them.
|
|
12
|
+
- If you need to send a VCM message, send at most one message to any single target role in the current Claude Code turn, then end the turn.
|
|
13
|
+
- After a successful vcmctl reply or vcmctl result, end the turn immediately. Do not run vcmctl inbox, poll, loop, or keep working while waiting for project-manager to answer.
|
|
14
|
+
- Do not wait in a loop for another role to answer. VCM will deliver later replies in a new turn.
|
|
15
|
+
- Do not use Claude Code Task/Subagent for VCM role delegation; communicate through vcmctl only.
|
|
12
16
|
`;
|
|
13
17
|
}
|
|
@@ -10,6 +10,9 @@ export function renderRootClaudeHarnessRules() {
|
|
|
10
10
|
- Non-PM roles only reply to project-manager; they do not message other roles directly.
|
|
11
11
|
- Role messaging is turn-based: do not send more than one active message to the same target role.
|
|
12
12
|
- After sending a message to a role, wait for that role to reply with vcmctl reply or vcmctl result before sending another message to the same role.
|
|
13
|
+
- After any successful vcmctl send, vcmctl reply, or vcmctl result, end the current Claude Code turn. Treat the command as the final coordination action of this turn.
|
|
14
|
+
- Do not run vcmctl inbox, poll files, start shell loops, or keep the turn open waiting for another role's answer. VCM will deliver replies in a later turn.
|
|
15
|
+
- Do not use Claude Code Task/Subagent for VCM role delegation; VCM owns the four role sessions and the message queue.
|
|
13
16
|
- If new information arrives while a role is still processing, update the relevant handoff artifact or wait; do not spam the target role's terminal.
|
|
14
17
|
- High-risk decisions involving schema, auth, permissions, payment, billing, security, data deletion, or unclear user intent must stop for project-manager/user approval.
|
|
15
18
|
- Required workflow gates: architect plan -> coder implementation/validation -> reviewer review -> architect docs sync -> project-manager final acceptance/commit/PR.
|
|
@@ -8,5 +8,9 @@ export function renderCoderHarnessRules() {
|
|
|
8
8
|
- Do not change module boundaries, public contracts, dependency direction, or test strategy without project-manager/architect replan.
|
|
9
9
|
- Stop and reply to project-manager when blocked, unclear, or when the plan no longer matches reality.
|
|
10
10
|
- Reply to project-manager once per received VCM message when complete, blocked, or unclear; do not send fragmented progress updates unless project-manager explicitly requested them.
|
|
11
|
+
- If you need to send a VCM message, send at most one message to any single target role in the current Claude Code turn, then end the turn.
|
|
12
|
+
- After a successful vcmctl reply or vcmctl result, end the turn immediately. Do not run vcmctl inbox, poll, loop, or keep working while waiting for project-manager to answer.
|
|
13
|
+
- Do not wait in a loop for another role to answer. VCM will deliver later replies in a new turn.
|
|
14
|
+
- Do not use Claude Code Task/Subagent for VCM role delegation; communicate through vcmctl only.
|
|
11
15
|
`;
|
|
12
16
|
}
|
|
@@ -7,6 +7,10 @@ export function renderProjectManagerHarnessRules() {
|
|
|
7
7
|
- Send role work as durable instructions with artifact refs when possible.
|
|
8
8
|
- Enforce per-role turn-taking: keep at most one in-flight message per target role.
|
|
9
9
|
- Before sending another task, question, revise, or review-request to the same role, wait for that role's vcmctl reply or vcmctl result.
|
|
10
|
+
- In one Claude Code turn, send at most one VCM message to any single target role.
|
|
11
|
+
- After a successful vcmctl send, end the turn immediately. Do not send another VCM message, run vcmctl inbox, poll for the target role's response, or keep the conversation open waiting for another agent.
|
|
12
|
+
- Continue orchestration only in a later turn after VCM delivers that role's vcmctl reply or vcmctl result.
|
|
13
|
+
- Do not use Claude Code Task/Subagent for VCM role delegation; VCM manages the four role sessions.
|
|
10
14
|
- Use cancel only for urgent supersession; include what is superseded.
|
|
11
15
|
- Track the workflow gates: architecture plan, implementation/validation, review, docs sync, final acceptance.
|
|
12
16
|
- Request architect post-review docs sync after reviewer completes.
|
|
@@ -10,5 +10,9 @@ export function renderReviewerHarnessRules() {
|
|
|
10
10
|
- Escalate architecture, public contract, design, or documentation drift issues to project-manager for architect follow-up.
|
|
11
11
|
- Do not take over broad implementation and do not weaken tests to pass validation.
|
|
12
12
|
- Reply to project-manager once per received VCM message when complete, blocked, or unclear; do not send fragmented progress updates unless project-manager explicitly requested them.
|
|
13
|
+
- If you need to send a VCM message, send at most one message to any single target role in the current Claude Code turn, then end the turn.
|
|
14
|
+
- After a successful vcmctl reply or vcmctl result, end the turn immediately. Do not run vcmctl inbox, poll, loop, or keep working while waiting for project-manager to answer.
|
|
15
|
+
- Do not wait in a loop for another role to answer. VCM will deliver later replies in a new turn.
|
|
16
|
+
- Do not use Claude Code Task/Subagent for VCM role delegation; communicate through vcmctl only.
|
|
13
17
|
`;
|
|
14
18
|
}
|
|
@@ -17,7 +17,9 @@ ${artifactRefs}
|
|
|
17
17
|
|
|
18
18
|
Instructions:
|
|
19
19
|
- Read the message and execute only within this VCM task.
|
|
20
|
-
- Reply to project-manager with vcmctl
|
|
20
|
+
- Reply to project-manager with vcmctl result when complete, or vcmctl reply when blocked or unclear.
|
|
21
|
+
- After a successful vcmctl reply or vcmctl result, end this Claude Code turn immediately.
|
|
22
|
+
- Do not run vcmctl inbox, poll, loop, or wait for project-manager in this turn. VCM will deliver later replies in a new turn.
|
|
21
23
|
[/VCM MESSAGE]
|
|
22
24
|
`;
|
|
23
25
|
}
|
package/dist/cli/vcmctl.js
CHANGED
|
@@ -33,6 +33,10 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
33
33
|
console.log(JSON.stringify(response, null, 2));
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
+
if (command === "hook-event") {
|
|
37
|
+
await sendHookEvent(await readStdinJson());
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
36
40
|
if (command === "ready") {
|
|
37
41
|
console.log("ready: VCM readiness signaling is planned for a later phase.");
|
|
38
42
|
return;
|
|
@@ -49,6 +53,31 @@ async function sendMessage(input) {
|
|
|
49
53
|
});
|
|
50
54
|
console.log(JSON.stringify(result, null, 2));
|
|
51
55
|
}
|
|
56
|
+
async function sendHookEvent(event) {
|
|
57
|
+
const input = {
|
|
58
|
+
taskSlug: getTaskSlug(),
|
|
59
|
+
role: getEnvRole(),
|
|
60
|
+
event
|
|
61
|
+
};
|
|
62
|
+
await fetchJson(`${getApiUrl()}/api/hooks/claude-code`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
body: JSON.stringify(input),
|
|
65
|
+
headers: {
|
|
66
|
+
"content-type": "application/json"
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function readStdinJson() {
|
|
71
|
+
const chunks = [];
|
|
72
|
+
for await (const chunk of process.stdin) {
|
|
73
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
74
|
+
}
|
|
75
|
+
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
76
|
+
if (!raw) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
return JSON.parse(raw);
|
|
80
|
+
}
|
|
52
81
|
function parseOptions(args) {
|
|
53
82
|
const options = {
|
|
54
83
|
artifactRefs: []
|
|
@@ -133,6 +162,7 @@ Usage:
|
|
|
133
162
|
vcmctl reply --type blocked --body "Need clarification."
|
|
134
163
|
vcmctl result --body-file /tmp/result.md --artifact .ai/vcm/handoffs/implementation-log.md
|
|
135
164
|
vcmctl inbox
|
|
165
|
+
vcmctl hook-event < hook-payload.json
|
|
136
166
|
`);
|
|
137
167
|
}
|
|
138
168
|
main().catch((error) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|