@osovv/vv-opencode 1.4.5 → 1.6.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 (143) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +47 -16
  3. package/dist/commands/patch-provider.d.ts +5 -5
  4. package/dist/commands/patch-provider.js +10 -6
  5. package/dist/commands/patch-provider.js.map +1 -1
  6. package/dist/lib/agent-tool-catalog.d.ts +144 -0
  7. package/dist/lib/agent-tool-catalog.js +2551 -0
  8. package/dist/lib/agent-tool-catalog.js.map +1 -0
  9. package/dist/lib/agent-tool-contract.d.ts +200 -0
  10. package/dist/lib/agent-tool-contract.js +407 -0
  11. package/dist/lib/agent-tool-contract.js.map +1 -0
  12. package/dist/lib/opencode/agent-registrations.d.ts +33 -0
  13. package/dist/lib/opencode/agent-registrations.js +469 -0
  14. package/dist/lib/opencode/agent-registrations.js.map +1 -0
  15. package/dist/lib/opencode/inspection.d.ts +84 -0
  16. package/dist/lib/opencode/inspection.js +367 -0
  17. package/dist/lib/opencode/inspection.js.map +1 -0
  18. package/dist/lib/opencode/model-overrides.d.ts +19 -0
  19. package/dist/lib/opencode/model-overrides.js +221 -0
  20. package/dist/lib/opencode/model-overrides.js.map +1 -0
  21. package/dist/lib/opencode/paths.d.ts +21 -0
  22. package/dist/lib/opencode/paths.js +62 -0
  23. package/dist/lib/opencode/paths.js.map +1 -0
  24. package/dist/lib/opencode/plugin-registration.d.ts +17 -0
  25. package/dist/lib/opencode/plugin-registration.js +210 -0
  26. package/dist/lib/opencode/plugin-registration.js.map +1 -0
  27. package/dist/lib/opencode/shared-utils.d.ts +30 -0
  28. package/dist/lib/opencode/shared-utils.js +183 -0
  29. package/dist/lib/opencode/shared-utils.js.map +1 -0
  30. package/dist/lib/opencode/vvoc-config-io.d.ts +9 -0
  31. package/dist/lib/opencode/vvoc-config-io.js +58 -0
  32. package/dist/lib/opencode/vvoc-config-io.js.map +1 -0
  33. package/dist/lib/opencode.d.ts +15 -174
  34. package/dist/lib/opencode.js +19 -1387
  35. package/dist/lib/opencode.js.map +1 -1
  36. package/dist/lib/spec-lint/cross-file-rules.d.ts +2 -0
  37. package/dist/lib/spec-lint/cross-file-rules.js +33 -0
  38. package/dist/lib/spec-lint/cross-file-rules.js.map +1 -0
  39. package/dist/lib/spec-lint/delegated-extraction.d.ts +8 -0
  40. package/dist/lib/spec-lint/delegated-extraction.js +112 -0
  41. package/dist/lib/spec-lint/delegated-extraction.js.map +1 -0
  42. package/dist/lib/spec-lint/lint.d.ts +7 -0
  43. package/dist/lib/spec-lint/lint.js +92 -0
  44. package/dist/lib/spec-lint/lint.js.map +1 -0
  45. package/dist/lib/spec-lint/parser.d.ts +101 -0
  46. package/dist/lib/spec-lint/parser.js +482 -0
  47. package/dist/lib/spec-lint/parser.js.map +1 -0
  48. package/dist/lib/spec-lint/plan-rules.d.ts +38 -0
  49. package/dist/lib/spec-lint/plan-rules.js +745 -0
  50. package/dist/lib/spec-lint/plan-rules.js.map +1 -0
  51. package/dist/lib/spec-lint/spec-rules.d.ts +8 -0
  52. package/dist/lib/spec-lint/spec-rules.js +188 -0
  53. package/dist/lib/spec-lint/spec-rules.js.map +1 -0
  54. package/dist/lib/spec-lint.d.ts +4 -63
  55. package/dist/lib/spec-lint.js +13 -1505
  56. package/dist/lib/spec-lint.js.map +1 -1
  57. package/dist/lib/vvoc-preset-registry.d.ts +7 -7
  58. package/dist/lib/vvoc-preset-registry.js +8 -8
  59. package/dist/lib/vvoc-preset-registry.js.map +1 -1
  60. package/dist/lib/workflow-contract.d.ts +12 -0
  61. package/dist/lib/workflow-contract.js +71 -18
  62. package/dist/lib/workflow-contract.js.map +1 -1
  63. package/dist/plugins/hashline-edit/index.js +102 -97
  64. package/dist/plugins/hashline-edit/index.js.map +1 -1
  65. package/dist/plugins/hashline-edit/normalize-edits.d.ts +2 -8
  66. package/dist/plugins/hashline-edit/normalize-edits.js +32 -17
  67. package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -1
  68. package/dist/plugins/hashline-edit/schemas.d.ts +246 -0
  69. package/dist/plugins/hashline-edit/schemas.js +659 -0
  70. package/dist/plugins/hashline-edit/schemas.js.map +1 -0
  71. package/dist/plugins/hashline-edit/str-replace-editor.d.ts +6 -17
  72. package/dist/plugins/hashline-edit/str-replace-editor.js +19 -21
  73. package/dist/plugins/hashline-edit/str-replace-editor.js.map +1 -1
  74. package/dist/plugins/hashline-edit/tool-description.d.ts +1 -0
  75. package/dist/plugins/hashline-edit/tool-description.js +20 -4
  76. package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
  77. package/dist/plugins/web-tools/fetch-service.d.ts +8 -5
  78. package/dist/plugins/web-tools/fetch-service.js +30 -45
  79. package/dist/plugins/web-tools/fetch-service.js.map +1 -1
  80. package/dist/plugins/web-tools/index.js +23 -5
  81. package/dist/plugins/web-tools/index.js.map +1 -1
  82. package/dist/plugins/web-tools/schemas.d.ts +469 -0
  83. package/dist/plugins/web-tools/schemas.js +523 -0
  84. package/dist/plugins/web-tools/schemas.js.map +1 -0
  85. package/dist/plugins/web-tools/search-service.d.ts +6 -3
  86. package/dist/plugins/web-tools/search-service.js +24 -29
  87. package/dist/plugins/web-tools/search-service.js.map +1 -1
  88. package/dist/plugins/workflow/authority.d.ts +6 -0
  89. package/dist/plugins/workflow/authority.js +45 -10
  90. package/dist/plugins/workflow/authority.js.map +1 -1
  91. package/dist/plugins/workflow/authorization.d.ts +30 -0
  92. package/dist/plugins/workflow/authorization.js +147 -0
  93. package/dist/plugins/workflow/authorization.js.map +1 -0
  94. package/dist/plugins/workflow/checkpoints.d.ts +41 -2
  95. package/dist/plugins/workflow/checkpoints.js +176 -47
  96. package/dist/plugins/workflow/checkpoints.js.map +1 -1
  97. package/dist/plugins/workflow/delegated.d.ts +15 -1
  98. package/dist/plugins/workflow/delegated.js +65 -35
  99. package/dist/plugins/workflow/delegated.js.map +1 -1
  100. package/dist/plugins/workflow/execution.d.ts +15 -30
  101. package/dist/plugins/workflow/execution.js +133 -33
  102. package/dist/plugins/workflow/execution.js.map +1 -1
  103. package/dist/plugins/workflow/index.js +197 -435
  104. package/dist/plugins/workflow/index.js.map +1 -1
  105. package/dist/plugins/workflow/input-validation.d.ts +48 -0
  106. package/dist/plugins/workflow/input-validation.js +536 -0
  107. package/dist/plugins/workflow/input-validation.js.map +1 -0
  108. package/dist/plugins/workflow/inspection.d.ts +60 -0
  109. package/dist/plugins/workflow/inspection.js +316 -0
  110. package/dist/plugins/workflow/inspection.js.map +1 -0
  111. package/dist/plugins/workflow/protocol.d.ts +2 -0
  112. package/dist/plugins/workflow/protocol.js +26 -4
  113. package/dist/plugins/workflow/protocol.js.map +1 -1
  114. package/dist/plugins/workflow/recovery.d.ts +18 -0
  115. package/dist/plugins/workflow/recovery.js +217 -0
  116. package/dist/plugins/workflow/recovery.js.map +1 -0
  117. package/dist/plugins/workflow/repair.d.ts +1 -1
  118. package/dist/plugins/workflow/repair.js +9 -10
  119. package/dist/plugins/workflow/repair.js.map +1 -1
  120. package/dist/plugins/workflow/results.d.ts +2566 -0
  121. package/dist/plugins/workflow/results.js +1111 -0
  122. package/dist/plugins/workflow/results.js.map +1 -0
  123. package/dist/plugins/workflow/schemas.d.ts +398 -0
  124. package/dist/plugins/workflow/schemas.js +399 -0
  125. package/dist/plugins/workflow/schemas.js.map +1 -0
  126. package/dist/plugins/workflow/state.d.ts +3 -2
  127. package/dist/plugins/workflow/state.js +15 -8
  128. package/dist/plugins/workflow/state.js.map +1 -1
  129. package/dist/plugins/workflow/system-instruction.md +17 -1
  130. package/dist/plugins/workflow/tooling.d.ts +11 -82
  131. package/dist/plugins/workflow/tooling.js +478 -461
  132. package/dist/plugins/workflow/tooling.js.map +1 -1
  133. package/dist/plugins/workflow/transactions.d.ts +13 -0
  134. package/dist/plugins/workflow/transactions.js +13 -3
  135. package/dist/plugins/workflow/transactions.js.map +1 -1
  136. package/package.json +6 -3
  137. package/schemas/vvoc/v3.json +1 -1
  138. package/templates/agents/vv-code-reviewer.md +13 -4
  139. package/templates/agents/vv-implementer.md +16 -9
  140. package/templates/agents/vv-spec-reviewer.md +13 -4
  141. package/templates/skills/vv-execute/SKILL.md +3 -3
  142. package/templates/skills/vv-execute/references/tool-contracts.md +1750 -0
  143. package/templates/skills/vv-review/SKILL.md +1 -1
@@ -0,0 +1,1750 @@
1
+ # vvoc agent tool contracts
2
+
3
+ Generated from the pure tool catalog. Do not edit by hand; run `bun run contracts:generate`.
4
+
5
+ - Package: `@osovv/vv-opencode@1.6.0`
6
+ - Tool contract revision: `1`
7
+ - Reference path: `templates/skills/vv-execute/references/tool-contracts.md`
8
+ - Current model-facing size: descriptions 8794 bytes, published input schemas 22572 bytes
9
+ - Baseline (commit f4319f8, SDK @opencode-ai/plugin@1.18.2, source-extraction): descriptions 8796 bytes, projected input schemas 6815 bytes
10
+
11
+ > Schema acceptance is structural only. It is not authorization, not proof of evidence,
12
+ > not reviewer acceptance, and not permission for a workflow transition. A declared
13
+ > `writeScope` is an edit boundary, not a universal sandbox, and no tool here grants a
14
+ > state transition on its own.
15
+
16
+ ## Reading guide
17
+
18
+ This is an on-demand reference; load only the tool section you need rather than the whole manual. Each tool section lists a closed field table, closed vocabularies, execute-time defaults, state/host prerequisites, conditional requirements, declared path kinds, result families, representative failures, and checked accept/reject examples. Tool sections: `work_item_open`, `work_item_list`, `work_item_close`, `work_item_decide`, `work_checkpoint`, `hashline_edit`, `str_replace_editor`, `web_search`, `web_fetch`.
19
+
20
+ ## Tools
21
+
22
+ ### `work_item_open`
23
+
24
+ - Summary: Open one or more work items idempotently, or register/append generic execution tasks.
25
+ - Description: Open one or more workflow work items idempotently with explicit mode and requiredReviewers.
26
+
27
+ | field | type | required | description |
28
+ | --- | --- | --- | --- |
29
+ | `items` | array | yes | Non-empty batch of work items or generic task bindings (unbounded count). |
30
+ | `execution` | object | no | Generic execution descriptor for registration; mutually exclusive with runId. Requires the trusted workspace root from the plugin context. |
31
+ | `runId` | string | no | Existing generic execution to append to; mutually exclusive with execution. |
32
+ | `amendmentId` | string | no | Bounded amendment identity (trimmed, at most 128 characters); required with runId appends. |
33
+ | `rationale` | string | no | Bounded amendment rationale; required with runId appends. |
34
+
35
+ Closed vocabularies:
36
+ - `items[].mode`: implementation | review_only | delegated
37
+ - `execution.source.kind`: conversation-scoped | provided-plan
38
+
39
+ State/host prerequisites:
40
+ - trusted workspace root from the plugin context for every generic registration
41
+ - existing generic runId for appends
42
+
43
+ Conditional requirements:
44
+ - execution and runId are mutually exclusive
45
+ - amendmentId and rationale are only valid with a runId append
46
+ - generic items require mode delegated and a non-empty write scope of exact files
47
+ - standalone implementation/review_only require a unique non-empty reviewer set and forbid writeScope
48
+
49
+ Path kinds:
50
+ - `items[].writeScope[]` (exact-file): workspace-relative exact file paths; wildcards, traversal, absolute/home/drive paths, backslashes, and trailing separators are rejected
51
+ - `execution.boundary.files[]` (exact-file): workspace-relative exact file paths inside the execution boundary
52
+ - `execution.boundary.directories[]` (directory-subtree): workspace-relative directory subtrees; one trailing separator is normalized away
53
+
54
+ Result families:
55
+ - `work_item_open:batch`: standalone batch envelope (per-item ok/failure, no top-level ok)
56
+ - `work_item_open:batch-failure`: standalone batch envelope with a per-item failure
57
+ - `work_item_open:register`: generic execution registration
58
+ - `work_item_open:amend`: generic execution amendment
59
+ - `work_item_open:failure`: bounded owned failure
60
+
61
+ Representative failures:
62
+ - `items[0].typo`: unknown nested item key is rejected with its path
63
+ - `execution.source.reference`: provided plan without a reference names the source field
64
+
65
+ Checked examples:
66
+ - `work_item_open:standalone-implementation` (accept):
67
+ ```json
68
+ {
69
+ "items": [
70
+ {
71
+ "key": "task-key",
72
+ "title": "Task title",
73
+ "mode": "implementation",
74
+ "requiredReviewers": [
75
+ "spec"
76
+ ]
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+ - `work_item_open:standalone-review-only` (accept):
82
+ ```json
83
+ {
84
+ "items": [
85
+ {
86
+ "key": "task-key",
87
+ "title": "Task title",
88
+ "mode": "review_only",
89
+ "requiredReviewers": [
90
+ "spec"
91
+ ]
92
+ }
93
+ ]
94
+ }
95
+ ```
96
+ - `work_item_open:standalone-delegated` (accept):
97
+ ```json
98
+ {
99
+ "items": [
100
+ {
101
+ "key": "task-key",
102
+ "title": "Task title",
103
+ "mode": "delegated",
104
+ "requiredReviewers": [],
105
+ "writeScope": [
106
+ "src/lib/a.ts"
107
+ ]
108
+ }
109
+ ]
110
+ }
111
+ ```
112
+ - `work_item_open:generic-register-conversation` (accept):
113
+ ```json
114
+ {
115
+ "items": [
116
+ {
117
+ "key": "task-key",
118
+ "title": "Task title",
119
+ "mode": "delegated",
120
+ "requiredReviewers": [],
121
+ "writeScope": [
122
+ "src/lib/a.ts"
123
+ ],
124
+ "taskId": "T-100"
125
+ }
126
+ ],
127
+ "execution": {
128
+ "executionKey": "exec-1",
129
+ "source": {
130
+ "kind": "conversation-scoped"
131
+ },
132
+ "goal": "Deliver the scoped work.",
133
+ "boundary": {
134
+ "files": [
135
+ "src/lib/a.ts"
136
+ ],
137
+ "directories": [
138
+ "src/lib/"
139
+ ]
140
+ }
141
+ }
142
+ }
143
+ ```
144
+ - `work_item_open:generic-register-provided-plan` (accept):
145
+ ```json
146
+ {
147
+ "items": [
148
+ {
149
+ "key": "task-key",
150
+ "title": "Task title",
151
+ "mode": "delegated",
152
+ "requiredReviewers": [],
153
+ "writeScope": [
154
+ "src/lib/a.ts"
155
+ ],
156
+ "taskId": "T-101"
157
+ }
158
+ ],
159
+ "execution": {
160
+ "executionKey": "exec-2",
161
+ "source": {
162
+ "kind": "provided-plan",
163
+ "reference": "docs/plan.xml",
164
+ "sha256": "abc123"
165
+ },
166
+ "goal": "Deliver the provided plan.",
167
+ "boundary": {
168
+ "files": [
169
+ "src/lib/a.ts"
170
+ ],
171
+ "directories": []
172
+ }
173
+ }
174
+ }
175
+ ```
176
+ - `work_item_open:generic-append` (accept):
177
+ ```json
178
+ {
179
+ "items": [
180
+ {
181
+ "key": "task-key",
182
+ "title": "Task title",
183
+ "mode": "delegated",
184
+ "requiredReviewers": [],
185
+ "writeScope": [
186
+ "src/lib/a.ts"
187
+ ],
188
+ "taskId": "T-102"
189
+ }
190
+ ],
191
+ "runId": "run-existing",
192
+ "amendmentId": "amend-1",
193
+ "rationale": "Append the follow-up."
194
+ }
195
+ ```
196
+ - `work_item_open:reject-unknown-key` (reject):
197
+ ```json
198
+ {
199
+ "items": [
200
+ {
201
+ "key": "task-key",
202
+ "title": "Task title",
203
+ "mode": "implementation",
204
+ "requiredReviewers": [
205
+ "spec"
206
+ ],
207
+ "typo": true
208
+ }
209
+ ]
210
+ }
211
+ ```
212
+ - `work_item_open:reject-unsupported-mode` (reject):
213
+ ```json
214
+ {
215
+ "items": [
216
+ {
217
+ "key": "task-key",
218
+ "title": "Task title",
219
+ "mode": "review",
220
+ "requiredReviewers": [
221
+ "spec"
222
+ ]
223
+ }
224
+ ]
225
+ }
226
+ ```
227
+ - `work_item_open:reject-empty-items` (reject):
228
+ ```json
229
+ {
230
+ "items": []
231
+ }
232
+ ```
233
+ - `work_item_open:reject-empty-reviewers` (reject):
234
+ ```json
235
+ {
236
+ "items": [
237
+ {
238
+ "key": "task-key",
239
+ "title": "Task title",
240
+ "mode": "implementation",
241
+ "requiredReviewers": []
242
+ }
243
+ ]
244
+ }
245
+ ```
246
+ - `work_item_open:reject-execution-and-runid` (reject):
247
+ ```json
248
+ {
249
+ "items": [
250
+ {
251
+ "key": "task-key",
252
+ "title": "Task title",
253
+ "mode": "delegated",
254
+ "requiredReviewers": [],
255
+ "writeScope": [
256
+ "src/lib/a.ts"
257
+ ]
258
+ }
259
+ ],
260
+ "runId": "run-1",
261
+ "execution": {
262
+ "executionKey": "exec-1",
263
+ "source": {
264
+ "kind": "conversation-scoped"
265
+ },
266
+ "goal": "Deliver.",
267
+ "boundary": {
268
+ "files": [
269
+ "src/lib/a.ts"
270
+ ],
271
+ "directories": []
272
+ }
273
+ }
274
+ }
275
+ ```
276
+ - `work_item_open:reject-unsupported-source-kind` (reject):
277
+ ```json
278
+ {
279
+ "items": [
280
+ {
281
+ "key": "task-key",
282
+ "title": "Task title",
283
+ "mode": "delegated",
284
+ "requiredReviewers": [],
285
+ "writeScope": [
286
+ "src/lib/a.ts"
287
+ ]
288
+ }
289
+ ],
290
+ "execution": {
291
+ "executionKey": "exec-1",
292
+ "source": {
293
+ "kind": "native-package"
294
+ },
295
+ "goal": "Deliver.",
296
+ "boundary": {
297
+ "files": [
298
+ "src/lib/a.ts"
299
+ ],
300
+ "directories": []
301
+ }
302
+ }
303
+ }
304
+ ```
305
+ - `work_item_open:reject-provided-plan-missing-reference` (reject):
306
+ ```json
307
+ {
308
+ "items": [
309
+ {
310
+ "key": "task-key",
311
+ "title": "Task title",
312
+ "mode": "delegated",
313
+ "requiredReviewers": [],
314
+ "writeScope": [
315
+ "src/lib/a.ts"
316
+ ]
317
+ }
318
+ ],
319
+ "execution": {
320
+ "executionKey": "exec-1",
321
+ "source": {
322
+ "kind": "provided-plan"
323
+ },
324
+ "goal": "Deliver.",
325
+ "boundary": {
326
+ "files": [
327
+ "src/lib/a.ts"
328
+ ],
329
+ "directories": []
330
+ }
331
+ }
332
+ }
333
+ ```
334
+ - `work_item_open:reject-delegated-reviewers` (reject):
335
+ ```json
336
+ {
337
+ "items": [
338
+ {
339
+ "key": "task-key",
340
+ "title": "Task title",
341
+ "mode": "delegated",
342
+ "requiredReviewers": [
343
+ "spec"
344
+ ],
345
+ "writeScope": [
346
+ "src/lib/a.ts"
347
+ ]
348
+ }
349
+ ]
350
+ }
351
+ ```
352
+ - `work_item_open:reject-review-only-empty-reviewers` (reject):
353
+ ```json
354
+ {
355
+ "items": [
356
+ {
357
+ "key": "task-key",
358
+ "title": "Task title",
359
+ "mode": "review_only",
360
+ "requiredReviewers": []
361
+ }
362
+ ]
363
+ }
364
+ ```
365
+ - `work_item_open:reject-generic-register-missing-goal` (reject):
366
+ ```json
367
+ {
368
+ "items": [
369
+ {
370
+ "key": "task-key",
371
+ "title": "Task title",
372
+ "mode": "delegated",
373
+ "requiredReviewers": [],
374
+ "writeScope": [
375
+ "src/lib/a.ts"
376
+ ]
377
+ }
378
+ ],
379
+ "execution": {
380
+ "executionKey": "exec-1",
381
+ "source": {
382
+ "kind": "conversation-scoped"
383
+ },
384
+ "goal": " ",
385
+ "boundary": {
386
+ "files": [
387
+ "src/lib/a.ts"
388
+ ],
389
+ "directories": []
390
+ }
391
+ }
392
+ }
393
+ ```
394
+ - `work_item_open:reject-generic-append-missing-amendment` (reject):
395
+ ```json
396
+ {
397
+ "items": [
398
+ {
399
+ "key": "task-key",
400
+ "title": "Task title",
401
+ "mode": "delegated",
402
+ "requiredReviewers": [],
403
+ "writeScope": [
404
+ "src/lib/a.ts"
405
+ ]
406
+ }
407
+ ],
408
+ "runId": "run-existing"
409
+ }
410
+ ```
411
+
412
+ ### `work_item_list`
413
+
414
+ - Summary: List current-session work items, native plan runs, and generic executions with contract identity.
415
+ - Description: List workflow work items for the current session.
416
+
417
+ | field | type | required | description |
418
+ | --- | --- | --- | --- |
419
+ | `includeClosed` | boolean | no | Include closed work items in the listing; defaults to false. |
420
+
421
+ State/host prerequisites:
422
+ - same-session store hydration from the plugin context
423
+
424
+ Conditional requirements:
425
+ - includeClosed defaults to false and is optional
426
+
427
+ Result families:
428
+ - `work_item_list:view`: inspection view with loaded contract identity
429
+ - `work_item_list:failure`: bounded owned failure
430
+
431
+ Representative failures:
432
+ - `includeClosed`: a non-boolean value is rejected rather than coerced
433
+
434
+ Checked examples:
435
+ - `work_item_list:default` (accept):
436
+ ```json
437
+ {}
438
+ ```
439
+ - `work_item_list:include-closed` (accept):
440
+ ```json
441
+ {
442
+ "includeClosed": true
443
+ }
444
+ ```
445
+ - `work_item_list:reject-unknown-key` (reject):
446
+ ```json
447
+ {
448
+ "includeClosed": false,
449
+ "extra": true
450
+ }
451
+ ```
452
+ - `work_item_list:reject-wrong-type` (reject):
453
+ ```json
454
+ {
455
+ "includeClosed": "true"
456
+ }
457
+ ```
458
+ - `work_item_list:reject-unknown-key-default` (reject):
459
+ ```json
460
+ {
461
+ "extra": true
462
+ }
463
+ ```
464
+ - `work_item_list:reject-unknown-key-include-closed` (reject):
465
+ ```json
466
+ {
467
+ "includeClosed": true,
468
+ "extra": true
469
+ }
470
+ ```
471
+
472
+ ### `work_item_close`
473
+
474
+ - Summary: Close a same-session work item once its reviews are complete and no concerns remain open.
475
+ - Description: Close a workflow work item by id when it is ready_to_close.
476
+
477
+ | field | type | required | description |
478
+ | --- | --- | --- | --- |
479
+ | `workItemId` | string | yes | Non-empty id of the work item to close. |
480
+
481
+ State/host prerequisites:
482
+ - same-session work item in ready_to_close state
483
+
484
+ Conditional requirements:
485
+ - open concerns or pending reviews refuse the close with the unmet prerequisite
486
+
487
+ Result families:
488
+ - `work_item_close:success`: closed work item
489
+ - `work_item_close:failure`: bounded owned failure
490
+
491
+ Representative failures:
492
+ - `workItemId`: blank ids are rejected before any state mutation
493
+
494
+ Checked examples:
495
+ - `work_item_close:close` (accept):
496
+ ```json
497
+ {
498
+ "workItemId": "wi-1"
499
+ }
500
+ ```
501
+ - `work_item_close:reject-unknown-key` (reject):
502
+ ```json
503
+ {
504
+ "workItemId": "wi-1",
505
+ "extra": true
506
+ }
507
+ ```
508
+ - `work_item_close:reject-blank-id` (reject):
509
+ ```json
510
+ {
511
+ "workItemId": " "
512
+ }
513
+ ```
514
+
515
+ ### `work_item_decide`
516
+
517
+ - Summary: Accept, request changes, authorize bounded rework, or recover a stopped delegated attempt.
518
+ - Description: Accept or request changes for the current completed delegated attempt, authorize bounded rework of an accepted task from a failed checkpoint, or recover a stopped or exhausted unaccepted task with a bounded diagnosis and changed condition.
519
+
520
+ | field | type | required | description |
521
+ | --- | --- | --- | --- |
522
+ | `workItemId` | string | yes | Non-empty id of the delegated work item (trimmed). |
523
+ | `attempt` | integer | yes | Positive integer attempt number the decision targets. |
524
+ | `decision` | enum(accept \| request_changes \| rework \| recover) | yes | Controller decision family for this call. |
525
+ | `rationale` | string | no | Bounded rationale (trimmed, at most 2000 characters). Required non-empty for accept/request_changes; optional reason for rework. |
526
+ | `evidence` | array | no | Bounded evidence references (at most 8). Required non-empty for accept/request_changes. |
527
+ | `concernsDisposition` | string | no | Bounded disposition of recorded concerns; required by the domain only when the terminal record demands it. |
528
+ | `runId` | string | no | Failed-checkpoint run for rework, or authority-owning run for recover. |
529
+ | `checkpointId` | string | no | Failed checkpoint id; required for rework. |
530
+ | `diagnosis` | string | no | Bounded recovery diagnosis; required non-empty for recover. |
531
+ | `changedCondition` | string | no | Bounded changed condition; required non-empty for recover. |
532
+ | `verification` | array | no | Bounded verification references (at most 8); required non-empty for recover. |
533
+ | `recoveryId` | string | no | Stable recovery identity (trimmed, at most 512 characters); required for recover. |
534
+ | `userMessageId` | string | no | Optional root-user authorization message id for recover. |
535
+ | `authorityId` | string | no | Recorded advance authority funding recover; requires the owning runId. |
536
+
537
+ Closed vocabularies:
538
+ - `decision`: accept | request_changes | rework | recover
539
+
540
+ State/host prerequisites:
541
+ - latest completed attempt identity and terminal status
542
+ - recorded concerns disposition when the terminal record requires one
543
+
544
+ Conditional requirements:
545
+ - accept/request_changes require balanced rationale and evidence
546
+ - rework requires its failed checkpoint binding
547
+ - recover requires recoveryId, diagnosis, changedCondition, and verification; runId only accompanies authorityId
548
+ - concernsDisposition is conditional on the recorded terminal status, not a caller-supplied status
549
+
550
+ Result families:
551
+ - `work_item_decide:accept-or-request-changes`: decision outcome (accept/request_changes)
552
+ - `work_item_decide:rework`: rework authorization outcome
553
+ - `work_item_decide:recover`: recovery outcome
554
+ - `work_item_decide:failure`: bounded owned failure
555
+
556
+ Representative failures:
557
+ - `evidence`: missing required evidence names the field
558
+ - `runId`: runId without authorityId is a conflict, not silently dropped
559
+
560
+ Checked examples:
561
+ - `work_item_decide:accept` (accept):
562
+ ```json
563
+ {
564
+ "workItemId": "wi-1",
565
+ "attempt": 1,
566
+ "decision": "accept",
567
+ "rationale": "Verified against the acceptance criteria.",
568
+ "evidence": [
569
+ "bun test"
570
+ ]
571
+ }
572
+ ```
573
+ - `work_item_decide:request-changes` (accept):
574
+ ```json
575
+ {
576
+ "workItemId": "wi-1",
577
+ "attempt": 1,
578
+ "decision": "request_changes",
579
+ "rationale": "Fix the edge case.",
580
+ "evidence": [
581
+ "review note"
582
+ ],
583
+ "concernsDisposition": "Resolved after rework."
584
+ }
585
+ ```
586
+ - `work_item_decide:rework` (accept):
587
+ ```json
588
+ {
589
+ "workItemId": "wi-1",
590
+ "attempt": 1,
591
+ "decision": "rework",
592
+ "runId": "run-1",
593
+ "checkpointId": "C-1",
594
+ "rationale": "Checkpoint failed."
595
+ }
596
+ ```
597
+ - `work_item_decide:recover` (accept):
598
+ ```json
599
+ {
600
+ "workItemId": "wi-1",
601
+ "attempt": 2,
602
+ "decision": "recover",
603
+ "recoveryId": "rec-1",
604
+ "diagnosis": "Both attempts stopped.",
605
+ "changedCondition": "Packet clarified.",
606
+ "verification": [
607
+ "bun test"
608
+ ]
609
+ }
610
+ ```
611
+ - `work_item_decide:recover-authority` (accept):
612
+ ```json
613
+ {
614
+ "workItemId": "wi-1",
615
+ "attempt": 2,
616
+ "decision": "recover",
617
+ "recoveryId": "rec-2",
618
+ "diagnosis": "Reserve advance.",
619
+ "changedCondition": "Authority recorded.",
620
+ "verification": [
621
+ "bun test"
622
+ ],
623
+ "authorityId": "auth-1",
624
+ "runId": "run-1"
625
+ }
626
+ ```
627
+ - `work_item_decide:reject-unknown-key` (reject):
628
+ ```json
629
+ {
630
+ "workItemId": "wi-1",
631
+ "attempt": 1,
632
+ "decision": "accept",
633
+ "rationale": "ok",
634
+ "evidence": [
635
+ "x"
636
+ ],
637
+ "typo": true
638
+ }
639
+ ```
640
+ - `work_item_decide:reject-unsupported-decision` (reject):
641
+ ```json
642
+ {
643
+ "workItemId": "wi-1",
644
+ "attempt": 1,
645
+ "decision": "approve"
646
+ }
647
+ ```
648
+ - `work_item_decide:reject-missing-evidence` (reject):
649
+ ```json
650
+ {
651
+ "workItemId": "wi-1",
652
+ "attempt": 1,
653
+ "decision": "accept",
654
+ "rationale": "ok"
655
+ }
656
+ ```
657
+ - `work_item_decide:reject-request-changes-missing-evidence` (reject):
658
+ ```json
659
+ {
660
+ "workItemId": "wi-1",
661
+ "attempt": 1,
662
+ "decision": "request_changes"
663
+ }
664
+ ```
665
+ - `work_item_decide:reject-rework-missing-checkpoint` (reject):
666
+ ```json
667
+ {
668
+ "workItemId": "wi-1",
669
+ "attempt": 1,
670
+ "decision": "rework"
671
+ }
672
+ ```
673
+ - `work_item_decide:reject-unconsumed-field` (reject):
674
+ ```json
675
+ {
676
+ "workItemId": "wi-1",
677
+ "attempt": 1,
678
+ "decision": "accept",
679
+ "rationale": "ok",
680
+ "evidence": [
681
+ "x"
682
+ ],
683
+ "recoveryId": "rec-1"
684
+ }
685
+ ```
686
+ - `work_item_decide:reject-runid-without-authority` (reject):
687
+ ```json
688
+ {
689
+ "workItemId": "wi-1",
690
+ "attempt": 2,
691
+ "decision": "recover",
692
+ "runId": "run-1",
693
+ "recoveryId": "rec-1",
694
+ "diagnosis": "d",
695
+ "changedCondition": "c",
696
+ "verification": [
697
+ "v"
698
+ ]
699
+ }
700
+ ```
701
+
702
+ ### `work_checkpoint`
703
+
704
+ - Summary: Register, start, verify, review, bind, amend, complete, or authorize/recover checkpoints and authority.
705
+ - Description: Register an approved delegated plan, start a declared review checkpoint, verify checkpoint outcomes, or recover a stopped or generation-exhausted checkpoint; verify with complete: true seals a finished final checkpoint.
706
+
707
+ | field | type | required | description |
708
+ | --- | --- | --- | --- |
709
+ | `action` | enum(register \| start \| verify \| recover \| review \| bind \| complete \| amend \| authorize \| record_approval \| revoke_authority) | yes | Checkpoint/authority action to perform. |
710
+ | `planPath` | string | no | Workspace-relative approved native plan path (trimmed, non-empty); native register only, never combined with runId. |
711
+ | `runId` | string | no | Target execution run. Required for every action except native register with planPath. |
712
+ | `checkpointId` | string | no | Checkpoint id (trimmed, at most 128 characters); required for start/verify/recover/review/bind. |
713
+ | `complete` | boolean | no | Seal a finished final checkpoint on verify. |
714
+ | `diagnosis` | string | no | Bounded recovery diagnosis; required non-empty for recover. |
715
+ | `changedCondition` | string | no | Bounded changed condition; required non-empty for recover. |
716
+ | `verification` | array | no | Bounded verification references (at most 8); required non-empty for recover and optional completion evidence for complete. |
717
+ | `recoveryId` | string | no | Stable recovery identity (trimmed, at most 512 characters); required for recover. |
718
+ | `userMessageId` | string | no | Root-user authorization message id; native-package checkpoint recovery only, not generic recovery. |
719
+ | `checkpoints` | array | no | Typed checkpoint contracts for generic register/amend batches (unbounded count). |
720
+ | `tasks` | array | no | Typed task items for generic register/amend batches (unbounded count). |
721
+ | `amendmentId` | string | no | Bounded amendment identity (trimmed, at most 128 characters); required for generic register/amend. |
722
+ | `rationale` | string | no | Bounded rationale; required for generic register/amend, optional context for complete/revocation. |
723
+ | `startFingerprint` | string | no | Optional expected start fingerprint for generic start. |
724
+ | `reviewer` | enum(spec \| code) | no | Optional canonical reviewer role for generic review/bind/verify. |
725
+ | `authorityId` | string | no | Recorded advance authority for authorize/approval/revocation or recover. |
726
+ | `messageId` | string | no | Eligible root-user authorization message id; required for authorize. |
727
+ | `approvalId` | string | no | Bounded stage-approval identity; required for record_approval. |
728
+ | `stage` | enum(specification \| planning \| implementation \| verification) | no | Authority stage being approved; required for record_approval. |
729
+ | `stages` | array | no | Delegatable stages (unbounded count). Required non-empty for authorize; optional surviving-stage set for revoke_authority narrowing. Every entry must be canonic |
730
+ | `decisionScope` | string | no | Bounded decision scope recorded with an authority grant; authorize only. An explicitly empty value keeps the documented empty default. |
731
+ | `fileBoundary` | array | no | File boundary recorded with an authority grant (unbounded count); authorize only. |
732
+ | `reservedStops` | array | no | Reserved lifecycle stops retained for explicit user action (unbounded count); every entry must be a canonical stage. authorize only; defaults to none. |
733
+ | `artifactPath` | string | no | Approved artifact path; required for record_approval. |
734
+ | `artifactSha256` | string | no | Approved artifact hash; required for record_approval. |
735
+ | `revocationId` | string | no | Bounded revocation identity; required for revoke_authority. |
736
+
737
+ Closed vocabularies:
738
+ - `action`: register | start | verify | recover | review | bind | complete | amend | authorize | record_approval | revoke_authority
739
+
740
+ State/host prerequisites:
741
+ - source (native planPath or generic runId) resolved before source-dependent validation
742
+ - eligible root-user authorization message for authorize
743
+
744
+ Conditional requirements:
745
+ - native register uses planPath and rejects runId; generic register appends a task batch to an existing runId with amendmentId and rationale
746
+ - generic review, bind, and verify consume the linked reviewer items' recorded outcomes; the reviewer callID launch binding happens in the host hook, not through this action
747
+ - native verify with complete:true seals only an eligible final checkpoint; generic executions seal through the complete action
748
+ - work_checkpoint recover consumes userMessageId only for native-package checkpoints: a generic checkpoint recover rejects userMessageId (a stopped generation resumes cost-free, an exhausted one needs a recorded advance authorityId with its runId). work_item_decide recover accepts userMessageId for standalone, native, and generic execution tasks
749
+ - authorize/record_approval/revoke_authority validate every supplied stage/stop before any ledger write
750
+
751
+ Path kinds:
752
+ - `planPath` (exact-file): workspace-relative approved native plan path; native register only
753
+ - `fileBoundary[]` (exact-file): workspace-relative exact files recorded with an authority grant
754
+ - `artifactPath` (exact-file): approved artifact path recorded with a stage approval
755
+
756
+ Result families:
757
+ - `work_checkpoint:register`: registration/amendment summary
758
+ - `work_checkpoint:amend`: generic amendment view
759
+ - `work_checkpoint:start`: started generation with reviewers to launch
760
+ - `work_checkpoint:verify-native`: native verify outcome
761
+ - `work_checkpoint:review-bind-verify`: generic review/bind/verify outcome
762
+ - `work_checkpoint:recover`: checkpoint recovery outcome
763
+ - `work_checkpoint:complete`: sealed execution
764
+ - `work_checkpoint:authorize`: authority grant/extension
765
+ - `work_checkpoint:record-approval`: stage approval record
766
+ - `work_checkpoint:revoke-authority`: authority revocation
767
+ - `work_checkpoint:failure`: bounded owned failure
768
+
769
+ Representative failures:
770
+ - `reservedStops[0]`: a misspelled stage rejects and never becomes a silent omission
771
+ - `action`: a field consumed by another action is rejected, not ignored
772
+
773
+ Checked examples:
774
+ - `work_checkpoint:register-native` (accept):
775
+ ```json
776
+ {
777
+ "action": "register",
778
+ "planPath": ".vvoc/specs/x/plan.xml"
779
+ }
780
+ ```
781
+ - `work_checkpoint:register-generic` (accept):
782
+ ```json
783
+ {
784
+ "action": "register",
785
+ "runId": "run-1",
786
+ "amendmentId": "amend-1",
787
+ "rationale": "Append a task batch to the existing run.",
788
+ "tasks": [
789
+ {
790
+ "key": "task-key",
791
+ "title": "Task title",
792
+ "mode": "delegated",
793
+ "requiredReviewers": [],
794
+ "writeScope": [
795
+ "src/lib/a.ts"
796
+ ]
797
+ }
798
+ ]
799
+ }
800
+ ```
801
+ - `work_checkpoint:start` (accept):
802
+ ```json
803
+ {
804
+ "action": "start",
805
+ "runId": "run-1",
806
+ "checkpointId": "C-1"
807
+ }
808
+ ```
809
+ - `work_checkpoint:verify` (accept):
810
+ ```json
811
+ {
812
+ "action": "verify",
813
+ "runId": "run-1",
814
+ "checkpointId": "C-1",
815
+ "complete": true
816
+ }
817
+ ```
818
+ - `work_checkpoint:recover` (accept):
819
+ ```json
820
+ {
821
+ "action": "recover",
822
+ "runId": "run-1",
823
+ "checkpointId": "C-1",
824
+ "recoveryId": "rec-1",
825
+ "diagnosis": "Generation stopped.",
826
+ "changedCondition": "Fresh reviewer assigned.",
827
+ "verification": [
828
+ "bun test"
829
+ ]
830
+ }
831
+ ```
832
+ - `work_checkpoint:review` (accept):
833
+ ```json
834
+ {
835
+ "action": "review",
836
+ "runId": "run-1",
837
+ "checkpointId": "C-1",
838
+ "reviewer": "code"
839
+ }
840
+ ```
841
+ - `work_checkpoint:bind` (accept):
842
+ ```json
843
+ {
844
+ "action": "bind",
845
+ "runId": "run-1",
846
+ "checkpointId": "C-1"
847
+ }
848
+ ```
849
+ - `work_checkpoint:complete` (accept):
850
+ ```json
851
+ {
852
+ "action": "complete",
853
+ "runId": "run-1",
854
+ "rationale": "All tasks accepted."
855
+ }
856
+ ```
857
+ - `work_checkpoint:amend` (accept):
858
+ ```json
859
+ {
860
+ "action": "amend",
861
+ "runId": "run-1",
862
+ "amendmentId": "amend-1",
863
+ "rationale": "Add coverage."
864
+ }
865
+ ```
866
+ - `work_checkpoint:authorize` (accept):
867
+ ```json
868
+ {
869
+ "action": "authorize",
870
+ "runId": "run-1",
871
+ "authorityId": "auth-1",
872
+ "messageId": "msg-1",
873
+ "stages": [
874
+ "implementation"
875
+ ],
876
+ "reservedStops": [
877
+ "specification"
878
+ ]
879
+ }
880
+ ```
881
+ - `work_checkpoint:record-approval` (accept):
882
+ ```json
883
+ {
884
+ "action": "record_approval",
885
+ "runId": "run-1",
886
+ "authorityId": "auth-1",
887
+ "approvalId": "appr-1",
888
+ "stage": "implementation",
889
+ "artifactPath": "src/lib/a.ts",
890
+ "artifactSha256": "abc123"
891
+ }
892
+ ```
893
+ - `work_checkpoint:revoke-authority` (accept):
894
+ ```json
895
+ {
896
+ "action": "revoke_authority",
897
+ "runId": "run-1",
898
+ "authorityId": "auth-1",
899
+ "revocationId": "revoke-1"
900
+ }
901
+ ```
902
+ - `work_checkpoint:revoke-narrow` (accept):
903
+ ```json
904
+ {
905
+ "action": "revoke_authority",
906
+ "runId": "run-1",
907
+ "authorityId": "auth-1",
908
+ "revocationId": "revoke-2",
909
+ "stages": [
910
+ "verification"
911
+ ],
912
+ "rationale": "Keep the final stage."
913
+ }
914
+ ```
915
+ - `work_checkpoint:reject-unknown-key` (reject):
916
+ ```json
917
+ {
918
+ "action": "start",
919
+ "runId": "run-1",
920
+ "checkpointId": "C-1",
921
+ "nestedUnknown": {
922
+ "deep": 1
923
+ }
924
+ }
925
+ ```
926
+ - `work_checkpoint:reject-unsupported-action` (reject):
927
+ ```json
928
+ {
929
+ "action": "unknown_action"
930
+ }
931
+ ```
932
+ - `work_checkpoint:reject-start-missing-runid` (reject):
933
+ ```json
934
+ {
935
+ "action": "start",
936
+ "checkpointId": "C-1"
937
+ }
938
+ ```
939
+ - `work_checkpoint:reject-register-both-routes` (reject):
940
+ ```json
941
+ {
942
+ "action": "register",
943
+ "planPath": ".vvoc/specs/x/plan.xml",
944
+ "runId": "run-1"
945
+ }
946
+ ```
947
+ - `work_checkpoint:reject-reserved-stop-typo` (reject):
948
+ ```json
949
+ {
950
+ "action": "authorize",
951
+ "runId": "run-1",
952
+ "authorityId": "auth-1",
953
+ "messageId": "msg-1",
954
+ "stages": [
955
+ "implementation"
956
+ ],
957
+ "reservedStops": [
958
+ "verificaton"
959
+ ]
960
+ }
961
+ ```
962
+ - `work_checkpoint:reject-unconsumed-action-field` (reject):
963
+ ```json
964
+ {
965
+ "action": "complete",
966
+ "runId": "run-1",
967
+ "planPath": ".vvoc/specs/x/plan.xml"
968
+ }
969
+ ```
970
+ - `work_checkpoint:reject-recover-incomplete` (reject):
971
+ ```json
972
+ {
973
+ "action": "recover",
974
+ "runId": "run-1",
975
+ "checkpointId": "C-1",
976
+ "recoveryId": "rec-1"
977
+ }
978
+ ```
979
+ - `work_checkpoint:reject-verify-missing-checkpoint` (reject):
980
+ ```json
981
+ {
982
+ "action": "verify",
983
+ "runId": "run-1"
984
+ }
985
+ ```
986
+ - `work_checkpoint:reject-review-missing-checkpoint` (reject):
987
+ ```json
988
+ {
989
+ "action": "review",
990
+ "runId": "run-1"
991
+ }
992
+ ```
993
+ - `work_checkpoint:reject-bind-missing-checkpoint` (reject):
994
+ ```json
995
+ {
996
+ "action": "bind",
997
+ "runId": "run-1"
998
+ }
999
+ ```
1000
+ - `work_checkpoint:reject-amend-missing-amendment` (reject):
1001
+ ```json
1002
+ {
1003
+ "action": "amend",
1004
+ "runId": "run-1"
1005
+ }
1006
+ ```
1007
+ - `work_checkpoint:reject-record-approval-missing-approval` (reject):
1008
+ ```json
1009
+ {
1010
+ "action": "record_approval",
1011
+ "runId": "run-1"
1012
+ }
1013
+ ```
1014
+ - `work_checkpoint:reject-revoke-authority-missing-revocation` (reject):
1015
+ ```json
1016
+ {
1017
+ "action": "revoke_authority",
1018
+ "runId": "run-1"
1019
+ }
1020
+ ```
1021
+
1022
+ ### `hashline_edit`
1023
+
1024
+ - Summary: Apply exact hash-anchored line edits, range replacements, boundary inserts, delete, or rename.
1025
+ - Description: Edit files using exact hash-anchored line references from the latest Read output.
1026
+
1027
+ | field | type | required | description |
1028
+ | --- | --- | --- | --- |
1029
+ | `filePath` | string | yes | Absolute path to the file to edit (non-empty; spaces inside the name are preserved) |
1030
+ | `delete` | boolean | no | Delete the file instead of editing it |
1031
+ | `rename` | string | no | Rename the file after edits are applied (non-empty when provided) |
1032
+ | `edits` | array | yes | Hash-anchored edit operations to apply to the file |
1033
+
1034
+ Closed vocabularies:
1035
+ - `edits[].op`: replace | replace_range | append | prepend
1036
+
1037
+ State/host prerequisites:
1038
+ - absolute existing file path and current-file anchor validation
1039
+ - model visibility for the routed edit tool
1040
+
1041
+ Conditional requirements:
1042
+ - replace requires pos; replace_range requires pos and end
1043
+ - append/prepend accept one anchor or none; null/[] deletes for replace/replace_range
1044
+ - delete requires an empty edits list and forbids rename
1045
+
1046
+ Path kinds:
1047
+ - `filePath` (absolute-file): absolute path; spaces inside the name are preserved
1048
+ - `rename` (absolute-file): non-empty absolute destination path when provided
1049
+
1050
+ Result families:
1051
+ - `hashline_edit:text-success`: model-visible success text returned to the host
1052
+ - `hashline_edit:text-error`: model-visible Error text for a rejected edit
1053
+ - `hashline_edit:success-metadata`: separately published bounded success metadata with filediff
1054
+
1055
+ Representative failures:
1056
+ - `edits[0].typo`: unknown nested key names the edit index
1057
+ - `edits[0].end`: conflicting insert anchors name the offending field
1058
+
1059
+ Checked examples:
1060
+ - `hashline_edit:replace` (accept):
1061
+ ```json
1062
+ {
1063
+ "filePath": "/tmp/a.ts",
1064
+ "edits": [
1065
+ {
1066
+ "op": "replace",
1067
+ "pos": "2#VK#ZZ",
1068
+ "lines": [
1069
+ "x"
1070
+ ]
1071
+ }
1072
+ ]
1073
+ }
1074
+ ```
1075
+ - `hashline_edit:replace-with-end` (accept):
1076
+ ```json
1077
+ {
1078
+ "filePath": "/tmp/a.ts",
1079
+ "edits": [
1080
+ {
1081
+ "op": "replace",
1082
+ "pos": "2#VK#ZZ",
1083
+ "end": "3#MB#ZZ",
1084
+ "lines": [
1085
+ "x"
1086
+ ]
1087
+ }
1088
+ ]
1089
+ }
1090
+ ```
1091
+ - `hashline_edit:replace-range` (accept):
1092
+ ```json
1093
+ {
1094
+ "filePath": "/tmp/a.ts",
1095
+ "edits": [
1096
+ {
1097
+ "op": "replace_range",
1098
+ "pos": "2#VK#ZZ",
1099
+ "end": "3#MB#ZZ",
1100
+ "lines": [
1101
+ "x"
1102
+ ]
1103
+ }
1104
+ ]
1105
+ }
1106
+ ```
1107
+ - `hashline_edit:delete-lines-null` (accept):
1108
+ ```json
1109
+ {
1110
+ "filePath": "/tmp/a.ts",
1111
+ "edits": [
1112
+ {
1113
+ "op": "replace_range",
1114
+ "pos": "2#VK#ZZ",
1115
+ "end": "3#MB#ZZ",
1116
+ "lines": null
1117
+ }
1118
+ ]
1119
+ }
1120
+ ```
1121
+ - `hashline_edit:append-boundary` (accept):
1122
+ ```json
1123
+ {
1124
+ "filePath": "/tmp/a.ts",
1125
+ "edits": [
1126
+ {
1127
+ "op": "append",
1128
+ "lines": [
1129
+ "x"
1130
+ ]
1131
+ }
1132
+ ]
1133
+ }
1134
+ ```
1135
+ - `hashline_edit:prepend-end-fallback` (accept):
1136
+ ```json
1137
+ {
1138
+ "filePath": "/tmp/a.ts",
1139
+ "edits": [
1140
+ {
1141
+ "op": "prepend",
1142
+ "end": "3#MB#ZZ",
1143
+ "lines": [
1144
+ "x"
1145
+ ]
1146
+ }
1147
+ ]
1148
+ }
1149
+ ```
1150
+ - `hashline_edit:delete-file` (accept):
1151
+ ```json
1152
+ {
1153
+ "filePath": "/tmp/a.ts",
1154
+ "delete": true,
1155
+ "edits": []
1156
+ }
1157
+ ```
1158
+ - `hashline_edit:rename` (accept):
1159
+ ```json
1160
+ {
1161
+ "filePath": "/tmp/a.ts",
1162
+ "rename": "/tmp/b.ts",
1163
+ "edits": [
1164
+ {
1165
+ "op": "append",
1166
+ "lines": [
1167
+ "x"
1168
+ ]
1169
+ }
1170
+ ]
1171
+ }
1172
+ ```
1173
+ - `hashline_edit:reject-unknown-nested-key` (reject):
1174
+ ```json
1175
+ {
1176
+ "filePath": "/tmp/a.ts",
1177
+ "edits": [
1178
+ {
1179
+ "op": "append",
1180
+ "lines": [
1181
+ "x"
1182
+ ],
1183
+ "typo": 1
1184
+ }
1185
+ ]
1186
+ }
1187
+ ```
1188
+ - `hashline_edit:reject-delete-rename` (reject):
1189
+ ```json
1190
+ {
1191
+ "filePath": "/tmp/a.ts",
1192
+ "delete": true,
1193
+ "rename": "/tmp/b.ts",
1194
+ "edits": []
1195
+ }
1196
+ ```
1197
+ - `hashline_edit:reject-replace-range-missing-end` (reject):
1198
+ ```json
1199
+ {
1200
+ "filePath": "/tmp/a.ts",
1201
+ "edits": [
1202
+ {
1203
+ "op": "replace_range",
1204
+ "pos": "2#VK#ZZ",
1205
+ "lines": [
1206
+ "x"
1207
+ ]
1208
+ }
1209
+ ]
1210
+ }
1211
+ ```
1212
+ - `hashline_edit:reject-conflicting-insert-anchors` (reject):
1213
+ ```json
1214
+ {
1215
+ "filePath": "/tmp/a.ts",
1216
+ "edits": [
1217
+ {
1218
+ "op": "append",
1219
+ "pos": "2#VK#ZZ",
1220
+ "end": "3#MB#ZZ",
1221
+ "lines": [
1222
+ "x"
1223
+ ]
1224
+ }
1225
+ ]
1226
+ }
1227
+ ```
1228
+ - `hashline_edit:reject-unsupported-op` (reject):
1229
+ ```json
1230
+ {
1231
+ "filePath": "/tmp/a.ts",
1232
+ "edits": [
1233
+ {
1234
+ "op": "set_line",
1235
+ "pos": "2#VK#ZZ",
1236
+ "lines": [
1237
+ "x"
1238
+ ]
1239
+ }
1240
+ ]
1241
+ }
1242
+ ```
1243
+ - `hashline_edit:reject-replace-missing-pos` (reject):
1244
+ ```json
1245
+ {
1246
+ "filePath": "/tmp/a.ts",
1247
+ "edits": [
1248
+ {
1249
+ "op": "replace",
1250
+ "lines": [
1251
+ "x"
1252
+ ]
1253
+ }
1254
+ ]
1255
+ }
1256
+ ```
1257
+ - `hashline_edit:reject-prepend-conflicting-anchors` (reject):
1258
+ ```json
1259
+ {
1260
+ "filePath": "/tmp/a.ts",
1261
+ "edits": [
1262
+ {
1263
+ "op": "prepend",
1264
+ "pos": "2#VK#ZZ",
1265
+ "end": "3#MB#ZZ",
1266
+ "lines": [
1267
+ "x"
1268
+ ]
1269
+ }
1270
+ ]
1271
+ }
1272
+ ```
1273
+ - `hashline_edit:reject-delete-blank-path` (reject):
1274
+ ```json
1275
+ {
1276
+ "filePath": "",
1277
+ "delete": true,
1278
+ "edits": []
1279
+ }
1280
+ ```
1281
+ - `hashline_edit:reject-rename-blank-path` (reject):
1282
+ ```json
1283
+ {
1284
+ "filePath": "",
1285
+ "rename": "/tmp/b.ts",
1286
+ "edits": [
1287
+ {
1288
+ "op": "append",
1289
+ "lines": [
1290
+ "x"
1291
+ ]
1292
+ }
1293
+ ]
1294
+ }
1295
+ ```
1296
+
1297
+ ### `str_replace_editor`
1298
+
1299
+ - Summary: View, create, exactly replace, or insert into a file with the dsh command surface.
1300
+ - Description: Custom editing tool for viewing, creating and editing files
1301
+
1302
+ | field | type | required | description |
1303
+ | --- | --- | --- | --- |
1304
+ | `command` | enum(view \| create \| str_replace \| insert) | yes | The command to run: view, create, str_replace, or insert |
1305
+ | `path` | string | yes | Absolute path to file or directory |
1306
+ | `file_text` | string | no | create only: content of the new file; an explicitly empty string is allowed |
1307
+ | `old_str` | string | no | str_replace only: the exact, non-empty text to replace (whitespace is significant) |
1308
+ | `new_str` | string | no | str_replace replacement text (omitted defaults to empty deletion; explicit empty is valid); required for insert |
1309
+ | `insert_line` | integer | no | insert only: integer line index >= 0; new_str is inserted AFTER this line (the file-dependent upper bound is enforced by the editor) |
1310
+ | `view_range` | array | no | view only: exact [start, end] line range. The length is fixed at 2; start >= 1 and end is -1 (end of file) or >= start are runtime-checked. |
1311
+
1312
+ Closed vocabularies:
1313
+ - `command`: view | create | str_replace | insert
1314
+
1315
+ State/host prerequisites:
1316
+ - path existence and directory checks in the editor
1317
+ - current-file freshness for str_replace and insert
1318
+
1319
+ Conditional requirements:
1320
+ - create requires file_text (explicit empty allowed)
1321
+ - str_replace requires a non-empty old_str; omitted new_str deletes
1322
+ - insert requires insert_line >= 0 and new_str; view_range length is exactly 2
1323
+
1324
+ Path kinds:
1325
+ - `path` (absolute-file): absolute file or directory path; non-empty
1326
+
1327
+ Result families:
1328
+ - `str_replace_editor:ok`: successful ok/output envelope
1329
+ - `str_replace_editor:error`: error envelope
1330
+
1331
+ Representative failures:
1332
+ - `path`: blank paths are rejected before any mutation
1333
+ - `view_range`: a non-two-element range is diagnosed
1334
+
1335
+ Checked examples:
1336
+ - `str_replace_editor:view` (accept):
1337
+ ```json
1338
+ {
1339
+ "command": "view",
1340
+ "path": "/tmp/a.ts",
1341
+ "view_range": [
1342
+ 2,
1343
+ -1
1344
+ ]
1345
+ }
1346
+ ```
1347
+ - `str_replace_editor:create` (accept):
1348
+ ```json
1349
+ {
1350
+ "command": "create",
1351
+ "path": "/tmp/a.ts",
1352
+ "file_text": ""
1353
+ }
1354
+ ```
1355
+ - `str_replace_editor:str-replace-explicit-empty` (accept):
1356
+ ```json
1357
+ {
1358
+ "command": "str_replace",
1359
+ "path": "/tmp/a.ts",
1360
+ "old_str": "x",
1361
+ "new_str": ""
1362
+ }
1363
+ ```
1364
+ - `str_replace_editor:str-replace-omitted-new-str` (accept):
1365
+ ```json
1366
+ {
1367
+ "command": "str_replace",
1368
+ "path": "/tmp/a.ts",
1369
+ "old_str": "x"
1370
+ }
1371
+ ```
1372
+ - `str_replace_editor:insert` (accept):
1373
+ ```json
1374
+ {
1375
+ "command": "insert",
1376
+ "path": "/tmp/a.ts",
1377
+ "insert_line": 0,
1378
+ "new_str": ""
1379
+ }
1380
+ ```
1381
+ - `str_replace_editor:reject-unknown-key` (reject):
1382
+ ```json
1383
+ {
1384
+ "command": "view",
1385
+ "path": "/tmp/a.ts",
1386
+ "nested": {
1387
+ "deep": 1
1388
+ }
1389
+ }
1390
+ ```
1391
+ - `str_replace_editor:reject-unsupported-command` (reject):
1392
+ ```json
1393
+ {
1394
+ "command": "delete",
1395
+ "path": "/tmp/a.ts"
1396
+ }
1397
+ ```
1398
+ - `str_replace_editor:reject-unconsumed-field` (reject):
1399
+ ```json
1400
+ {
1401
+ "command": "view",
1402
+ "path": "/tmp/a.ts",
1403
+ "old_str": "x"
1404
+ }
1405
+ ```
1406
+ - `str_replace_editor:reject-create-missing-file-text` (reject):
1407
+ ```json
1408
+ {
1409
+ "command": "create",
1410
+ "path": "/tmp/a.ts"
1411
+ }
1412
+ ```
1413
+ - `str_replace_editor:reject-empty-old-str` (reject):
1414
+ ```json
1415
+ {
1416
+ "command": "str_replace",
1417
+ "path": "/tmp/a.ts",
1418
+ "old_str": "",
1419
+ "new_str": "x"
1420
+ }
1421
+ ```
1422
+ - `str_replace_editor:reject-insert-missing-line` (reject):
1423
+ ```json
1424
+ {
1425
+ "command": "insert",
1426
+ "path": "/tmp/a.ts",
1427
+ "new_str": "x"
1428
+ }
1429
+ ```
1430
+ - `str_replace_editor:reject-view-range-shape` (reject):
1431
+ ```json
1432
+ {
1433
+ "command": "view",
1434
+ "path": "/tmp/a.ts",
1435
+ "view_range": [
1436
+ 1
1437
+ ]
1438
+ }
1439
+ ```
1440
+ - `str_replace_editor:reject-view-range-order` (reject):
1441
+ ```json
1442
+ {
1443
+ "command": "view",
1444
+ "path": "/tmp/a.ts",
1445
+ "view_range": [
1446
+ 3,
1447
+ 2
1448
+ ]
1449
+ }
1450
+ ```
1451
+
1452
+ ### `web_search`
1453
+
1454
+ - Summary: Search the configured provider and return ranked Markdown results.
1455
+ - Description: Search the web using the configured provider and return ranked results as Markdown. Use for discovering information; returns titles, URLs, snippets, and dates.
1456
+
1457
+ | field | type | required | description |
1458
+ | --- | --- | --- | --- |
1459
+ | `query` | string | yes | The search query; the text is sent unchanged. |
1460
+ | `count` | integer | no | Number of results, integer 1 through 20, default 8. |
1461
+ | `freshness` | enum(day \| week \| month \| year) | no | Optional time window restricting results: day, week, month, or year. |
1462
+
1463
+ Closed vocabularies:
1464
+ - `freshness`: day | week | month | year
1465
+
1466
+ Execute-time defaults:
1467
+ - `count` = `8` (re-applied at execute time)
1468
+
1469
+ State/host prerequisites:
1470
+ - configured provider and permission prompt
1471
+ - resolved credential (env or config) for non-native providers
1472
+
1473
+ Conditional requirements:
1474
+ - count is an integer 1..20; freshness is optional
1475
+
1476
+ Result families:
1477
+ - `web_search:exa`: ranked Markdown result from the Exa provider
1478
+ - `web_search:brave`: ranked Markdown result from the Brave provider
1479
+ - `web_search:zai`: ranked Markdown result from the regional Z.AI provider
1480
+
1481
+ Representative failures:
1482
+ - `count`: an out-of-range count is rejected before dispatch
1483
+ - `credential`: unknown credential/provider fields are rejected
1484
+
1485
+ Checked examples:
1486
+ - `web_search:default-count` (accept):
1487
+ ```json
1488
+ {
1489
+ "query": "vvoc"
1490
+ }
1491
+ ```
1492
+ - `web_search:freshness-day` (accept):
1493
+ ```json
1494
+ {
1495
+ "query": "vvoc",
1496
+ "freshness": "day"
1497
+ }
1498
+ ```
1499
+ - `web_search:freshness-week` (accept):
1500
+ ```json
1501
+ {
1502
+ "query": "vvoc",
1503
+ "freshness": "week"
1504
+ }
1505
+ ```
1506
+ - `web_search:freshness-month` (accept):
1507
+ ```json
1508
+ {
1509
+ "query": "vvoc",
1510
+ "freshness": "month"
1511
+ }
1512
+ ```
1513
+ - `web_search:freshness-year` (accept):
1514
+ ```json
1515
+ {
1516
+ "query": "vvoc",
1517
+ "freshness": "year"
1518
+ }
1519
+ ```
1520
+ - `web_search:max-count` (accept):
1521
+ ```json
1522
+ {
1523
+ "query": "vvoc",
1524
+ "count": 20
1525
+ }
1526
+ ```
1527
+ - `web_search:reject-unknown-key` (reject):
1528
+ ```json
1529
+ {
1530
+ "query": "vvoc",
1531
+ "extra": true
1532
+ }
1533
+ ```
1534
+ - `web_search:reject-count-low` (reject):
1535
+ ```json
1536
+ {
1537
+ "query": "vvoc",
1538
+ "count": 0
1539
+ }
1540
+ ```
1541
+ - `web_search:reject-count-high` (reject):
1542
+ ```json
1543
+ {
1544
+ "query": "vvoc",
1545
+ "count": 21
1546
+ }
1547
+ ```
1548
+ - `web_search:reject-fractional-count` (reject):
1549
+ ```json
1550
+ {
1551
+ "query": "vvoc",
1552
+ "count": 1.5
1553
+ }
1554
+ ```
1555
+ - `web_search:reject-string-count` (reject):
1556
+ ```json
1557
+ {
1558
+ "query": "vvoc",
1559
+ "count": "8"
1560
+ }
1561
+ ```
1562
+ - `web_search:reject-unknown-freshness` (reject):
1563
+ ```json
1564
+ {
1565
+ "query": "vvoc",
1566
+ "freshness": "hour"
1567
+ }
1568
+ ```
1569
+ - `web_search:reject-freshness-day-invalid-count` (reject):
1570
+ ```json
1571
+ {
1572
+ "query": "vvoc",
1573
+ "freshness": "day",
1574
+ "count": 0
1575
+ }
1576
+ ```
1577
+ - `web_search:reject-freshness-week-invalid-count` (reject):
1578
+ ```json
1579
+ {
1580
+ "query": "vvoc",
1581
+ "freshness": "week",
1582
+ "count": 0
1583
+ }
1584
+ ```
1585
+ - `web_search:reject-freshness-month-invalid-count` (reject):
1586
+ ```json
1587
+ {
1588
+ "query": "vvoc",
1589
+ "freshness": "month",
1590
+ "count": 0
1591
+ }
1592
+ ```
1593
+ - `web_search:reject-freshness-year-invalid-count` (reject):
1594
+ ```json
1595
+ {
1596
+ "query": "vvoc",
1597
+ "freshness": "year",
1598
+ "count": 0
1599
+ }
1600
+ ```
1601
+ - `web_search:reject-credential` (reject):
1602
+ ```json
1603
+ {
1604
+ "query": "vvoc",
1605
+ "credential": "secret",
1606
+ "provider": "brave"
1607
+ }
1608
+ ```
1609
+
1610
+ ### `web_fetch`
1611
+
1612
+ - Summary: Fetch a known HTTP(S) URL and return Markdown, text, HTML, or a media attachment.
1613
+ - Description: Fetch a known HTTP or HTTPS URL using the configured provider. Returns Markdown, text, raw HTML, or an image/PDF attachment.
1614
+
1615
+ | field | type | required | description |
1616
+ | --- | --- | --- | --- |
1617
+ | `url` | string | yes | The HTTP or HTTPS URL to retrieve; the URL is requested unchanged. |
1618
+ | `format` | enum(markdown \| text \| html) | no | Output format for textual resources: markdown, text, or html. Default markdown. |
1619
+ | `timeout` | number | no | Timeout in seconds: greater than 0 and at most 120; fractional values are allowed. Default 30. |
1620
+
1621
+ Closed vocabularies:
1622
+ - `format`: markdown | text | html
1623
+
1624
+ Execute-time defaults:
1625
+ - `format` = `"markdown"` (re-applied at execute time)
1626
+ - `timeout` = `30` (re-applied at execute time; positive and at most 120)
1627
+
1628
+ State/host prerequisites:
1629
+ - configured provider and permission prompt
1630
+ - resolved credential for spider/zai providers
1631
+
1632
+ Conditional requirements:
1633
+ - format defaults to markdown; timeout is positive and at most 120
1634
+
1635
+ Path kinds:
1636
+ - `url` (url): absolute http(s) URL; the URL is requested unchanged and never echoed in diagnostics
1637
+
1638
+ Result families:
1639
+ - `web_fetch:text-native`: native textual result envelope
1640
+ - `web_fetch:text-spider`: Spider textual result envelope with request timing
1641
+ - `web_fetch:text-zai`: regional Z.AI textual result envelope with reader metadata
1642
+ - `web_fetch:media-native`: native media result envelope with a real attachment
1643
+ - `web_fetch:media-spider`: Spider media result envelope with request timing
1644
+ - `web_fetch:media-zai`: regional Z.AI media result envelope with a real attachment
1645
+
1646
+ Representative failures:
1647
+ - `url`: a non-http(s) URL is rejected without echoing the raw URL
1648
+ - `timeout`: an out-of-bounds timeout is rejected before dispatch
1649
+
1650
+ Checked examples:
1651
+ - `web_fetch:default-format` (accept):
1652
+ ```json
1653
+ {
1654
+ "url": "https://example.test/page"
1655
+ }
1656
+ ```
1657
+ - `web_fetch:format-text` (accept):
1658
+ ```json
1659
+ {
1660
+ "url": "https://example.test/page",
1661
+ "format": "text",
1662
+ "timeout": 0.5
1663
+ }
1664
+ ```
1665
+ - `web_fetch:format-html` (accept):
1666
+ ```json
1667
+ {
1668
+ "url": "https://example.test/page",
1669
+ "format": "html",
1670
+ "timeout": 120
1671
+ }
1672
+ ```
1673
+ - `web_fetch:reject-unknown-key` (reject):
1674
+ ```json
1675
+ {
1676
+ "url": "https://example.test/page",
1677
+ "extra": true
1678
+ }
1679
+ ```
1680
+ - `web_fetch:reject-relative-url` (reject):
1681
+ ```json
1682
+ {
1683
+ "url": "/page"
1684
+ }
1685
+ ```
1686
+ - `web_fetch:reject-file-scheme` (reject):
1687
+ ```json
1688
+ {
1689
+ "url": "file:///tmp/secret"
1690
+ }
1691
+ ```
1692
+ - `web_fetch:reject-data-scheme` (reject):
1693
+ ```json
1694
+ {
1695
+ "url": "data:text/plain,hello"
1696
+ }
1697
+ ```
1698
+ - `web_fetch:reject-unsupported-format` (reject):
1699
+ ```json
1700
+ {
1701
+ "url": "https://example.test/page",
1702
+ "format": "pdf"
1703
+ }
1704
+ ```
1705
+ - `web_fetch:reject-markdown-invalid-timeout` (reject):
1706
+ ```json
1707
+ {
1708
+ "url": "https://example.test/page",
1709
+ "format": "markdown",
1710
+ "timeout": 0
1711
+ }
1712
+ ```
1713
+ - `web_fetch:reject-text-invalid-timeout` (reject):
1714
+ ```json
1715
+ {
1716
+ "url": "https://example.test/page",
1717
+ "format": "text",
1718
+ "timeout": 0
1719
+ }
1720
+ ```
1721
+ - `web_fetch:reject-html-invalid-timeout` (reject):
1722
+ ```json
1723
+ {
1724
+ "url": "https://example.test/page",
1725
+ "format": "html",
1726
+ "timeout": 0
1727
+ }
1728
+ ```
1729
+ - `web_fetch:reject-zero-timeout` (reject):
1730
+ ```json
1731
+ {
1732
+ "url": "https://example.test/page",
1733
+ "timeout": 0
1734
+ }
1735
+ ```
1736
+ - `web_fetch:reject-string-timeout` (reject):
1737
+ ```json
1738
+ {
1739
+ "url": "https://example.test/page",
1740
+ "timeout": "30"
1741
+ }
1742
+ ```
1743
+ - `web_fetch:reject-credential` (reject):
1744
+ ```json
1745
+ {
1746
+ "url": "https://example.test/page",
1747
+ "apiKey": "secret",
1748
+ "provider": "spider"
1749
+ }
1750
+ ```