@osovv/vv-opencode 0.35.22 → 0.35.24
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/CHANGELOG.md +20 -0
- package/README.md +19 -2
- package/dist/commands/patch-provider.d.ts +8 -0
- package/dist/commands/patch-provider.js +8 -0
- package/dist/commands/patch-provider.js.map +1 -1
- package/dist/lib/opencode.js +4 -4
- package/dist/lib/opencode.js.map +1 -1
- package/dist/plugins/workflow/index.js +52 -39
- package/dist/plugins/workflow/index.js.map +1 -1
- package/dist/plugins/workflow/persistence.js +61 -3
- package/dist/plugins/workflow/persistence.js.map +1 -1
- package/dist/plugins/workflow/state.d.ts +79 -29
- package/dist/plugins/workflow/state.js +299 -121
- package/dist/plugins/workflow/state.js.map +1 -1
- package/dist/plugins/workflow/system-instruction.md +4 -1
- package/dist/plugins/workflow/tooling.d.ts +4 -2
- package/dist/plugins/workflow/tooling.js +94 -34
- package/dist/plugins/workflow/tooling.js.map +1 -1
- package/dist/plugins/workflow/transitions.d.ts +10 -5
- package/dist/plugins/workflow/transitions.js +105 -63
- package/dist/plugins/workflow/transitions.js.map +1 -1
- package/package.json +1 -1
- package/schemas/vvoc/v3.json +1 -1
- package/templates/agents/vv-controller.md +3 -3
- package/templates/skills/vv-execute/SKILL.md +1 -1
- package/templates/skills/vv-plan/SKILL.md +1 -1
- package/templates/skills/vv-review/SKILL.md +2 -2
|
@@ -8,8 +8,10 @@ export type WorkflowToolDefinition<TArgs, TResult> = {
|
|
|
8
8
|
execute: (args: TArgs, context: WorkflowToolContext, store?: WorkItemStore) => TResult;
|
|
9
9
|
};
|
|
10
10
|
type OpenInputItem = {
|
|
11
|
-
key
|
|
12
|
-
title
|
|
11
|
+
key?: unknown;
|
|
12
|
+
title?: unknown;
|
|
13
|
+
mode?: unknown;
|
|
14
|
+
requiredReviewers?: unknown;
|
|
13
15
|
};
|
|
14
16
|
type OpenArgs = {
|
|
15
17
|
items: OpenInputItem[];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// FILE: src/plugins/workflow/tooling.ts
|
|
2
|
-
// VERSION: 0.
|
|
2
|
+
// VERSION: 0.2.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
|
-
// PURPOSE: Provide work-item tooling handlers that wrap workflow state operations with structured protocol-friendly responses.
|
|
5
|
-
// SCOPE: work_item_open, work_item_list, and work_item_close tool definitions and deterministic execution responses.
|
|
4
|
+
// PURPOSE: Provide work-item tooling handlers that wrap explicit workflow state operations with structured protocol-friendly responses.
|
|
5
|
+
// SCOPE: work_item_open, work_item_list, and work_item_close tool definitions, explicit open-contract validation, round metadata serialization, and deterministic execution responses.
|
|
6
6
|
// DEPENDS: [src/plugins/workflow/state.ts]
|
|
7
7
|
// LINKS: [M-WORKFLOW-TOOLING]
|
|
8
8
|
// ROLE: RUNTIME
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
// START_MODULE_MAP
|
|
13
13
|
// WorkflowToolContext - Minimal execution context required by workflow tools.
|
|
14
14
|
// WorkflowToolDefinition - Deterministic tool definition shape with execute handler.
|
|
15
|
-
// createWorkItemOpenTool - Creates work_item_open tool wrapper around openWorkItem.
|
|
16
|
-
// createWorkItemListTool - Creates work_item_list tool wrapper
|
|
17
|
-
// createWorkItemCloseTool - Creates work_item_close tool wrapper
|
|
15
|
+
// createWorkItemOpenTool - Creates work_item_open tool wrapper around explicit openWorkItem contract.
|
|
16
|
+
// createWorkItemListTool - Creates work_item_list tool wrapper with mode and round metadata.
|
|
17
|
+
// createWorkItemCloseTool - Creates work_item_close tool wrapper with ready_to_close gating responses.
|
|
18
18
|
// END_MODULE_MAP
|
|
19
19
|
//
|
|
20
20
|
// START_CHANGE_SUMMARY
|
|
21
|
+
// LAST_CHANGE: [v0.2.0 - Required explicit work-item mode and requiredReviewers, and exposed review-round metadata in list/open tool output.]
|
|
21
22
|
// LAST_CHANGE: [v0.1.1 - Wired work_item_list includeClosed flag into state listing options.]
|
|
22
23
|
// LAST_CHANGE: [v0.1.0 - Added workflow core tooling handlers for open/list/close operations with structured results and VVOC headers.]
|
|
23
24
|
// END_CHANGE_SUMMARY
|
|
@@ -28,8 +29,83 @@ function coerceNonEmptyString(value) {
|
|
|
28
29
|
const trimmed = value.trim();
|
|
29
30
|
return trimmed || undefined;
|
|
30
31
|
}
|
|
32
|
+
function isWorkItemMode(value) {
|
|
33
|
+
return value === "implementation" || value === "review_only";
|
|
34
|
+
}
|
|
35
|
+
function isReviewerRole(value) {
|
|
36
|
+
return value === "spec" || value === "code";
|
|
37
|
+
}
|
|
38
|
+
function canonicalizeReviewers(value) {
|
|
39
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (!value.every(isReviewerRole))
|
|
42
|
+
return undefined;
|
|
43
|
+
const unique = new Set(value);
|
|
44
|
+
if (unique.size !== value.length)
|
|
45
|
+
return undefined;
|
|
46
|
+
return [...value].sort((left, right) => {
|
|
47
|
+
if (left === right)
|
|
48
|
+
return 0;
|
|
49
|
+
return left === "spec" ? -1 : 1;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function normalizeOpenInputItem(item, sessionId) {
|
|
53
|
+
const key = coerceNonEmptyString(item.key);
|
|
54
|
+
const title = coerceNonEmptyString(item.title);
|
|
55
|
+
if (!key || !title) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
errorCode: "INVALID_INPUT",
|
|
59
|
+
message: "INVALID_INPUT: key and title must be non-empty strings",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (!isWorkItemMode(item.mode)) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
errorCode: "INVALID_INPUT",
|
|
66
|
+
message: "INVALID_INPUT: mode must be implementation or review_only",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const requiredReviewers = canonicalizeReviewers(item.requiredReviewers);
|
|
70
|
+
if (!requiredReviewers) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
errorCode: "INVALID_INPUT",
|
|
74
|
+
message: "INVALID_INPUT: requiredReviewers must be a non-empty array containing unique spec/code reviewers",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
ok: true,
|
|
79
|
+
input: {
|
|
80
|
+
sessionId,
|
|
81
|
+
key,
|
|
82
|
+
title,
|
|
83
|
+
mode: item.mode,
|
|
84
|
+
requiredReviewers,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function serializeWorkItem(record) {
|
|
89
|
+
return {
|
|
90
|
+
workItemId: record.workItemId,
|
|
91
|
+
header: `VVOC_WORK_ITEM_ID: ${record.workItemId}`,
|
|
92
|
+
key: record.key,
|
|
93
|
+
title: record.title,
|
|
94
|
+
mode: record.mode,
|
|
95
|
+
requiredReviewers: record.requiredReviewers,
|
|
96
|
+
state: record.state,
|
|
97
|
+
specReviewCount: record.specReviewCount,
|
|
98
|
+
codeReviewCount: record.codeReviewCount,
|
|
99
|
+
reviewRound: getReviewRound(record),
|
|
100
|
+
currentRound: record.currentRound,
|
|
101
|
+
completedReviewRoundCount: record.completedReviewRoundCount,
|
|
102
|
+
createdAt: record.createdAt,
|
|
103
|
+
updatedAt: record.updatedAt,
|
|
104
|
+
...(record.closedAt ? { closedAt: record.closedAt } : {}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
31
107
|
// START_CONTRACT: createWorkItemOpenTool
|
|
32
|
-
// PURPOSE: Build work_item_open handler that supports deterministic batch idempotent open operations.
|
|
108
|
+
// PURPOSE: Build work_item_open handler that supports deterministic batch idempotent open operations with explicit workflow intent.
|
|
33
109
|
// INPUTS: { store: WorkItemStore - workflow in-memory store }
|
|
34
110
|
// OUTPUTS: { WorkflowToolDefinition<OpenArgs, unknown> - executable tool definition }
|
|
35
111
|
// SIDE_EFFECTS: [Mutates in-memory work-item store through open operations]
|
|
@@ -38,24 +114,19 @@ function coerceNonEmptyString(value) {
|
|
|
38
114
|
export function createWorkItemOpenTool(store) {
|
|
39
115
|
return {
|
|
40
116
|
name: "work_item_open",
|
|
41
|
-
description: "Open one or more workflow work items idempotently.",
|
|
117
|
+
description: "Open one or more workflow work items idempotently with explicit mode and requiredReviewers.",
|
|
42
118
|
execute: (args, context, overrideStore) => {
|
|
43
119
|
const inputItems = Array.isArray(args.items) ? args.items : [];
|
|
44
120
|
const results = inputItems.map((item) => {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
if (!key || !title) {
|
|
121
|
+
const normalized = normalizeOpenInputItem(item, context.sessionId);
|
|
122
|
+
if (!normalized.ok) {
|
|
48
123
|
return {
|
|
49
124
|
ok: false,
|
|
50
|
-
errorCode:
|
|
51
|
-
message:
|
|
125
|
+
errorCode: normalized.errorCode,
|
|
126
|
+
message: normalized.message,
|
|
52
127
|
};
|
|
53
128
|
}
|
|
54
|
-
const opened = openWorkItem(overrideStore ?? store,
|
|
55
|
-
sessionId: context.sessionId,
|
|
56
|
-
key,
|
|
57
|
-
title,
|
|
58
|
-
});
|
|
129
|
+
const opened = openWorkItem(overrideStore ?? store, normalized.input);
|
|
59
130
|
if (!opened.ok) {
|
|
60
131
|
return {
|
|
61
132
|
ok: false,
|
|
@@ -69,7 +140,7 @@ export function createWorkItemOpenTool(store) {
|
|
|
69
140
|
reused: opened.reused,
|
|
70
141
|
workItemId: opened.record.workItemId,
|
|
71
142
|
header: opened.header,
|
|
72
|
-
|
|
143
|
+
...serializeWorkItem(opened.record),
|
|
73
144
|
};
|
|
74
145
|
});
|
|
75
146
|
return {
|
|
@@ -81,7 +152,7 @@ export function createWorkItemOpenTool(store) {
|
|
|
81
152
|
};
|
|
82
153
|
}
|
|
83
154
|
// START_CONTRACT: createWorkItemListTool
|
|
84
|
-
// PURPOSE: Build work_item_list handler that returns current work items and review metadata.
|
|
155
|
+
// PURPOSE: Build work_item_list handler that returns current work items and explicit review-round metadata.
|
|
85
156
|
// INPUTS: { store: WorkItemStore - workflow in-memory store }
|
|
86
157
|
// OUTPUTS: { WorkflowToolDefinition<ListArgs, unknown> - executable tool definition }
|
|
87
158
|
// SIDE_EFFECTS: [none]
|
|
@@ -99,24 +170,13 @@ export function createWorkItemListTool(store) {
|
|
|
99
170
|
tool: "work_item_list",
|
|
100
171
|
sessionId: context.sessionId,
|
|
101
172
|
includeClosed,
|
|
102
|
-
items: records.map(
|
|
103
|
-
workItemId: record.workItemId,
|
|
104
|
-
header: `VVOC_WORK_ITEM_ID: ${record.workItemId}`,
|
|
105
|
-
key: record.key,
|
|
106
|
-
title: record.title,
|
|
107
|
-
state: record.state,
|
|
108
|
-
specReviewCount: record.specReviewCount,
|
|
109
|
-
codeReviewCount: record.codeReviewCount,
|
|
110
|
-
reviewRound: getReviewRound(record),
|
|
111
|
-
createdAt: record.createdAt,
|
|
112
|
-
updatedAt: record.updatedAt,
|
|
113
|
-
})),
|
|
173
|
+
items: records.map(serializeWorkItem),
|
|
114
174
|
};
|
|
115
175
|
},
|
|
116
176
|
};
|
|
117
177
|
}
|
|
118
178
|
// START_CONTRACT: createWorkItemCloseTool
|
|
119
|
-
// PURPOSE: Build work_item_close handler that closes
|
|
179
|
+
// PURPOSE: Build work_item_close handler that closes a ready_to_close work item.
|
|
120
180
|
// INPUTS: { store: WorkItemStore - workflow in-memory store }
|
|
121
181
|
// OUTPUTS: { WorkflowToolDefinition<CloseArgs, unknown> - executable tool definition }
|
|
122
182
|
// SIDE_EFFECTS: [Mutates in-memory work-item store through close operations]
|
|
@@ -125,7 +185,7 @@ export function createWorkItemListTool(store) {
|
|
|
125
185
|
export function createWorkItemCloseTool(store) {
|
|
126
186
|
return {
|
|
127
187
|
name: "work_item_close",
|
|
128
|
-
description: "Close a workflow work item by id.",
|
|
188
|
+
description: "Close a workflow work item by id when it is ready_to_close.",
|
|
129
189
|
execute: (args, context, overrideStore) => {
|
|
130
190
|
const s = overrideStore ?? store;
|
|
131
191
|
const workItemId = coerceNonEmptyString(args.workItemId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooling.js","sourceRoot":"","sources":["../../../src/plugins/workflow/tooling.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,iBAAiB;AACjB,wBAAwB;AACxB,
|
|
1
|
+
{"version":3,"file":"tooling.js","sourceRoot":"","sources":["../../../src/plugins/workflow/tooling.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { WorkItemState } from "./state.js";
|
|
1
|
+
import type { TrackedAgentName } from "./protocol.js";
|
|
2
|
+
import type { ReviewerAgentName, ReviewerRole, ReviewRound, WorkItemRecord, WorkItemState } from "./state.js";
|
|
3
3
|
export declare const MAX_REVIEW_ROUNDS = 2;
|
|
4
|
-
export declare function
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function
|
|
4
|
+
export declare function getReviewerRoleForAgent(agent: TrackedAgentName): ReviewerRole | undefined;
|
|
5
|
+
export declare function getReviewerAgentForRole(role: ReviewerRole): ReviewerAgentName;
|
|
6
|
+
export declare function hasNeedsContextResult(round: ReviewRound): boolean;
|
|
7
|
+
export declare function getAllowedNextAgents(record: WorkItemRecord): TrackedAgentName[];
|
|
8
|
+
export declare function isAllowedTransition(record: WorkItemRecord, agent: TrackedAgentName): boolean;
|
|
9
|
+
export declare function getAttemptedImplementationRound(record: WorkItemRecord): number;
|
|
10
|
+
export declare function isRoundSettled(round: ReviewRound): boolean;
|
|
11
|
+
export declare function resolveCompletedRoundState(record: WorkItemRecord, round: ReviewRound): WorkItemState;
|
|
7
12
|
export declare function shouldBlockRound(reviewRound: number): boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// FILE: src/plugins/workflow/transitions.ts
|
|
2
|
-
// VERSION: 0.
|
|
2
|
+
// VERSION: 0.3.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
|
-
// PURPOSE: Provide deterministic workflow
|
|
5
|
-
// SCOPE:
|
|
4
|
+
// PURPOSE: Provide deterministic workflow launch policy, reviewer role mapping, review-round aggregation, and loop-gate policy checks.
|
|
5
|
+
// SCOPE: Record-aware launch allowance resolution, reviewer agent/role mapping, explicit review-round settlement checks, mode-specific aggregate state resolution, and implementation retry round-limit helpers.
|
|
6
6
|
// DEPENDS: [src/plugins/workflow/protocol.ts, src/plugins/workflow/state.ts]
|
|
7
7
|
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
8
8
|
// ROLE: RUNTIME
|
|
@@ -10,90 +10,132 @@
|
|
|
10
10
|
// END_MODULE_CONTRACT
|
|
11
11
|
//
|
|
12
12
|
// START_MODULE_MAP
|
|
13
|
-
// MAX_REVIEW_ROUNDS - Maximum allowed review rounds before loop-gate block.
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
13
|
+
// MAX_REVIEW_ROUNDS - Maximum allowed implementation review rounds before loop-gate block.
|
|
14
|
+
// getReviewerRoleForAgent - Maps tracked reviewer subagent name to domain reviewer role.
|
|
15
|
+
// getReviewerAgentForRole - Maps domain reviewer role to tracked reviewer subagent name.
|
|
16
|
+
// getAllowedNextAgents - Returns tracked agents currently allowed for a work item.
|
|
17
|
+
// isAllowedTransition - Checks whether launching a tracked agent is valid for a work item.
|
|
18
|
+
// getAttemptedImplementationRound - Computes the implementation retry round for loop gating.
|
|
19
|
+
// shouldBlockRound - Enforces loop-gate policy for implementation retry rounds.
|
|
20
|
+
// hasNeedsContextResult - Checks whether a round already recorded NEEDS_CONTEXT.
|
|
21
|
+
// isRoundSettled - Checks whether a review round can aggregate to a lifecycle state.
|
|
22
|
+
// resolveCompletedRoundState - Resolves mode-specific lifecycle state for a settled review round.
|
|
18
23
|
// END_MODULE_MAP
|
|
19
24
|
//
|
|
20
25
|
// START_CHANGE_SUMMARY
|
|
26
|
+
// LAST_CHANGE: [v0.3.0 - Replaced sequential reviewer transitions with record-aware explicit review-round launch policy and mode-specific collect-all aggregation.]
|
|
21
27
|
// LAST_CHANGE: [v0.2.0 - Allowed fresh work items to start with reviewer subagents for review-only workflows.]
|
|
22
28
|
// LAST_CHANGE: [v0.1.0 - Added deterministic state transition policy, launch-allowance resolution, and review round-gate checks.]
|
|
23
29
|
// END_CHANGE_SUMMARY
|
|
24
30
|
export const MAX_REVIEW_ROUNDS = 2;
|
|
25
|
-
// START_CONTRACT:
|
|
26
|
-
// PURPOSE:
|
|
27
|
-
// INPUTS: {
|
|
28
|
-
// OUTPUTS: {
|
|
31
|
+
// START_CONTRACT: getReviewerRoleForAgent
|
|
32
|
+
// PURPOSE: Map a tracked reviewer subagent to the stored domain reviewer role.
|
|
33
|
+
// INPUTS: { agent: TrackedAgentName - tracked subagent name }
|
|
34
|
+
// OUTPUTS: { ReviewerRole | undefined - reviewer role for reviewer subagents, undefined for implementer }
|
|
35
|
+
// SIDE_EFFECTS: [none]
|
|
36
|
+
// LINKS: [M-WORKFLOW-TRANSITIONS, M-WORKFLOW-STATE]
|
|
37
|
+
// END_CONTRACT: getReviewerRoleForAgent
|
|
38
|
+
export function getReviewerRoleForAgent(agent) {
|
|
39
|
+
if (agent === "vv-spec-reviewer")
|
|
40
|
+
return "spec";
|
|
41
|
+
if (agent === "vv-code-reviewer")
|
|
42
|
+
return "code";
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
// START_CONTRACT: getReviewerAgentForRole
|
|
46
|
+
// PURPOSE: Map a domain reviewer role to the tracked reviewer subagent that satisfies it.
|
|
47
|
+
// INPUTS: { role: ReviewerRole - domain reviewer role }
|
|
48
|
+
// OUTPUTS: { ReviewerAgentName - tracked reviewer subagent }
|
|
49
|
+
// SIDE_EFFECTS: [none]
|
|
50
|
+
// LINKS: [M-WORKFLOW-TRANSITIONS, M-WORKFLOW-STATE]
|
|
51
|
+
// END_CONTRACT: getReviewerAgentForRole
|
|
52
|
+
export function getReviewerAgentForRole(role) {
|
|
53
|
+
return role === "spec" ? "vv-spec-reviewer" : "vv-code-reviewer";
|
|
54
|
+
}
|
|
55
|
+
// START_CONTRACT: hasNeedsContextResult
|
|
56
|
+
// PURPOSE: Check whether a review round already recorded a NEEDS_CONTEXT result.
|
|
57
|
+
// INPUTS: { round: ReviewRound - current or completed review round }
|
|
58
|
+
// OUTPUTS: { boolean - true when any reviewer result is NEEDS_CONTEXT }
|
|
29
59
|
// SIDE_EFFECTS: [none]
|
|
30
60
|
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
31
|
-
// END_CONTRACT:
|
|
32
|
-
export function
|
|
33
|
-
|
|
34
|
-
|
|
61
|
+
// END_CONTRACT: hasNeedsContextResult
|
|
62
|
+
export function hasNeedsContextResult(round) {
|
|
63
|
+
return Object.values(round.results).some((result) => result?.status === "NEEDS_CONTEXT");
|
|
64
|
+
}
|
|
65
|
+
// START_CONTRACT: getAllowedNextAgents
|
|
66
|
+
// PURPOSE: Resolve all tracked agents currently allowed to launch for a work item.
|
|
67
|
+
// INPUTS: { record: WorkItemRecord - current work-item record }
|
|
68
|
+
// OUTPUTS: { TrackedAgentName[] - allowed tracked agents, empty when none are allowed }
|
|
69
|
+
// SIDE_EFFECTS: [none]
|
|
70
|
+
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
71
|
+
// END_CONTRACT: getAllowedNextAgents
|
|
72
|
+
export function getAllowedNextAgents(record) {
|
|
73
|
+
if (record.mode === "implementation" &&
|
|
74
|
+
(record.state === "open" || record.state === "awaiting_implementer")) {
|
|
75
|
+
return ["vv-implementer"];
|
|
35
76
|
}
|
|
36
|
-
if (state
|
|
37
|
-
|
|
77
|
+
if (record.state !== "awaiting_reviews" ||
|
|
78
|
+
!record.currentRound ||
|
|
79
|
+
record.currentRound.status !== "active") {
|
|
80
|
+
return [];
|
|
38
81
|
}
|
|
39
|
-
if (
|
|
40
|
-
return
|
|
82
|
+
if (hasNeedsContextResult(record.currentRound)) {
|
|
83
|
+
return [];
|
|
41
84
|
}
|
|
42
|
-
return
|
|
85
|
+
return record.currentRound.pendingReviewers.map(getReviewerAgentForRole);
|
|
43
86
|
}
|
|
44
87
|
// START_CONTRACT: isAllowedTransition
|
|
45
|
-
// PURPOSE: Check whether launching
|
|
46
|
-
// INPUTS: {
|
|
47
|
-
// OUTPUTS: { boolean - true when launch is allowed }
|
|
88
|
+
// PURPOSE: Check whether launching a tracked agent is valid for the current work-item record.
|
|
89
|
+
// INPUTS: { record: WorkItemRecord - current work-item record, agent: TrackedAgentName - requested tracked subagent }
|
|
90
|
+
// OUTPUTS: { boolean - true when launch is currently allowed }
|
|
48
91
|
// SIDE_EFFECTS: [none]
|
|
49
92
|
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
50
93
|
// END_CONTRACT: isAllowedTransition
|
|
51
|
-
export function isAllowedTransition(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
94
|
+
export function isAllowedTransition(record, agent) {
|
|
95
|
+
return getAllowedNextAgents(record).includes(agent);
|
|
96
|
+
}
|
|
97
|
+
// START_CONTRACT: getAttemptedImplementationRound
|
|
98
|
+
// PURPOSE: Compute the implementation retry round that would be entered by launching vv-implementer now.
|
|
99
|
+
// INPUTS: { record: WorkItemRecord - current work item }
|
|
100
|
+
// OUTPUTS: { number - attempted implementation round }
|
|
101
|
+
// SIDE_EFFECTS: [none]
|
|
102
|
+
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
103
|
+
// END_CONTRACT: getAttemptedImplementationRound
|
|
104
|
+
export function getAttemptedImplementationRound(record) {
|
|
105
|
+
return record.completedReviewRoundCount + 1;
|
|
106
|
+
}
|
|
107
|
+
// START_CONTRACT: isRoundSettled
|
|
108
|
+
// PURPOSE: Determine whether a review round can aggregate to a lifecycle state.
|
|
109
|
+
// INPUTS: { round: ReviewRound - current review round }
|
|
110
|
+
// OUTPUTS: { boolean - true when no in-flight result can still change aggregation timing }
|
|
111
|
+
// SIDE_EFFECTS: [none]
|
|
112
|
+
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
113
|
+
// END_CONTRACT: isRoundSettled
|
|
114
|
+
export function isRoundSettled(round) {
|
|
115
|
+
if (round.inFlightReviewers.length > 0)
|
|
116
|
+
return false;
|
|
117
|
+
if (hasNeedsContextResult(round))
|
|
118
|
+
return true;
|
|
119
|
+
return round.pendingReviewers.length === 0;
|
|
56
120
|
}
|
|
57
|
-
// START_CONTRACT:
|
|
58
|
-
// PURPOSE:
|
|
59
|
-
// INPUTS: {
|
|
121
|
+
// START_CONTRACT: resolveCompletedRoundState
|
|
122
|
+
// PURPOSE: Resolve the lifecycle state for a settled review round using mode-specific aggregation rules.
|
|
123
|
+
// INPUTS: { record: WorkItemRecord - owning work item, round: ReviewRound - settled review round }
|
|
60
124
|
// OUTPUTS: { WorkItemState - next lifecycle state }
|
|
61
125
|
// SIDE_EFFECTS: [none]
|
|
62
126
|
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
63
|
-
// END_CONTRACT:
|
|
64
|
-
export function
|
|
65
|
-
if (
|
|
66
|
-
if (result.status === "DONE" || result.status === "DONE_WITH_CONCERNS") {
|
|
67
|
-
return "awaiting_spec_review";
|
|
68
|
-
}
|
|
69
|
-
if (result.status === "NEEDS_CONTEXT") {
|
|
70
|
-
return "needs_context";
|
|
71
|
-
}
|
|
72
|
-
return "blocked";
|
|
73
|
-
}
|
|
74
|
-
if (result.agent === "vv-spec-reviewer") {
|
|
75
|
-
if (result.status === "PASS") {
|
|
76
|
-
return "awaiting_code_review";
|
|
77
|
-
}
|
|
78
|
-
if (result.status === "FAIL") {
|
|
79
|
-
return "awaiting_implementer";
|
|
80
|
-
}
|
|
81
|
-
return "needs_context";
|
|
82
|
-
}
|
|
83
|
-
if (result.agent === "vv-code-reviewer") {
|
|
84
|
-
if (result.status === "PASS") {
|
|
85
|
-
return "ready_to_close";
|
|
86
|
-
}
|
|
87
|
-
if (result.status === "FAIL") {
|
|
88
|
-
return "awaiting_implementer";
|
|
89
|
-
}
|
|
127
|
+
// END_CONTRACT: resolveCompletedRoundState
|
|
128
|
+
export function resolveCompletedRoundState(record, round) {
|
|
129
|
+
if (hasNeedsContextResult(round))
|
|
90
130
|
return "needs_context";
|
|
91
|
-
|
|
92
|
-
|
|
131
|
+
const allPass = round.requiredReviewers.every((reviewer) => round.results[reviewer]?.status === "PASS");
|
|
132
|
+
if (allPass)
|
|
133
|
+
return "ready_to_close";
|
|
134
|
+
return record.mode === "review_only" ? "ready_to_close" : "awaiting_implementer";
|
|
93
135
|
}
|
|
94
136
|
// START_CONTRACT: shouldBlockRound
|
|
95
|
-
// PURPOSE: Enforce loop-gate policy by rejecting rounds above MAX_REVIEW_ROUNDS.
|
|
96
|
-
// INPUTS: { reviewRound: number -
|
|
137
|
+
// PURPOSE: Enforce loop-gate policy by rejecting implementation rounds above MAX_REVIEW_ROUNDS.
|
|
138
|
+
// INPUTS: { reviewRound: number - attempted implementation round }
|
|
97
139
|
// OUTPUTS: { boolean - true when launch must be blocked }
|
|
98
140
|
// SIDE_EFFECTS: [none]
|
|
99
141
|
// LINKS: [M-WORKFLOW-TRANSITIONS]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transitions.js","sourceRoot":"","sources":["../../../src/plugins/workflow/transitions.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,iBAAiB;AACjB,wBAAwB;AACxB,
|
|
1
|
+
{"version":3,"file":"transitions.js","sourceRoot":"","sources":["../../../src/plugins/workflow/transitions.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osovv/vv-opencode",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.24",
|
|
4
4
|
"description": "Portable OpenCode workflow toolkit — 6 plugins, managed agents & skills, a spec-to-code pipeline, security, and the vvoc CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
package/schemas/vvoc/v3.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://cdn.jsdelivr.net/npm/@osovv/vv-opencode@0.35.
|
|
3
|
+
"$id": "https://cdn.jsdelivr.net/npm/@osovv/vv-opencode@0.35.24/schemas/vvoc/v3.json",
|
|
4
4
|
"title": "vvoc config",
|
|
5
5
|
"description": "Canonical vvoc configuration document.",
|
|
6
6
|
"type": "object",
|
|
@@ -28,7 +28,7 @@ Choose the lightest safe route for each request:
|
|
|
28
28
|
- `docs_only`: documentation-only change. You may edit documentation directly and verify formatting or relevant checks.
|
|
29
29
|
- `investigate_first`: bugs, pasted errors, regressions, failing tests, unclear behavior, or unknown root cause. Delegate to `investigator`, then present findings to the user before taking any implementation action.
|
|
30
30
|
- `change_with_review`: multi-file, ambiguous, risky, public API/config/setup behavior, persistence, security-sensitive, or cross-module changes. Use the tracked implementer/reviewer loop.
|
|
31
|
-
- `review_only`: explicit review request. Decide whether spec review, code review, or both are needed. Open
|
|
31
|
+
- `review_only`: explicit review request. Decide whether spec review, code review, or both are needed. Open one work item with `mode: "review_only"` and `requiredReviewers` containing `"spec"`, `"code"`, or both before invoking tracked reviewers. Findings are the final output — reviewer `FAIL` is a completed review result, not a route to `vv-implementer`; do not proceed to fixes without user confirmation.
|
|
32
32
|
- `large_feature`: broad feature or architectural change. Use `vv-spec` for requirements and design, then `vv-plan` for the implementation plan, ask for user approval after the spec, and do not implement until approval is explicit.
|
|
33
33
|
|
|
34
34
|
Prefer existing project patterns, libraries, and established repository structure over novel approaches.
|
|
@@ -95,7 +95,7 @@ When rerouting, state the current route, the trigger, the next route, and why th
|
|
|
95
95
|
|
|
96
96
|
<tracked_implementation_loop>
|
|
97
97
|
- Use this for `change_with_review` and for implementation after an approved `large_feature` architecture.
|
|
98
|
-
- Open a work item with `work_item_open` before launching `vv-implementer`, `vv-spec-reviewer`, or `vv-code-reviewer
|
|
98
|
+
- Open a work item with `work_item_open` before launching `vv-implementer`, `vv-spec-reviewer`, or `vv-code-reviewer`; each item must include `key`, `title`, `mode` (`implementation` or `review_only`), and `requiredReviewers` (`spec`, `code`, or both).
|
|
99
99
|
- Put the returned `VVOC_WORK_ITEM_ID: wi-N` header as the first line of each tracked subagent prompt.
|
|
100
100
|
- On implementation retries after review findings, include the normalized finding packet immediately after the required `VVOC_WORK_ITEM_ID` header in the `vv-implementer` assignment so the implementer starts from settled files, lines, scopes, and evidence without rebuilding the packet from scratch.
|
|
101
101
|
- Treat `NEEDS_CONTEXT` and `BLOCKED` as hard stops requiring explicit user action.
|
|
@@ -103,7 +103,7 @@ When rerouting, state the current route, the trigger, the next route, and why th
|
|
|
103
103
|
- Close completed work items with `work_item_close` after implementation, review, and verification are complete.
|
|
104
104
|
- Use work-item identity for all review loops.
|
|
105
105
|
|
|
106
|
-
Execution order: 1. `vv-implementer` 2. `vv-spec-reviewer`
|
|
106
|
+
Execution order for implementation mode: 1. `vv-implementer` 2. launch all required reviewers (`vv-spec-reviewer` for `spec`, `vv-code-reviewer` for `code`) as needed 3. collect the full review round before deciding whether to retry implementation or close 4. verification and close
|
|
107
107
|
</tracked_implementation_loop>
|
|
108
108
|
|
|
109
109
|
<hard_stop_handoff>
|
|
@@ -174,7 +174,7 @@ Every material finding from plan.xml must be enumerated explicitly in the packet
|
|
|
174
174
|
</step>
|
|
175
175
|
|
|
176
176
|
<step name="dispatch">
|
|
177
|
-
Open
|
|
177
|
+
Open an implementation work item with work_item_open for this task (e.g. `{ key, title, mode: "implementation", requiredReviewers: ["spec", "code"] }`).
|
|
178
178
|
Dispatch vv-implementer with VVOC_WORK_ITEM_ID header + the constructed packet.
|
|
179
179
|
The implementer writes code, runs tests, and returns a status. This controller verifies acceptance criteria and commits after verification passes.
|
|
180
180
|
</step>
|
|
@@ -160,7 +160,7 @@ export type CacheStoreOptions = {
|
|
|
160
160
|
<rule>If the user requests changes, keep the plan status as draft, make the changes, re-run self-review, save the updated plan, and ask for approval again.</rule>
|
|
161
161
|
<rule>After explicit user approval, update the saved plan file so the top-level status is <status>approved</status>.</rule>
|
|
162
162
|
<rule>After the saved plan status is approved, present the user with two execution options:</rule>
|
|
163
|
-
<option name="workflow">Workflow tracked loop (recommended) — vv-implementer executes tasks, followed by
|
|
163
|
+
<option name="workflow">Workflow tracked loop (recommended) — vv-implementer executes tasks, followed by required reviewers. Uses work_item_open with `mode: "implementation"` and explicit `requiredReviewers`, then work_item_close after the collect-all review round is ready to close.</option>
|
|
164
164
|
<option name="manual">Manual execution — the user or another agent executes tasks step by step following the plan directly.</option>
|
|
165
165
|
<rule>Wait for the user's choice. Do NOT start implementation.</rule>
|
|
166
166
|
</execution_handoff>
|
|
@@ -14,9 +14,9 @@ You are the vv-review skill. Your job is to route review requests to the appropr
|
|
|
14
14
|
- Spec review (vv-spec-reviewer): when checking against a spec or acceptance criteria
|
|
15
15
|
- Code review (vv-code-reviewer): when checking for bugs, regressions, maintainability, or security
|
|
16
16
|
- Both: when the request calls for comprehensive review</rule>
|
|
17
|
-
<step>Open
|
|
17
|
+
<step>Open one review-only work item with work_item_open before dispatching tracked reviewer sub-agents. Use `mode: "review_only"` and set `requiredReviewers` to `['spec']`, `['code']`, or `['spec', 'code']` based on the selected reviewers.</step>
|
|
18
18
|
<step>Put the VVOC_WORK_ITEM_ID header as the first line of each reviewer sub-agent prompt.</step>
|
|
19
|
-
<step>Collect findings from each reviewer.
|
|
19
|
+
<step>Collect findings from each required reviewer. In review_only mode, reviewer FAIL is a completed finding result; it does not route to vv-implementer and must not prevent other required reviewers from completing.</step>
|
|
20
20
|
<step>Findings are the FINAL output. Do NOT proceed to fixes without explicit user confirmation.</step>
|
|
21
21
|
<step>Close the work item with work_item_close after the review is complete.</step>
|
|
22
22
|
</workflow>
|