vibe-coding-master 0.6.22 → 0.6.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 +37 -3
- package/dist/backend/adapters/filesystem.js +8 -0
- package/dist/backend/api/harness-routes.js +54 -0
- package/dist/backend/api/runtime-state-routes.js +6 -2
- package/dist/backend/server.js +16 -0
- package/dist/backend/services/app-settings-service.js +1 -0
- package/dist/backend/services/auto-memory-service.js +760 -0
- package/dist/backend/services/claude-hook-service.js +66 -0
- package/dist/backend/services/runtime-coordinator-service.js +34 -1
- package/dist/backend/services/session-service.js +3 -0
- package/dist/backend/templates/harness/architect-agent.js +3 -0
- package/dist/backend/templates/harness/claude-root.js +3 -1
- package/dist/backend/templates/harness/coder-agent.js +3 -0
- package/dist/backend/templates/harness/gate-review.js +3 -0
- package/dist/backend/templates/harness/harness-engineer-agent.js +32 -8
- package/dist/backend/templates/harness/project-manager-agent.js +3 -0
- package/dist/backend/templates/harness/role-memory.js +9 -0
- package/dist/backend/templates/harness/tester-agent.js +3 -0
- package/dist/shared/types/memory.js +8 -0
- package/dist-frontend/assets/index-9V9COJZy.js +96 -0
- package/dist-frontend/assets/{index-DmSHDyiQ.css → index-C2QzumXk.css} +1 -1
- package/dist-frontend/index.html +2 -2
- package/package.json +1 -1
- package/dist-frontend/assets/index-DYBg_qYS.js +0 -96
package/README.md
CHANGED
|
@@ -333,7 +333,7 @@ Gateway can:
|
|
|
333
333
|
- create a task
|
|
334
334
|
- close a task with confirmation
|
|
335
335
|
- send plain text to Project Manager
|
|
336
|
-
- push PM
|
|
336
|
+
- push the PM Round-final reply and Round status back to the active chat
|
|
337
337
|
- translate mobile messages when Gateway translation is enabled
|
|
338
338
|
|
|
339
339
|
Gateway does not expose the embedded terminal and does not send directly to
|
|
@@ -361,6 +361,12 @@ Common commands:
|
|
|
361
361
|
Gateway credentials and audit logs are stored in app-local state, not connected
|
|
362
362
|
repositories.
|
|
363
363
|
|
|
364
|
+
When Gateway starts, VCM enables conversation translation, auto-send, and the
|
|
365
|
+
`Round final reply` scope. On a normal Round end, Gateway sends the PM original
|
|
366
|
+
reply first, then reuses the matching translation already produced for the
|
|
367
|
+
translation panel. `/retry` explicitly creates a new translation only when the
|
|
368
|
+
previous Gateway translation failed or was unavailable.
|
|
369
|
+
|
|
364
370
|
## Harness Studio
|
|
365
371
|
|
|
366
372
|
Harness Studio is the UI for VCM harness maintenance.
|
|
@@ -371,8 +377,10 @@ Use it to:
|
|
|
371
377
|
- run bootstrap
|
|
372
378
|
- open Harness Engineer
|
|
373
379
|
- review harness files
|
|
380
|
+
- view and edit shared or role-specific VCM memory
|
|
381
|
+
- review and revert memory changes recorded in the active task worktree
|
|
374
382
|
- copy file paths for discussion
|
|
375
|
-
- review task harness after
|
|
383
|
+
- review task harness after post-task memory processing completes
|
|
376
384
|
- inspect commit diffs for harness changes
|
|
377
385
|
- merge task harness commits back to the connected repository branch when
|
|
378
386
|
appropriate
|
|
@@ -380,6 +388,32 @@ Use it to:
|
|
|
380
388
|
Harness Engineer is project-scoped and resumable. When it performs task work,
|
|
381
389
|
VCM runs it from the active task worktree.
|
|
382
390
|
|
|
391
|
+
### Auto Memory
|
|
392
|
+
|
|
393
|
+
Enable `Auto memory` in the `VCM Harness` sidebar group to collect durable role
|
|
394
|
+
knowledge after a complete task passes Final Acceptance. Project Manager,
|
|
395
|
+
Architect, Coder, Tester, and an enabled Gate Reviewer submit memory drafts in
|
|
396
|
+
sequence. Harness Engineer verifies and consolidates them before VCM applies
|
|
397
|
+
the result.
|
|
398
|
+
|
|
399
|
+
Canonical memory is stored under the base repository's `.ai/vcm/memory/`.
|
|
400
|
+
Harness Studio shows current memory and task-local applied history. Memory is
|
|
401
|
+
applied before user review; while the task worktree remains available, the user
|
|
402
|
+
can edit current memory or revert a recorded change.
|
|
403
|
+
|
|
404
|
+
Post-task processing is ordered by the backend:
|
|
405
|
+
|
|
406
|
+
```text
|
|
407
|
+
Final Acceptance
|
|
408
|
+
-> Auto Memory, when enabled
|
|
409
|
+
-> Task Harness Retrospective
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Auto Memory adds no retrospective prerequisite when it is disabled. When it is
|
|
413
|
+
enabled, both automatic and manual retrospective requests wait until memory has
|
|
414
|
+
been applied for the current Final Acceptance. A failed memory review must be
|
|
415
|
+
retried from Harness Studio before retrospective can run.
|
|
416
|
+
|
|
383
417
|
## Closing a Task
|
|
384
418
|
|
|
385
419
|
`Close Task` is destructive.
|
|
@@ -480,5 +514,5 @@ npm start
|
|
|
480
514
|
- `docs/ARCHITECTURE.md`: repository architecture
|
|
481
515
|
- `docs/TESTING.md`: validation strategy
|
|
482
516
|
- `docs/vcm-cc-best-practices.md`: current VCM Claude Code harness practice
|
|
483
|
-
- `docs/v0.5-custom-workflow-plan.md`:
|
|
517
|
+
- `docs/v0.5-custom-workflow-plan.md`: deferred custom workflow proposal
|
|
484
518
|
- `docs/cc-best-practices.md`: archived generic Claude Code harness notes
|
|
@@ -47,6 +47,14 @@ export function createNodeFileSystemAdapter() {
|
|
|
47
47
|
await fs.writeFile(targetPath, content, "utf8");
|
|
48
48
|
});
|
|
49
49
|
},
|
|
50
|
+
async writeTextAtomic(targetPath, content) {
|
|
51
|
+
await runFileOperation(async () => {
|
|
52
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
53
|
+
const tempPath = `${targetPath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
54
|
+
await fs.writeFile(tempPath, content, "utf8");
|
|
55
|
+
await fs.rename(tempPath, targetPath);
|
|
56
|
+
});
|
|
57
|
+
},
|
|
50
58
|
async appendText(targetPath, content) {
|
|
51
59
|
await runFileOperation(async () => {
|
|
52
60
|
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
@@ -66,11 +66,13 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
66
66
|
});
|
|
67
67
|
app.post("/api/projects/harness/bootstrap/start", async (request) => {
|
|
68
68
|
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
69
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
69
70
|
await deps.harnessFeedbackService.assertHarnessEngineerAvailable(project.repoRoot);
|
|
70
71
|
return deps.harnessService.startHarnessBootstrap(project.repoRoot, task.worktreePath, request.body ?? {});
|
|
71
72
|
});
|
|
72
73
|
app.post("/api/projects/harness/bootstrap/restart", async (request) => {
|
|
73
74
|
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
75
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
74
76
|
await deps.harnessFeedbackService.assertHarnessEngineerAvailable(project.repoRoot);
|
|
75
77
|
return deps.harnessService.restartHarnessBootstrap(project.repoRoot, task.worktreePath, request.body ?? {});
|
|
76
78
|
});
|
|
@@ -80,6 +82,7 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
80
82
|
});
|
|
81
83
|
app.post("/api/projects/harness/bootstrap/run", async (request) => {
|
|
82
84
|
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
85
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
83
86
|
await deps.harnessFeedbackService.assertHarnessEngineerAvailable(project.repoRoot);
|
|
84
87
|
return deps.harnessService.runHarnessBootstrap(project.repoRoot, task.worktreePath);
|
|
85
88
|
});
|
|
@@ -93,14 +96,26 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
93
96
|
});
|
|
94
97
|
app.post("/api/projects/harness/engineer/session/start", async (request) => {
|
|
95
98
|
const project = await requireCurrentProject(deps.projectService);
|
|
99
|
+
if (request.body?.taskSlug) {
|
|
100
|
+
const task = await deps.taskService.loadTask(project.repoRoot, request.body.taskSlug);
|
|
101
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
102
|
+
}
|
|
96
103
|
return deps.sessionService.startProjectHarnessEngineerSession(project.repoRoot, request.body);
|
|
97
104
|
});
|
|
98
105
|
app.post("/api/projects/harness/engineer/session/resume", async (request) => {
|
|
99
106
|
const project = await requireCurrentProject(deps.projectService);
|
|
107
|
+
if (request.body?.taskSlug) {
|
|
108
|
+
const task = await deps.taskService.loadTask(project.repoRoot, request.body.taskSlug);
|
|
109
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
110
|
+
}
|
|
100
111
|
return deps.sessionService.resumeProjectHarnessEngineerSession(project.repoRoot, request.body);
|
|
101
112
|
});
|
|
102
113
|
app.post("/api/projects/harness/engineer/session/restart", async (request) => {
|
|
103
114
|
const project = await requireCurrentProject(deps.projectService);
|
|
115
|
+
if (request.body?.taskSlug) {
|
|
116
|
+
const task = await deps.taskService.loadTask(project.repoRoot, request.body.taskSlug);
|
|
117
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
118
|
+
}
|
|
104
119
|
return deps.sessionService.restartProjectHarnessEngineerSession(project.repoRoot, request.body);
|
|
105
120
|
});
|
|
106
121
|
app.post("/api/projects/harness/engineer/session/stop", async () => {
|
|
@@ -127,6 +142,10 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
127
142
|
});
|
|
128
143
|
}
|
|
129
144
|
const taskSlug = await normalizeOptionalTaskSlug(deps, project.repoRoot, request.body?.taskSlug);
|
|
145
|
+
if (taskSlug && (action === "approve" || action === "comment")) {
|
|
146
|
+
const task = await deps.taskService.loadTask(project.repoRoot, taskSlug);
|
|
147
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
148
|
+
}
|
|
130
149
|
return deps.harnessFeedbackService.decide(project.repoRoot, {
|
|
131
150
|
action,
|
|
132
151
|
taskSlug,
|
|
@@ -135,6 +154,14 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
135
154
|
});
|
|
136
155
|
app.post("/api/projects/harness/task-retrospective", async (request) => {
|
|
137
156
|
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
157
|
+
await deps.autoMemoryService.assertTaskRetrospectiveReady({
|
|
158
|
+
baseRepoRoot: project.repoRoot,
|
|
159
|
+
taskRepoRoot: task.worktreePath,
|
|
160
|
+
taskSlug: task.taskSlug,
|
|
161
|
+
handoffDir: task.handoffDir,
|
|
162
|
+
roundReady: true
|
|
163
|
+
});
|
|
164
|
+
await deps.autoMemoryService.assertHarnessEngineerAvailable(task.worktreePath);
|
|
138
165
|
const trigger = request.body?.trigger === "auto" ? "auto" : "manual";
|
|
139
166
|
return deps.harnessFeedbackService.startTaskRetrospective(project.repoRoot, {
|
|
140
167
|
taskSlug: task.taskSlug,
|
|
@@ -143,6 +170,33 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
143
170
|
trigger
|
|
144
171
|
});
|
|
145
172
|
});
|
|
173
|
+
app.get("/api/projects/harness/memory", async (request) => {
|
|
174
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.query.taskSlug);
|
|
175
|
+
return deps.autoMemoryService.getState(project.repoRoot, task.worktreePath);
|
|
176
|
+
});
|
|
177
|
+
app.get("/api/projects/harness/memory/file", async (request) => {
|
|
178
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.query.taskSlug);
|
|
179
|
+
return deps.autoMemoryService.getFile(project.repoRoot, task.worktreePath, request.query.path ?? "");
|
|
180
|
+
});
|
|
181
|
+
app.put("/api/projects/harness/memory/file", async (request) => {
|
|
182
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.query.taskSlug ?? request.body?.taskSlug);
|
|
183
|
+
if (typeof request.body?.content !== "string") {
|
|
184
|
+
throw new VcmError({
|
|
185
|
+
code: "MEMORY_FILE_CONTENT_INVALID",
|
|
186
|
+
message: "Memory file content must be a string.",
|
|
187
|
+
statusCode: 400
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return deps.autoMemoryService.updateFile(project.repoRoot, task.worktreePath, task.taskSlug, request.query.path ?? "", request.body.content);
|
|
191
|
+
});
|
|
192
|
+
app.post("/api/projects/harness/memory/revert", async (request) => {
|
|
193
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
194
|
+
return deps.autoMemoryService.revertRun(project.repoRoot, task.worktreePath, request.body?.runId ?? "");
|
|
195
|
+
});
|
|
196
|
+
app.post("/api/projects/harness/memory/retry", async (request) => {
|
|
197
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
198
|
+
return deps.autoMemoryService.retryFailedReview(project.repoRoot, task.worktreePath);
|
|
199
|
+
});
|
|
146
200
|
}
|
|
147
201
|
function degradedHarnessStatus(error) {
|
|
148
202
|
return {
|
|
@@ -18,14 +18,16 @@ export function registerRuntimeStateRoutes(app, deps) {
|
|
|
18
18
|
harnessStatus: null,
|
|
19
19
|
harnessBootstrapStatus: null,
|
|
20
20
|
harnessFeedbackState,
|
|
21
|
+
autoMemoryState: null,
|
|
21
22
|
gatewayStatus: coordinated.gatewayStatus
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
25
|
try {
|
|
25
26
|
const task = await deps.taskService.loadTask(project.repoRoot, taskSlug);
|
|
26
|
-
const [harnessStatus, harnessBootstrapStatus] = await Promise.all([
|
|
27
|
+
const [harnessStatus, harnessBootstrapStatus, autoMemoryState] = await Promise.all([
|
|
27
28
|
withOpenFileLimitFallback(() => deps.harnessService.getHarnessStatus(task.worktreePath), (error) => degradedHarnessStatus(error)),
|
|
28
|
-
withOpenFileLimitFallback(() => deps.harnessService.getBootstrapStatus(project.repoRoot, task.worktreePath), (error) => degradedBootstrapStatus(error))
|
|
29
|
+
withOpenFileLimitFallback(() => deps.harnessService.getBootstrapStatus(project.repoRoot, task.worktreePath), (error) => degradedBootstrapStatus(error)),
|
|
30
|
+
deps.autoMemoryService.getState(project.repoRoot, task.worktreePath)
|
|
29
31
|
]);
|
|
30
32
|
return {
|
|
31
33
|
translatorSession,
|
|
@@ -34,6 +36,7 @@ export function registerRuntimeStateRoutes(app, deps) {
|
|
|
34
36
|
harnessStatus,
|
|
35
37
|
harnessBootstrapStatus,
|
|
36
38
|
harnessFeedbackState,
|
|
39
|
+
autoMemoryState,
|
|
37
40
|
gatewayStatus: coordinated.gatewayStatus
|
|
38
41
|
};
|
|
39
42
|
}
|
|
@@ -46,6 +49,7 @@ export function registerRuntimeStateRoutes(app, deps) {
|
|
|
46
49
|
harnessStatus: degradedHarnessStatus(error),
|
|
47
50
|
harnessBootstrapStatus: degradedBootstrapStatus(error),
|
|
48
51
|
harnessFeedbackState,
|
|
52
|
+
autoMemoryState: null,
|
|
49
53
|
gatewayStatus: coordinated.gatewayStatus
|
|
50
54
|
};
|
|
51
55
|
}
|
package/dist/backend/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createCommandDispatcher } from "./services/command-dispatcher.js";
|
|
|
9
9
|
import { createClaudeHookService } from "./services/claude-hook-service.js";
|
|
10
10
|
import { createGitAdapter } from "./adapters/git-adapter.js";
|
|
11
11
|
import { createAppSettingsService } from "./services/app-settings-service.js";
|
|
12
|
+
import { createAutoMemoryService } from "./services/auto-memory-service.js";
|
|
12
13
|
import { createClaudeTranscriptService } from "./services/claude-transcript-service.js";
|
|
13
14
|
import { createGateReviewService } from "./services/gate-review-service.js";
|
|
14
15
|
import { createHarnessFeedbackService } from "./services/harness-feedback-service.js";
|
|
@@ -94,6 +95,7 @@ export async function createServer(deps, options = {}) {
|
|
|
94
95
|
projectService: deps.projectService,
|
|
95
96
|
harnessService: deps.harnessService,
|
|
96
97
|
harnessFeedbackService: deps.harnessFeedbackService,
|
|
98
|
+
autoMemoryService: deps.autoMemoryService,
|
|
97
99
|
sessionService: deps.sessionService,
|
|
98
100
|
taskService: deps.taskService
|
|
99
101
|
});
|
|
@@ -104,6 +106,7 @@ export async function createServer(deps, options = {}) {
|
|
|
104
106
|
translationWorkerService: deps.translationWorkerService,
|
|
105
107
|
harnessService: deps.harnessService,
|
|
106
108
|
harnessFeedbackService: deps.harnessFeedbackService,
|
|
109
|
+
autoMemoryService: deps.autoMemoryService,
|
|
107
110
|
runtimeCoordinator: deps.runtimeCoordinator
|
|
108
111
|
});
|
|
109
112
|
registerTaskRoutes(app, {
|
|
@@ -222,6 +225,16 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
222
225
|
runtime,
|
|
223
226
|
sessionService
|
|
224
227
|
});
|
|
228
|
+
const autoMemoryService = createAutoMemoryService({
|
|
229
|
+
fs,
|
|
230
|
+
runtime,
|
|
231
|
+
sessionService,
|
|
232
|
+
appSettings,
|
|
233
|
+
async isHarnessEngineerAvailable(repoRoot) {
|
|
234
|
+
const state = await harnessFeedbackService.getState(repoRoot);
|
|
235
|
+
return state.status === "idle";
|
|
236
|
+
}
|
|
237
|
+
});
|
|
225
238
|
const commandDispatcher = createCommandDispatcher({
|
|
226
239
|
runtime,
|
|
227
240
|
sessionService,
|
|
@@ -314,6 +327,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
314
327
|
translationService,
|
|
315
328
|
harnessService,
|
|
316
329
|
harnessFeedbackService,
|
|
330
|
+
autoMemoryService,
|
|
317
331
|
roundService,
|
|
318
332
|
gatewayService,
|
|
319
333
|
async getStateRoot(repoRoot) {
|
|
@@ -338,6 +352,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
338
352
|
runtime,
|
|
339
353
|
harnessService,
|
|
340
354
|
harnessFeedbackService,
|
|
355
|
+
autoMemoryService,
|
|
341
356
|
gatewayService,
|
|
342
357
|
jobGuard: createJobGuardService(),
|
|
343
358
|
translationWorkerService
|
|
@@ -363,6 +378,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
363
378
|
artifactService,
|
|
364
379
|
harnessService,
|
|
365
380
|
harnessFeedbackService,
|
|
381
|
+
autoMemoryService,
|
|
366
382
|
commandDispatcher,
|
|
367
383
|
claudeHookService,
|
|
368
384
|
messageService,
|
|
@@ -242,6 +242,7 @@ function normalizePreferences(input) {
|
|
|
242
242
|
roleRetryEnabled: candidate.roleRetryEnabled !== false,
|
|
243
243
|
permissionRequestMode: normalizePermissionRequestMode(candidate.permissionRequestMode),
|
|
244
244
|
autoTaskHarnessReviewEnabled: candidate.autoTaskHarnessReviewEnabled === true,
|
|
245
|
+
autoMemoryEnabled: candidate.autoMemoryEnabled === true,
|
|
245
246
|
translationEnabled: candidate.translationEnabled === true,
|
|
246
247
|
translationAutoSendEnabled: candidate.translationAutoSendEnabled === true,
|
|
247
248
|
translationTargetLanguage: normalizeTranslationTargetLanguage(candidate.translationTargetLanguage),
|