@osovv/vv-opencode 0.21.0 → 0.24.0

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 +45 -9
  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,161 @@
1
+ // FILE: src/plugins/workflow/tooling.ts
2
+ // VERSION: 0.1.1
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.
6
+ // DEPENDS: [src/plugins/workflow/state.ts]
7
+ // LINKS: [M-WORKFLOW-TOOLING]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // WorkflowToolContext - Minimal execution context required by workflow tools.
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.
18
+ // END_MODULE_MAP
19
+ //
20
+ // START_CHANGE_SUMMARY
21
+ // LAST_CHANGE: [v0.1.1 - Wired work_item_list includeClosed flag into state listing options.]
22
+ // LAST_CHANGE: [v0.1.0 - Added workflow core tooling handlers for open/list/close operations with structured results and VVOC headers.]
23
+ // END_CHANGE_SUMMARY
24
+ import { closeWorkItem, getReviewRound, listWorkItems, openWorkItem, } from "./state.js";
25
+ function coerceNonEmptyString(value) {
26
+ if (typeof value !== "string")
27
+ return undefined;
28
+ const trimmed = value.trim();
29
+ return trimmed || undefined;
30
+ }
31
+ // START_CONTRACT: createWorkItemOpenTool
32
+ // PURPOSE: Build work_item_open handler that supports deterministic batch idempotent open operations.
33
+ // INPUTS: { store: WorkItemStore - workflow in-memory store }
34
+ // OUTPUTS: { WorkflowToolDefinition<OpenArgs, unknown> - executable tool definition }
35
+ // SIDE_EFFECTS: [Mutates in-memory work-item store through open operations]
36
+ // LINKS: [M-WORKFLOW-TOOLING, M-WORKFLOW-STATE]
37
+ // END_CONTRACT: createWorkItemOpenTool
38
+ export function createWorkItemOpenTool(store) {
39
+ return {
40
+ name: "work_item_open",
41
+ description: "Open one or more workflow work items idempotently.",
42
+ execute: (args, context) => {
43
+ const inputItems = Array.isArray(args.items) ? args.items : [];
44
+ const results = inputItems.map((item) => {
45
+ const key = coerceNonEmptyString(item.key);
46
+ const title = coerceNonEmptyString(item.title);
47
+ if (!key || !title) {
48
+ return {
49
+ ok: false,
50
+ errorCode: "INVALID_INPUT",
51
+ message: "INVALID_INPUT: key and title must be non-empty strings",
52
+ };
53
+ }
54
+ const opened = openWorkItem(store, {
55
+ sessionId: context.sessionId,
56
+ key,
57
+ title,
58
+ });
59
+ if (!opened.ok) {
60
+ return {
61
+ ok: false,
62
+ errorCode: opened.errorCode,
63
+ message: opened.message,
64
+ existingWorkItemId: opened.existingWorkItemId,
65
+ };
66
+ }
67
+ return {
68
+ ok: true,
69
+ reused: opened.reused,
70
+ workItemId: opened.record.workItemId,
71
+ header: opened.header,
72
+ state: opened.record.state,
73
+ };
74
+ });
75
+ return {
76
+ tool: "work_item_open",
77
+ sessionId: context.sessionId,
78
+ items: results,
79
+ };
80
+ },
81
+ };
82
+ }
83
+ // START_CONTRACT: createWorkItemListTool
84
+ // PURPOSE: Build work_item_list handler that returns current work items and review metadata.
85
+ // INPUTS: { store: WorkItemStore - workflow in-memory store }
86
+ // OUTPUTS: { WorkflowToolDefinition<ListArgs, unknown> - executable tool definition }
87
+ // SIDE_EFFECTS: [none]
88
+ // LINKS: [M-WORKFLOW-TOOLING, M-WORKFLOW-STATE]
89
+ // END_CONTRACT: createWorkItemListTool
90
+ export function createWorkItemListTool(store) {
91
+ return {
92
+ name: "work_item_list",
93
+ description: "List workflow work items for the current session.",
94
+ execute: (args, context) => {
95
+ const includeClosed = args.includeClosed === true;
96
+ const records = listWorkItems(store, context.sessionId, { includeClosed });
97
+ return {
98
+ tool: "work_item_list",
99
+ sessionId: context.sessionId,
100
+ includeClosed,
101
+ items: records.map((record) => ({
102
+ workItemId: record.workItemId,
103
+ header: `VVOC_WORK_ITEM_ID: ${record.workItemId}`,
104
+ key: record.key,
105
+ title: record.title,
106
+ state: record.state,
107
+ specReviewCount: record.specReviewCount,
108
+ codeReviewCount: record.codeReviewCount,
109
+ reviewRound: getReviewRound(record),
110
+ createdAt: record.createdAt,
111
+ updatedAt: record.updatedAt,
112
+ })),
113
+ };
114
+ },
115
+ };
116
+ }
117
+ // START_CONTRACT: createWorkItemCloseTool
118
+ // PURPOSE: Build work_item_close handler that closes an existing work item.
119
+ // INPUTS: { store: WorkItemStore - workflow in-memory store }
120
+ // OUTPUTS: { WorkflowToolDefinition<CloseArgs, unknown> - executable tool definition }
121
+ // SIDE_EFFECTS: [Mutates in-memory work-item store through close operations]
122
+ // LINKS: [M-WORKFLOW-TOOLING, M-WORKFLOW-STATE]
123
+ // END_CONTRACT: createWorkItemCloseTool
124
+ export function createWorkItemCloseTool(store) {
125
+ return {
126
+ name: "work_item_close",
127
+ description: "Close a workflow work item by id.",
128
+ execute: (args, context) => {
129
+ const workItemId = coerceNonEmptyString(args.workItemId);
130
+ if (!workItemId) {
131
+ return {
132
+ tool: "work_item_close",
133
+ sessionId: context.sessionId,
134
+ ok: false,
135
+ errorCode: "INVALID_INPUT",
136
+ message: "INVALID_INPUT: workItemId must be a non-empty string",
137
+ };
138
+ }
139
+ const closed = closeWorkItem(store, context.sessionId, workItemId);
140
+ if (!closed.ok) {
141
+ return {
142
+ tool: "work_item_close",
143
+ sessionId: context.sessionId,
144
+ ok: false,
145
+ errorCode: closed.errorCode,
146
+ message: closed.message,
147
+ };
148
+ }
149
+ return {
150
+ tool: "work_item_close",
151
+ sessionId: context.sessionId,
152
+ ok: true,
153
+ workItemId: closed.record.workItemId,
154
+ header: closed.header,
155
+ state: closed.record.state,
156
+ closedAt: closed.record.closedAt,
157
+ };
158
+ },
159
+ };
160
+ }
161
+ //# sourceMappingURL=tooling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooling.js","sourceRoot":"","sources":["../../../src/plugins/workflow/tooling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ParsedResultBlock, TrackedAgentName } from "./protocol.js";
2
+ import type { WorkItemState } from "./state.js";
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;
7
+ export declare function shouldBlockRound(reviewRound: number): boolean;
@@ -0,0 +1,102 @@
1
+ // FILE: src/plugins/workflow/transitions.ts
2
+ // VERSION: 0.1.0
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.
6
+ // DEPENDS: [src/plugins/workflow/protocol.ts, src/plugins/workflow/state.ts]
7
+ // LINKS: [M-WORKFLOW-TRANSITIONS]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
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.
18
+ // END_MODULE_MAP
19
+ //
20
+ // START_CHANGE_SUMMARY
21
+ // LAST_CHANGE: [v0.1.0 - Added deterministic state transition policy, launch-allowance resolution, and review round-gate checks.]
22
+ // END_CHANGE_SUMMARY
23
+ export const MAX_REVIEW_ROUNDS = 2;
24
+ // START_CONTRACT: getAllowedNextAgent
25
+ // PURPOSE: Resolve the single tracked agent allowed to run from the current state.
26
+ // INPUTS: { state: WorkItemState - current work-item lifecycle state }
27
+ // OUTPUTS: { TrackedAgentName | null - allowed tracked agent or null when no launch is allowed }
28
+ // SIDE_EFFECTS: [none]
29
+ // LINKS: [M-WORKFLOW-TRANSITIONS]
30
+ // END_CONTRACT: getAllowedNextAgent
31
+ export function getAllowedNextAgent(state) {
32
+ if (state === "open" || state === "awaiting_implementer") {
33
+ return "vv-implementer";
34
+ }
35
+ if (state === "awaiting_spec_review") {
36
+ return "vv-spec-reviewer";
37
+ }
38
+ if (state === "awaiting_code_review") {
39
+ return "vv-code-reviewer";
40
+ }
41
+ return null;
42
+ }
43
+ // START_CONTRACT: isAllowedTransition
44
+ // PURPOSE: Check whether launching the requested tracked agent is valid for current state.
45
+ // INPUTS: { state: WorkItemState - current state, agent: TrackedAgentName - requested tracked subagent }
46
+ // OUTPUTS: { boolean - true when launch is allowed }
47
+ // SIDE_EFFECTS: [none]
48
+ // LINKS: [M-WORKFLOW-TRANSITIONS]
49
+ // END_CONTRACT: isAllowedTransition
50
+ export function isAllowedTransition(state, agent) {
51
+ return getAllowedNextAgent(state) === agent;
52
+ }
53
+ // START_CONTRACT: getNextState
54
+ // PURPOSE: Compute deterministic next work-item state from a tracked subagent result.
55
+ // INPUTS: { currentState: WorkItemState - current lifecycle state, result: ParsedResultBlock - validated tracked result block }
56
+ // OUTPUTS: { WorkItemState - next lifecycle state }
57
+ // SIDE_EFFECTS: [none]
58
+ // LINKS: [M-WORKFLOW-TRANSITIONS]
59
+ // END_CONTRACT: getNextState
60
+ export function getNextState(currentState, result) {
61
+ if (result.agent === "vv-implementer") {
62
+ if (result.status === "DONE" || result.status === "DONE_WITH_CONCERNS") {
63
+ return "awaiting_spec_review";
64
+ }
65
+ if (result.status === "NEEDS_CONTEXT") {
66
+ return "needs_context";
67
+ }
68
+ return "blocked";
69
+ }
70
+ if (result.agent === "vv-spec-reviewer") {
71
+ if (result.status === "PASS") {
72
+ return "awaiting_code_review";
73
+ }
74
+ if (result.status === "FAIL") {
75
+ return "awaiting_implementer";
76
+ }
77
+ return "needs_context";
78
+ }
79
+ if (result.agent === "vv-code-reviewer") {
80
+ if (result.status === "PASS") {
81
+ return "ready_to_close";
82
+ }
83
+ if (result.status === "FAIL") {
84
+ return "awaiting_implementer";
85
+ }
86
+ return "needs_context";
87
+ }
88
+ return currentState;
89
+ }
90
+ // START_CONTRACT: shouldBlockRound
91
+ // PURPOSE: Enforce loop-gate policy by rejecting rounds above MAX_REVIEW_ROUNDS.
92
+ // INPUTS: { reviewRound: number - computed review round }
93
+ // OUTPUTS: { boolean - true when launch must be blocked }
94
+ // SIDE_EFFECTS: [none]
95
+ // LINKS: [M-WORKFLOW-TRANSITIONS]
96
+ // END_CONTRACT: shouldBlockRound
97
+ // START_BLOCK_CHECK_ROUND_LIMIT
98
+ export function shouldBlockRound(reviewRound) {
99
+ return reviewRound > MAX_REVIEW_ROUNDS;
100
+ }
101
+ // END_BLOCK_CHECK_ROUND_LIMIT
102
+ //# sourceMappingURL=transitions.js.map
@@ -0,0 +1 @@
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.21.0",
3
+ "version": "0.24.0",
4
4
  "description": "Portable OpenCode workflow plugins, explicit memory, and CLI tooling.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,6 +38,10 @@
38
38
  "types": "./dist/plugins/guardian/index.d.ts",
39
39
  "import": "./dist/plugins/guardian/index.js"
40
40
  },
41
+ "./plugins/hashline-edit": {
42
+ "types": "./dist/plugins/hashline-edit/index.d.ts",
43
+ "import": "./dist/plugins/hashline-edit/index.js"
44
+ },
41
45
  "./plugins/memory": {
42
46
  "types": "./dist/plugins/memory/index.d.ts",
43
47
  "import": "./dist/plugins/memory/index.js"
@@ -50,20 +54,24 @@
50
54
  "types": "./dist/plugins/system-context-injection/index.d.ts",
51
55
  "import": "./dist/plugins/system-context-injection/index.js"
52
56
  },
57
+ "./plugins/workflow": {
58
+ "types": "./dist/plugins/workflow/index.d.ts",
59
+ "import": "./dist/plugins/workflow/index.js"
60
+ },
53
61
  "./plugins/secrets-redaction": {
54
62
  "types": "./dist/plugins/secrets-redaction/index.d.ts",
55
63
  "import": "./dist/plugins/secrets-redaction/index.js"
56
64
  }
57
65
  },
58
66
  "scripts": {
59
- "build": "rm -rf dist && tsc -p tsconfig.build.json && mkdir -p dist/plugins/memory && cp src/plugins/memory/system-instruction.md dist/plugins/memory/system-instruction.md",
67
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && mkdir -p dist/plugins/memory dist/plugins/workflow && cp src/plugins/memory/system-instruction.md dist/plugins/memory/system-instruction.md && cp src/plugins/workflow/system-instruction.md dist/plugins/workflow/system-instruction.md",
60
68
  "typecheck": "tsc --noEmit -p tsconfig.json",
61
69
  "lint": "oxlint --deny warnings src",
62
70
  "fmt": "oxfmt --write src",
63
71
  "fmt:check": "oxfmt --check src",
64
72
  "test": "bun test",
65
73
  "check": "bun run typecheck && bun run lint && bun run fmt:check && bun test",
66
- "pack:check": "bun run build && bun -e \"const root = await import('./dist/index.js'); if (!('GuardianPlugin' in root)) throw new Error('dist root export missing GuardianPlugin'); if (!('MemoryPlugin' in root)) throw new Error('dist root export missing MemoryPlugin'); if (!('ModelRolesPlugin' in root)) throw new Error('dist root export missing ModelRolesPlugin'); if (!('SystemContextInjectionPlugin' in root)) throw new Error('dist root export missing SystemContextInjectionPlugin'); if (!('SecretsRedactionPlugin' in root)) throw new Error('dist root export missing SecretsRedactionPlugin'); await import('./dist/plugins/guardian/index.js'); await import('./dist/plugins/memory/index.js'); await import('./dist/plugins/model-roles/index.js'); await import('./dist/plugins/system-context-injection/index.js')\" && npm pack --dry-run",
74
+ "pack:check": "bun run build && bun -e \"const root = await import('./dist/index.js'); if (!('GuardianPlugin' in root)) throw new Error('dist root export missing GuardianPlugin'); if (!('HashlineEditPlugin' in root)) throw new Error('dist root export missing HashlineEditPlugin'); if (!('MemoryPlugin' in root)) throw new Error('dist root export missing MemoryPlugin'); if (!('ModelRolesPlugin' in root)) throw new Error('dist root export missing ModelRolesPlugin'); if (!('SystemContextInjectionPlugin' in root)) throw new Error('dist root export missing SystemContextInjectionPlugin'); if (!('WorkflowPlugin' in root)) throw new Error('dist root export missing WorkflowPlugin'); if (!('SecretsRedactionPlugin' in root)) throw new Error('dist root export missing SecretsRedactionPlugin'); await import('./dist/plugins/guardian/index.js'); await import('./dist/plugins/hashline-edit/index.js'); await import('./dist/plugins/memory/index.js'); await import('./dist/plugins/model-roles/index.js'); await import('./dist/plugins/system-context-injection/index.js'); await import('./dist/plugins/workflow/index.js')\" && npm pack --dry-run",
67
75
  "prepare": "lefthook install --force"
68
76
  },
69
77
  "dependencies": {
@@ -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.21.0/schemas/vvoc/v1.json",
3
+ "$id": "https://cdn.jsdelivr.net/npm/@osovv/vv-opencode@0.24.0/schemas/vvoc/v1.json",
4
4
  "title": "vvoc config",
5
5
  "description": "Canonical vvoc configuration document.",
6
6
  "type": "object",
@@ -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.21.0/schemas/vvoc/v2.json",
3
+ "$id": "https://cdn.jsdelivr.net/npm/@osovv/vv-opencode@0.24.0/schemas/vvoc/v2.json",
4
4
  "title": "vvoc config",
5
5
  "description": "Canonical vvoc configuration document.",
6
6
  "type": "object",
@@ -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.21.0/schemas/vvoc/v3.json",
3
+ "$id": "https://cdn.jsdelivr.net/npm/@osovv/vv-opencode@0.24.0/schemas/vvoc/v3.json",
4
4
  "title": "vvoc config",
5
5
  "description": "Canonical vvoc configuration document.",
6
6
  "type": "object",
@@ -5,7 +5,7 @@ permission:
5
5
  edit: deny
6
6
  ---
7
7
 
8
- You are the code-reviewer subagent.
8
+ You are the vv-code-reviewer subagent.
9
9
 
10
10
  Review the actual code with a practical senior-engineering mindset.
11
11
  Do not make code changes.
@@ -37,13 +37,21 @@ Rules:
37
37
  - If a concern lacks a concrete failure mode, keep it under residual risks instead of calling it a finding.
38
38
  - If no issues are found, say `No findings` explicitly and mention any residual risk or testing gap.
39
39
 
40
- Output format:
40
+ Final response protocol:
41
+
42
+ - Start with this top block in this exact key order:
43
+ - `VVOC_WORK_ITEM_ID: wi-1`
44
+ - `VVOC_STATUS: PASS`
45
+ - Replace values as needed using only allowed values.
46
+ - `Status: PASS | FAIL | NEEDS_CONTEXT`
47
+ - Allowed statuses: `PASS | FAIL | NEEDS_CONTEXT`
48
+
49
+ Output format after the top block:
41
50
 
42
- - Status: PASS | FAIL
43
51
  - Critical
44
52
  - Important
45
53
  - Minor
46
54
  - Residual risks / testing gaps
47
55
  - Brief assessment
48
56
 
49
- If no issues are found, say `Status: PASS` and use `- none` under Critical, Important, and Minor.
57
+ If no issues are found, keep `VVOC_STATUS: PASS` and use `- none` under Critical, Important, and Minor.
@@ -3,7 +3,7 @@ description: Implements approved changes with focused verification and a minimal
3
3
  mode: subagent
4
4
  ---
5
5
 
6
- You are the implementer subagent.
6
+ You are the vv-implementer subagent.
7
7
 
8
8
  Your job is to execute the assigned task exactly, with the smallest correct change and fresh verification evidence.
9
9
 
@@ -58,14 +58,20 @@ Before reporting back, self-review your work:
58
58
 
59
59
  If you find issues during self-review, fix them before reporting.
60
60
 
61
- Report format:
61
+ Final response protocol:
62
62
 
63
- - Status: DONE | DONE_WITH_CONCERNS | NEEDS_CONTEXT | BLOCKED
64
- - Route: current route and any reroute that occurred
65
- - Changed: what you implemented
66
- - Verified: exact commands run and what they proved
67
- - Assumptions: material assumptions that affected implementation, or `none`
68
- - Concerns: remaining risks, doubts, or missing context
63
+ - Start with this top block in this exact key order:
64
+ - `VVOC_WORK_ITEM_ID: wi-1`
65
+ - `VVOC_STATUS: DONE`
66
+ - `VVOC_ROUTE: change_with_review`
67
+ - Replace values as needed using only allowed values.
68
+ - `Status: DONE | DONE_WITH_CONCERNS | NEEDS_CONTEXT | BLOCKED`
69
+ - Allowed statuses: `DONE | DONE_WITH_CONCERNS | NEEDS_CONTEXT | BLOCKED`
70
+ - Then provide:
71
+ - `Changed: ...`
72
+ - `Verified: ...`
73
+ - `Assumptions: ...`
74
+ - `Concerns: ...`
69
75
 
70
76
  Use DONE_WITH_CONCERNS when the task is complete but you still have a material concern.
71
77
  Use NEEDS_CONTEXT when safe completion depends on information that was not provided.
@@ -5,7 +5,7 @@ permission:
5
5
  edit: deny
6
6
  ---
7
7
 
8
- You are the spec-reviewer subagent.
8
+ You are the vv-spec-reviewer subagent.
9
9
 
10
10
  Your job is to verify whether the implementation matches the requested behavior. Nothing more, nothing less.
11
11
  Do not make code changes.
@@ -42,13 +42,21 @@ Method:
42
42
  - Do not fail purely for route or process choices unless they caused a concrete spec mismatch.
43
43
  - If the request is too incomplete to score safely, return `NEEDS_CONTEXT` instead of guessing.
44
44
 
45
- Output:
45
+ Final response protocol:
46
46
 
47
- - Use this exact structure:
47
+ - Start with this top block in this exact key order:
48
+ - `VVOC_WORK_ITEM_ID: wi-1`
49
+ - `VVOC_STATUS: PASS`
50
+ - Replace values as needed using only allowed values.
48
51
  - `Status: PASS | FAIL | NEEDS_CONTEXT`
52
+ - Allowed statuses: `PASS | FAIL | NEEDS_CONTEXT`
53
+
54
+ Output:
55
+
56
+ - Use this exact structure after the top block:
49
57
  - `Findings:`
50
58
  - `- [Missing|Extra|Wrong|Unproven] path:line - explanation`
51
59
  - `Residual uncertainty:`
52
- - If compliant, say `Status: PASS` explicitly and set `Findings:` to `- none`.
60
+ - If compliant, set `Findings:` to `- none`.
53
61
  - If not compliant, list findings first with file references and label each one as Missing, Extra, Wrong, or Unproven.
54
- - If the request itself is unstable or incomplete, use `Status: NEEDS_CONTEXT` and explain what prevents a safe pass/fail judgment.
62
+ - If the request itself is unstable or incomplete, use `VVOC_STATUS: NEEDS_CONTEXT` and explain what prevents a safe pass/fail judgment.