@osovv/vv-opencode 0.35.23 → 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.
@@ -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: string;
12
- title: string;
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.1.1
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 around listWorkItems.
17
- // createWorkItemCloseTool - Creates work_item_close tool wrapper around closeWorkItem.
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 key = coerceNonEmptyString(item.key);
46
- const title = coerceNonEmptyString(item.title);
47
- if (!key || !title) {
121
+ const normalized = normalizeOpenInputItem(item, context.sessionId);
122
+ if (!normalized.ok) {
48
123
  return {
49
124
  ok: false,
50
- errorCode: "INVALID_INPUT",
51
- message: "INVALID_INPUT: key and title must be non-empty strings",
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
- state: opened.record.state,
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((record) => ({
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 an existing work item.
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":"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"}
1
+ {"version":3,"file":"tooling.js","sourceRoot":"","sources":["../../../src/plugins/workflow/tooling.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,iBAAiB;AACjB,wBAAwB;AACxB,0IAA0I;AAC1I,yLAAyL;AACzL,6CAA6C;AAC7C,gCAAgC;AAChC,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,gFAAgF;AAChF,uFAAuF;AACvF,wGAAwG;AACxG,+FAA+F;AAC/F,yGAAyG;AACzG,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,gJAAgJ;AAChJ,gGAAgG;AAChG,0IAA0I;AAC1I,qBAAqB;AAErB,OAAO,EACL,aAAa,EACb,cAAc,EACd,aAAa,EACb,YAAY,GAMb,MAAM,YAAY,CAAC;AA+BpB,SAAS,oBAAoB,CAAC,KAAc;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,OAAO,IAAI,SAAS,CAAC;AAC9B,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,KAAK,KAAK,gBAAgB,IAAI,KAAK,KAAK,aAAa,CAAC;AAC/D,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,CAAC;AAC9C,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACrC,IAAI,IAAI,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;QAC7B,OAAO,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB,CAC7B,IAAmB,EACnB,SAAiB;IAIjB,MAAM,GAAG,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,eAAe;YAC1B,OAAO,EAAE,wDAAwD;SAClE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,eAAe;YAC1B,OAAO,EAAE,2DAA2D;SACrE,CAAC;IACJ,CAAC;IACD,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACxE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,eAAe;YAC1B,OAAO,EACL,kGAAkG;SACrG,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,SAAS;YACT,GAAG;YACH,KAAK;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,iBAAiB;SAClB;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAsB;IAC/C,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,sBAAsB,MAAM,CAAC,UAAU,EAAE;QACjD,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;QAC3C,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,WAAW,EAAE,cAAc,CAAC,MAAM,CAAC;QACnC,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;QAC3D,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,yCAAyC;AACzC,sIAAsI;AACtI,gEAAgE;AAChE,wFAAwF;AACxF,8EAA8E;AAC9E,kDAAkD;AAClD,uCAAuC;AACvC,MAAM,UAAU,sBAAsB,CACpC,KAAoB;IAEpB,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,6FAA6F;QAC/F,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;YACxC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAE/D,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACtC,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;gBACnE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;oBACnB,OAAO;wBACL,EAAE,EAAE,KAAK;wBACT,SAAS,EAAE,UAAU,CAAC,SAAS;wBAC/B,OAAO,EAAE,UAAU,CAAC,OAAO;qBAC5B,CAAC;gBACJ,CAAC;gBAED,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,IAAI,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;gBACtE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;oBACf,OAAO;wBACL,EAAE,EAAE,KAAK;wBACT,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;qBAC9C,CAAC;gBACJ,CAAC;gBAED,OAAO;oBACL,EAAE,EAAE,IAAI;oBACR,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;oBACpC,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC;iBACpC,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,OAAO;gBACL,IAAI,EAAE,gBAAgB;gBACtB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,KAAK,EAAE,OAAO;aACf,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,yCAAyC;AACzC,8GAA8G;AAC9G,gEAAgE;AAChE,wFAAwF;AACxF,yBAAyB;AACzB,kDAAkD;AAClD,uCAAuC;AACvC,MAAM,UAAU,sBAAsB,CACpC,KAAoB;IAEpB,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;YACxC,MAAM,CAAC,GAAG,aAAa,IAAI,KAAK,CAAC;YACjC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC;YAClD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC;YACvE,OAAO;gBACL,IAAI,EAAE,gBAAgB;gBACtB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,aAAa;gBACb,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;aACtC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,0CAA0C;AAC1C,mFAAmF;AACnF,gEAAgE;AAChE,yFAAyF;AACzF,+EAA+E;AAC/E,kDAAkD;AAClD,wCAAwC;AACxC,MAAM,UAAU,uBAAuB,CACrC,KAAoB;IAEpB,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,6DAA6D;QAC1E,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;YACxC,MAAM,CAAC,GAAG,aAAa,IAAI,KAAK,CAAC;YACjC,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,OAAO;oBACL,IAAI,EAAE,iBAAiB;oBACvB,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,EAAE,EAAE,KAAK;oBACT,SAAS,EAAE,eAAe;oBAC1B,OAAO,EAAE,sDAAsD;iBAChE,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YAC/D,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,OAAO;oBACL,IAAI,EAAE,iBAAiB;oBACvB,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,EAAE,EAAE,KAAK;oBACT,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;iBACxB,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,iBAAiB;gBACvB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,EAAE,EAAE,IAAI;gBACR,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;gBACpC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK;gBAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ;aACjC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,7 +1,12 @@
1
- import type { ParsedResultBlock, TrackedAgentName } from "./protocol.js";
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 getAllowedNextAgent(state: WorkItemState): TrackedAgentName | null;
5
- export declare function isAllowedTransition(state: WorkItemState, agent: TrackedAgentName): boolean;
6
- export declare function getNextState(currentState: WorkItemState, result: ParsedResultBlock): WorkItemState;
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.0
2
+ // VERSION: 0.3.0
3
3
  // START_MODULE_CONTRACT
4
- // PURPOSE: Provide deterministic workflow transition rules, allowed-next-agent resolution, and loop-gate policy checks.
5
- // SCOPE: Work-item state transition mapping from tracked results, launch permission checks by state, and review-round limit checks.
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
- // getNextState - Computes next work-item state from tracked agent result.
15
- // getAllowedNextAgent - Resolves the only allowed tracked agent for a state.
16
- // isAllowedTransition - Checks whether launching an agent from current state is allowed.
17
- // shouldBlockRound - Enforces loop-gate policy for review rounds.
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: getAllowedNextAgent
26
- // PURPOSE: Resolve the single tracked agent allowed to run from the current state.
27
- // INPUTS: { state: WorkItemState - current work-item lifecycle state }
28
- // OUTPUTS: { TrackedAgentName | null - allowed tracked agent or null when no launch is allowed }
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: getAllowedNextAgent
32
- export function getAllowedNextAgent(state) {
33
- if (state === "open" || state === "awaiting_implementer") {
34
- return "vv-implementer";
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 === "awaiting_spec_review") {
37
- return "vv-spec-reviewer";
77
+ if (record.state !== "awaiting_reviews" ||
78
+ !record.currentRound ||
79
+ record.currentRound.status !== "active") {
80
+ return [];
38
81
  }
39
- if (state === "awaiting_code_review") {
40
- return "vv-code-reviewer";
82
+ if (hasNeedsContextResult(record.currentRound)) {
83
+ return [];
41
84
  }
42
- return null;
85
+ return record.currentRound.pendingReviewers.map(getReviewerAgentForRole);
43
86
  }
44
87
  // START_CONTRACT: isAllowedTransition
45
- // PURPOSE: Check whether launching the requested tracked agent is valid for current state.
46
- // INPUTS: { state: WorkItemState - current state, agent: TrackedAgentName - requested tracked subagent }
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(state, agent) {
52
- if (state === "open") {
53
- return (agent === "vv-implementer" || agent === "vv-spec-reviewer" || agent === "vv-code-reviewer");
54
- }
55
- return getAllowedNextAgent(state) === agent;
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: getNextState
58
- // PURPOSE: Compute deterministic next work-item state from a tracked subagent result.
59
- // INPUTS: { currentState: WorkItemState - current lifecycle state, result: ParsedResultBlock - validated tracked result block }
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: getNextState
64
- export function getNextState(currentState, result) {
65
- if (result.agent === "vv-implementer") {
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
- return currentState;
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 - computed review round }
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":"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"}
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.23",
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",
@@ -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.23/schemas/vvoc/v3.json",
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 a work item before invoking tracked reviewers. Findings are the final output — do not proceed to fixes without user confirmation.
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` 3. `vv-code-reviewer` 4. verification and close
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 a work item with work_item_open for this task (e.g. "Implement &lt;component&gt;").
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 &lt;status&gt;approved&lt;/status&gt;.</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 vv-spec-reviewer and vv-code-reviewer. Uses work_item_open/close for each implementation wave.</option>
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 a work item with work_item_open before dispatching any tracked reviewer sub-agents.</step>
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. Present them together as the review report.</step>
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>