vibe-coding-master 0.6.20 → 0.6.22
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 +5 -5
- package/dist/backend/api/artifact-routes.js +2 -2
- package/dist/backend/api/gate-review-routes.js +1 -1
- package/dist/backend/api/task-routes.js +1 -1
- package/dist/backend/cli/install-vcm-harness.js +66 -20
- package/dist/backend/services/app-settings-service.js +11 -2
- package/dist/backend/services/artifact-service.js +9 -8
- package/dist/backend/services/gate-review-service.js +322 -24
- package/dist/backend/services/harness-feedback-service.js +8 -3
- package/dist/backend/services/harness-service.js +100 -13
- package/dist/backend/services/job-guard-service.js +2 -2
- package/dist/backend/services/message-service.js +12 -0
- package/dist/backend/services/session-service.js +18 -11
- package/dist/backend/services/status-service.js +1 -4
- package/dist/backend/templates/handoff.js +105 -17
- package/dist/backend/templates/harness/architect-agent.js +110 -49
- package/dist/backend/templates/harness/claude-root.js +45 -15
- package/dist/backend/templates/harness/coder-agent.js +66 -47
- package/dist/backend/templates/harness/coder-worker-agent.js +45 -17
- package/dist/backend/templates/harness/gate-review.js +237 -39
- package/dist/backend/templates/harness/harness-engineer-agent.js +39 -12
- package/dist/backend/templates/harness/project-coding-standards.js +73 -0
- package/dist/backend/templates/harness/project-glossary.js +30 -0
- package/dist/backend/templates/harness/project-known-issues.js +33 -0
- package/dist/backend/templates/harness/project-manager-agent.js +103 -34
- package/dist/backend/templates/harness/pull-request-template.js +6 -4
- package/dist/backend/templates/harness/tester-agent.js +82 -0
- package/dist/backend/templates/harness/vcm-final-acceptance-skill.js +22 -17
- package/dist/backend/templates/harness/vcm-harness-bootstrap-skill.js +19 -2
- package/dist/backend/templates/harness/vcm-long-running-validation-skill.js +1 -1
- package/dist/backend/templates/harness/vcm-report-harness-issue-skill.js +18 -12
- package/dist/backend/templates/harness/vcm-route-message-skill.js +48 -8
- package/dist/backend/templates/message-envelope.js +2 -5
- package/dist/shared/constants.js +3 -3
- package/dist/shared/types/gate-review.js +6 -1
- package/dist/shared/validation/artifact-check.js +64 -10
- package/dist-frontend/assets/{index-C5E5jLp-.js → index-DYBg_qYS.js} +4 -4
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
- package/scripts/verify-package.mjs +1 -1
- package/dist/backend/templates/harness/reviewer-agent.js +0 -60
|
@@ -8,9 +8,12 @@ import { renderGateReviewerAgentRules, renderRequestGateReviewTool, renderTransl
|
|
|
8
8
|
import { renderHarnessEngineerHarnessRules } from "../templates/harness/harness-engineer-agent.js";
|
|
9
9
|
import { renderRootClaudeHarnessRules } from "../templates/harness/claude-root.js";
|
|
10
10
|
import { renderGitignoreHarnessRules } from "../templates/harness/gitignore.js";
|
|
11
|
+
import { renderLegacyProjectCodingStandardsTemplate, renderProjectCodingStandardsProjectSection, renderProjectCodingStandardsRules } from "../templates/harness/project-coding-standards.js";
|
|
12
|
+
import { renderProjectGlossaryTemplate } from "../templates/harness/project-glossary.js";
|
|
13
|
+
import { renderLegacyProjectKnownIssuesTemplate, renderProjectKnownIssuesRules, renderProjectKnownIssuesSection } from "../templates/harness/project-known-issues.js";
|
|
11
14
|
import { renderProjectManagerHarnessRules } from "../templates/harness/project-manager-agent.js";
|
|
12
15
|
import { renderPullRequestTemplateHarnessRules } from "../templates/harness/pull-request-template.js";
|
|
13
|
-
import {
|
|
16
|
+
import { renderTesterHarnessRules } from "../templates/harness/tester-agent.js";
|
|
14
17
|
import { renderVcmFinalAcceptanceSkillRules } from "../templates/harness/vcm-final-acceptance-skill.js";
|
|
15
18
|
import { renderVcmHarnessBootstrapSkillRules } from "../templates/harness/vcm-harness-bootstrap-skill.js";
|
|
16
19
|
import { renderVcmLongRunningValidationSkillRules } from "../templates/harness/vcm-long-running-validation-skill.js";
|
|
@@ -38,6 +41,7 @@ const VCM_STOP_HOOK_COMMAND = `sh -c 'if [ -z "\${VCM_TASK_SLUG:-}" ] || [ -z "\
|
|
|
38
41
|
const VCM_PERMISSION_REQUEST_HOOK_COMMAND = `sh -c 'if [ -z "\${VCM_TASK_SLUG:-}" ] || [ -z "\${VCM_ROLE:-}" ] || [ -z "\${VCM_API_URL:-}" ]; then exit 0; fi; node -e '"'"'let s="";process.stdin.setEncoding("utf8");process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{let event={};try{event=s.trim()?JSON.parse(s):{};}catch{event={raw:s};}process.stdout.write(JSON.stringify({taskSlug:process.env.VCM_TASK_SLUG,role:process.env.VCM_ROLE,event}));});'"'"' | curl -fsS --max-time 5 -X POST "\${VCM_API_URL}/api/hooks/claude-code/permission-request" -H "content-type: application/json" --data-binary @- || true'`;
|
|
39
42
|
const VCM_BASH_GUARD_HOOK_COMMAND = `sh -c 'if [ -z "\${VCM_TASK_SLUG:-}" ] || [ -z "\${VCM_ROLE:-}" ]; then exit 0; fi; guard=""; repo="$(git rev-parse --show-toplevel 2>/dev/null || true)"; if [ -n "$repo" ] && [ -f "$repo/.ai/tools/vcm-bash-guard" ]; then guard="$repo/.ai/tools/vcm-bash-guard"; else cwd="$(pwd -P 2>/dev/null || pwd)"; dir="$cwd"; while [ -n "$dir" ] && [ "$dir" != "/" ]; do if [ -f "$dir/.ai/tools/vcm-bash-guard" ]; then guard="$dir/.ai/tools/vcm-bash-guard"; break; fi; dir="$(dirname "$dir")"; done; if [ -z "$guard" ] && [ -n "\${CLAUDE_PROJECT_DIR:-}" ] && [ -f "\${CLAUDE_PROJECT_DIR}/.ai/tools/vcm-bash-guard" ]; then guard="\${CLAUDE_PROJECT_DIR}/.ai/tools/vcm-bash-guard"; fi; fi; [ -n "$guard" ] || exit 0; python3 "$guard" || exit 0'`;
|
|
40
43
|
const VCM_BASH_DEFAULT_TIMEOUT_MS = "600000";
|
|
44
|
+
const VCM_AUTO_MEMORY_ENABLED = false;
|
|
41
45
|
const VCM_HOOK_DEFINITIONS = [
|
|
42
46
|
{ eventName: "PreToolUse", matcher: "Bash", command: VCM_BASH_GUARD_HOOK_COMMAND, timeout: 10 },
|
|
43
47
|
{ eventName: "UserPromptSubmit", command: VCM_HOOK_COMMAND, timeout: 5 },
|
|
@@ -54,6 +58,29 @@ const HARNESS_FILES = [
|
|
|
54
58
|
blankLineBeforeEnd: true,
|
|
55
59
|
renderRules: renderRootClaudeHarnessRules
|
|
56
60
|
},
|
|
61
|
+
{
|
|
62
|
+
kind: "project-glossary",
|
|
63
|
+
path: "docs/GLOSSARY.md",
|
|
64
|
+
title: "Glossary",
|
|
65
|
+
ownership: "project-file",
|
|
66
|
+
renderRules: renderProjectGlossaryTemplate
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
kind: "project-coding-standards",
|
|
70
|
+
path: "docs/CODING_STANDARDS.md",
|
|
71
|
+
title: "Coding Standards",
|
|
72
|
+
defaultContentAfterBlock: renderProjectCodingStandardsProjectSection(),
|
|
73
|
+
legacyWholeFile: renderLegacyProjectCodingStandardsTemplate(),
|
|
74
|
+
renderRules: renderProjectCodingStandardsRules
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
kind: "project-known-issues",
|
|
78
|
+
path: "docs/known-issues.md",
|
|
79
|
+
title: "Known Issues",
|
|
80
|
+
defaultContentAfterBlock: renderProjectKnownIssuesSection(),
|
|
81
|
+
legacyWholeFile: renderLegacyProjectKnownIssuesTemplate(),
|
|
82
|
+
renderRules: renderProjectKnownIssuesRules
|
|
83
|
+
},
|
|
57
84
|
{
|
|
58
85
|
kind: "gitignore",
|
|
59
86
|
path: ".gitignore",
|
|
@@ -71,7 +98,7 @@ const HARNESS_FILES = [
|
|
|
71
98
|
kind: "skill-vcm-route-message",
|
|
72
99
|
path: ".claude/skills/vcm-route-message/SKILL.md",
|
|
73
100
|
title: "VCM Route Message Skill",
|
|
74
|
-
frontmatter: renderSkillFrontmatter("vcm-route-message", "Use when a VCM role
|
|
101
|
+
frontmatter: renderSkillFrontmatter("vcm-route-message", "Use when project-manager dispatches a VCM role or when a VCM role reports a question, result, blocker, or finding back to project-manager."),
|
|
75
102
|
ownership: "whole-file",
|
|
76
103
|
renderRules: renderVcmRouteMessageSkillRules
|
|
77
104
|
},
|
|
@@ -79,7 +106,7 @@ const HARNESS_FILES = [
|
|
|
79
106
|
kind: "skill-vcm-final-acceptance",
|
|
80
107
|
path: ".claude/skills/vcm-final-acceptance/SKILL.md",
|
|
81
108
|
title: "VCM Final Acceptance Skill",
|
|
82
|
-
frontmatter: renderSkillFrontmatter("vcm-final-acceptance", "Use when project-manager is ready to
|
|
109
|
+
frontmatter: renderSkillFrontmatter("vcm-final-acceptance", "Use when project-manager is ready to close a complete VCM code-delivery flow."),
|
|
83
110
|
ownership: "whole-file",
|
|
84
111
|
renderRules: renderVcmFinalAcceptanceSkillRules
|
|
85
112
|
},
|
|
@@ -119,7 +146,7 @@ const HARNESS_FILES = [
|
|
|
119
146
|
kind: "agent-gate-reviewer",
|
|
120
147
|
path: ".claude/agents/gate-reviewer.md",
|
|
121
148
|
title: "Gate Reviewer Agent",
|
|
122
|
-
frontmatter: renderAgentFrontmatter("gate-reviewer", "VCM independent gate review role for architecture plans, validation adequacy, and
|
|
149
|
+
frontmatter: renderAgentFrontmatter("gate-reviewer", "VCM independent gate review role for architecture plans, validation adequacy, and code diffs.", { tools: "Read, Grep, Glob, Bash, Write" }),
|
|
123
150
|
renderRules: renderGateReviewerAgentRules
|
|
124
151
|
},
|
|
125
152
|
{
|
|
@@ -173,11 +200,11 @@ const HARNESS_FILES = [
|
|
|
173
200
|
renderRules: renderCoderHarnessRules
|
|
174
201
|
},
|
|
175
202
|
{
|
|
176
|
-
kind: "agent-
|
|
177
|
-
path: ".claude/agents/
|
|
178
|
-
title: "
|
|
179
|
-
frontmatter: renderAgentFrontmatter("
|
|
180
|
-
renderRules:
|
|
203
|
+
kind: "agent-tester",
|
|
204
|
+
path: ".claude/agents/tester.md",
|
|
205
|
+
title: "Tester Agent",
|
|
206
|
+
frontmatter: renderAgentFrontmatter("tester", "VCM testing role for validation, test adequacy, approved-scope validation, and risk findings."),
|
|
207
|
+
renderRules: renderTesterHarnessRules
|
|
181
208
|
}
|
|
182
209
|
];
|
|
183
210
|
export function createHarnessService(deps) {
|
|
@@ -976,7 +1003,7 @@ function assertManagedBlockUnchanged(definition, currentContent, nextContent) {
|
|
|
976
1003
|
}
|
|
977
1004
|
}
|
|
978
1005
|
function extractManagedBlock(definition, content) {
|
|
979
|
-
if (definition.ownership === "whole-file" || definition.ownership === "raw-file") {
|
|
1006
|
+
if (definition.ownership === "whole-file" || definition.ownership === "raw-file" || definition.ownership === "project-file") {
|
|
980
1007
|
return undefined;
|
|
981
1008
|
}
|
|
982
1009
|
return content.match(getManagedBlockPattern(definition))?.[0];
|
|
@@ -991,6 +1018,27 @@ async function analyzeHarnessFiles(fs, repoRoot) {
|
|
|
991
1018
|
}
|
|
992
1019
|
async function analyzeHarnessFile(fs, repoRoot, definition) {
|
|
993
1020
|
const absolutePath = resolveHarnessPath(repoRoot, definition.path);
|
|
1021
|
+
if (definition.ownership === "project-file") {
|
|
1022
|
+
const exists = await fs.pathExists(absolutePath);
|
|
1023
|
+
return {
|
|
1024
|
+
definition,
|
|
1025
|
+
status: {
|
|
1026
|
+
kind: definition.kind,
|
|
1027
|
+
path: definition.path,
|
|
1028
|
+
exists,
|
|
1029
|
+
hasManagedBlock: false,
|
|
1030
|
+
action: exists ? "ok" : "create"
|
|
1031
|
+
},
|
|
1032
|
+
plannedChange: exists
|
|
1033
|
+
? undefined
|
|
1034
|
+
: {
|
|
1035
|
+
path: definition.path,
|
|
1036
|
+
action: "create",
|
|
1037
|
+
reason: "Project-owned harness file is missing; VCM will create an editable default."
|
|
1038
|
+
},
|
|
1039
|
+
nextContent: exists ? undefined : ensureTrailingNewline(definition.renderRules().trimEnd())
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
994
1042
|
const expectedContent = definition.ownership === "whole-file" || definition.ownership === "raw-file"
|
|
995
1043
|
? renderWholeHarnessFile(definition)
|
|
996
1044
|
: undefined;
|
|
@@ -1046,6 +1094,25 @@ async function analyzeHarnessFile(fs, repoRoot, definition) {
|
|
|
1046
1094
|
}
|
|
1047
1095
|
const match = currentContent.match(managedBlockPattern);
|
|
1048
1096
|
if (!match) {
|
|
1097
|
+
const migratedContent = migrateLegacyHarnessFile(definition, currentContent, expectedBlock);
|
|
1098
|
+
if (migratedContent) {
|
|
1099
|
+
return {
|
|
1100
|
+
definition,
|
|
1101
|
+
status: {
|
|
1102
|
+
kind: definition.kind,
|
|
1103
|
+
path: definition.path,
|
|
1104
|
+
exists: true,
|
|
1105
|
+
hasManagedBlock: false,
|
|
1106
|
+
action: "update"
|
|
1107
|
+
},
|
|
1108
|
+
plannedChange: {
|
|
1109
|
+
path: definition.path,
|
|
1110
|
+
action: "update",
|
|
1111
|
+
reason: "Legacy VCM whole-file baseline will be migrated to a managed block."
|
|
1112
|
+
},
|
|
1113
|
+
nextContent: migratedContent
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1049
1116
|
return {
|
|
1050
1117
|
definition,
|
|
1051
1118
|
status: {
|
|
@@ -1166,11 +1233,24 @@ function getManagedBlockPattern(definition) {
|
|
|
1166
1233
|
? HASH_MANAGED_BLOCK_PATTERN
|
|
1167
1234
|
: MANAGED_BLOCK_PATTERN;
|
|
1168
1235
|
}
|
|
1169
|
-
function renderNewHarnessFile(definition, block) {
|
|
1236
|
+
function renderNewHarnessFile(definition, block, contentAfterBlock = definition.defaultContentAfterBlock) {
|
|
1170
1237
|
const frontmatter = definition.frontmatter
|
|
1171
1238
|
? `${definition.frontmatter.trimEnd()}\n\n`
|
|
1172
1239
|
: "";
|
|
1173
|
-
|
|
1240
|
+
const suffix = contentAfterBlock?.trim();
|
|
1241
|
+
return `${frontmatter}# ${definition.title}\n\n${block}${suffix ? `\n\n${suffix}` : ""}\n`;
|
|
1242
|
+
}
|
|
1243
|
+
function migrateLegacyHarnessFile(definition, currentContent, block) {
|
|
1244
|
+
const legacyContent = definition.legacyWholeFile?.trimEnd();
|
|
1245
|
+
if (!legacyContent) {
|
|
1246
|
+
return undefined;
|
|
1247
|
+
}
|
|
1248
|
+
const current = currentContent.trimEnd();
|
|
1249
|
+
if (current !== legacyContent && !current.startsWith(`${legacyContent}\n`)) {
|
|
1250
|
+
return undefined;
|
|
1251
|
+
}
|
|
1252
|
+
const projectContent = current.slice(legacyContent.length).trim();
|
|
1253
|
+
return renderNewHarnessFile(definition, block, projectContent || undefined);
|
|
1174
1254
|
}
|
|
1175
1255
|
function renderWholeHarnessFile(definition) {
|
|
1176
1256
|
if (definition.ownership === "raw-file") {
|
|
@@ -1265,7 +1345,8 @@ function withVcmClaudeHooks(settings) {
|
|
|
1265
1345
|
return {
|
|
1266
1346
|
...settings,
|
|
1267
1347
|
hooks,
|
|
1268
|
-
env
|
|
1348
|
+
env,
|
|
1349
|
+
autoMemoryEnabled: VCM_AUTO_MEMORY_ENABLED
|
|
1269
1350
|
};
|
|
1270
1351
|
}
|
|
1271
1352
|
function isVcmHookMatcher(value) {
|
|
@@ -1334,6 +1415,8 @@ async function getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vc
|
|
|
1334
1415
|
await checkProjectContext(deps.fs, targetRepoRoot),
|
|
1335
1416
|
checkGeneratedJson(moduleIndex, ".ai/generated/module-index.json", "module-index", "Module index"),
|
|
1336
1417
|
checkGeneratedJson(await readOptionalJsonObject(deps.fs, targetRepoRoot, ".ai/generated/public-surface.json"), ".ai/generated/public-surface.json", "public-surface", "Public surface"),
|
|
1418
|
+
await checkFilledMarkdown(deps.fs, targetRepoRoot, "docs/GLOSSARY.md", "Glossary", "glossary-doc"),
|
|
1419
|
+
await checkFilledMarkdown(deps.fs, targetRepoRoot, "docs/CODING_STANDARDS.md", "Coding standards", "coding-standards-doc"),
|
|
1337
1420
|
await checkFilledMarkdown(deps.fs, targetRepoRoot, "docs/ARCHITECTURE.md", "Project architecture", "project-architecture"),
|
|
1338
1421
|
await checkModuleArchitectureDocs(deps.fs, targetRepoRoot, moduleIndex),
|
|
1339
1422
|
await checkFilledMarkdown(deps.fs, targetRepoRoot, "docs/TESTING.md", "Testing doc", "testing-doc")
|
|
@@ -1367,6 +1450,8 @@ async function checkFixedHarness(fs, repoRoot, vcmVersion) {
|
|
|
1367
1450
|
"CLAUDE.md",
|
|
1368
1451
|
MANIFEST_PATH,
|
|
1369
1452
|
".claude/skills/vcm-harness-bootstrap/SKILL.md",
|
|
1453
|
+
"docs/GLOSSARY.md",
|
|
1454
|
+
"docs/CODING_STANDARDS.md",
|
|
1370
1455
|
".ai/tools/generate-module-index",
|
|
1371
1456
|
".ai/tools/generate-public-surface"
|
|
1372
1457
|
];
|
|
@@ -1665,6 +1750,8 @@ Required work:
|
|
|
1665
1750
|
- Run .ai/tools/generate-module-index from the target task worktree when available.
|
|
1666
1751
|
- Run .ai/tools/generate-public-surface from the target task worktree after module-index.json exists.
|
|
1667
1752
|
- Add or update project-specific Project Context and Project Constraints in target CLAUDE.md above the VCM managed block.
|
|
1753
|
+
- Fill target docs/GLOSSARY.md with the project abbreviation allowlist.
|
|
1754
|
+
- Add project-specific coding standards outside the VCM managed block in target docs/CODING_STANDARDS.md when needed; do not edit the installer-maintained baseline.
|
|
1668
1755
|
- Fill target docs/ARCHITECTURE.md with project-level module overview, responsibilities, relationships, dependency direction, project-wide constraints, and links to module-level architecture docs.
|
|
1669
1756
|
- Create or update target module-level ARCHITECTURE.md files for clear non-root module boundaries with architectureDoc paths in module-index.json.
|
|
1670
1757
|
- Fill target docs/TESTING.md with project-native validation levels, commands, validation selection rules, final-validation cleanup, test layout, integration/E2E case lists, generated-context freshness checks, and known testing gaps.
|
|
@@ -177,9 +177,9 @@ function buildCoderWorkerBlockReason(tasks) {
|
|
|
177
177
|
const reports = tasks
|
|
178
178
|
.map((task) => task.reportPath)
|
|
179
179
|
.filter((reportPath) => Boolean(reportPath));
|
|
180
|
-
const reportHint = reports.length > 0 ? `
|
|
180
|
+
const reportHint = reports.length > 0 ? ` Test report(s): ${reports.join(", ")}.` : "";
|
|
181
181
|
return `VCM: coder worker task ${listing} is still unhandled. Do not end the Coder turn while worker tasks are unhandled. `
|
|
182
|
-
+ `Wait for worker subagents,
|
|
182
|
+
+ `Wait for worker subagents, test reports and commits, resolve failed or incomplete workers, set \`handled: true\` in each worker state, and continue.${reportHint}`;
|
|
183
183
|
}
|
|
184
184
|
function latestMtime(...values) {
|
|
185
185
|
return values.reduce((latest, value) => value !== undefined && (latest === undefined || value > latest) ? value : latest, undefined);
|
|
@@ -10,6 +10,7 @@ const DEFAULT_AUTO_DISPATCH_ENTER_DELAY_MS = 500;
|
|
|
10
10
|
const DEFAULT_DISPATCH_CONFIRMATION_RETRY_DELAYS_MS = [1500, 3000];
|
|
11
11
|
const DEFAULT_DISPATCH_CONFIRMATION_FAILURE_DELAY_MS = 3000;
|
|
12
12
|
const DISPATCH_NOT_CONFIRMED_REASON = "Auto orchestration pasted the message, but Claude Code did not confirm submission. Press Enter in the target terminal or resend the route message.";
|
|
13
|
+
const INVALID_ROUTE_REASON = "Invalid route: non-PM roles must route through project-manager.";
|
|
13
14
|
export function createMessageService(deps) {
|
|
14
15
|
const now = deps.now ?? (() => new Date().toISOString());
|
|
15
16
|
const id = deps.id ?? (() => `msg_${randomUUID()}`);
|
|
@@ -61,6 +62,14 @@ export function createMessageService(deps) {
|
|
|
61
62
|
return all.filter((routeFile) => routeFile.pending);
|
|
62
63
|
}
|
|
63
64
|
async function dispatchRouteFile(input, routeFile, state, timestamp) {
|
|
65
|
+
if (!isAllowedRoute(routeFile.fromRole, routeFile.toRole)) {
|
|
66
|
+
return {
|
|
67
|
+
delivered: false,
|
|
68
|
+
requiresUserApproval: false,
|
|
69
|
+
clearedRouteFile: false,
|
|
70
|
+
failureReason: INVALID_ROUTE_REASON
|
|
71
|
+
};
|
|
72
|
+
}
|
|
64
73
|
const session = await deps.sessionService.getRoleSession(input.repoRoot, input.taskSlug, routeFile.toRole);
|
|
65
74
|
if (!session || session.status !== "running") {
|
|
66
75
|
return {
|
|
@@ -357,6 +366,9 @@ function getDefaultMessageType(fromRole, toRole) {
|
|
|
357
366
|
}
|
|
358
367
|
return "question";
|
|
359
368
|
}
|
|
369
|
+
function isAllowedRoute(fromRole, toRole) {
|
|
370
|
+
return (fromRole === PM_ROLE && toRole !== PM_ROLE) || (fromRole !== PM_ROLE && toRole === PM_ROLE);
|
|
371
|
+
}
|
|
360
372
|
function selectDispatchCandidates(routeFiles, stoppedRole) {
|
|
361
373
|
const candidates = stoppedRole
|
|
362
374
|
? routeFiles.filter((routeFile) => routeFile.fromRole === stoppedRole || routeFile.toRole === stoppedRole)
|
|
@@ -15,6 +15,7 @@ const HARNESS_ENGINEER_SESSION_PATH = ".ai/vcm/harness-engineer/session.json";
|
|
|
15
15
|
const PROJECT_TRANSLATOR_SCOPE = "__project__";
|
|
16
16
|
const PROJECT_HARNESS_ENGINEER_SCOPE = "__project_harness_engineer__";
|
|
17
17
|
const PROJECT_TOOL_CD_ENTER_DELAY_MS = 500;
|
|
18
|
+
const CLAUDE_CODE_DISABLE_AUTO_MEMORY = "1";
|
|
18
19
|
// Project tool sessions launch a Claude Code TUI inside a PTY. The PTY reports
|
|
19
20
|
// "running" the instant it is spawned, which is earlier than the moment the TUI
|
|
20
21
|
// can actually accept pasted input. These bounds drive a quiescence-based
|
|
@@ -81,14 +82,14 @@ export function createSessionService(deps) {
|
|
|
81
82
|
command: startCommand.command,
|
|
82
83
|
args: startCommand.args,
|
|
83
84
|
cwd: startCommand.cwd,
|
|
84
|
-
env: {
|
|
85
|
+
env: withClaudeCodeRuntimeEnv({
|
|
85
86
|
VCM_API_URL: deps.apiUrl,
|
|
86
87
|
VCM_BASE_REPO_ROOT: repoRoot,
|
|
87
88
|
VCM_TASK_REPO_ROOT: taskRepoRoot,
|
|
88
89
|
VCM_TASK_SLUG: taskSlug,
|
|
89
90
|
VCM_ROLE: role,
|
|
90
91
|
VCM_SESSION_ID: claudeSessionId || undefined
|
|
91
|
-
},
|
|
92
|
+
}),
|
|
92
93
|
cols: input.cols,
|
|
93
94
|
rows: input.rows
|
|
94
95
|
});
|
|
@@ -174,7 +175,7 @@ export function createSessionService(deps) {
|
|
|
174
175
|
command: startCommand.command,
|
|
175
176
|
args: startCommand.args,
|
|
176
177
|
cwd: startCommand.cwd,
|
|
177
|
-
env: {
|
|
178
|
+
env: withClaudeCodeRuntimeEnv({
|
|
178
179
|
VCM_API_URL: deps.apiUrl,
|
|
179
180
|
VCM_BASE_REPO_ROOT: repoRoot,
|
|
180
181
|
VCM_TASK_REPO_ROOT: taskContext.taskRepoRoot,
|
|
@@ -184,7 +185,7 @@ export function createSessionService(deps) {
|
|
|
184
185
|
VCM_TASK_SLUG: PROJECT_TRANSLATOR_SCOPE,
|
|
185
186
|
VCM_ROLE: TRANSLATOR_ROLE,
|
|
186
187
|
VCM_SESSION_ID: claudeSessionId || undefined
|
|
187
|
-
},
|
|
188
|
+
}),
|
|
188
189
|
cols: input.cols,
|
|
189
190
|
rows: input.rows
|
|
190
191
|
});
|
|
@@ -279,7 +280,7 @@ export function createSessionService(deps) {
|
|
|
279
280
|
command: startCommand.command,
|
|
280
281
|
args: startCommand.args,
|
|
281
282
|
cwd: startCommand.cwd,
|
|
282
|
-
env: {
|
|
283
|
+
env: withClaudeCodeRuntimeEnv({
|
|
283
284
|
VCM_API_URL: deps.apiUrl,
|
|
284
285
|
VCM_BASE_REPO_ROOT: repoRoot,
|
|
285
286
|
VCM_TASK_REPO_ROOT: taskContext.taskRepoRoot,
|
|
@@ -289,7 +290,7 @@ export function createSessionService(deps) {
|
|
|
289
290
|
VCM_TASK_SLUG: PROJECT_HARNESS_ENGINEER_SCOPE,
|
|
290
291
|
VCM_ROLE: HARNESS_ENGINEER_ROLE,
|
|
291
292
|
VCM_SESSION_ID: claudeSessionId || undefined
|
|
292
|
-
},
|
|
293
|
+
}),
|
|
293
294
|
cols: input.cols,
|
|
294
295
|
rows: input.rows
|
|
295
296
|
});
|
|
@@ -468,14 +469,14 @@ export function createSessionService(deps) {
|
|
|
468
469
|
command: startCommand.command,
|
|
469
470
|
args: startCommand.args,
|
|
470
471
|
cwd: startCommand.cwd,
|
|
471
|
-
env: {
|
|
472
|
+
env: withClaudeCodeRuntimeEnv({
|
|
472
473
|
VCM_API_URL: deps.apiUrl,
|
|
473
474
|
VCM_BASE_REPO_ROOT: repoRoot,
|
|
474
475
|
VCM_TASK_REPO_ROOT: targetCwd,
|
|
475
476
|
VCM_TASK_SLUG: normalizeProjectScopedRecordForPersistence(session).taskSlug,
|
|
476
477
|
VCM_ROLE: session.role,
|
|
477
478
|
VCM_SESSION_ID: session.claudeSessionId
|
|
478
|
-
}
|
|
479
|
+
})
|
|
479
480
|
});
|
|
480
481
|
if ((await waitForSessionInputReady(runtimeSession.id)) === "exited") {
|
|
481
482
|
deps.registry.remove(runtimeSession.id);
|
|
@@ -1217,8 +1218,8 @@ function getHandoffArtifactPath(paths, role) {
|
|
|
1217
1218
|
if (role === "architect") {
|
|
1218
1219
|
return paths.architecturePlanPath;
|
|
1219
1220
|
}
|
|
1220
|
-
if (role === "
|
|
1221
|
-
return paths.
|
|
1221
|
+
if (role === "tester") {
|
|
1222
|
+
return paths.testReportPath;
|
|
1222
1223
|
}
|
|
1223
1224
|
return undefined;
|
|
1224
1225
|
}
|
|
@@ -1472,7 +1473,7 @@ function createEmptyTaskSessionRecord(taskSlug, updatedAt) {
|
|
|
1472
1473
|
"project-manager": { id: null, status: "not_started" },
|
|
1473
1474
|
architect: { id: null, status: "not_started" },
|
|
1474
1475
|
coder: { id: null, status: "not_started" },
|
|
1475
|
-
|
|
1476
|
+
tester: { id: null, status: "not_started" }
|
|
1476
1477
|
}
|
|
1477
1478
|
};
|
|
1478
1479
|
}
|
|
@@ -1517,6 +1518,12 @@ function formatClaudeCdCommand(targetCwd) {
|
|
|
1517
1518
|
function isExitedStatus(status) {
|
|
1518
1519
|
return status === "exited" || status === "crashed" || status === "missing";
|
|
1519
1520
|
}
|
|
1521
|
+
function withClaudeCodeRuntimeEnv(env) {
|
|
1522
|
+
return {
|
|
1523
|
+
...env,
|
|
1524
|
+
CLAUDE_CODE_DISABLE_AUTO_MEMORY
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1520
1527
|
function delay(ms) {
|
|
1521
1528
|
if (ms <= 0) {
|
|
1522
1529
|
return Promise.resolve();
|
|
@@ -31,9 +31,6 @@ export function createStatusService(deps) {
|
|
|
31
31
|
}
|
|
32
32
|
warnings.push(`Role sessions are temporarily unavailable because the backend hit the open-files limit: ${errorMessage(error)}`);
|
|
33
33
|
}
|
|
34
|
-
warnings.push(...artifacts.checks
|
|
35
|
-
.filter((check) => check.status !== "ok")
|
|
36
|
-
.map((check) => `${check.path}: ${check.status}`));
|
|
37
34
|
return {
|
|
38
35
|
task,
|
|
39
36
|
sessions,
|
|
@@ -55,7 +52,7 @@ function degradedArtifactSummary(handoffDir) {
|
|
|
55
52
|
messageRoutePaths: {},
|
|
56
53
|
architecturePlanPath: `${handoffDir}/architecture-plan.md`,
|
|
57
54
|
knownIssuesPath: `${handoffDir}/known-issues.md`,
|
|
58
|
-
|
|
55
|
+
testReportPath: `${handoffDir}/test-report.md`,
|
|
59
56
|
docsSyncReportPath: `${handoffDir}/docs-sync-report.md`,
|
|
60
57
|
finalAcceptancePath: `${handoffDir}/final-acceptance.md`
|
|
61
58
|
},
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export function renderArchitecturePlanTemplate(taskSlug) {
|
|
2
2
|
return `# Architecture Plan: ${taskSlug}
|
|
3
3
|
|
|
4
|
-
##
|
|
4
|
+
## Accepted Scope
|
|
5
|
+
|
|
6
|
+
TBD
|
|
7
|
+
|
|
8
|
+
## Current Code Reality
|
|
5
9
|
|
|
6
10
|
TBD
|
|
7
11
|
|
|
@@ -9,25 +13,37 @@ TBD
|
|
|
9
13
|
|
|
10
14
|
TBD
|
|
11
15
|
|
|
16
|
+
## Module/File Plan
|
|
17
|
+
|
|
18
|
+
TBD
|
|
19
|
+
|
|
20
|
+
## Public Surface Impact
|
|
21
|
+
|
|
22
|
+
TBD
|
|
23
|
+
|
|
12
24
|
## Scaffold Manifest
|
|
13
25
|
|
|
14
26
|
Task-specific context and coder guidance go here, not in source-code comments.
|
|
15
27
|
Source-code comments should only describe durable behavior, contracts, invariants,
|
|
16
28
|
error boundaries, or non-obvious logic that should remain useful after this task.
|
|
17
29
|
|
|
18
|
-
| ID | File
|
|
19
|
-
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
20
|
-
| SCF-001 | TBD | TBD | TBD | TBD | TBD | TBD | TBD |
|
|
30
|
+
| ID | File / Action | Why In Scope | Coder Work | Allowed Freedom | Expected VCM:CODE | Durable Comment Needs | Behavior / Contract Proof Points |
|
|
31
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
32
|
+
| SCF-001 | TBD | TBD | TBD | TBD | TBD | TBD | TBD |
|
|
21
33
|
|
|
22
|
-
##
|
|
34
|
+
## Tester Coverage Hints
|
|
23
35
|
|
|
24
36
|
TBD
|
|
25
37
|
|
|
26
|
-
##
|
|
38
|
+
## Docs Impact
|
|
27
39
|
|
|
28
40
|
TBD
|
|
29
41
|
|
|
30
|
-
##
|
|
42
|
+
## Known Risks
|
|
43
|
+
|
|
44
|
+
TBD
|
|
45
|
+
|
|
46
|
+
## Coder Handoff Notes
|
|
31
47
|
|
|
32
48
|
TBD
|
|
33
49
|
`;
|
|
@@ -44,22 +60,90 @@ No unresolved task issues recorded yet.
|
|
|
44
60
|
At task close, promote still-relevant confirmed issues to \`docs/known-issues.md\`; delete this task-local file with the rest of \`.ai/vcm/\` runtime state.
|
|
45
61
|
`;
|
|
46
62
|
}
|
|
47
|
-
export function
|
|
48
|
-
return `#
|
|
63
|
+
export function renderTestReportTemplate(taskSlug) {
|
|
64
|
+
return `# Test Report: ${taskSlug}
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
Test Result: pass|fail
|
|
67
|
+
|
|
68
|
+
## Evidence Reviewed
|
|
51
69
|
|
|
52
70
|
TBD
|
|
53
71
|
|
|
54
|
-
##
|
|
72
|
+
## Tests Added Or Updated
|
|
55
73
|
|
|
56
74
|
TBD
|
|
57
75
|
|
|
58
|
-
##
|
|
76
|
+
## Commands Run Or Checked
|
|
59
77
|
|
|
60
78
|
TBD
|
|
61
79
|
|
|
62
|
-
##
|
|
80
|
+
## Validation Results
|
|
81
|
+
|
|
82
|
+
TBD
|
|
83
|
+
|
|
84
|
+
## Failed Expectations
|
|
85
|
+
|
|
86
|
+
TBD
|
|
87
|
+
|
|
88
|
+
## Reproduction Steps
|
|
89
|
+
|
|
90
|
+
TBD
|
|
91
|
+
|
|
92
|
+
## Skipped Checks With Reasons
|
|
93
|
+
|
|
94
|
+
TBD
|
|
95
|
+
|
|
96
|
+
## Coverage Gaps
|
|
97
|
+
|
|
98
|
+
TBD
|
|
99
|
+
|
|
100
|
+
## Blocking Validation Issues
|
|
101
|
+
|
|
102
|
+
TBD
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
export function renderCoderCompletionTemplate(taskSlug) {
|
|
106
|
+
return `# Coder Completion: ${taskSlug}
|
|
107
|
+
|
|
108
|
+
Decision: ready_for_review|incomplete|failed
|
|
109
|
+
|
|
110
|
+
## Scaffold Completion
|
|
111
|
+
|
|
112
|
+
TBD
|
|
113
|
+
|
|
114
|
+
## Remaining Markers
|
|
115
|
+
|
|
116
|
+
TBD
|
|
117
|
+
|
|
118
|
+
## Changed Files
|
|
119
|
+
|
|
120
|
+
TBD
|
|
121
|
+
|
|
122
|
+
## Private Helpers Added
|
|
123
|
+
|
|
124
|
+
TBD
|
|
125
|
+
|
|
126
|
+
## Manifest Deviations
|
|
127
|
+
|
|
128
|
+
TBD
|
|
129
|
+
|
|
130
|
+
## Generated Context
|
|
131
|
+
|
|
132
|
+
TBD
|
|
133
|
+
|
|
134
|
+
## Baseline Tests Added Or Updated
|
|
135
|
+
|
|
136
|
+
TBD
|
|
137
|
+
|
|
138
|
+
## L0/L1 Validation
|
|
139
|
+
|
|
140
|
+
TBD
|
|
141
|
+
|
|
142
|
+
## Worker Results
|
|
143
|
+
|
|
144
|
+
TBD
|
|
145
|
+
|
|
146
|
+
## Objective Failures
|
|
63
147
|
|
|
64
148
|
TBD
|
|
65
149
|
`;
|
|
@@ -113,11 +197,11 @@ TBD
|
|
|
113
197
|
|
|
114
198
|
## Scope Traceability
|
|
115
199
|
|
|
116
|
-
### Expected
|
|
200
|
+
### Expected Files
|
|
117
201
|
|
|
118
202
|
TBD
|
|
119
203
|
|
|
120
|
-
### Supporting
|
|
204
|
+
### Supporting Files
|
|
121
205
|
|
|
122
206
|
TBD
|
|
123
207
|
|
|
@@ -125,11 +209,11 @@ TBD
|
|
|
125
209
|
|
|
126
210
|
TBD
|
|
127
211
|
|
|
128
|
-
### Unexplained
|
|
212
|
+
### Unexplained Files
|
|
129
213
|
|
|
130
214
|
TBD
|
|
131
215
|
|
|
132
|
-
### High-Risk Unexpected
|
|
216
|
+
### High-Risk Unexpected Files
|
|
133
217
|
|
|
134
218
|
TBD
|
|
135
219
|
|
|
@@ -145,6 +229,10 @@ TBD
|
|
|
145
229
|
|
|
146
230
|
TBD
|
|
147
231
|
|
|
232
|
+
## Gate Review Gates
|
|
233
|
+
|
|
234
|
+
TBD
|
|
235
|
+
|
|
148
236
|
## Cleanup Readiness
|
|
149
237
|
|
|
150
238
|
TBD
|