@osovv/vv-opencode 0.21.0 → 0.24.1

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.
Files changed (75) hide show
  1. package/README.md +46 -10
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +9 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/managed-agents.d.ts +3 -3
  6. package/dist/lib/managed-agents.js +14 -13
  7. package/dist/lib/managed-agents.js.map +1 -1
  8. package/dist/lib/model-roles.d.ts +3 -3
  9. package/dist/lib/model-roles.js +5 -4
  10. package/dist/lib/model-roles.js.map +1 -1
  11. package/dist/lib/opencode.js +100 -5
  12. package/dist/lib/opencode.js.map +1 -1
  13. package/dist/lib/vvoc-config.js +5 -4
  14. package/dist/lib/vvoc-config.js.map +1 -1
  15. package/dist/plugins/hashline-edit/autocorrect-replacement-lines.d.ts +1 -0
  16. package/dist/plugins/hashline-edit/autocorrect-replacement-lines.js +184 -0
  17. package/dist/plugins/hashline-edit/autocorrect-replacement-lines.js.map +1 -0
  18. package/dist/plugins/hashline-edit/constants.d.ts +4 -0
  19. package/dist/plugins/hashline-edit/constants.js +26 -0
  20. package/dist/plugins/hashline-edit/constants.js.map +1 -0
  21. package/dist/plugins/hashline-edit/edit-operation-primitives.d.ts +10 -0
  22. package/dist/plugins/hashline-edit/edit-operation-primitives.js +114 -0
  23. package/dist/plugins/hashline-edit/edit-operation-primitives.js.map +1 -0
  24. package/dist/plugins/hashline-edit/edit-operations.d.ts +7 -0
  25. package/dist/plugins/hashline-edit/edit-operations.js +168 -0
  26. package/dist/plugins/hashline-edit/edit-operations.js.map +1 -0
  27. package/dist/plugins/hashline-edit/edit-text-normalization.d.ts +6 -0
  28. package/dist/plugins/hashline-edit/edit-text-normalization.js +123 -0
  29. package/dist/plugins/hashline-edit/edit-text-normalization.js.map +1 -0
  30. package/dist/plugins/hashline-edit/file-text-canonicalization.d.ts +7 -0
  31. package/dist/plugins/hashline-edit/file-text-canonicalization.js +52 -0
  32. package/dist/plugins/hashline-edit/file-text-canonicalization.js.map +1 -0
  33. package/dist/plugins/hashline-edit/hash-computation.d.ts +3 -0
  34. package/dist/plugins/hashline-edit/hash-computation.js +34 -0
  35. package/dist/plugins/hashline-edit/hash-computation.js.map +1 -0
  36. package/dist/plugins/hashline-edit/index.d.ts +2 -0
  37. package/dist/plugins/hashline-edit/index.js +246 -0
  38. package/dist/plugins/hashline-edit/index.js.map +1 -0
  39. package/dist/plugins/hashline-edit/normalize-edits.d.ts +10 -0
  40. package/dist/plugins/hashline-edit/normalize-edits.js +82 -0
  41. package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -0
  42. package/dist/plugins/hashline-edit/tool-description.d.ts +1 -0
  43. package/dist/plugins/hashline-edit/tool-description.js +35 -0
  44. package/dist/plugins/hashline-edit/tool-description.js.map +1 -0
  45. package/dist/plugins/hashline-edit/types.d.ts +17 -0
  46. package/dist/plugins/hashline-edit/types.js +19 -0
  47. package/dist/plugins/hashline-edit/types.js.map +1 -0
  48. package/dist/plugins/hashline-edit/validation.d.ts +20 -0
  49. package/dist/plugins/hashline-edit/validation.js +160 -0
  50. package/dist/plugins/hashline-edit/validation.js.map +1 -0
  51. package/dist/plugins/system-context-injection/index.js +65 -2
  52. package/dist/plugins/system-context-injection/index.js.map +1 -1
  53. package/dist/plugins/workflow/index.d.ts +2 -0
  54. package/dist/plugins/workflow/index.js +411 -0
  55. package/dist/plugins/workflow/index.js.map +1 -0
  56. package/dist/plugins/workflow/protocol.d.ts +33 -0
  57. package/dist/plugins/workflow/protocol.js +188 -0
  58. package/dist/plugins/workflow/protocol.js.map +1 -0
  59. package/dist/plugins/workflow/state.d.ts +79 -0
  60. package/dist/plugins/workflow/state.js +307 -0
  61. package/dist/plugins/workflow/state.js.map +1 -0
  62. package/dist/plugins/workflow/system-instruction.md +14 -0
  63. package/dist/plugins/workflow/tooling.d.ts +26 -0
  64. package/dist/plugins/workflow/tooling.js +161 -0
  65. package/dist/plugins/workflow/tooling.js.map +1 -0
  66. package/dist/plugins/workflow/transitions.d.ts +7 -0
  67. package/dist/plugins/workflow/transitions.js +102 -0
  68. package/dist/plugins/workflow/transitions.js.map +1 -0
  69. package/package.json +11 -3
  70. package/schemas/vvoc/v1.json +1 -1
  71. package/schemas/vvoc/v2.json +1 -1
  72. package/schemas/vvoc/v3.json +1 -1
  73. package/templates/agents/{code-reviewer.md → vv-code-reviewer.md} +12 -4
  74. package/templates/agents/{implementer.md → vv-implementer.md} +14 -8
  75. package/templates/agents/{spec-reviewer.md → vv-spec-reviewer.md} +13 -5
@@ -0,0 +1,188 @@
1
+ // FILE: src/plugins/workflow/protocol.ts
2
+ // VERSION: 0.1.2
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Define the tracked subagent result protocol, strict top-block parsing rules, and work-item header extraction.
5
+ // SCOPE: Tracked agent/status constants, status validation per agent, strict result-block parsing, protocol error reporting, and VVOC_WORK_ITEM_ID header parsing.
6
+ // DEPENDS: [none]
7
+ // LINKS: [M-WORKFLOW-PROTOCOL]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // TrackedAgentName - Tracked subagent names used by workflow enforcement.
14
+ // VVocStatus - Union of all supported protocol statuses.
15
+ // ParsedResultBlock - Parsed strict top-block fields from tracked subagent output.
16
+ // ProtocolErrorCode - Stable machine-readable protocol error codes.
17
+ // ProtocolError - Structured protocol error payload.
18
+ // ProtocolResult - Deterministic success/failure wrapper for parsing and validation operations.
19
+ // TRACKED_SUBAGENT_NAMES - Ordered tracked subagent names.
20
+ // ALLOWED_STATUSES - Allowed VVOC_STATUS values per tracked subagent.
21
+ // parseResultBlock - Parses strict top-block protocol fields from tracked subagent output.
22
+ // validateStatusForAgent - Validates VVOC_STATUS against tracked agent allowances.
23
+ // parseWorkItemHeader - Extracts and validates the top-line VVOC_WORK_ITEM_ID prompt header.
24
+ // END_MODULE_MAP
25
+ //
26
+ // START_CHANGE_SUMMARY
27
+ // LAST_CHANGE: [v0.1.2 - Rejected duplicate strict top-block protocol fields to keep parse outcomes deterministic.]
28
+ // LAST_CHANGE: [v0.1.1 - Enforced case-sensitive status validation and strict top-block line validation for protocol-only fields.]
29
+ // LAST_CHANGE: [v0.1.0 - Added workflow protocol grammar, strict top-block parser, per-agent status validation, and prompt-header extraction.]
30
+ // END_CHANGE_SUMMARY
31
+ export const TRACKED_SUBAGENT_NAMES = [
32
+ "vv-implementer",
33
+ "vv-spec-reviewer",
34
+ "vv-code-reviewer",
35
+ ];
36
+ export const ALLOWED_STATUSES = {
37
+ "vv-implementer": ["DONE", "DONE_WITH_CONCERNS", "NEEDS_CONTEXT", "BLOCKED"],
38
+ "vv-spec-reviewer": ["PASS", "FAIL", "NEEDS_CONTEXT"],
39
+ "vv-code-reviewer": ["PASS", "FAIL", "NEEDS_CONTEXT"],
40
+ };
41
+ const WORK_ITEM_HEADER_RE = /^VVOC_WORK_ITEM_ID:\s*(wi-\d+)\s*$/;
42
+ function createProtocolError(code, message) {
43
+ return {
44
+ ok: false,
45
+ error: {
46
+ code,
47
+ message,
48
+ },
49
+ };
50
+ }
51
+ function splitTopBlock(text) {
52
+ const lines = text.replace(/\r\n/g, "\n").split("\n");
53
+ const firstMeaningfulIndex = lines.findIndex((line) => line.trim().length > 0);
54
+ if (firstMeaningfulIndex < 0)
55
+ return [];
56
+ const block = [];
57
+ for (let index = firstMeaningfulIndex; index < lines.length; index += 1) {
58
+ const line = lines[index] ?? "";
59
+ if (line.trim().length === 0) {
60
+ break;
61
+ }
62
+ block.push(line.trim());
63
+ }
64
+ return block;
65
+ }
66
+ function readTopBlockField(topBlockLines, field) {
67
+ const fieldPattern = new RegExp(`^${field}\\s*:\\s*(.+)$`);
68
+ for (const line of topBlockLines) {
69
+ const match = fieldPattern.exec(line);
70
+ if (!match) {
71
+ continue;
72
+ }
73
+ const value = match[1]?.trim() ?? "";
74
+ return value || undefined;
75
+ }
76
+ return undefined;
77
+ }
78
+ function validateTopBlockLines(topBlockLines) {
79
+ const allowedFields = new Set(["VVOC_WORK_ITEM_ID", "VVOC_STATUS", "VVOC_ROUTE"]);
80
+ const seenFields = new Set();
81
+ for (const line of topBlockLines) {
82
+ const match = /^([A-Z_]+)\s*:\s*(.+)$/.exec(line);
83
+ if (!match) {
84
+ return createProtocolError("UNEXPECTED_TOP_BLOCK_LINE", `UNEXPECTED_TOP_BLOCK_LINE: strict top block contains a non-protocol line \`${line}\``);
85
+ }
86
+ const field = match[1] ?? "";
87
+ if (!allowedFields.has(field)) {
88
+ return createProtocolError("UNEXPECTED_TOP_BLOCK_LINE", `UNEXPECTED_TOP_BLOCK_LINE: strict top block field \`${field}\` is not recognized`);
89
+ }
90
+ if (seenFields.has(field)) {
91
+ return createProtocolError("DUPLICATE_TOP_BLOCK_FIELD", `DUPLICATE_TOP_BLOCK_FIELD: strict top block repeats field \`${field}\``);
92
+ }
93
+ seenFields.add(field);
94
+ }
95
+ return { ok: true, value: true };
96
+ }
97
+ // START_CONTRACT: validateStatusForAgent
98
+ // PURPOSE: Validate that the provided VVOC_STATUS value is allowed for a tracked subagent.
99
+ // INPUTS: { agent: TrackedAgentName - tracked subagent name, status: string - candidate status value }
100
+ // OUTPUTS: { ProtocolResult<VVocStatus> - normalized status success or protocol validation error }
101
+ // SIDE_EFFECTS: [none]
102
+ // LINKS: [M-WORKFLOW-PROTOCOL]
103
+ // END_CONTRACT: validateStatusForAgent
104
+ export function validateStatusForAgent(agent, status) {
105
+ const normalized = status.trim();
106
+ const allowed = ALLOWED_STATUSES[agent];
107
+ const allKnownStatuses = new Set(Object.values(ALLOWED_STATUSES).flatMap((entries) => [...entries]));
108
+ if (!allKnownStatuses.has(normalized)) {
109
+ return createProtocolError("UNKNOWN_STATUS", `UNKNOWN_STATUS: ${normalized || "<empty>"} is not a recognized VVOC_STATUS`);
110
+ }
111
+ if (!allowed.some((entry) => entry === normalized)) {
112
+ return createProtocolError("STATUS_NOT_ALLOWED", `STATUS_NOT_ALLOWED: ${normalized} is not allowed for ${agent}`);
113
+ }
114
+ return {
115
+ ok: true,
116
+ value: normalized,
117
+ };
118
+ }
119
+ // START_CONTRACT: parseResultBlock
120
+ // PURPOSE: Parse strict top-block workflow protocol fields from tracked subagent output.
121
+ // INPUTS: { agent: TrackedAgentName - tracked subagent source, output: string - subagent textual output, expectedWorkItemId?: string - optional ID to match against parsed output }
122
+ // OUTPUTS: { ProtocolResult<ParsedResultBlock> - parsed protocol fields or protocol error }
123
+ // SIDE_EFFECTS: [none]
124
+ // LINKS: [M-WORKFLOW-PROTOCOL]
125
+ // END_CONTRACT: parseResultBlock
126
+ // START_BLOCK_PARSE_RESULT
127
+ export function parseResultBlock(options) {
128
+ const topBlockLines = splitTopBlock(options.output);
129
+ const topBlockValidation = validateTopBlockLines(topBlockLines);
130
+ if (!topBlockValidation.ok) {
131
+ return topBlockValidation;
132
+ }
133
+ const workItemId = readTopBlockField(topBlockLines, "VVOC_WORK_ITEM_ID");
134
+ if (!workItemId) {
135
+ return createProtocolError("MISSING_WORK_ITEM_ID", "MISSING_WORK_ITEM_ID: strict top block must include VVOC_WORK_ITEM_ID");
136
+ }
137
+ if (!/^wi-\d+$/.test(workItemId)) {
138
+ return createProtocolError("MISSING_WORK_ITEM_ID", `MISSING_WORK_ITEM_ID: invalid work item id format ${workItemId}`);
139
+ }
140
+ if (options.expectedWorkItemId && options.expectedWorkItemId !== workItemId) {
141
+ return createProtocolError("WORK_ITEM_MISMATCH", `WORK_ITEM_MISMATCH: expected ${options.expectedWorkItemId} but parsed ${workItemId}`);
142
+ }
143
+ const rawStatus = readTopBlockField(topBlockLines, "VVOC_STATUS");
144
+ if (!rawStatus) {
145
+ return createProtocolError("MISSING_STATUS", "MISSING_STATUS: strict top block must include VVOC_STATUS");
146
+ }
147
+ const statusValidation = validateStatusForAgent(options.agent, rawStatus);
148
+ if (!statusValidation.ok) {
149
+ return statusValidation;
150
+ }
151
+ const route = readTopBlockField(topBlockLines, "VVOC_ROUTE");
152
+ if (options.agent === "vv-implementer" && !route) {
153
+ return createProtocolError("MISSING_ROUTE", "MISSING_ROUTE: vv-implementer output must include VVOC_ROUTE");
154
+ }
155
+ return {
156
+ ok: true,
157
+ value: {
158
+ agent: options.agent,
159
+ workItemId,
160
+ status: statusValidation.value,
161
+ ...(route ? { route } : {}),
162
+ },
163
+ };
164
+ }
165
+ // END_BLOCK_PARSE_RESULT
166
+ // START_CONTRACT: parseWorkItemHeader
167
+ // PURPOSE: Extract VVOC_WORK_ITEM_ID from the first meaningful line of a tracked subagent prompt header.
168
+ // INPUTS: { promptText: string - full prompt text }
169
+ // OUTPUTS: { ProtocolResult<string> - parsed work item ID or protocol error }
170
+ // SIDE_EFFECTS: [none]
171
+ // LINKS: [M-WORKFLOW-PROTOCOL]
172
+ // END_CONTRACT: parseWorkItemHeader
173
+ export function parseWorkItemHeader(promptText) {
174
+ const lines = promptText.replace(/\r\n/g, "\n").split("\n");
175
+ const firstMeaningfulLine = lines.find((line) => line.trim().length > 0)?.trim();
176
+ if (!firstMeaningfulLine) {
177
+ return createProtocolError("MISSING_WORK_ITEM_HEADER", "MISSING_WORK_ITEM_HEADER: prompt must begin with VVOC_WORK_ITEM_ID header");
178
+ }
179
+ const match = WORK_ITEM_HEADER_RE.exec(firstMeaningfulLine);
180
+ if (!match) {
181
+ return createProtocolError("MALFORMED_WORK_ITEM_HEADER", `MALFORMED_WORK_ITEM_HEADER: first meaningful line must match \`VVOC_WORK_ITEM_ID: wi-<n>\` but received \`${firstMeaningfulLine}\``);
182
+ }
183
+ return {
184
+ ok: true,
185
+ value: match[1],
186
+ };
187
+ }
188
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/plugins/workflow/protocol.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,iBAAiB;AACjB,wBAAwB;AACxB,2HAA2H;AAC3H,qKAAqK;AACrK,oBAAoB;AACpB,iCAAiC;AACjC,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,4EAA4E;AAC5E,2DAA2D;AAC3D,qFAAqF;AACrF,sEAAsE;AACtE,uDAAuD;AACvD,kGAAkG;AAClG,6DAA6D;AAC7D,wEAAwE;AACxE,6FAA6F;AAC7F,qFAAqF;AACrF,+FAA+F;AAC/F,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,sHAAsH;AACtH,qIAAqI;AACrI,iJAAiJ;AACjJ,qBAAqB;AAErB,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;CACV,CAAC;AAIX,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,gBAAgB,EAAE,CAAC,MAAM,EAAE,oBAAoB,EAAE,eAAe,EAAE,SAAS,CAAC;IAC5E,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC;IACrD,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC;CAC7C,CAAC;AA4CX,MAAM,mBAAmB,GAAG,oCAAoC,CAAC;AAEjE,SAAS,mBAAmB,CAAC,IAAuB,EAAE,OAAe;IACnE,OAAO;QACL,EAAE,EAAE,KAAK;QACT,KAAK,EAAE;YACL,IAAI;YACJ,OAAO;SACR;KACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,oBAAoB,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/E,IAAI,oBAAoB,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,KAAK,GAAG,oBAAoB,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM;QACR,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CAAC,aAAuB,EAAE,KAAa;IAC/D,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;IAC3D,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACrC,OAAO,KAAK,IAAI,SAAS,CAAC;IAC5B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,qBAAqB,CAAC,aAAuB;IACpD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,mBAAmB,EAAE,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC;IAClF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,mBAAmB,CACxB,2BAA2B,EAC3B,8EAA8E,IAAI,IAAI,CACvF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,mBAAmB,CACxB,2BAA2B,EAC3B,uDAAuD,KAAK,sBAAsB,CACnF,CAAC;QACJ,CAAC;QAED,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,mBAAmB,CACxB,2BAA2B,EAC3B,+DAA+D,KAAK,IAAI,CACzE,CAAC;QACJ,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACnC,CAAC;AAED,yCAAyC;AACzC,6FAA6F;AAC7F,yGAAyG;AACzG,qGAAqG;AACrG,yBAAyB;AACzB,iCAAiC;AACjC,uCAAuC;AACvC,MAAM,UAAU,sBAAsB,CACpC,KAAuB,EACvB,MAAc;IAEd,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAsB,CAAC;IAC7D,MAAM,gBAAgB,GAAgB,IAAI,GAAG,CAC3C,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CACnE,CAAC;IAEF,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,OAAO,mBAAmB,CACxB,gBAAgB,EAChB,mBAAmB,UAAU,IAAI,SAAS,kCAAkC,CAC7E,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,UAAU,CAAC,EAAE,CAAC;QACnD,OAAO,mBAAmB,CACxB,oBAAoB,EACpB,uBAAuB,UAAU,uBAAuB,KAAK,EAAE,CAChE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,UAAwB;KAChC,CAAC;AACJ,CAAC;AAED,mCAAmC;AACnC,2FAA2F;AAC3F,sLAAsL;AACtL,8FAA8F;AAC9F,yBAAyB;AACzB,iCAAiC;AACjC,iCAAiC;AACjC,2BAA2B;AAC3B,MAAM,UAAU,gBAAgB,CAAC,OAIhC;IACC,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAChE,IAAI,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC;QAC3B,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC;IACzE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,mBAAmB,CACxB,sBAAsB,EACtB,uEAAuE,CACxE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,OAAO,mBAAmB,CACxB,sBAAsB,EACtB,qDAAqD,UAAU,EAAE,CAClE,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,KAAK,UAAU,EAAE,CAAC;QAC5E,OAAO,mBAAmB,CACxB,oBAAoB,EACpB,gCAAgC,OAAO,CAAC,kBAAkB,eAAe,UAAU,EAAE,CACtF,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,mBAAmB,CACxB,gBAAgB,EAChB,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAC1E,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC;QACzB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,MAAM,KAAK,GAAG,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAC7D,IAAI,OAAO,CAAC,KAAK,KAAK,gBAAgB,IAAI,CAAC,KAAK,EAAE,CAAC;QACjD,OAAO,mBAAmB,CACxB,eAAe,EACf,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,UAAU;YACV,MAAM,EAAE,gBAAgB,CAAC,KAAK;YAC9B,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5B;KACF,CAAC;AACJ,CAAC;AACD,yBAAyB;AAEzB,sCAAsC;AACtC,2GAA2G;AAC3G,sDAAsD;AACtD,gFAAgF;AAChF,yBAAyB;AACzB,iCAAiC;AACjC,oCAAoC;AACpC,MAAM,UAAU,mBAAmB,CAAC,UAAkB;IACpD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,mBAAmB,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAEjF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,mBAAmB,CACxB,0BAA0B,EAC1B,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,mBAAmB,CACxB,4BAA4B,EAC5B,6GAA6G,mBAAmB,IAAI,CACrI,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,79 @@
1
+ import type { TrackedAgentName } from "./protocol.js";
2
+ export type WorkItemState = "open" | "awaiting_implementer" | "awaiting_spec_review" | "awaiting_code_review" | "needs_context" | "blocked" | "ready_to_close" | "closed";
3
+ export type WorkItemRecord = {
4
+ sessionId: string;
5
+ workItemId: string;
6
+ key: string;
7
+ title: string;
8
+ state: WorkItemState;
9
+ specReviewCount: number;
10
+ codeReviewCount: number;
11
+ createdAt: string;
12
+ updatedAt: string;
13
+ closedAt?: string;
14
+ };
15
+ export type OpenWorkItemResult = {
16
+ ok: true;
17
+ reused: boolean;
18
+ record: WorkItemRecord;
19
+ header: string;
20
+ } | {
21
+ ok: false;
22
+ errorCode: "WORK_ITEM_KEY_CONFLICT";
23
+ message: string;
24
+ existingWorkItemId: string;
25
+ };
26
+ export type CloseWorkItemResult = {
27
+ ok: true;
28
+ record: WorkItemRecord;
29
+ header: string;
30
+ } | {
31
+ ok: false;
32
+ errorCode: "WORK_ITEM_NOT_FOUND" | "WORK_ITEM_ALREADY_CLOSED";
33
+ message: string;
34
+ };
35
+ export type TransitionWorkItemStateResult = {
36
+ ok: true;
37
+ record: WorkItemRecord;
38
+ } | {
39
+ ok: false;
40
+ errorCode: "WORK_ITEM_NOT_FOUND" | "WORK_ITEM_ALREADY_CLOSED" | "INVALID_STATE_TRANSITION" | "MISSING_TRANSITION_ACTOR";
41
+ message: string;
42
+ };
43
+ export type WorkItemStore = {
44
+ openWorkItem: (input: {
45
+ sessionId: string;
46
+ key: string;
47
+ title: string;
48
+ }) => OpenWorkItemResult;
49
+ getWorkItem: (sessionId: string, workItemId: string) => WorkItemRecord | undefined;
50
+ listWorkItems: (sessionId: string, options?: {
51
+ includeClosed?: boolean;
52
+ }) => WorkItemRecord[];
53
+ closeWorkItem: (sessionId: string, workItemId: string) => CloseWorkItemResult;
54
+ transitionWorkItemState: (input: {
55
+ sessionId: string;
56
+ workItemId: string;
57
+ state: WorkItemState;
58
+ actor?: TrackedAgentName;
59
+ }) => TransitionWorkItemStateResult;
60
+ getReviewRound: (record: Pick<WorkItemRecord, "specReviewCount" | "codeReviewCount">) => number;
61
+ };
62
+ export declare function getReviewRound(record: Pick<WorkItemRecord, "specReviewCount" | "codeReviewCount">): number;
63
+ export declare function createWorkItemStore(): WorkItemStore;
64
+ export declare function openWorkItem(store: WorkItemStore, input: {
65
+ sessionId: string;
66
+ key: string;
67
+ title: string;
68
+ }): OpenWorkItemResult;
69
+ export declare function getWorkItem(store: WorkItemStore, sessionId: string, workItemId: string): WorkItemRecord | undefined;
70
+ export declare function listWorkItems(store: WorkItemStore, sessionId: string, options?: {
71
+ includeClosed?: boolean;
72
+ }): WorkItemRecord[];
73
+ export declare function closeWorkItem(store: WorkItemStore, sessionId: string, workItemId: string): CloseWorkItemResult;
74
+ export declare function transitionWorkItemState(store: WorkItemStore, input: {
75
+ sessionId: string;
76
+ workItemId: string;
77
+ state: WorkItemState;
78
+ actor?: TrackedAgentName;
79
+ }): TransitionWorkItemStateResult;
@@ -0,0 +1,307 @@
1
+ // FILE: src/plugins/workflow/state.ts
2
+ // VERSION: 0.1.2
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Manage in-memory workflow work-item state scoped by session with idempotent open semantics.
5
+ // SCOPE: Session-scoped work-item storage, id generation, idempotent open-by-key, state transitions, review counters, and close/list/get operations.
6
+ // DEPENDS: [src/plugins/workflow/protocol.ts]
7
+ // LINKS: [M-WORKFLOW-STATE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // WorkItemState - Allowed lifecycle states for a tracked work item.
14
+ // WorkItemRecord - Canonical in-memory state record for a work item.
15
+ // WorkItemStore - Store interface exposing deterministic workflow state operations.
16
+ // OpenWorkItemResult - Structured open operation result with idempotency and conflict signaling.
17
+ // CloseWorkItemResult - Structured close operation result.
18
+ // TransitionWorkItemStateResult - Structured transition operation result.
19
+ // createWorkItemStore - Creates a new in-memory store instance.
20
+ // openWorkItem - Opens an item idempotently by (sessionId, key).
21
+ // getWorkItem - Fetches an item by session and work-item id.
22
+ // listWorkItems - Lists session items with optional closed inclusion.
23
+ // closeWorkItem - Closes an existing open item.
24
+ // transitionWorkItemState - Applies deterministic state transitions and increments review counters.
25
+ // getReviewRound - Computes review round as max(specReviewCount, codeReviewCount).
26
+ // END_MODULE_MAP
27
+ //
28
+ // START_CHANGE_SUMMARY
29
+ // LAST_CHANGE: [v0.1.2 - Required actor metadata for tracked transitions so reviewer counters cannot be bypassed by actor-less updates.]
30
+ // LAST_CHANGE: [v0.1.1 - Enforced deterministic transition invariants with sticky hard-stop states and optional closed-item listing support.]
31
+ // LAST_CHANGE: [v0.1.0 - Added session-scoped in-memory workflow state store with idempotent open, transitions, close/list/get, and review-round helpers.]
32
+ // END_CHANGE_SUMMARY
33
+ function createRecordLookupKey(sessionId, workItemId) {
34
+ return `${sessionId}::${workItemId}`;
35
+ }
36
+ function cloneRecord(record) {
37
+ return {
38
+ ...record,
39
+ };
40
+ }
41
+ function createHeader(workItemId) {
42
+ return `VVOC_WORK_ITEM_ID: ${workItemId}`;
43
+ }
44
+ function toIsoNow() {
45
+ return new Date().toISOString();
46
+ }
47
+ function openWorkItemInStore(store, input) {
48
+ const sessionIndex = store.keyIndexBySession.get(input.sessionId) ??
49
+ (() => {
50
+ const index = new Map();
51
+ store.keyIndexBySession.set(input.sessionId, index);
52
+ return index;
53
+ })();
54
+ const existingId = sessionIndex.get(input.key);
55
+ if (existingId) {
56
+ const existing = store.records.get(createRecordLookupKey(input.sessionId, existingId));
57
+ if (!existing) {
58
+ sessionIndex.delete(input.key);
59
+ }
60
+ else if (existing.title !== input.title) {
61
+ return {
62
+ ok: false,
63
+ errorCode: "WORK_ITEM_KEY_CONFLICT",
64
+ message: `WORK_ITEM_KEY_CONFLICT: key ${input.key} is already associated with a different title`,
65
+ existingWorkItemId: existing.workItemId,
66
+ };
67
+ }
68
+ else {
69
+ return {
70
+ ok: true,
71
+ reused: true,
72
+ record: cloneRecord(existing),
73
+ header: createHeader(existing.workItemId),
74
+ };
75
+ }
76
+ }
77
+ const workItemId = `wi-${store.nextId}`;
78
+ store.nextId += 1;
79
+ const now = toIsoNow();
80
+ const record = {
81
+ sessionId: input.sessionId,
82
+ workItemId,
83
+ key: input.key,
84
+ title: input.title,
85
+ state: "open",
86
+ specReviewCount: 0,
87
+ codeReviewCount: 0,
88
+ createdAt: now,
89
+ updatedAt: now,
90
+ };
91
+ sessionIndex.set(input.key, workItemId);
92
+ store.records.set(createRecordLookupKey(input.sessionId, workItemId), record);
93
+ return {
94
+ ok: true,
95
+ reused: false,
96
+ record: cloneRecord(record),
97
+ header: createHeader(workItemId),
98
+ };
99
+ }
100
+ function getWorkItemInStore(store, sessionId, workItemId) {
101
+ const record = store.records.get(createRecordLookupKey(sessionId, workItemId));
102
+ return record ? cloneRecord(record) : undefined;
103
+ }
104
+ function isTransitionAllowed(fromState, toState) {
105
+ const allowed = {
106
+ open: ["awaiting_spec_review", "needs_context", "blocked"],
107
+ awaiting_implementer: ["awaiting_spec_review", "needs_context", "blocked"],
108
+ awaiting_spec_review: ["awaiting_code_review", "awaiting_implementer", "needs_context"],
109
+ awaiting_code_review: ["ready_to_close", "awaiting_implementer", "needs_context"],
110
+ ready_to_close: [],
111
+ needs_context: [],
112
+ blocked: [],
113
+ closed: [],
114
+ };
115
+ return allowed[fromState].includes(toState);
116
+ }
117
+ function getAllowedActorForState(state) {
118
+ if (state === "open" || state === "awaiting_implementer") {
119
+ return "vv-implementer";
120
+ }
121
+ if (state === "awaiting_spec_review") {
122
+ return "vv-spec-reviewer";
123
+ }
124
+ if (state === "awaiting_code_review") {
125
+ return "vv-code-reviewer";
126
+ }
127
+ return undefined;
128
+ }
129
+ function listWorkItemsInStore(store, sessionId, options = {}) {
130
+ const includeClosed = options.includeClosed === true;
131
+ return [...store.records.values()]
132
+ .filter((record) => record.sessionId === sessionId && (includeClosed || record.state !== "closed"))
133
+ .sort((left, right) => {
134
+ const leftNumber = Number(left.workItemId.slice("wi-".length));
135
+ const rightNumber = Number(right.workItemId.slice("wi-".length));
136
+ return leftNumber - rightNumber;
137
+ })
138
+ .map((record) => cloneRecord(record));
139
+ }
140
+ function closeWorkItemInStore(store, sessionId, workItemId) {
141
+ const lookupKey = createRecordLookupKey(sessionId, workItemId);
142
+ const existing = store.records.get(lookupKey);
143
+ if (!existing) {
144
+ return {
145
+ ok: false,
146
+ errorCode: "WORK_ITEM_NOT_FOUND",
147
+ message: `WORK_ITEM_NOT_FOUND: no work item ${workItemId} for session ${sessionId}`,
148
+ };
149
+ }
150
+ if (existing.state === "closed") {
151
+ return {
152
+ ok: false,
153
+ errorCode: "WORK_ITEM_ALREADY_CLOSED",
154
+ message: `WORK_ITEM_ALREADY_CLOSED: ${workItemId} is already closed`,
155
+ };
156
+ }
157
+ const now = toIsoNow();
158
+ const updated = {
159
+ ...existing,
160
+ state: "closed",
161
+ closedAt: now,
162
+ updatedAt: now,
163
+ };
164
+ store.records.set(lookupKey, updated);
165
+ return {
166
+ ok: true,
167
+ record: cloneRecord(updated),
168
+ header: createHeader(workItemId),
169
+ };
170
+ }
171
+ function transitionWorkItemStateInStore(store, input) {
172
+ const lookupKey = createRecordLookupKey(input.sessionId, input.workItemId);
173
+ const existing = store.records.get(lookupKey);
174
+ if (!existing) {
175
+ return {
176
+ ok: false,
177
+ errorCode: "WORK_ITEM_NOT_FOUND",
178
+ message: `WORK_ITEM_NOT_FOUND: no work item ${input.workItemId} for session ${input.sessionId}`,
179
+ };
180
+ }
181
+ if (existing.state === "closed") {
182
+ return {
183
+ ok: false,
184
+ errorCode: "WORK_ITEM_ALREADY_CLOSED",
185
+ message: `WORK_ITEM_ALREADY_CLOSED: ${input.workItemId} is already closed`,
186
+ };
187
+ }
188
+ const allowedActor = getAllowedActorForState(existing.state);
189
+ if (allowedActor && !input.actor) {
190
+ return {
191
+ ok: false,
192
+ errorCode: "MISSING_TRANSITION_ACTOR",
193
+ message: `MISSING_TRANSITION_ACTOR: state ${existing.state} requires actor metadata`,
194
+ };
195
+ }
196
+ if (input.actor && allowedActor && input.actor !== allowedActor) {
197
+ return {
198
+ ok: false,
199
+ errorCode: "INVALID_STATE_TRANSITION",
200
+ message: `INVALID_STATE_TRANSITION: actor ${input.actor} is not allowed for state ${existing.state}`,
201
+ };
202
+ }
203
+ if (!isTransitionAllowed(existing.state, input.state)) {
204
+ return {
205
+ ok: false,
206
+ errorCode: "INVALID_STATE_TRANSITION",
207
+ message: `INVALID_STATE_TRANSITION: cannot transition from ${existing.state} to ${input.state}`,
208
+ };
209
+ }
210
+ const updated = {
211
+ ...existing,
212
+ state: input.state,
213
+ updatedAt: toIsoNow(),
214
+ specReviewCount: input.actor === "vv-spec-reviewer" ? existing.specReviewCount + 1 : existing.specReviewCount,
215
+ codeReviewCount: input.actor === "vv-code-reviewer" ? existing.codeReviewCount + 1 : existing.codeReviewCount,
216
+ };
217
+ store.records.set(lookupKey, updated);
218
+ return {
219
+ ok: true,
220
+ record: cloneRecord(updated),
221
+ };
222
+ }
223
+ // START_CONTRACT: getReviewRound
224
+ // PURPOSE: Compute deterministic review round from reviewer counters.
225
+ // INPUTS: { record: Pick<WorkItemRecord, "specReviewCount" | "codeReviewCount"> - review counters }
226
+ // OUTPUTS: { number - max(specReviewCount, codeReviewCount) }
227
+ // SIDE_EFFECTS: [none]
228
+ // LINKS: [M-WORKFLOW-STATE]
229
+ // END_CONTRACT: getReviewRound
230
+ export function getReviewRound(record) {
231
+ return Math.max(record.specReviewCount, record.codeReviewCount);
232
+ }
233
+ // START_CONTRACT: createWorkItemStore
234
+ // PURPOSE: Create a session-scoped in-memory work-item store with deterministic operation behavior.
235
+ // INPUTS: { none }
236
+ // OUTPUTS: { WorkItemStore - operation surface for open/get/list/close/transition operations }
237
+ // SIDE_EFFECTS: [none]
238
+ // LINKS: [M-WORKFLOW-STATE]
239
+ // END_CONTRACT: createWorkItemStore
240
+ export function createWorkItemStore() {
241
+ const data = {
242
+ nextId: 1,
243
+ records: new Map(),
244
+ keyIndexBySession: new Map(),
245
+ };
246
+ return {
247
+ openWorkItem: (input) => openWorkItemInStore(data, input),
248
+ getWorkItem: (sessionId, workItemId) => getWorkItemInStore(data, sessionId, workItemId),
249
+ listWorkItems: (sessionId, options) => listWorkItemsInStore(data, sessionId, options),
250
+ closeWorkItem: (sessionId, workItemId) => closeWorkItemInStore(data, sessionId, workItemId),
251
+ transitionWorkItemState: (input) => transitionWorkItemStateInStore(data, input),
252
+ getReviewRound,
253
+ };
254
+ }
255
+ // START_CONTRACT: openWorkItem
256
+ // PURPOSE: Open a work item idempotently by (sessionId, key) while enforcing key/title consistency.
257
+ // INPUTS: { store: WorkItemStoreData - backing store, input: { sessionId, key, title } - open parameters }
258
+ // OUTPUTS: { OpenWorkItemResult - success with record/header or WORK_ITEM_KEY_CONFLICT }
259
+ // SIDE_EFFECTS: [Mutates in-memory work-item store]
260
+ // LINKS: [M-WORKFLOW-STATE]
261
+ // END_CONTRACT: openWorkItem
262
+ export function openWorkItem(store, input) {
263
+ return store.openWorkItem(input);
264
+ }
265
+ // START_CONTRACT: getWorkItem
266
+ // PURPOSE: Return a work item by session and work-item id.
267
+ // INPUTS: { store: WorkItemStoreData - backing store, sessionId: string - session scope, workItemId: string - work item id }
268
+ // OUTPUTS: { WorkItemRecord | undefined - matching record when present }
269
+ // SIDE_EFFECTS: [none]
270
+ // LINKS: [M-WORKFLOW-STATE]
271
+ // END_CONTRACT: getWorkItem
272
+ export function getWorkItem(store, sessionId, workItemId) {
273
+ return store.getWorkItem(sessionId, workItemId);
274
+ }
275
+ // START_CONTRACT: listWorkItems
276
+ // PURPOSE: List session work items with optional closed-item inclusion.
277
+ // INPUTS: { store: WorkItemStoreData - backing store, sessionId: string - session scope, options?: { includeClosed?: boolean } - list behavior options }
278
+ // OUTPUTS: { WorkItemRecord[] - records sorted by numeric work-item id }
279
+ // SIDE_EFFECTS: [none]
280
+ // LINKS: [M-WORKFLOW-STATE]
281
+ // END_CONTRACT: listWorkItems
282
+ export function listWorkItems(store, sessionId, options) {
283
+ return store.listWorkItems(sessionId, options);
284
+ }
285
+ // START_CONTRACT: closeWorkItem
286
+ // PURPOSE: Close an existing open work item and stamp closedAt.
287
+ // INPUTS: { store: WorkItemStoreData - backing store, sessionId: string - session scope, workItemId: string - target id }
288
+ // OUTPUTS: { CloseWorkItemResult - success with updated record/header or failure code }
289
+ // SIDE_EFFECTS: [Mutates in-memory work-item store]
290
+ // LINKS: [M-WORKFLOW-STATE]
291
+ // END_CONTRACT: closeWorkItem
292
+ export function closeWorkItem(store, sessionId, workItemId) {
293
+ return store.closeWorkItem(sessionId, workItemId);
294
+ }
295
+ // START_CONTRACT: transitionWorkItemState
296
+ // PURPOSE: Update work-item state deterministically and maintain reviewer counters.
297
+ // INPUTS: { store: WorkItemStoreData - backing store, input: { sessionId, workItemId, state, actor? } - transition payload }
298
+ // OUTPUTS: { TransitionWorkItemStateResult - success with updated record or failure code }
299
+ // SIDE_EFFECTS: [Mutates in-memory work-item store]
300
+ // LINKS: [M-WORKFLOW-STATE]
301
+ // END_CONTRACT: transitionWorkItemState
302
+ // START_BLOCK_TRANSITION_STATE
303
+ export function transitionWorkItemState(store, input) {
304
+ return store.transitionWorkItemState(input);
305
+ }
306
+ // END_BLOCK_TRANSITION_STATE
307
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/plugins/workflow/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ <workflow_protocol>
2
+ Workflow tracking is active for vv-managed review loops.
3
+
4
+ For tracked subagents (`vv-implementer`, `vv-spec-reviewer`, `vv-code-reviewer`):
5
+
6
+ 1. Open work items first with `work_item_open`.
7
+ 2. Reuse the returned `VVOC_WORK_ITEM_ID`.
8
+ 3. Put that header as the first line in tracked subagent prompts.
9
+ 4. Treat `NEEDS_CONTEXT` as a hard stop.
10
+ 5. Use `work_item_list` to inspect workflow state before retrying.
11
+ 6. Avoid free-form review loops without explicit work-item identity.
12
+
13
+ Use `work_item_close` explicitly when a work item is complete.
14
+ </workflow_protocol>
@@ -0,0 +1,26 @@
1
+ import { type WorkItemStore } from "./state.js";
2
+ export type WorkflowToolContext = {
3
+ sessionId: string;
4
+ };
5
+ export type WorkflowToolDefinition<TArgs, TResult> = {
6
+ name: string;
7
+ description: string;
8
+ execute: (args: TArgs, context: WorkflowToolContext) => TResult;
9
+ };
10
+ type OpenInputItem = {
11
+ key: string;
12
+ title: string;
13
+ };
14
+ type OpenArgs = {
15
+ items: OpenInputItem[];
16
+ };
17
+ type ListArgs = {
18
+ includeClosed?: boolean;
19
+ };
20
+ type CloseArgs = {
21
+ workItemId: string;
22
+ };
23
+ export declare function createWorkItemOpenTool(store: WorkItemStore): WorkflowToolDefinition<OpenArgs, Record<string, unknown>>;
24
+ export declare function createWorkItemListTool(store: WorkItemStore): WorkflowToolDefinition<ListArgs, Record<string, unknown>>;
25
+ export declare function createWorkItemCloseTool(store: WorkItemStore): WorkflowToolDefinition<CloseArgs, Record<string, unknown>>;
26
+ export {};