vibe-coding-master 0.8.11 → 0.8.13
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/dist/backend/api/message-routes.js +4 -0
- package/dist/backend/services/auto-memory-service.js +2 -1
- package/dist/backend/services/code-intelligence-service.js +3 -1
- package/dist/backend/services/gate-review-service.js +24 -15
- package/dist/backend/services/harness-service.js +2 -1
- package/dist/backend/services/lsp-plugin.js +26 -0
- package/dist/backend/services/message-service.js +17 -1
- package/dist/backend/services/pm-user-question.js +2 -1
- package/dist/backend/services/session-service.js +8 -5
- package/dist/backend/services/workflow-control-service.js +17 -5
- package/dist/backend/templates/harness/architect-agent.js +3 -2
- package/dist/backend/templates/harness/architect-evidence-worker-agent.js +2 -1
- package/dist/backend/templates/harness/architect-scaffold-worker-agent.js +8 -2
- package/dist/backend/templates/harness/architect-validation-worker-agent.js +2 -1
- package/dist/backend/templates/harness/coder-worker-agent.js +1 -0
- package/dist/backend/templates/harness/vcm-code-navigation-skill.js +1 -1
- package/dist/backend/templates/harness/vcm-propose-memory-skill.js +4 -0
- package/dist/backend/templates/harness/vcm-report-harness-issue-skill.js +6 -2
- package/dist-frontend/assets/{index-Db0OTAez.js → index-DqANomt1.js} +24 -24
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
- package/scripts/harness-tools/vcm-artifact +1 -1
|
@@ -24,6 +24,10 @@ export function registerMessageRoutes(app, deps) {
|
|
|
24
24
|
const context = await getRouteContext(deps, request.params.taskSlug);
|
|
25
25
|
return deps.messageService.deleteMessageHistory(context);
|
|
26
26
|
});
|
|
27
|
+
app.post("/api/tasks/:taskSlug/messages/:messageId/confirm-delivered", async (request) => {
|
|
28
|
+
const context = await getRouteContext(deps, request.params.taskSlug);
|
|
29
|
+
return deps.messageService.confirmDeliveredDispatch(context, request.params.messageId);
|
|
30
|
+
});
|
|
27
31
|
app.get("/api/tasks/:taskSlug/orchestration", async (request) => {
|
|
28
32
|
return withOpenFileLimitFallback(async () => {
|
|
29
33
|
const context = await getRouteContext(deps, request.params.taskSlug);
|
|
@@ -1470,7 +1470,8 @@ function buildRoleDraftPrompt(taskRepoRoot, state, draft, planningCandidatePath)
|
|
|
1470
1470
|
"Review that candidate against final task evidence. Carry forward only facts that remain verified after implementation and testing."
|
|
1471
1471
|
]
|
|
1472
1472
|
: []),
|
|
1473
|
-
`Assigned proposal path: ${
|
|
1473
|
+
`Assigned proposal path: ${draft.path}`,
|
|
1474
|
+
"Pass the assigned repository-relative path to vcm-artifact --path."
|
|
1474
1475
|
];
|
|
1475
1476
|
return [
|
|
1476
1477
|
...prompt,
|
|
@@ -64,7 +64,9 @@ export function createHarnessCodeIntelligenceDetector(fs, options = {}) {
|
|
|
64
64
|
const now = options.now ?? Date.now;
|
|
65
65
|
const cacheTtlMs = options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
66
66
|
return {
|
|
67
|
-
async detect(repoRoot) {
|
|
67
|
+
async detect(repoRoot, detectOptions) {
|
|
68
|
+
if (detectOptions?.refresh)
|
|
69
|
+
probeCache.clear();
|
|
68
70
|
return detectCodeIntelligence(fs, repoRoot, options, async (definition, executablePath) => {
|
|
69
71
|
const cacheKey = `${executablePath}\u0000${definition.probeArgs.join("\u0000")}`;
|
|
70
72
|
const cached = probeCache.get(cacheKey);
|
|
@@ -1173,7 +1173,7 @@ async function resolveCodeDiffBaseCommit(deps, context, record, headCommit) {
|
|
|
1173
1173
|
"merge-base",
|
|
1174
1174
|
"HEAD",
|
|
1175
1175
|
rootBranch
|
|
1176
|
-
], {
|
|
1176
|
+
], { expectedFailure: "no-common-ancestor" })).trim();
|
|
1177
1177
|
if (mergeBase
|
|
1178
1178
|
&& mergeBase !== headCommit
|
|
1179
1179
|
&& await isAncestor(deps.runner, context.taskRepoRoot, mergeBase, headCommit)) {
|
|
@@ -1185,13 +1185,13 @@ async function resolveCodeDiffBaseCommit(deps, context, record, headCommit) {
|
|
|
1185
1185
|
"--abbrev-ref",
|
|
1186
1186
|
"--symbolic-full-name",
|
|
1187
1187
|
"@{upstream}"
|
|
1188
|
-
], {
|
|
1188
|
+
], { expectedFailure: "missing-upstream" })).trim();
|
|
1189
1189
|
if (upstream) {
|
|
1190
1190
|
const mergeBase = (await commandStdout(deps.runner, context.taskRepoRoot, [
|
|
1191
1191
|
"merge-base",
|
|
1192
1192
|
"HEAD",
|
|
1193
1193
|
upstream
|
|
1194
|
-
], {
|
|
1194
|
+
], { expectedFailure: "no-common-ancestor" })).trim();
|
|
1195
1195
|
if (mergeBase
|
|
1196
1196
|
&& mergeBase !== headCommit
|
|
1197
1197
|
&& await isAncestor(deps.runner, context.taskRepoRoot, mergeBase, headCommit)) {
|
|
@@ -1201,7 +1201,9 @@ async function resolveCodeDiffBaseCommit(deps, context, record, headCommit) {
|
|
|
1201
1201
|
return headCommit;
|
|
1202
1202
|
}
|
|
1203
1203
|
async function isAncestor(runner, cwd, ancestor, descendant) {
|
|
1204
|
-
const result = await runner
|
|
1204
|
+
const result = await readGateGit(runner, cwd, ["merge-base", "--is-ancestor", ancestor, descendant], {
|
|
1205
|
+
expectedFailure: "not-ancestor"
|
|
1206
|
+
});
|
|
1205
1207
|
return result.exitCode === 0;
|
|
1206
1208
|
}
|
|
1207
1209
|
async function computeInputHash(deps, taskRepoRoot, gate, codeDiffInput, codeDiffSources) {
|
|
@@ -1412,18 +1414,19 @@ async function readCodeDiffSourceArtifactError(fs, taskRepoRoot, source) {
|
|
|
1412
1414
|
return undefined;
|
|
1413
1415
|
}
|
|
1414
1416
|
async function commandStdout(runner, cwd, args, options = {}) {
|
|
1415
|
-
const
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1417
|
+
const result = await readGateGit(runner, cwd, args, options);
|
|
1418
|
+
return result.exitCode === 0 ? result.stdout : "";
|
|
1419
|
+
}
|
|
1420
|
+
async function readGateGit(runner, cwd, args, options = {}) {
|
|
1421
|
+
const retryDelays = [500, 1000, 2000];
|
|
1422
|
+
for (let attempt = 0;; attempt += 1) {
|
|
1423
|
+
const result = await runner.run("git", ["-c", `safe.directory=${path.resolve(cwd)}`, ...args], { cwd });
|
|
1424
|
+
if (result.exitCode === 0 || isExpectedGitFailure(result, options.expectedFailure))
|
|
1425
|
+
return result;
|
|
1426
|
+
if (attempt < retryDelays.length) {
|
|
1427
|
+
await delay(retryDelays[attempt]);
|
|
1423
1428
|
continue;
|
|
1424
1429
|
}
|
|
1425
|
-
if (options.allowFailure)
|
|
1426
|
-
return "";
|
|
1427
1430
|
const detail = result.stderr.trim() || result.stdout.trim() || "Git did not provide an error message.";
|
|
1428
1431
|
throw new VcmError({
|
|
1429
1432
|
code: "GATE_REVIEW_GIT_COMMAND_FAILED",
|
|
@@ -1431,7 +1434,13 @@ async function commandStdout(runner, cwd, args, options = {}) {
|
|
|
1431
1434
|
statusCode: 409
|
|
1432
1435
|
});
|
|
1433
1436
|
}
|
|
1434
|
-
|
|
1437
|
+
}
|
|
1438
|
+
function isExpectedGitFailure(result, expected) {
|
|
1439
|
+
if (expected === "not-ancestor" || expected === "no-common-ancestor") {
|
|
1440
|
+
return result.exitCode === 1 && !result.stderr.trim() && !result.stdout.trim();
|
|
1441
|
+
}
|
|
1442
|
+
return expected === "missing-upstream" && result.exitCode === 128
|
|
1443
|
+
&& /^fatal: (no upstream configured for branch |HEAD does not point to a branch)/.test(result.stderr.trim());
|
|
1435
1444
|
}
|
|
1436
1445
|
function splitLines(value) {
|
|
1437
1446
|
return value
|
|
@@ -37,6 +37,7 @@ import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
|
37
37
|
import { VcmError } from "../errors.js";
|
|
38
38
|
import { bumpHarnessRevision, readHarnessRevisionState } from "./harness-revision.js";
|
|
39
39
|
import { createHarnessCodeIntelligenceDetector } from "./code-intelligence-service.js";
|
|
40
|
+
import { lspUnavailableWarning } from "./lsp-plugin.js";
|
|
40
41
|
const execFileAsync = promisify(execFile);
|
|
41
42
|
const BOOTSTRAP_SESSION_PATH = ".ai/vcm/bootstrap/session.json";
|
|
42
43
|
const HARNESS_ENGINEER_SESSION_PATH = ".ai/vcm/harness-engineer/session.json";
|
|
@@ -1410,7 +1411,7 @@ function renderHarnessStatus(harnessRevision, analyses, legacyChanges = [], mani
|
|
|
1410
1411
|
...(plannedChanges.length > 0 ? ["Review and commit VCM Harness changes before starting long-running work."] : []),
|
|
1411
1412
|
...((codeIntelligence?.languages ?? [])
|
|
1412
1413
|
.filter((language) => language.state !== "server_runnable")
|
|
1413
|
-
.map(
|
|
1414
|
+
.map(lspUnavailableWarning))
|
|
1414
1415
|
]
|
|
1415
1416
|
};
|
|
1416
1417
|
}
|
|
@@ -17,3 +17,29 @@ export async function prepareTaskLspPlugin(fs, taskRepoRoot, status) {
|
|
|
17
17
|
await fs.writeJsonAtomic(pluginManifestPath, { ...manifest, lspServers });
|
|
18
18
|
return [pluginDir];
|
|
19
19
|
}
|
|
20
|
+
export function lspUnavailableWarning(language) {
|
|
21
|
+
const installCommands = {
|
|
22
|
+
"rust-analyzer": "rustup component add rust-analyzer",
|
|
23
|
+
"typescript-language-server": "npm install -g typescript typescript-language-server",
|
|
24
|
+
"pyright-langserver": "npm install -g pyright",
|
|
25
|
+
"gopls": "go install golang.org/x/tools/gopls@latest"
|
|
26
|
+
};
|
|
27
|
+
const recovery = language.state === "plugin_missing"
|
|
28
|
+
? "Refresh the VCM Harness to restore the LSP plugin."
|
|
29
|
+
: `Install or repair ${language.serverCommand} in the environment running the VCM backend${installCommands[language.serverCommand] ? ` (${installCommands[language.serverCommand]})` : ""} and ensure it is executable on PATH.`;
|
|
30
|
+
return `Architect LSP for ${language.label} is unavailable: ${language.error ?? `${language.serverCommand} is not runnable.`} ${recovery} Restart Architect after fixing the environment so VCM can detect and register the server again.`;
|
|
31
|
+
}
|
|
32
|
+
export function renderArchitectLspNotice(status) {
|
|
33
|
+
if (status.languages.length === 0)
|
|
34
|
+
return undefined;
|
|
35
|
+
const available = status.languages.filter((language) => language.state === "server_runnable");
|
|
36
|
+
const unavailable = status.languages.filter((language) => language.state !== "server_runnable");
|
|
37
|
+
return [
|
|
38
|
+
"[VCM Architect LSP Availability]",
|
|
39
|
+
`Registered language servers: ${available.map((language) => `${language.label} (${language.serverCommand})`).join(", ") || "none"}.`,
|
|
40
|
+
...unavailable.map(lspUnavailableWarning),
|
|
41
|
+
...(unavailable.length > 0 ? [
|
|
42
|
+
"If your assignment requires a semantic query in an unavailable language, stop that work and report the environment prerequisite through the current communication channel. Do not substitute source text search or claim the relationship is verified. Continue only after the server is available."
|
|
43
|
+
] : [])
|
|
44
|
+
].join("\n");
|
|
45
|
+
}
|
|
@@ -11,7 +11,7 @@ const DEFAULT_PRE_DISPATCH_SWITCH_DELAY_MS = 500;
|
|
|
11
11
|
const DEFAULT_AUTO_DISPATCH_ENTER_DELAY_MS = 500;
|
|
12
12
|
const DEFAULT_DISPATCH_CONFIRMATION_RETRY_DELAYS_MS = [1500, 3000];
|
|
13
13
|
const DEFAULT_DISPATCH_CONFIRMATION_FAILURE_DELAY_MS = 3000;
|
|
14
|
-
const DISPATCH_NOT_CONFIRMED_REASON = "Auto orchestration pasted the message, but Claude Code did not confirm submission.
|
|
14
|
+
const DISPATCH_NOT_CONFIRMED_REASON = "Auto orchestration pasted the message, but Claude Code did not confirm submission. Inspect the target terminal: press Enter if the prompt was not submitted, or use Confirm Executed if the role already executed it.";
|
|
15
15
|
const INVALID_ROUTE_REASON = "Invalid route: non-PM roles must route through project-manager.";
|
|
16
16
|
export function createMessageService(deps) {
|
|
17
17
|
const now = deps.now ?? (() => new Date().toISOString());
|
|
@@ -208,6 +208,22 @@ export function createMessageService(deps) {
|
|
|
208
208
|
return accepted;
|
|
209
209
|
});
|
|
210
210
|
},
|
|
211
|
+
async confirmDeliveredDispatch(input, messageId) {
|
|
212
|
+
return withTaskLock(taskLocks, getMessagesPath(getStateRepoRoot(input), input.stateRoot, input.taskSlug), async () => {
|
|
213
|
+
const messages = await readLatestMessages(deps.fs, getMessagesPath(getStateRepoRoot(input), input.stateRoot, input.taskSlug));
|
|
214
|
+
const message = messages.find((entry) => entry.id === messageId);
|
|
215
|
+
if (!message || message.fromRole !== PM_ROLE || !message.deliveredAt || !deps.workflowControlService) {
|
|
216
|
+
throw new VcmError({ code: "MESSAGE_NOT_DELIVERED", message: `Message ${messageId} is not a delivered PM workflow dispatch.`, statusCode: 409 });
|
|
217
|
+
}
|
|
218
|
+
if (message.acceptedAt)
|
|
219
|
+
return message;
|
|
220
|
+
await deps.workflowControlService.confirmDispatch(toWorkflowContext(input), messageId, "manual");
|
|
221
|
+
const accepted = { ...message, acceptedAt: now(), confirmationSource: "manual", failureReason: undefined };
|
|
222
|
+
await appendMessageSnapshot(deps.fs, input, accepted);
|
|
223
|
+
await clearRouteFileIfStillMatchesMessage(deps.fs, input, accepted);
|
|
224
|
+
return accepted;
|
|
225
|
+
});
|
|
226
|
+
},
|
|
211
227
|
async markAllDone(input) {
|
|
212
228
|
return withTaskLock(taskLocks, getMessagesPath(getStateRepoRoot(input), input.stateRoot, input.taskSlug), async () => {
|
|
213
229
|
const messages = await readLatestMessages(deps.fs, getMessagesPath(getStateRepoRoot(input), input.stateRoot, input.taskSlug));
|
|
@@ -6,7 +6,8 @@ const markdown = unified().use(remarkParse).use(remarkGfm).freeze();
|
|
|
6
6
|
const DIRECT_REQUESTS = [
|
|
7
7
|
/^(?:can|could|do|did|are|have|should|will|would)\s+you\b/i,
|
|
8
8
|
/^(?:should|shall|may|can|could)\s+(?:i|we)\b/i,
|
|
9
|
-
/^(?:which|what|how|where|when|who)\
|
|
9
|
+
/^(?:which|what|how|where|when|who)\s+(?:is|are|was|were|do|did|have|has|can|could|will|would|should|shall|may)\s+(?:you|your|i|we)\b/i,
|
|
10
|
+
/^(?:which|what|how|where|when|who)\b[^.!?:,;]*\b(?:do|did|can|could|will|would|should|shall|may)\s+(?:you|i|we)\b/i,
|
|
10
11
|
/^(?:which|what)\s+(?:option|approach|behavior|behaviour|choice)\b[^.!?]*\bshould\s+be\b/i,
|
|
11
12
|
/^(?:please\s+)?(?:answer|reply|respond|choose|confirm|decide|provide|select|tell\s+me|let\s+me\s+know|give\s+(?:me|your))\b/i,
|
|
12
13
|
/^i\s+need\s+your\s+(?:decision|choice|confirmation|answer|approval)\b/i,
|
|
@@ -8,7 +8,7 @@ import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
|
8
8
|
import { claudeTranscriptPath } from "./claude-transcript-service.js";
|
|
9
9
|
import { readHarnessRevisionState } from "./harness-revision.js";
|
|
10
10
|
import { getTaskRuntimeRepoRoot } from "./task-service.js";
|
|
11
|
-
import { roleUsesLsp, prepareTaskLspPlugin, VCM_LSP_PLUGIN_DIR } from "./lsp-plugin.js";
|
|
11
|
+
import { roleUsesLsp, prepareTaskLspPlugin, renderArchitectLspNotice, VCM_LSP_PLUGIN_DIR } from "./lsp-plugin.js";
|
|
12
12
|
const TRANSLATOR_ROLE = "translator";
|
|
13
13
|
const HARNESS_ENGINEER_ROLE = "harness-engineer";
|
|
14
14
|
const TRANSLATION_DIR = ".ai/vcm/translations";
|
|
@@ -82,13 +82,16 @@ export function createSessionService(deps) {
|
|
|
82
82
|
: resumeClaudeSessionId
|
|
83
83
|
? claudeTranscriptPath(taskRepoRoot, resumeClaudeSessionId, persisted?.claudeConfigDir)
|
|
84
84
|
: undefined;
|
|
85
|
+
const lspStatus = roleUsesLsp(role) && deps.codeIntelligenceDetector
|
|
86
|
+
? await deps.codeIntelligenceDetector.detect(taskRepoRoot, { refresh: true })
|
|
87
|
+
: undefined;
|
|
85
88
|
const lspPluginDirs = roleUsesLsp(role)
|
|
86
|
-
? deps.
|
|
87
|
-
? await prepareTaskLspPlugin(deps.fs, taskRepoRoot, await deps.codeIntelligenceDetector.detect(taskRepoRoot))
|
|
88
|
-
: [VCM_LSP_PLUGIN_DIR]
|
|
89
|
+
? lspStatus ? await prepareTaskLspPlugin(deps.fs, taskRepoRoot, lspStatus) : [VCM_LSP_PLUGIN_DIR]
|
|
89
90
|
: [];
|
|
91
|
+
const appendSystemPrompt = [input.appendSystemPrompt, lspStatus && renderArchitectLspNotice(lspStatus)]
|
|
92
|
+
.filter(Boolean).join("\n\n") || undefined;
|
|
90
93
|
const startCommand = {
|
|
91
|
-
...deps.claude.buildRoleStartCommand(role, config.claudeCommand, permissionMode, resumeClaudeSessionId, launchMode === "resume", model, effort, modelSettingsOverride,
|
|
94
|
+
...deps.claude.buildRoleStartCommand(role, config.claudeCommand, permissionMode, resumeClaudeSessionId, launchMode === "resume", model, effort, modelSettingsOverride, appendSystemPrompt, lspPluginDirs),
|
|
92
95
|
cwd: taskRepoRoot
|
|
93
96
|
};
|
|
94
97
|
const runtimeSessionToken = randomUUID();
|
|
@@ -189,6 +189,9 @@ export function createWorkflowControlService(deps) {
|
|
|
189
189
|
await assertRouteAuthorized(input);
|
|
190
190
|
const state = await getState(input);
|
|
191
191
|
const pending = state.pendingDispatch;
|
|
192
|
+
const timestamp = now();
|
|
193
|
+
const progress = await readProgress(deps.fs, input);
|
|
194
|
+
const evidenceBaseline = await captureEvidenceBaseline(deps.fs, input, progress.history.length + 1, pending.effectiveFlow, pending.targetRole, timestamp);
|
|
192
195
|
await saveState(input, {
|
|
193
196
|
...state,
|
|
194
197
|
pendingDispatch: {
|
|
@@ -196,7 +199,8 @@ export function createWorkflowControlService(deps) {
|
|
|
196
199
|
status: "dispatching",
|
|
197
200
|
routeContentHash: input.routeContentHash,
|
|
198
201
|
messageId: input.messageId,
|
|
199
|
-
|
|
202
|
+
evidenceBaseline,
|
|
203
|
+
updatedAt: timestamp
|
|
200
204
|
},
|
|
201
205
|
updatedAt: now()
|
|
202
206
|
});
|
|
@@ -216,6 +220,7 @@ export function createWorkflowControlService(deps) {
|
|
|
216
220
|
routeContentHash: undefined,
|
|
217
221
|
messageId: undefined,
|
|
218
222
|
confirmationError: undefined,
|
|
223
|
+
evidenceBaseline: undefined,
|
|
219
224
|
updatedAt: now()
|
|
220
225
|
},
|
|
221
226
|
updatedAt: now()
|
|
@@ -257,7 +262,7 @@ export function createWorkflowControlService(deps) {
|
|
|
257
262
|
});
|
|
258
263
|
});
|
|
259
264
|
}
|
|
260
|
-
async function confirmDispatch(input, messageId) {
|
|
265
|
+
async function confirmDispatch(input, messageId, source = "hook") {
|
|
261
266
|
await withLock(statePath(input), async () => {
|
|
262
267
|
const state = await getState(input);
|
|
263
268
|
failOnStateWarnings({
|
|
@@ -269,6 +274,9 @@ export function createWorkflowControlService(deps) {
|
|
|
269
274
|
if (!pending || pending.status !== "dispatching" || pending.messageId !== messageId) {
|
|
270
275
|
throw workflowError("WORKFLOW_DISPATCH_CONFIRMATION_MISMATCH", `Message ${messageId} does not own the pending workflow dispatch.`, "Do not advance Workflow Progress from an unrelated UserPromptSubmit event.");
|
|
271
276
|
}
|
|
277
|
+
if (source === "manual" && !pending.confirmationError) {
|
|
278
|
+
throw workflowError("WORKFLOW_DISPATCH_NOT_UNCONFIRMED", "Manual confirmation is only available for a delivered dispatch whose confirmation failed.");
|
|
279
|
+
}
|
|
272
280
|
const current = await readProgress(deps.fs, input);
|
|
273
281
|
if (current.revision !== pending.revision || historyHash(current.history) !== pending.baseHistoryHash) {
|
|
274
282
|
throw workflowError("WORKFLOW_APPROVAL_STALE", "Workflow Progress changed before the approved dispatch was confirmed.", "Repair workflow-progress.md before continuing.");
|
|
@@ -278,12 +286,14 @@ export function createWorkflowControlService(deps) {
|
|
|
278
286
|
sequence: current.history.length + 1,
|
|
279
287
|
flow: pending.effectiveFlow,
|
|
280
288
|
targetRole: pending.targetRole,
|
|
281
|
-
evidence:
|
|
289
|
+
evidence: source === "manual"
|
|
290
|
+
? `${pending.evidence} [User manually confirmed execution of message ${messageId}.]`
|
|
291
|
+
: pending.evidence,
|
|
282
292
|
overrideAuthorizationId: pending.overrideAuthorizationId,
|
|
283
293
|
followUpApprovalId: pending.followUpApprovalId,
|
|
284
294
|
confirmedAt: timestamp
|
|
285
295
|
};
|
|
286
|
-
const activeDispatch = await captureEvidenceBaseline(deps.fs, input, entry.sequence, entry.flow, entry.targetRole, timestamp);
|
|
296
|
+
const activeDispatch = pending.evidenceBaseline ?? await captureEvidenceBaseline(deps.fs, input, entry.sequence, entry.flow, entry.targetRole, timestamp);
|
|
287
297
|
const flowRun = await advanceFlowRun(deps.fs, input, state, current, pending.effectiveFlow, entry.sequence);
|
|
288
298
|
const completed = {
|
|
289
299
|
...current,
|
|
@@ -339,6 +349,7 @@ export function createWorkflowControlService(deps) {
|
|
|
339
349
|
routeContentHash: undefined,
|
|
340
350
|
messageId: undefined,
|
|
341
351
|
confirmationError: undefined,
|
|
352
|
+
evidenceBaseline: undefined,
|
|
342
353
|
updatedAt: now()
|
|
343
354
|
},
|
|
344
355
|
updatedAt: now()
|
|
@@ -1292,7 +1303,7 @@ function stateProgressConsistencyWarnings(state, progress) {
|
|
|
1292
1303
|
}
|
|
1293
1304
|
function unconfirmedDispatchWarning(pending) {
|
|
1294
1305
|
return pending?.confirmationError
|
|
1295
|
-
? `PM dispatch ${pending.messageId ?? "unknown"} to ${pending.targetRole} was delivered but not confirmed: ${pending.confirmationError} Inspect the target session
|
|
1306
|
+
? `PM dispatch ${pending.messageId ?? "unknown"} to ${pending.targetRole} was delivered but not confirmed: ${pending.confirmationError} Inspect the target session and use Confirm Executed if it already ran; do not resend executed work.`
|
|
1296
1307
|
: undefined;
|
|
1297
1308
|
}
|
|
1298
1309
|
function abandonPendingApprovals(state, pending, reason, timestamp) {
|
|
@@ -1569,6 +1580,7 @@ function isPendingDispatch(value) {
|
|
|
1569
1580
|
&& (value.routeContentHash === undefined || typeof value.routeContentHash === "string")
|
|
1570
1581
|
&& (value.messageId === undefined || typeof value.messageId === "string")
|
|
1571
1582
|
&& (value.confirmationError === undefined || typeof value.confirmationError === "string")
|
|
1583
|
+
&& (value.evidenceBaseline === undefined || Boolean(normalizeDispatchEvidenceBaseline(value.evidenceBaseline)))
|
|
1572
1584
|
&& typeof value.createdAt === "string"
|
|
1573
1585
|
&& typeof value.updatedAt === "string";
|
|
1574
1586
|
}
|
|
@@ -22,7 +22,7 @@ ${renderRoleMemoryRules("architect")}
|
|
|
22
22
|
### Semantic Code Navigation
|
|
23
23
|
|
|
24
24
|
- Follow the preloaded \`vcm-code-navigation\` skill whenever work requires code definitions, implementations, references, callers, callees, or behavior paths. This applies in every Architect mode and in direct user communication.
|
|
25
|
-
- LSP is mandatory
|
|
25
|
+
- LSP is mandatory for navigating project source code. Start source-code navigation with a registered LSP server. If a required language server is unavailable, stop the affected work and report its language, command, error, and installation hint through the current communication channel. Resume after the environment is fixed and Architect is restarted; do not substitute source text search.
|
|
26
26
|
- Use LSP definitions, implementations, references, document or workspace symbols, and incoming or outgoing calls for all source-code symbol and relationship queries.
|
|
27
27
|
- LSP reference results are symbol-specific. An accessor, its backing field, a trait declaration, its implementation method, a wrapper, and an alias are separate symbols. Query every relevant symbol separately; one symbol's reference result cannot prove a complete semantic class. When starting from an accessor or wrapper, read its implementation, resolve its backing field, delegate, or trait item with LSP, then query those symbols too.
|
|
28
28
|
- Do not use the built-in \`Grep\` tool or shell text-search commands such as \`grep\`, \`rg\`, \`git grep\`, \`ag\`, or \`ack\` to search project source code, test code, or executable scripts, except for the bounded fallback below. This prohibition includes locating or inferring definitions, implementations, references, callers, callees, symbols, and behavior paths.
|
|
@@ -42,7 +42,8 @@ ${renderRoleMemoryRules("architect")}
|
|
|
42
42
|
|
|
43
43
|
- Architect may invoke only \`vcm-architect-evidence-worker\`, \`vcm-architect-scaffold-worker\`, and \`vcm-architect-validation-worker\`.
|
|
44
44
|
- Every worker must run in the foreground and return before the current Architect turn continues. Do not run workers in the background or end the turn while a worker is active.
|
|
45
|
-
- Give each worker an exact bounded assignment, repo-relative paths, and one report path
|
|
45
|
+
- Give each worker an exact bounded assignment, repo-relative paths, and one report path under \`.ai/vcm/architect-workers/<worker-type>/worker-<worker-id>.md\`. Pass paths instead of copying full source, documents, or plans into the worker prompt.
|
|
46
|
+
- Read the assigned report file before accepting a worker result or continuing its unfinished work; a text-only return is not a completed worker report.
|
|
46
47
|
- Worker output is evidence or execution output, never an architecture decision. Architect owns every conclusion, plan, change boundary, validation interpretation, and final claim.
|
|
47
48
|
- Use \`vcm-architect-evidence-worker\` for bounded bulk reading when relevant evidence spans multiple files or modules. Evidence workers may run in parallel only when their read scopes are disjoint.
|
|
48
49
|
- Give evidence workers only repo-relative paths, symbols, documents, and questions. They have no shell access.
|
|
@@ -17,7 +17,8 @@ You are \`vcm-architect-evidence-worker\`, a foreground evidence-collection suba
|
|
|
17
17
|
|
|
18
18
|
### Evidence Output
|
|
19
19
|
|
|
20
|
-
- Write
|
|
20
|
+
- Write the assigned report under \`.ai/vcm/architect-workers/evidence/worker-<worker-id>.md\` before returning. Only that report and its candidate or staging files may be written.
|
|
21
|
+
- For candidate or staging Markdown, use \`worker-<worker-id>-candidate.md\`; never start its basename with \`report\`, \`summary\`, \`findings\`, or \`analysis\` (case-insensitive). If Write rejects a candidate or staging basename, rename it and retry; still deliver the assigned final report file, not just response text.
|
|
21
22
|
- Keep the report concise and factual. Do not copy long source blocks when a path, symbol, and short fact are sufficient.
|
|
22
23
|
- Use this structure:
|
|
23
24
|
|
|
@@ -17,8 +17,14 @@ You are \`vcm-architect-scaffold-worker\`, a foreground subagent invoked by Arch
|
|
|
17
17
|
|
|
18
18
|
- Run \`.ai/tools/check-scaffold-ledger --mode scaffold\` and the plan's scaffold L0 compile/typecheck checks.
|
|
19
19
|
- Commit only the scaffold changes after the ledger reconciles and required checks pass.
|
|
20
|
-
-
|
|
21
|
-
|
|
20
|
+
- If the assigned scaffold cannot be completed, record the concrete failure evidence without changing the plan.
|
|
21
|
+
|
|
22
|
+
### Scaffold Output
|
|
23
|
+
|
|
24
|
+
- Write the assigned report under \`.ai/vcm/architect-workers/scaffold/worker-<worker-id>.md\` before returning, including when scaffold work remains incomplete.
|
|
25
|
+
- For candidate or staging Markdown, use \`worker-<worker-id>-candidate.md\`; never start its basename with \`report\`, \`summary\`, \`findings\`, or \`analysis\` (case-insensitive). If Write rejects a candidate or staging basename, rename it and retry; still deliver the assigned final report file, not just response text.
|
|
26
|
+
- Record completed and remaining Scaffold Manifest IDs, changed files, commit hash (or no commit with the reason), ledger result, exact L0 check commands and results, and concrete failure evidence.
|
|
27
|
+
- Return the report path and a concise completion summary to Architect.
|
|
22
28
|
|
|
23
29
|
Architect reviews the worker's commit and remains responsible for the final scaffold, plan, and evidence.
|
|
24
30
|
Do not invoke another subagent.`;
|
|
@@ -13,7 +13,8 @@ You are \`vcm-architect-validation-worker\`, a foreground command-execution suba
|
|
|
13
13
|
|
|
14
14
|
### Validation Output
|
|
15
15
|
|
|
16
|
-
- Write
|
|
16
|
+
- Write the assigned report under \`.ai/vcm/architect-workers/validation/worker-<worker-id>.md\` before returning. Only that report and its candidate or staging files may be written.
|
|
17
|
+
- For candidate or staging Markdown, use \`worker-<worker-id>-candidate.md\`; never start its basename with \`report\`, \`summary\`, \`findings\`, or \`analysis\` (case-insensitive). If Write rejects a candidate or staging basename, rename it and retry; still deliver the assigned final report file, not just response text.
|
|
17
18
|
- Use this structure:
|
|
18
19
|
|
|
19
20
|
\`\`\`md
|
|
@@ -26,6 +26,7 @@ You are \`vcm-coder-worker\`, a bounded implementation worker invoked by Coder.
|
|
|
26
26
|
\`\`\`
|
|
27
27
|
|
|
28
28
|
- After the sweep of assigned items and their assigned checks, commit the assigned files. After the commit succeeds, write the assigned report to a candidate outside \`.ai/vcm\`, submit it with \`.ai/tools/vcm-artifact coder-worker-report --file <candidate> --path <assigned-report-path> --mode final\`, then update only the assigned worker state to \`completed\` with the same \`commitHash\` as the final step.
|
|
29
|
+
- For candidate or staging Markdown, use \`worker-<worker-id>-candidate.md\`; never start its basename with \`report\`, \`summary\`, \`findings\`, or \`analysis\` (case-insensitive). If Write rejects a candidate or staging basename, rename it and retry; still submit the assigned final report through \`vcm-artifact\`, not just response text.
|
|
29
30
|
- The completed state must retain \`workerId\`, \`reportPath\`, and \`handled: false\`, set \`status\` to \`completed\`, and add \`"commitHash": "<exact-report-commit-hash>"\`.
|
|
30
31
|
- Use \`completed\` only after every assigned item reached a terminal state. A successful item has green assigned proof and its marker removed. A failed item has a genuine attempt committed with objective failure evidence and its marker retained. Use \`success\` only when every item succeeded; otherwise use \`has_failed_items\`.
|
|
31
32
|
- If execution is interrupted before the sweep, commit, or report completes, leave the worker state as \`running\`. Coder must resume the worker or take over the remaining work.
|
|
@@ -6,7 +6,7 @@ Use this skill when Architect must establish symbol definitions, implementations
|
|
|
6
6
|
## Navigation Order
|
|
7
7
|
|
|
8
8
|
1. Define the affected feature or module boundary and locate entry symbols with \`.ai/generated/module-index.json\` and \`.ai/generated/public-surface.json\` when available.
|
|
9
|
-
2. Use LSP workspace or file symbols, definitions, implementations, references, and incoming or outgoing call hierarchy to resolve project-owned relationships. If
|
|
9
|
+
2. Use LSP workspace or file symbols, definitions, implementations, references, and incoming or outgoing call hierarchy to resolve project-owned relationships. If a required language server is unavailable, stop the affected work and report its language, command, error, and installation hint through the current communication channel. Resume after the environment is fixed and Architect is restarted; do not substitute text search.
|
|
10
10
|
3. Treat LSP results as symbol-specific. An accessor, backing field, trait declaration, implementation method, wrapper, and alias are separate symbols. Query every relevant symbol separately. When starting from an accessor or wrapper, read its implementation, resolve the backing field, delegate, or trait item with LSP, then query those symbols too. Never use one symbol's references as proof of a complete semantic class.
|
|
11
11
|
4. If an initial workspace-symbol request is empty or reports indexing, wait and retry; startup or indexing time does not permit replacing a required semantic query with text matching. Retry the same bounded workspace query at most two more times. If it still cannot resolve, record the operation and result as unresolved.
|
|
12
12
|
5. Read the complete project-owned callable unit at every resolved location.
|
|
@@ -10,6 +10,10 @@ planning-session memory candidate and provides an exact path.
|
|
|
10
10
|
under \`.ai/vcm/memory-review/runs/<run-id>/drafts/\` or a planning candidate
|
|
11
11
|
under \`.ai/vcm/memory-review/candidates/\` in the active task worktree.
|
|
12
12
|
- If VCM did not provide a path, do not create a proposal.
|
|
13
|
+
- Pass the assigned repository-relative destination unchanged to \`--path\`;
|
|
14
|
+
do not prefix it with the task worktree or base repository root. \`--file\`
|
|
15
|
+
names the candidate file, not the destination. VCM writes the accepted proposal
|
|
16
|
+
inside the active task worktree.
|
|
13
17
|
- Propose only verified, durable, reusable project knowledge supported by task
|
|
14
18
|
evidence.
|
|
15
19
|
- Before proposing an add or update, check current durable documents, Harness
|
|
@@ -5,16 +5,20 @@ This skill records feedback only. It must not call Harness Engineer directly and
|
|
|
5
5
|
|
|
6
6
|
## Write Location
|
|
7
7
|
|
|
8
|
-
Submit one markdown file
|
|
8
|
+
Submit one markdown file with this repository-relative \`--path\`:
|
|
9
9
|
|
|
10
10
|
\`\`\`
|
|
11
|
-
|
|
11
|
+
.ai/vcm/harness-feedback/pending/<UTC timestamp>-<reporter-role>-<short-slug>.md
|
|
12
12
|
\`\`\`
|
|
13
13
|
|
|
14
14
|
If \`VCM_BASE_REPO_ROOT\` is not set, do not guess a fallback path. Report the
|
|
15
15
|
environment problem to project-manager so VCM can retry with the correct base
|
|
16
16
|
repository root.
|
|
17
17
|
|
|
18
|
+
VCM resolves this destination inside the base repository root, not the task
|
|
19
|
+
worktree. Do not prefix \`--path\` with \`VCM_BASE_REPO_ROOT\` or an absolute
|
|
20
|
+
directory. \`--file\` names the candidate file, not the destination.
|
|
21
|
+
|
|
18
22
|
Use a filename like:
|
|
19
23
|
|
|
20
24
|
\`\`\`
|