vibe-coding-master 0.7.43 → 0.7.44
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 +40 -13
- package/dist/backend/api/artifact-routes.js +3 -0
- package/dist/backend/api/harness-routes.js +16 -0
- package/dist/backend/api/task-routes.js +1 -0
- package/dist/backend/api/workflow-control-routes.js +12 -0
- package/dist/backend/cli/install-vcm-harness.js +21 -0
- package/dist/backend/server.js +3 -1
- package/dist/backend/services/artifact-service.js +7 -30
- package/dist/backend/services/auto-memory-service.js +640 -12
- package/dist/backend/services/claude-hook-service.js +80 -2
- package/dist/backend/services/gate-review-service.js +173 -74
- package/dist/backend/services/harness-feedback-service.js +76 -78
- package/dist/backend/services/harness-service.js +27 -3
- package/dist/backend/services/runtime-coordinator-service.js +2 -1
- package/dist/backend/services/status-service.js +1 -0
- package/dist/backend/services/translation-worker-service.js +19 -4
- package/dist/backend/services/workflow-control-service.js +96 -12
- package/dist/backend/templates/handoff.js +44 -2
- package/dist/backend/templates/harness/architect-agent.js +13 -7
- package/dist/backend/templates/harness/architect-scaffold-worker-agent.js +1 -1
- package/dist/backend/templates/harness/check-scaffold-ledger.js +234 -10
- package/dist/backend/templates/harness/claude-root.js +3 -2
- package/dist/backend/templates/harness/coder-agent.js +8 -0
- package/dist/backend/templates/harness/gate-review.js +144 -49
- package/dist/backend/templates/harness/harness-engineer-agent.js +25 -10
- package/dist/backend/templates/harness/project-manager-agent.js +16 -10
- package/dist/backend/templates/harness/resolve-durable-doc-assignment.js +60 -0
- package/dist/backend/templates/harness/tester-agent.js +13 -0
- package/dist/backend/templates/harness/vcm-ask-user-skill.js +82 -0
- package/dist/backend/templates/harness/vcm-code-navigation-skill.js +7 -5
- package/dist/backend/templates/harness/vcm-task-state-skill.js +2 -2
- package/dist/backend/templates/harness/vcm-workflow-review-skill.js +1 -1
- package/dist/shared/types/workflow.js +1 -0
- package/dist/shared/validation/artifact-check.js +3 -3
- package/dist/shared/validation/artifact-contract.js +1 -1
- package/dist/shared/validation/artifact-registry.js +16 -0
- package/dist-frontend/assets/{index-VW9tYPP5.js → index-BvCmrFlN.js} +49 -49
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
- package/scripts/claude-plugins/vcm-lsp-bridge/.claude-plugin/plugin.json +21 -6
- package/scripts/harness-tools/vcm-artifact +1 -2
- package/scripts/harness-tools/vcm-bash-guard +1 -1
package/README.md
CHANGED
|
@@ -190,6 +190,12 @@ restart, but it does not infer transitions or choose the next role. Current
|
|
|
190
190
|
artifacts, Gate Review state, Round/Turn state, and the role rules remain
|
|
191
191
|
authoritative.
|
|
192
192
|
|
|
193
|
+
Whenever Project Manager asks the user a question, it first uses
|
|
194
|
+
`vcm-ask-user`. VCM records the wait and cancels any pending role dispatch in
|
|
195
|
+
one state update. Stop Hook then ends the PM turn without route scanning. Only
|
|
196
|
+
a new direct user message clears the wait, and the next role dispatch requires
|
|
197
|
+
a fresh Workflow Review.
|
|
198
|
+
|
|
193
199
|
Typical flow:
|
|
194
200
|
|
|
195
201
|
```text
|
|
@@ -329,7 +335,8 @@ strict `workflow-progress.md` transition through `vcm-workflow-review`. VCM
|
|
|
329
335
|
checks the confirmed dispatch history and current task artifacts, then grants
|
|
330
336
|
one matching route. The target role's `UserPromptSubmit` consumes that approval
|
|
331
337
|
and appends the confirmed transition. A rejected transition can be bypassed
|
|
332
|
-
only by
|
|
338
|
+
only by the user's exact one-time authorization recorded in the next Workflow
|
|
339
|
+
Progress submission.
|
|
333
340
|
|
|
334
341
|
If the flow stops, VCM always shows a blocking pause alert. `Pause alert sound`
|
|
335
342
|
only controls the looping sound. Enabling Gateway turns that preference off once;
|
|
@@ -479,7 +486,10 @@ including CCR launches. The project environment must still
|
|
|
479
486
|
provide the language server for each detected language: `rust-analyzer`,
|
|
480
487
|
`typescript-language-server`, `pyright-langserver`, `gopls`, `clangd`, or
|
|
481
488
|
`jdtls`. Architect preloads `vcm-code-navigation` and uses LSP for semantic
|
|
482
|
-
relationships
|
|
489
|
+
relationships. Accessors, backing fields, trait items, implementations, wrappers,
|
|
490
|
+
and aliases are queried as separate symbols; a bounded source-text fallback may
|
|
491
|
+
only locate candidates after the correct LSP query is demonstrably partial.
|
|
492
|
+
Other roles use generated context and ordinary source reads.
|
|
483
493
|
Harness Studio reports
|
|
484
494
|
whether the server executable and plugin can run; the role Session performs the
|
|
485
495
|
real workspace indexing and semantic query retries. VCM uses Claude Code progress
|
|
@@ -498,10 +508,11 @@ files.
|
|
|
498
508
|
`Auto memory` is the switch for the entire automated memory workflow. During
|
|
499
509
|
Review Task Harness after Final Acceptance, Project Manager, Architect, Coder,
|
|
500
510
|
Tester, and an enabled Reviewer submit proposals in sequence through
|
|
501
|
-
`vcm-propose-memory`. Harness Engineer verifies and consolidates them
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
assigned Auto Memory
|
|
511
|
+
`vcm-propose-memory`. Harness Engineer verifies and consolidates them, commits
|
|
512
|
+
the reviewed memory, and writes the assigned machine-readable review result as
|
|
513
|
+
part of the same Task Harness Retrospective. Workflow roles cannot edit active
|
|
514
|
+
memory directly; Harness Engineer edits it only during the assigned Auto Memory
|
|
515
|
+
Retrospective.
|
|
505
516
|
|
|
506
517
|
When Auto Memory is enabled, the planning Architect writes a provisional memory
|
|
507
518
|
candidate before its post-planning Session restart. VCM snapshots that candidate
|
|
@@ -528,7 +539,10 @@ Final Acceptance
|
|
|
528
539
|
-> Review pending Harness Feedback
|
|
529
540
|
-> Review Auto Memory proposals, when Auto Memory is enabled
|
|
530
541
|
-> Harness Engineer updates and commits memory, when Auto Memory is enabled
|
|
531
|
-
|
|
542
|
+
-> Harness Engineer writes review-result.json, when Auto Memory is enabled
|
|
543
|
+
-> VCM validates and records the committed memory result
|
|
544
|
+
-> VCM dispatches durable-document assignments one at a time
|
|
545
|
+
-> Complete Task Harness Retrospective after every assignment completes
|
|
532
546
|
```
|
|
533
547
|
|
|
534
548
|
Memory proposal prompts sent to Project Manager, Architect, Coder, Tester, and
|
|
@@ -542,16 +556,29 @@ impact, and durable-document disposition, then evaluates every proposal item
|
|
|
542
556
|
independently. Each Add or Update decision records why the memory is necessary,
|
|
543
557
|
what happens if it is absent, whether it belongs in memory or a durable
|
|
544
558
|
document, and the exact final memory content when retained. VCM validates that
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
559
|
+
every existing entry and proposal has one structurally valid decision, every
|
|
560
|
+
move decision has one durable-document assignment, moved content has already
|
|
561
|
+
been removed from memory, and the commit changes only assigned memory host
|
|
562
|
+
files and only their `<VCM-memory>` blocks. VCM does not decide whether the
|
|
563
|
+
Harness Engineer's semantic judgment is correct. Harness Engineer review and
|
|
564
|
+
retrospective work remain tool role activity and do not participate in Round
|
|
565
|
+
completion.
|
|
566
|
+
|
|
567
|
+
For `move-to-durable-doc`, memory is removed in the Harness Engineer commit
|
|
568
|
+
before documentation work starts. VCM assigns architecture and known-issues
|
|
569
|
+
documents to Architect and testing documentation to Tester. For another target,
|
|
570
|
+
PM selects Architect, Coder, or Tester and asks the user only when ownership
|
|
571
|
+
cannot be determined. These assignments are backend-dispatched work rather than
|
|
572
|
+
a Docs-Only Flow. Each owner updates and commits the document, submits the exact
|
|
573
|
+
assignment ID in `docs-update-report.md`, and finishes before the next assignment
|
|
574
|
+
starts. Harness Studio shows assignment status and allows failed work to be
|
|
575
|
+
retried.
|
|
549
576
|
|
|
550
577
|
When Auto Memory is disabled, Review Task Harness does not collect proposals or
|
|
551
578
|
ask Harness Engineer to update memory. When enabled, both automatic and manual
|
|
552
579
|
review requests collect proposals before starting the retrospective. A failed
|
|
553
|
-
proposal collection
|
|
554
|
-
from Harness Studio.
|
|
580
|
+
proposal collection, combined retrospective memory review, or durable-document
|
|
581
|
+
assignment must be retried from Harness Studio.
|
|
555
582
|
|
|
556
583
|
## Closing a Task
|
|
557
584
|
|
|
@@ -144,6 +144,9 @@ function artifactNameToPath(paths, artifactName) {
|
|
|
144
144
|
if (artifactName === "test-report.md") {
|
|
145
145
|
return paths.testReportPath;
|
|
146
146
|
}
|
|
147
|
+
if (artifactName === "docs-update-report.md") {
|
|
148
|
+
return paths.docsUpdateReportPath;
|
|
149
|
+
}
|
|
147
150
|
if (artifactName === "docs-sync-report.md") {
|
|
148
151
|
return paths.docsSyncReportPath;
|
|
149
152
|
}
|
|
@@ -208,6 +208,22 @@ export function registerHarnessRoutes(app, deps) {
|
|
|
208
208
|
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
209
209
|
return deps.autoMemoryService.retryFailedReview(project.repoRoot, task.worktreePath);
|
|
210
210
|
});
|
|
211
|
+
app.post("/api/projects/harness/memory/assignments/retry", async (request) => {
|
|
212
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
213
|
+
return deps.autoMemoryService.retryDurableDocAssignment(project.repoRoot, task.worktreePath, request.body?.assignmentId ?? "");
|
|
214
|
+
});
|
|
215
|
+
app.post("/api/projects/harness/memory/assignments/owner", async (request) => {
|
|
216
|
+
const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
|
|
217
|
+
const owner = request.body?.owner;
|
|
218
|
+
if (owner !== "architect" && owner !== "coder" && owner !== "tester") {
|
|
219
|
+
throw new VcmError({
|
|
220
|
+
code: "DURABLE_DOC_OWNER_INVALID",
|
|
221
|
+
message: "Durable-document owner must be architect, coder, or tester.",
|
|
222
|
+
statusCode: 400
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return deps.autoMemoryService.resolveDurableDocAssignmentOwner(project.repoRoot, task.worktreePath, request.body?.assignmentId ?? "", owner);
|
|
226
|
+
});
|
|
211
227
|
}
|
|
212
228
|
async function persistHarnessEngineerDefaults(appSettings, session) {
|
|
213
229
|
const defaults = createDefaultToolSessionDefaults()["harness-engineer"];
|
|
@@ -235,6 +235,7 @@ function degradedArtifactSummary(handoffDir) {
|
|
|
235
235
|
architectDebugPath: `${handoffDir}/architect-debug.md`,
|
|
236
236
|
architectureDiagnosisPath: `${handoffDir}/architecture-diagnosis.md`,
|
|
237
237
|
testReportPath: `${handoffDir}/test-report.md`,
|
|
238
|
+
docsUpdateReportPath: `${handoffDir}/docs-update-report.md`,
|
|
238
239
|
docsSyncReportPath: `${handoffDir}/docs-sync-report.md`,
|
|
239
240
|
workflowProgressPath: `${handoffDir}/workflow-progress.md`,
|
|
240
241
|
finalAcceptancePath: `${handoffDir}/final-acceptance.md`
|
|
@@ -5,6 +5,18 @@ export function registerWorkflowControlRoutes(app, deps) {
|
|
|
5
5
|
const context = await getContext(deps, request.params.taskSlug);
|
|
6
6
|
return deps.workflowControlService.getState(context);
|
|
7
7
|
});
|
|
8
|
+
app.post("/api/tasks/:taskSlug/ask-user", async (request) => {
|
|
9
|
+
const context = await getContext(deps, request.params.taskSlug);
|
|
10
|
+
const question = typeof request.body?.question === "string" ? request.body.question.trim() : "";
|
|
11
|
+
if (!question) {
|
|
12
|
+
throw new VcmError({
|
|
13
|
+
code: "WORKFLOW_USER_QUESTION_REQUIRED",
|
|
14
|
+
message: "A non-empty user question is required.",
|
|
15
|
+
statusCode: 400
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return deps.workflowControlService.requestUserInput(context, question);
|
|
19
|
+
});
|
|
8
20
|
}
|
|
9
21
|
async function getContext(deps, taskSlug) {
|
|
10
22
|
const project = await deps.projectService.getCurrentProject();
|
|
@@ -28,10 +28,12 @@ import { renderVcmLongRunningValidationSkillRules } from "../templates/harness/v
|
|
|
28
28
|
import { renderVcmProposeMemorySkillRules } from "../templates/harness/vcm-propose-memory-skill.js";
|
|
29
29
|
import { renderVcmReportHarnessIssueSkillRules } from "../templates/harness/vcm-report-harness-issue-skill.js";
|
|
30
30
|
import { renderVcmRouteMessageSkillRules } from "../templates/harness/vcm-route-message-skill.js";
|
|
31
|
+
import { renderAskUserTool, renderVcmAskUserSkillRules } from "../templates/harness/vcm-ask-user-skill.js";
|
|
31
32
|
import { renderUpdateTaskStateTool, renderVcmTaskStateSkillRules } from "../templates/harness/vcm-task-state-skill.js";
|
|
32
33
|
import { renderVcmWorkflowReviewSkillRules } from "../templates/harness/vcm-workflow-review-skill.js";
|
|
33
34
|
import { renderCheckScaffoldLedgerTool } from "../templates/harness/check-scaffold-ledger.js";
|
|
34
35
|
import { renderRequestArchitectRestartTool, renderRestartArchitectSkillRules } from "../templates/harness/restart-architect-skill.js";
|
|
36
|
+
import { renderResolveDurableDocAssignmentTool } from "../templates/harness/resolve-durable-doc-assignment.js";
|
|
35
37
|
import { readVcmPackageVersion } from "../app-version.js";
|
|
36
38
|
const CLI_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
37
39
|
const APP_ROOT = path.resolve(CLI_DIR, "../../..");
|
|
@@ -318,6 +320,12 @@ const WHOLE_FILES = [
|
|
|
318
320
|
mode: 0o644,
|
|
319
321
|
content: renderSkillFile("VCM Route Message Skill", "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.", renderVcmRouteMessageSkillRules())
|
|
320
322
|
},
|
|
323
|
+
{
|
|
324
|
+
path: ".claude/skills/vcm-ask-user/SKILL.md",
|
|
325
|
+
category: "skill",
|
|
326
|
+
mode: 0o644,
|
|
327
|
+
content: renderSkillFile("VCM Ask User Skill", "vcm-ask-user", "Use whenever project-manager asks the user a question and must pause the workflow.", renderVcmAskUserSkillRules())
|
|
328
|
+
},
|
|
321
329
|
{
|
|
322
330
|
path: ".claude/skills/vcm-task-state/SKILL.md",
|
|
323
331
|
category: "skill",
|
|
@@ -360,6 +368,12 @@ const WHOLE_FILES = [
|
|
|
360
368
|
mode: 0o755,
|
|
361
369
|
content: renderRequestGateReviewTool()
|
|
362
370
|
},
|
|
371
|
+
{
|
|
372
|
+
path: ".ai/tools/vcm-ask-user",
|
|
373
|
+
category: "runtime-tool",
|
|
374
|
+
mode: 0o755,
|
|
375
|
+
content: renderAskUserTool()
|
|
376
|
+
},
|
|
363
377
|
{
|
|
364
378
|
path: ".ai/tools/update-task-state",
|
|
365
379
|
category: "runtime-tool",
|
|
@@ -378,6 +392,12 @@ const WHOLE_FILES = [
|
|
|
378
392
|
mode: 0o755,
|
|
379
393
|
content: renderRequestArchitectRestartTool()
|
|
380
394
|
},
|
|
395
|
+
{
|
|
396
|
+
path: ".ai/tools/resolve-durable-doc-assignment",
|
|
397
|
+
category: "runtime-tool",
|
|
398
|
+
mode: 0o755,
|
|
399
|
+
content: renderResolveDurableDocAssignmentTool()
|
|
400
|
+
},
|
|
381
401
|
{
|
|
382
402
|
path: ".ai/tools/run-long-check",
|
|
383
403
|
category: "runtime-tool",
|
|
@@ -642,6 +662,7 @@ function fixedDirectories() {
|
|
|
642
662
|
".claude/skills/vcm-harness-bootstrap/",
|
|
643
663
|
".claude/skills/vcm-long-running-validation/",
|
|
644
664
|
".claude/skills/vcm-route-message/",
|
|
665
|
+
".claude/skills/vcm-ask-user/",
|
|
645
666
|
".claude/skills/vcm-task-state/",
|
|
646
667
|
".claude/skills/vcm-workflow-review/",
|
|
647
668
|
".claude/skills/vcm-gate-review/",
|
package/dist/backend/server.js
CHANGED
|
@@ -332,6 +332,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
332
332
|
appSettings,
|
|
333
333
|
sessionService,
|
|
334
334
|
roundService,
|
|
335
|
+
workflowControlService,
|
|
335
336
|
onArchitecturePlanDisposition: ({ repoRoot, taskSlug, accepted }) => architectRestartService.recordArchitectureGateDisposition(repoRoot, taskSlug, accepted)
|
|
336
337
|
});
|
|
337
338
|
const translationWorkerService = createTranslationWorkerService({
|
|
@@ -416,7 +417,8 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
416
417
|
jobGuard: createJobGuardService(),
|
|
417
418
|
translationWorkerService,
|
|
418
419
|
architectRestartService,
|
|
419
|
-
roleStallDetector
|
|
420
|
+
roleStallDetector,
|
|
421
|
+
workflowControlService
|
|
420
422
|
});
|
|
421
423
|
const runtimeCoordinator = createRuntimeCoordinatorService({
|
|
422
424
|
appSettings,
|
|
@@ -4,7 +4,7 @@ import { checkMarkdownArtifact } from "../../shared/validation/artifact-check.js
|
|
|
4
4
|
import { getArtifactDefinition, isArtifactKind } from "../../shared/validation/artifact-registry.js";
|
|
5
5
|
import { VcmError } from "../errors.js";
|
|
6
6
|
import { resolveRepoPath } from "../adapters/filesystem.js";
|
|
7
|
-
import { renderArchitectureBriefTemplate, renderArchitectureDiagnosisTemplate, renderArchitectureEvidenceTemplate, renderArchitecturePlanTemplate, renderArchitectDebugTemplate, renderCoderCompletionTemplate, renderDocsSyncReportTemplate, renderFinalAcceptanceTemplate, renderKnownIssuesTemplate, renderPlanningProgressTemplate, renderMessageRouteTemplate, renderTestReportTemplate, renderWorkflowProgressTemplate } from "../templates/handoff.js";
|
|
7
|
+
import { renderArchitectureBriefTemplate, renderArchitectureDiagnosisTemplate, renderArchitectureEvidenceTemplate, renderArchitecturePlanTemplate, renderArchitectDebugTemplate, renderCoderCompletionTemplate, renderDocsUpdateReportTemplate, renderDocsSyncReportTemplate, renderFinalAcceptanceTemplate, renderKnownIssuesTemplate, renderPlanningProgressTemplate, renderMessageRouteTemplate, renderTestReportTemplate, renderWorkflowProgressTemplate } from "../templates/handoff.js";
|
|
8
8
|
import { renderRoleCommandTemplate } from "../templates/role-command.js";
|
|
9
9
|
import { validateMemoryProposal } from "./memory-proposal-validation.js";
|
|
10
10
|
import { isMemoryProposalSubmissionPath } from "./memory-review-paths.js";
|
|
@@ -18,6 +18,7 @@ const ARTIFACT_PATH_KEYS = [
|
|
|
18
18
|
["architect-debug", "architectDebugPath"],
|
|
19
19
|
["architecture-diagnosis", "architectureDiagnosisPath"],
|
|
20
20
|
["test-report", "testReportPath"],
|
|
21
|
+
["docs-update-report", "docsUpdateReportPath"],
|
|
21
22
|
["docs-sync-report", "docsSyncReportPath"],
|
|
22
23
|
["workflow-progress", "workflowProgressPath"],
|
|
23
24
|
["final-acceptance", "finalAcceptancePath"]
|
|
@@ -55,6 +56,7 @@ export function createArtifactService(fs, deps = {}) {
|
|
|
55
56
|
architectDebugPath: path.posix.join(handoffDir, "architect-debug.md"),
|
|
56
57
|
architectureDiagnosisPath: path.posix.join(handoffDir, "architecture-diagnosis.md"),
|
|
57
58
|
testReportPath: path.posix.join(handoffDir, "test-report.md"),
|
|
59
|
+
docsUpdateReportPath: path.posix.join(handoffDir, "docs-update-report.md"),
|
|
58
60
|
docsSyncReportPath: path.posix.join(handoffDir, "docs-sync-report.md"),
|
|
59
61
|
workflowProgressPath: path.posix.join(handoffDir, "workflow-progress.md"),
|
|
60
62
|
finalAcceptancePath: path.posix.join(handoffDir, "final-acceptance.md")
|
|
@@ -85,6 +87,7 @@ export function createArtifactService(fs, deps = {}) {
|
|
|
85
87
|
[paths.architectDebugPath, renderArchitectDebugTemplate(input.taskSlug)],
|
|
86
88
|
[paths.architectureDiagnosisPath, renderArchitectureDiagnosisTemplate(input.taskSlug)],
|
|
87
89
|
[paths.testReportPath, renderTestReportTemplate(input.taskSlug)],
|
|
90
|
+
[paths.docsUpdateReportPath, renderDocsUpdateReportTemplate(input.taskSlug)],
|
|
88
91
|
[paths.docsSyncReportPath, renderDocsSyncReportTemplate(input.taskSlug)],
|
|
89
92
|
[paths.workflowProgressPath, renderWorkflowProgressTemplate(input.taskSlug)],
|
|
90
93
|
[paths.finalAcceptancePath, renderFinalAcceptanceTemplate(input.taskSlug)],
|
|
@@ -190,10 +193,11 @@ export function createArtifactService(fs, deps = {}) {
|
|
|
190
193
|
}
|
|
191
194
|
if (isArtifactKind(input.kind)) {
|
|
192
195
|
const definition = getArtifactDefinition(input.kind);
|
|
193
|
-
|
|
196
|
+
const owners = Array.isArray(definition.owner) ? definition.owner : [definition.owner];
|
|
197
|
+
if (!owners.includes(input.role)) {
|
|
194
198
|
throw new VcmError({
|
|
195
199
|
code: "ARTIFACT_OWNER_MISMATCH",
|
|
196
|
-
message: `${input.kind} is owned by ${
|
|
200
|
+
message: `${input.kind} is owned by ${owners.join("|")}, not ${input.role}.`,
|
|
197
201
|
statusCode: 403
|
|
198
202
|
});
|
|
199
203
|
}
|
|
@@ -334,39 +338,12 @@ async function validateDynamicArtifact(fs, input, content, workflowControlServic
|
|
|
334
338
|
validateHarnessFeedback(content);
|
|
335
339
|
return { kind: input.kind, root: input.baseRepoRoot, path: artifactPath };
|
|
336
340
|
}
|
|
337
|
-
if (input.kind === "retrospective-report") {
|
|
338
|
-
if (input.role !== "harness-engineer") {
|
|
339
|
-
throw artifactRejected(input.kind, ["Only Harness Engineer may submit a retrospective report."]);
|
|
340
|
-
}
|
|
341
|
-
if (!/^\.ai\/vcm\/harness-feedback\/task-retrospectives\/[A-Za-z0-9._-]+\.md$/.test(artifactPath)) {
|
|
342
|
-
throw artifactRejected(input.kind, ["Retrospective report path must be under .ai/vcm/harness-feedback/task-retrospectives/."]);
|
|
343
|
-
}
|
|
344
|
-
validateRetrospectiveReport(content);
|
|
345
|
-
return { kind: input.kind, root: input.baseRepoRoot, path: artifactPath };
|
|
346
|
-
}
|
|
347
341
|
throw new VcmError({
|
|
348
342
|
code: "ARTIFACT_KIND_INVALID",
|
|
349
343
|
message: `Unknown managed artifact kind: ${input.kind}`,
|
|
350
344
|
statusCode: 400
|
|
351
345
|
});
|
|
352
346
|
}
|
|
353
|
-
function validateRetrospectiveReport(content) {
|
|
354
|
-
const errors = getRetrospectiveReportErrors(content);
|
|
355
|
-
if (errors.length > 0)
|
|
356
|
-
throw artifactRejected("retrospective-report", errors);
|
|
357
|
-
}
|
|
358
|
-
export function getRetrospectiveReportErrors(content) {
|
|
359
|
-
const errors = [];
|
|
360
|
-
if (!/^# Task Harness Retrospective(?::\s*.+)?\s*$/m.test(content)) {
|
|
361
|
-
errors.push("Retrospective report requires '# Task Harness Retrospective: <task>'.");
|
|
362
|
-
}
|
|
363
|
-
for (const heading of ["Findings", "Feedback Dispositions", "Recommended Harness Changes", "VCM Issue Drafts"]) {
|
|
364
|
-
if (!new RegExp(`^## ${escapeRegExp(heading)}\\s*$`, "m").test(content)) {
|
|
365
|
-
errors.push(`Missing required section: ${heading}.`);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
return errors;
|
|
369
|
-
}
|
|
370
347
|
function validateCoderWorkerReport(content) {
|
|
371
348
|
const errors = [];
|
|
372
349
|
if (!/^# Coder Worker Report:\s*\S.+$/m.test(content)) {
|