vgxness 0.1.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 (121) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +110 -0
  3. package/dist/agents/agent-activation-service.js +144 -0
  4. package/dist/agents/agent-registry-service.js +46 -0
  5. package/dist/agents/agent-resolver.js +249 -0
  6. package/dist/agents/agent-seed-service.js +146 -0
  7. package/dist/agents/manager-profile-overlay-service.js +34 -0
  8. package/dist/agents/profile-model-routing.js +26 -0
  9. package/dist/agents/renderers/claude-renderer.js +98 -0
  10. package/dist/agents/renderers/index.js +16 -0
  11. package/dist/agents/renderers/json-renderer.js +87 -0
  12. package/dist/agents/renderers/opencode-renderer.js +100 -0
  13. package/dist/agents/renderers/provider-adapter.js +6 -0
  14. package/dist/agents/repositories/agents.js +185 -0
  15. package/dist/agents/repositories/manager-profile-overlays.js +81 -0
  16. package/dist/agents/schema.js +1 -0
  17. package/dist/cli/dashboard-operational-read-models.js +153 -0
  18. package/dist/cli/dashboard-renderer.js +109 -0
  19. package/dist/cli/dashboard-screen-renderers.js +332 -0
  20. package/dist/cli/dashboard-tui-read-model.js +71 -0
  21. package/dist/cli/dashboard-tui-state.js +218 -0
  22. package/dist/cli/dispatcher.js +2880 -0
  23. package/dist/cli/index.js +27 -0
  24. package/dist/cli/interactive-dashboard.js +29 -0
  25. package/dist/cli/mcp-start-path.js +21 -0
  26. package/dist/cli/setup-status-renderer.js +29 -0
  27. package/dist/cli/setup-wizard-read-model.js +56 -0
  28. package/dist/cli/setup-wizard-renderer.js +148 -0
  29. package/dist/cli/setup-wizard-state.js +82 -0
  30. package/dist/cli/tui-render-helpers.js +192 -0
  31. package/dist/export/redaction.js +71 -0
  32. package/dist/harness/tools/agents.js +245 -0
  33. package/dist/harness/tools/memory.js +29 -0
  34. package/dist/mcp/client-install-opencode-contract.js +227 -0
  35. package/dist/mcp/client-install-opencode.js +194 -0
  36. package/dist/mcp/client-setup-preview.js +38 -0
  37. package/dist/mcp/control-plane.js +175 -0
  38. package/dist/mcp/doctor.js +193 -0
  39. package/dist/mcp/index.js +10 -0
  40. package/dist/mcp/opencode-default-agent-config.js +156 -0
  41. package/dist/mcp/opencode-visibility.js +102 -0
  42. package/dist/mcp/schema.js +234 -0
  43. package/dist/mcp/stdio-server.js +56 -0
  44. package/dist/mcp/validation.js +761 -0
  45. package/dist/memory/import/dry-run-planner.js +58 -0
  46. package/dist/memory/import/index.js +3 -0
  47. package/dist/memory/import/observation-writer.js +220 -0
  48. package/dist/memory/import/package.js +178 -0
  49. package/dist/memory/memory-service.js +126 -0
  50. package/dist/memory/repositories/artifacts.js +41 -0
  51. package/dist/memory/repositories/observations.js +133 -0
  52. package/dist/memory/repositories/sessions.js +105 -0
  53. package/dist/memory/repositories/traces.js +58 -0
  54. package/dist/memory/schema.js +1 -0
  55. package/dist/memory/search.js +11 -0
  56. package/dist/memory/sqlite/database.js +97 -0
  57. package/dist/memory/sqlite/migrations/001_initial.sql +128 -0
  58. package/dist/memory/sqlite/migrations/002_observation_revisions.sql +14 -0
  59. package/dist/memory/sqlite/migrations/003_agent_registry.sql +26 -0
  60. package/dist/memory/sqlite/migrations/004_run_runtime.sql +62 -0
  61. package/dist/memory/sqlite/migrations/005_run_approvals.sql +20 -0
  62. package/dist/memory/sqlite/migrations/006_run_operation_attempts.sql +32 -0
  63. package/dist/memory/sqlite/migrations/007_abandoned_operation_attempts.sql +46 -0
  64. package/dist/memory/sqlite/migrations/008_run_execution_plan_events.sql +105 -0
  65. package/dist/memory/sqlite/migrations/009_multiple_operation_attempts.sql +73 -0
  66. package/dist/memory/sqlite/migrations/010_skill_registry.sql +66 -0
  67. package/dist/memory/sqlite/migrations/011_skill_usage_resolution_outcomes.sql +21 -0
  68. package/dist/memory/sqlite/migrations/012_skill_improvement_proposals.sql +37 -0
  69. package/dist/memory/sqlite/migrations/013_skill_evaluation_scenarios.sql +43 -0
  70. package/dist/memory/sqlite/migrations/014_manager_profile_overlays.sql +14 -0
  71. package/dist/memory/storage-paths.js +72 -0
  72. package/dist/orchestrator/natural-language-planner.js +191 -0
  73. package/dist/orchestrator/schema.js +1 -0
  74. package/dist/permissions/index.js +2 -0
  75. package/dist/permissions/policy-evaluator.js +109 -0
  76. package/dist/permissions/schema.js +1 -0
  77. package/dist/providers/opencode/injection-preview.js +134 -0
  78. package/dist/providers/opencode/manager-payload.js +129 -0
  79. package/dist/runs/execution-planning.js +117 -0
  80. package/dist/runs/operation-execution.js +1 -0
  81. package/dist/runs/operation-retry.js +124 -0
  82. package/dist/runs/repositories/runs.js +611 -0
  83. package/dist/runs/run-insights.js +145 -0
  84. package/dist/runs/run-service.js +713 -0
  85. package/dist/runs/run-snapshot-export-service.js +31 -0
  86. package/dist/runs/sandbox-process-execution.js +218 -0
  87. package/dist/runs/sandbox-worktree-planning.js +59 -0
  88. package/dist/runs/schema.js +1 -0
  89. package/dist/sdd/artifact-portability-service.js +118 -0
  90. package/dist/sdd/schema.js +17 -0
  91. package/dist/sdd/sdd-workflow-service.js +217 -0
  92. package/dist/setup/backup-rollback-service.js +76 -0
  93. package/dist/setup/index.js +3 -0
  94. package/dist/setup/providers/antigravity-setup-adapter.js +18 -0
  95. package/dist/setup/providers/claude-setup-adapter.js +30 -0
  96. package/dist/setup/providers/custom-setup-adapter.js +18 -0
  97. package/dist/setup/providers/index.js +6 -0
  98. package/dist/setup/providers/opencode-setup-adapter.js +104 -0
  99. package/dist/setup/providers/provider-setup-adapter.js +15 -0
  100. package/dist/setup/providers/provider-setup-registry.js +11 -0
  101. package/dist/setup/schema.js +1 -0
  102. package/dist/setup/setup-defaults.js +11 -0
  103. package/dist/setup/setup-lifecycle-service.js +175 -0
  104. package/dist/setup/setup-plan.js +105 -0
  105. package/dist/skills/repositories/skill-evaluation-scenarios.js +289 -0
  106. package/dist/skills/repositories/skill-improvement-proposals.js +288 -0
  107. package/dist/skills/repositories/skills.js +430 -0
  108. package/dist/skills/schema.js +1 -0
  109. package/dist/skills/skill-payload.js +94 -0
  110. package/dist/skills/skill-registry-service.js +92 -0
  111. package/dist/skills/skill-resolver.js +191 -0
  112. package/dist/workflows/command-allowlist-adapter.js +70 -0
  113. package/dist/workflows/schema.js +4 -0
  114. package/dist/workflows/workflow-executor.js +345 -0
  115. package/dist/workflows/workflow-registry.js +66 -0
  116. package/docs/architecture.md +698 -0
  117. package/docs/cli.md +741 -0
  118. package/docs/funcionamiento-del-sistema.md +868 -0
  119. package/docs/harness-gap-analysis.md +229 -0
  120. package/docs/prd.md +372 -0
  121. package/package.json +57 -0
@@ -0,0 +1,761 @@
1
+ import { isSddPhase, sddPhases } from '../sdd/schema.js';
2
+ import { errorEnvelope, isVgxMcpToolName } from './schema.js';
3
+ const scopes = ['project', 'personal'];
4
+ const agentModes = ['agent', 'subagent'];
5
+ const memoryTypes = ['architecture', 'decision', 'bugfix', 'pattern', 'config', 'discovery', 'learning', 'preference', 'manual'];
6
+ const activityKinds = ['prompt', 'tool_call', 'artifact', 'summary', 'error'];
7
+ const runStatuses = ['created', 'planned', 'running', 'needs-human', 'completed', 'failed', 'blocked', 'cancelled'];
8
+ const finalRunStatuses = ['completed', 'failed', 'blocked', 'cancelled'];
9
+ const runOutcomes = ['success', 'partial', 'failure', 'blocked', 'cancelled'];
10
+ const permissionCategories = ['read', 'edit', 'shell', 'network', 'git', 'memory', 'external-directory', 'provider-tool', 'secrets'];
11
+ const permissionDecisions = ['allow', 'ask', 'deny'];
12
+ const validChangePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
13
+ const validMemoryTopicKeyPattern = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;
14
+ const maxMemoryTitleLength = 200;
15
+ const maxMemoryContentLength = 20_000;
16
+ const maxMemoryTopicKeyLength = 200;
17
+ export function validateVgxMcpToolCall(call) {
18
+ const envelope = asRecord(call, undefined, 'Tool call must be an object');
19
+ if (!envelope.ok)
20
+ return toValidationResultFailure(envelope);
21
+ const tool = readString(envelope.value, 'tool', undefined);
22
+ if (!tool.ok)
23
+ return toValidationResultFailure(tool);
24
+ if (!isVgxMcpToolName(tool.value))
25
+ return toValidationResultFailure(validationFailure(`Unsupported MCP control-plane tool: ${tool.value}`));
26
+ const input = envelope.value.input;
27
+ switch (tool.value) {
28
+ case 'vgxness_sdd_status':
29
+ return validationSuccess(tool.value, validateSddStatusInput(input, tool.value));
30
+ case 'vgxness_sdd_ready':
31
+ return validationSuccess(tool.value, validateSddReadyInput(input, tool.value));
32
+ case 'vgxness_sdd_save_artifact':
33
+ return validationSuccess(tool.value, validateSddSaveArtifactInput(input, tool.value));
34
+ case 'vgxness_sdd_get_artifact':
35
+ return validationSuccess(tool.value, validateSddGetArtifactInput(input, tool.value));
36
+ case 'vgxness_sdd_list_artifacts':
37
+ return validationSuccess(tool.value, validateSddListArtifactsInput(input, tool.value));
38
+ case 'vgxness_sdd_next':
39
+ return validationSuccess(tool.value, validateSddNextInput(input, tool.value));
40
+ case 'vgxness_memory_save':
41
+ return validationSuccess(tool.value, validateMemorySaveInput(input, tool.value));
42
+ case 'vgxness_memory_search':
43
+ return validationSuccess(tool.value, validateMemorySearchInput(input, tool.value));
44
+ case 'vgxness_memory_get':
45
+ return validationSuccess(tool.value, validateMemoryGetInput(input, tool.value));
46
+ case 'vgxness_memory_update':
47
+ return validationSuccess(tool.value, validateMemoryUpdateInput(input, tool.value));
48
+ case 'vgxness_session_start':
49
+ return validationSuccess(tool.value, validateSessionStartInput(input, tool.value));
50
+ case 'vgxness_session_append_activity':
51
+ return validationSuccess(tool.value, validateSessionAppendActivityInput(input, tool.value));
52
+ case 'vgxness_session_close':
53
+ return validationSuccess(tool.value, validateSessionCloseInput(input, tool.value));
54
+ case 'vgxness_session_restore':
55
+ return validationSuccess(tool.value, validateSessionRestoreInput(input, tool.value));
56
+ case 'vgxness_agent_resolve':
57
+ return validationSuccess(tool.value, validateAgentResolveInput(input, tool.value));
58
+ case 'vgxness_agent_activate':
59
+ return validationSuccess(tool.value, validateAgentActivateInput(input, tool.value));
60
+ case 'vgxness_manager_profile_get':
61
+ return validationSuccess(tool.value, validateManagerProfileGetInput(input, tool.value));
62
+ case 'vgxness_manager_profile_set':
63
+ return validationSuccess(tool.value, validateManagerProfileSetInput(input, tool.value));
64
+ case 'vgxness_skill_payload':
65
+ return validationSuccess(tool.value, validateSkillPayloadInput(input, tool.value));
66
+ case 'vgxness_opencode_manager_payload':
67
+ return validationSuccess(tool.value, validateOpenCodeManagerPayloadInput(input, tool.value));
68
+ case 'vgxness_run_list':
69
+ return validationSuccess(tool.value, validateRunListInput(input, tool.value));
70
+ case 'vgxness_run_get':
71
+ return validationSuccess(tool.value, validateRunGetInput(input, tool.value));
72
+ case 'vgxness_run_preflight':
73
+ return validationSuccess(tool.value, validateRunPreflightInput(input, tool.value));
74
+ case 'vgxness_run_start':
75
+ return validationSuccess(tool.value, validateRunStartInput(input, tool.value));
76
+ case 'vgxness_run_checkpoint':
77
+ return validationSuccess(tool.value, validateRunCheckpointInput(input, tool.value));
78
+ case 'vgxness_run_finalize':
79
+ return validationSuccess(tool.value, validateRunFinalizeInput(input, tool.value));
80
+ }
81
+ }
82
+ export function validateVgxMcpToolInput(tool, input) {
83
+ return validateVgxMcpToolCall({ tool, input });
84
+ }
85
+ function validateSddStatusInput(input, tool) {
86
+ const record = inputRecord(input, tool, ['project', 'change']);
87
+ if (!record.ok)
88
+ return record;
89
+ return readProjectAndChange(record.value, tool);
90
+ }
91
+ function validateSddNextInput(input, tool) {
92
+ const record = inputRecord(input, tool, ['project', 'change']);
93
+ if (!record.ok)
94
+ return record;
95
+ return readProjectAndChange(record.value, tool);
96
+ }
97
+ function readProjectAndChange(record, tool) {
98
+ const project = readNonEmptyString(record, 'project', tool);
99
+ if (!project.ok)
100
+ return project;
101
+ const change = readChange(record, tool);
102
+ if (!change.ok)
103
+ return change;
104
+ return { ok: true, value: { project: project.value, change: change.value } };
105
+ }
106
+ function validateSddReadyInput(input, tool) {
107
+ const record = inputRecord(input, tool, ['project', 'change', 'phase']);
108
+ if (!record.ok)
109
+ return record;
110
+ const base = readProjectAndChange(record.value, tool);
111
+ if (!base.ok)
112
+ return base;
113
+ const phase = readPhase(record.value, tool);
114
+ if (!phase.ok)
115
+ return phase;
116
+ return { ok: true, value: { ...base.value, phase: phase.value } };
117
+ }
118
+ function validateSddSaveArtifactInput(input, tool) {
119
+ const record = inputRecord(input, tool, ['project', 'change', 'phase', 'content']);
120
+ if (!record.ok)
121
+ return record;
122
+ const base = readProjectAndChange(record.value, tool);
123
+ if (!base.ok)
124
+ return base;
125
+ const phase = readPhase(record.value, tool);
126
+ if (!phase.ok)
127
+ return phase;
128
+ const content = readNonEmptyString(record.value, 'content', tool);
129
+ if (!content.ok)
130
+ return content;
131
+ return { ok: true, value: { ...base.value, phase: phase.value, content: content.value } };
132
+ }
133
+ function validateSddGetArtifactInput(input, tool) {
134
+ const record = inputRecord(input, tool, ['project', 'change', 'phase']);
135
+ if (!record.ok)
136
+ return record;
137
+ const base = readProjectAndChange(record.value, tool);
138
+ if (!base.ok)
139
+ return base;
140
+ const phase = readPhase(record.value, tool);
141
+ if (!phase.ok)
142
+ return phase;
143
+ return { ok: true, value: { ...base.value, phase: phase.value } };
144
+ }
145
+ function validateSddListArtifactsInput(input, tool) {
146
+ const record = inputRecord(input, tool, ['project', 'change']);
147
+ if (!record.ok)
148
+ return record;
149
+ return readProjectAndChange(record.value, tool);
150
+ }
151
+ function validateMemorySaveInput(input, tool) {
152
+ const record = inputRecord(input, tool, ['project', 'scope', 'type', 'title', 'content', 'topicKey']);
153
+ if (!record.ok)
154
+ return record;
155
+ const project = readLimitedNonEmptyString(record.value, 'project', tool, undefined);
156
+ if (!project.ok)
157
+ return project;
158
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
159
+ if (!scope.ok)
160
+ return scope;
161
+ const type = readRequiredOneOf(record.value, 'type', memoryTypes, tool);
162
+ if (!type.ok)
163
+ return type;
164
+ const title = readLimitedNonEmptyString(record.value, 'title', tool, maxMemoryTitleLength);
165
+ if (!title.ok)
166
+ return title;
167
+ const content = readLimitedNonEmptyString(record.value, 'content', tool, maxMemoryContentLength);
168
+ if (!content.ok)
169
+ return content;
170
+ const topicKey = readOptionalTopicKey(record.value, tool);
171
+ if (!topicKey.ok)
172
+ return topicKey;
173
+ const result = { project: project.value, scope: scope.value ?? 'project', type: type.value, title: title.value, content: content.value };
174
+ if (topicKey.value !== undefined)
175
+ result.topicKey = topicKey.value;
176
+ return { ok: true, value: result };
177
+ }
178
+ function validateMemorySearchInput(input, tool) {
179
+ const record = inputRecord(input, tool, ['project', 'scope', 'type', 'topicKey', 'query', 'limit']);
180
+ if (!record.ok)
181
+ return record;
182
+ const result = {};
183
+ const copied = copyOptionalLimitedStrings(result, record.value, tool, ['project', 'query'], undefined);
184
+ if (!copied.ok)
185
+ return copied;
186
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
187
+ if (!scope.ok)
188
+ return scope;
189
+ if (scope.value !== undefined)
190
+ result.scope = scope.value;
191
+ const type = readOptionalOneOf(record.value, 'type', memoryTypes, tool);
192
+ if (!type.ok)
193
+ return type;
194
+ if (type.value !== undefined)
195
+ result.type = type.value;
196
+ const topicKey = readOptionalTopicKey(record.value, tool);
197
+ if (!topicKey.ok)
198
+ return topicKey;
199
+ if (topicKey.value !== undefined)
200
+ result.topicKey = topicKey.value;
201
+ const limit = readMemorySearchLimit(record.value, tool);
202
+ if (!limit.ok)
203
+ return limit;
204
+ result.limit = limit.value;
205
+ return { ok: true, value: result };
206
+ }
207
+ function validateMemoryGetInput(input, tool) {
208
+ const record = inputRecord(input, tool, ['id']);
209
+ if (!record.ok)
210
+ return record;
211
+ const id = readNonEmptyString(record.value, 'id', tool);
212
+ if (!id.ok)
213
+ return id;
214
+ return { ok: true, value: { id: id.value } };
215
+ }
216
+ function validateMemoryUpdateInput(input, tool) {
217
+ const record = inputRecord(input, tool, ['id', 'type', 'title', 'content', 'topicKey']);
218
+ if (!record.ok)
219
+ return record;
220
+ const id = readNonEmptyString(record.value, 'id', tool);
221
+ if (!id.ok)
222
+ return id;
223
+ const result = { id: id.value };
224
+ const type = readOptionalOneOf(record.value, 'type', memoryTypes, tool);
225
+ if (!type.ok)
226
+ return type;
227
+ if (type.value !== undefined)
228
+ result.type = type.value;
229
+ const copied = copyOptionalLimitedStrings(result, record.value, tool, ['title', 'content'], undefined);
230
+ if (!copied.ok)
231
+ return copied;
232
+ if (result.title !== undefined && result.title.length > maxMemoryTitleLength)
233
+ return validationFailure(`title must be ${maxMemoryTitleLength} characters or fewer`, tool);
234
+ if (result.content !== undefined && result.content.length > maxMemoryContentLength)
235
+ return validationFailure(`content must be ${maxMemoryContentLength} characters or fewer`, tool);
236
+ const topicKey = readOptionalTopicKey(record.value, tool);
237
+ if (!topicKey.ok)
238
+ return topicKey;
239
+ if (topicKey.value !== undefined)
240
+ result.topicKey = topicKey.value;
241
+ if (result.type === undefined && result.title === undefined && result.content === undefined && result.topicKey === undefined) {
242
+ return validationFailure('At least one editable field is required', tool);
243
+ }
244
+ return { ok: true, value: result };
245
+ }
246
+ function validateSessionStartInput(input, tool) {
247
+ const record = inputRecord(input, tool, ['id', 'project', 'directory']);
248
+ if (!record.ok)
249
+ return record;
250
+ const project = readNonEmptyString(record.value, 'project', tool);
251
+ if (!project.ok)
252
+ return project;
253
+ const result = { project: project.value };
254
+ const copied = copyOptionalStrings(result, record.value, tool, ['id', 'directory']);
255
+ if (!copied.ok)
256
+ return copied;
257
+ return { ok: true, value: result };
258
+ }
259
+ function validateSessionAppendActivityInput(input, tool) {
260
+ const record = inputRecord(input, tool, ['sessionId', 'actor', 'kind', 'payloadJson']);
261
+ if (!record.ok)
262
+ return record;
263
+ const result = {};
264
+ const copied = copyRequiredStrings(result, record.value, tool, ['sessionId', 'actor', 'payloadJson']);
265
+ if (!copied.ok)
266
+ return copied;
267
+ const kind = readRequiredOneOf(record.value, 'kind', activityKinds, tool);
268
+ if (!kind.ok)
269
+ return kind;
270
+ result.kind = kind.value;
271
+ return { ok: true, value: result };
272
+ }
273
+ function validateSessionCloseInput(input, tool) {
274
+ const record = inputRecord(input, tool, ['sessionId', 'actor', 'summary']);
275
+ if (!record.ok)
276
+ return record;
277
+ const result = {};
278
+ const copied = copyRequiredStrings(result, record.value, tool, ['sessionId', 'actor', 'summary']);
279
+ if (!copied.ok)
280
+ return copied;
281
+ return { ok: true, value: result };
282
+ }
283
+ function validateSessionRestoreInput(input, tool) {
284
+ const record = inputRecord(input, tool, ['project', 'directory']);
285
+ if (!record.ok)
286
+ return record;
287
+ const project = readNonEmptyString(record.value, 'project', tool);
288
+ if (!project.ok)
289
+ return project;
290
+ const result = { project: project.value };
291
+ const copied = copyOptionalStrings(result, record.value, tool, ['directory']);
292
+ if (!copied.ok)
293
+ return copied;
294
+ return { ok: true, value: result };
295
+ }
296
+ function validateAgentResolveInput(input, tool) {
297
+ const record = inputRecord(input, tool, ['project', 'scope', 'taskDescription', 'intent', 'desiredCapabilities', 'workflow', 'phase', 'providerAdapter', 'mode']);
298
+ if (!record.ok)
299
+ return record;
300
+ const result = {};
301
+ const copied = copyOptionalStrings(result, record.value, tool, ['project', 'taskDescription', 'intent', 'workflow', 'phase', 'providerAdapter']);
302
+ if (!copied.ok)
303
+ return copied;
304
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
305
+ if (!scope.ok)
306
+ return scope;
307
+ if (scope.value !== undefined)
308
+ result.scope = scope.value;
309
+ const mode = readOptionalOneOf(record.value, 'mode', agentModes, tool);
310
+ if (!mode.ok)
311
+ return mode;
312
+ if (mode.value !== undefined)
313
+ result.mode = mode.value;
314
+ const desiredCapabilities = readOptionalStringArray(record.value, 'desiredCapabilities', tool);
315
+ if (!desiredCapabilities.ok)
316
+ return desiredCapabilities;
317
+ if (desiredCapabilities.value !== undefined)
318
+ result.desiredCapabilities = desiredCapabilities.value;
319
+ return { ok: true, value: result };
320
+ }
321
+ function validateAgentActivateInput(input, tool) {
322
+ const record = inputRecord(input, tool, ['project', 'scope', 'agentId', 'userIntent', 'workflow', 'phase', 'workspaceRoot', 'maxSourceBytes', 'providerAdapter']);
323
+ if (!record.ok)
324
+ return record;
325
+ const project = readNonEmptyString(record.value, 'project', tool);
326
+ if (!project.ok)
327
+ return project;
328
+ const userIntent = readNonEmptyString(record.value, 'userIntent', tool);
329
+ if (!userIntent.ok)
330
+ return userIntent;
331
+ const result = { project: project.value, scope: 'project', userIntent: userIntent.value, workflow: 'agent-activation', phase: 'activation' };
332
+ const copied = copyOptionalStrings(result, record.value, tool, ['agentId', 'workflow', 'phase', 'workspaceRoot']);
333
+ if (!copied.ok)
334
+ return copied;
335
+ if (record.value.providerAdapter !== undefined) {
336
+ const providerAdapter = readNonEmptyString(record.value, 'providerAdapter', tool);
337
+ if (!providerAdapter.ok)
338
+ return providerAdapter;
339
+ result.providerAdapter = providerAdapter.value.trim();
340
+ }
341
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
342
+ if (!scope.ok)
343
+ return scope;
344
+ result.scope = scope.value ?? 'project';
345
+ if (record.value.maxSourceBytes !== undefined) {
346
+ const maxSourceBytes = record.value.maxSourceBytes;
347
+ if (typeof maxSourceBytes !== 'number' || !Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)
348
+ return validationFailure('maxSourceBytes must be a positive safe integer', tool);
349
+ result.maxSourceBytes = maxSourceBytes;
350
+ }
351
+ return { ok: true, value: result };
352
+ }
353
+ function validateSkillPayloadInput(input, tool) {
354
+ const record = inputRecord(input, tool, ['workspaceRoot', 'maxSourceBytes', 'project', 'scope', 'agentId', 'agentName', 'workflow', 'phase', 'providerAdapter', 'runId']);
355
+ if (!record.ok)
356
+ return record;
357
+ const workspaceRoot = readNonEmptyString(record.value, 'workspaceRoot', tool);
358
+ if (!workspaceRoot.ok)
359
+ return workspaceRoot;
360
+ const result = { workspaceRoot: workspaceRoot.value };
361
+ const copied = copyOptionalStrings(result, record.value, tool, ['project', 'agentId', 'agentName', 'workflow', 'phase', 'providerAdapter', 'runId']);
362
+ if (!copied.ok)
363
+ return copied;
364
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
365
+ if (!scope.ok)
366
+ return scope;
367
+ if (scope.value !== undefined)
368
+ result.scope = scope.value;
369
+ if (record.value.maxSourceBytes !== undefined) {
370
+ const maxSourceBytes = record.value.maxSourceBytes;
371
+ if (typeof maxSourceBytes !== 'number' || !Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)
372
+ return validationFailure('maxSourceBytes must be a positive safe integer', tool);
373
+ result.maxSourceBytes = maxSourceBytes;
374
+ }
375
+ return { ok: true, value: result };
376
+ }
377
+ function validateManagerProfileGetInput(input, tool) {
378
+ const record = inputRecord(input, tool, ['project', 'scope', 'managerName']);
379
+ if (!record.ok)
380
+ return record;
381
+ const project = readNonEmptyString(record.value, 'project', tool);
382
+ if (!project.ok)
383
+ return project;
384
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
385
+ if (!scope.ok)
386
+ return scope;
387
+ const result = { project: project.value };
388
+ if (scope.value !== undefined)
389
+ result.scope = scope.value;
390
+ const copied = copyOptionalStrings(result, record.value, tool, ['managerName']);
391
+ if (!copied.ok)
392
+ return copied;
393
+ return { ok: true, value: result };
394
+ }
395
+ function validateManagerProfileSetInput(input, tool) {
396
+ const record = inputRecord(input, tool, ['project', 'scope', 'managerName', 'instructions']);
397
+ if (!record.ok)
398
+ return record;
399
+ const result = {};
400
+ const copied = copyRequiredStrings(result, record.value, tool, ['project', 'managerName', 'instructions']);
401
+ if (!copied.ok)
402
+ return copied;
403
+ const scope = readRequiredOneOf(record.value, 'scope', scopes, tool);
404
+ if (!scope.ok)
405
+ return scope;
406
+ result.scope = scope.value;
407
+ return { ok: true, value: result };
408
+ }
409
+ function validateOpenCodeManagerPayloadInput(input, tool) {
410
+ const record = inputRecord(input, tool, ['project', 'scope', 'agentId', 'agentName', 'workspaceRoot', 'maxSourceBytes']);
411
+ if (!record.ok)
412
+ return record;
413
+ const project = readNonEmptyString(record.value, 'project', tool);
414
+ if (!project.ok)
415
+ return project;
416
+ const result = { project: project.value };
417
+ const copied = copyOptionalStrings(result, record.value, tool, ['agentId', 'agentName', 'workspaceRoot']);
418
+ if (!copied.ok)
419
+ return copied;
420
+ // Some MCP hosts expose optional fields as required in their generated tool
421
+ // facade. Accept both selectors here and let the provider payload service
422
+ // verify that they refer to the same top-level agent.
423
+ if (result.agentId === undefined && result.agentName === undefined)
424
+ result.agentName = 'vgxness-manager';
425
+ const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
426
+ if (!scope.ok)
427
+ return scope;
428
+ result.scope = scope.value ?? 'project';
429
+ if (record.value.maxSourceBytes !== undefined) {
430
+ const maxSourceBytes = record.value.maxSourceBytes;
431
+ if (typeof maxSourceBytes !== 'number' || !Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)
432
+ return validationFailure('maxSourceBytes must be a positive safe integer', tool);
433
+ result.maxSourceBytes = maxSourceBytes;
434
+ }
435
+ return { ok: true, value: result };
436
+ }
437
+ function validateRunListInput(input, tool) {
438
+ const record = inputRecord(input, tool, ['project', 'status', 'limit']);
439
+ if (!record.ok)
440
+ return record;
441
+ const result = {};
442
+ const project = copyOptionalStrings(result, record.value, tool, ['project']);
443
+ if (!project.ok)
444
+ return project;
445
+ const status = readOptionalOneOf(record.value, 'status', runStatuses, tool);
446
+ if (!status.ok)
447
+ return status;
448
+ if (status.value !== undefined)
449
+ result.status = status.value;
450
+ const limit = readBoundedLimit(record.value, tool);
451
+ if (!limit.ok)
452
+ return limit;
453
+ result.limit = limit.value;
454
+ return { ok: true, value: result };
455
+ }
456
+ function validateRunGetInput(input, tool) {
457
+ const record = inputRecord(input, tool, ['id']);
458
+ if (!record.ok)
459
+ return record;
460
+ const id = readNonEmptyString(record.value, 'id', tool);
461
+ if (!id.ok)
462
+ return id;
463
+ return { ok: true, value: { id: id.value } };
464
+ }
465
+ function validateRunPreflightInput(input, tool) {
466
+ const record = inputRecord(input, tool, ['runId', 'category', 'operation', 'workspaceRoot', 'targetPath', 'providerToolName', 'agent', 'sandboxStrategy', 'destructive', 'external', 'privileged', 'ambiguous']);
467
+ if (!record.ok)
468
+ return record;
469
+ const runId = readNonEmptyString(record.value, 'runId', tool);
470
+ if (!runId.ok)
471
+ return runId;
472
+ const category = readRequiredOneOf(record.value, 'category', permissionCategories, tool);
473
+ if (!category.ok)
474
+ return category;
475
+ const operation = readNonEmptyString(record.value, 'operation', tool);
476
+ if (!operation.ok)
477
+ return operation;
478
+ const result = { runId: runId.value, category: category.value, operation: operation.value };
479
+ const copied = copyOptionalStrings(result, record.value, tool, ['workspaceRoot', 'targetPath', 'providerToolName']);
480
+ if (!copied.ok)
481
+ return copied;
482
+ const sandboxStrategy = readOptionalOneOf(record.value, 'sandboxStrategy', ['worktree'], tool);
483
+ if (!sandboxStrategy.ok)
484
+ return sandboxStrategy;
485
+ if (sandboxStrategy.value !== undefined)
486
+ result.sandboxStrategy = sandboxStrategy.value;
487
+ const booleans = copyOptionalBooleans(result, record.value, tool, ['destructive', 'external', 'privileged', 'ambiguous']);
488
+ if (!booleans.ok)
489
+ return booleans;
490
+ if (record.value.agent !== undefined) {
491
+ const agent = readPreflightAgent(record.value.agent, tool);
492
+ if (!agent.ok)
493
+ return agent;
494
+ result.agent = agent.value;
495
+ }
496
+ return { ok: true, value: result };
497
+ }
498
+ function validateRunStartInput(input, tool) {
499
+ const record = inputRecord(input, tool, ['project', 'userIntent', 'workflow', 'phase', 'selectedAgentId', 'providerAdapter', 'model']);
500
+ if (!record.ok)
501
+ return record;
502
+ const result = {};
503
+ const copied = copyRequiredStrings(result, record.value, tool, ['project', 'userIntent', 'workflow', 'phase', 'selectedAgentId', 'providerAdapter', 'model']);
504
+ if (!copied.ok)
505
+ return copied;
506
+ return { ok: true, value: result };
507
+ }
508
+ function validateRunCheckpointInput(input, tool) {
509
+ const record = inputRecord(input, tool, ['runId', 'label', 'state']);
510
+ if (!record.ok)
511
+ return record;
512
+ const runId = readNonEmptyString(record.value, 'runId', tool);
513
+ if (!runId.ok)
514
+ return runId;
515
+ const label = readNonEmptyString(record.value, 'label', tool);
516
+ if (!label.ok)
517
+ return label;
518
+ const state = readJsonValue(record.value, 'state', tool);
519
+ if (!state.ok)
520
+ return state;
521
+ return { ok: true, value: { runId: runId.value, label: label.value, state: state.value } };
522
+ }
523
+ function validateRunFinalizeInput(input, tool) {
524
+ const record = inputRecord(input, tool, ['runId', 'status', 'outcome', 'outcomeReason']);
525
+ if (!record.ok)
526
+ return record;
527
+ const runId = readNonEmptyString(record.value, 'runId', tool);
528
+ if (!runId.ok)
529
+ return runId;
530
+ const status = readRequiredOneOf(record.value, 'status', finalRunStatuses, tool);
531
+ if (!status.ok)
532
+ return status;
533
+ const outcome = readRequiredOneOf(record.value, 'outcome', runOutcomes, tool);
534
+ if (!outcome.ok)
535
+ return outcome;
536
+ const result = { runId: runId.value, status: status.value, outcome: outcome.value };
537
+ const copied = copyOptionalStrings(result, record.value, tool, ['outcomeReason']);
538
+ if (!copied.ok)
539
+ return copied;
540
+ return { ok: true, value: result };
541
+ }
542
+ function validationSuccess(tool, validation) {
543
+ if (!validation.ok)
544
+ return validation;
545
+ return { ok: true, tool, input: validation.value };
546
+ }
547
+ function inputRecord(input, tool, allowed) {
548
+ const record = asRecord(input, tool, 'Tool input must be an object');
549
+ if (!record.ok)
550
+ return record;
551
+ const unexpected = Object.keys(record.value).find((key) => !allowed.includes(key));
552
+ if (unexpected !== undefined)
553
+ return validationFailure(`Unexpected field: ${unexpected}`, tool);
554
+ return record;
555
+ }
556
+ function asRecord(value, tool, message) {
557
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
558
+ return validationFailure(message, tool);
559
+ return { ok: true, value: value };
560
+ }
561
+ function readString(record, field, tool) {
562
+ const value = record[field];
563
+ if (typeof value !== 'string')
564
+ return validationFailure(`${field} must be a string`, tool);
565
+ return { ok: true, value };
566
+ }
567
+ function readNonEmptyString(record, field, tool) {
568
+ if (record[field] === undefined)
569
+ return validationFailure(`${field} is required`, tool);
570
+ const value = readString(record, field, tool);
571
+ if (!value.ok)
572
+ return value;
573
+ if (value.value.trim().length === 0)
574
+ return validationFailure(`${field} must not be empty`, tool);
575
+ return value;
576
+ }
577
+ function readChange(record, tool) {
578
+ const change = readNonEmptyString(record, 'change', tool);
579
+ if (!change.ok)
580
+ return change;
581
+ if (!validChangePattern.test(change.value))
582
+ return validationFailure(`Invalid SDD change id: ${change.value}`, tool);
583
+ return change;
584
+ }
585
+ function readPhase(record, tool) {
586
+ const phase = readNonEmptyString(record, 'phase', tool);
587
+ if (!phase.ok)
588
+ return phase;
589
+ if (!isSddPhase(phase.value))
590
+ return validationFailure(`phase must be one of: ${sddPhases.join(', ')}`, tool);
591
+ return { ok: true, value: phase.value };
592
+ }
593
+ function copyOptionalStrings(target, record, tool, fields) {
594
+ for (const field of fields) {
595
+ if (record[field] === undefined)
596
+ continue;
597
+ const value = readNonEmptyString(record, field, tool);
598
+ if (!value.ok)
599
+ return value;
600
+ target[field] = value.value;
601
+ }
602
+ return { ok: true, value: undefined };
603
+ }
604
+ function copyRequiredStrings(target, record, tool, fields) {
605
+ for (const field of fields) {
606
+ const value = readNonEmptyString(record, field, tool);
607
+ if (!value.ok)
608
+ return value;
609
+ target[field] = value.value;
610
+ }
611
+ return { ok: true, value: undefined };
612
+ }
613
+ function readJsonValue(record, field, tool) {
614
+ if (record[field] === undefined)
615
+ return validationFailure(`${field} is required`, tool);
616
+ if (!isJsonValue(record[field]))
617
+ return validationFailure(`${field} must be JSON-compatible`, tool);
618
+ return { ok: true, value: record[field] };
619
+ }
620
+ function isJsonValue(value) {
621
+ if (value === null)
622
+ return true;
623
+ if (typeof value === 'string' || typeof value === 'boolean')
624
+ return true;
625
+ if (typeof value === 'number')
626
+ return Number.isFinite(value);
627
+ if (Array.isArray(value))
628
+ return value.every(isJsonValue);
629
+ if (typeof value !== 'object')
630
+ return false;
631
+ return Object.values(value).every(isJsonValue);
632
+ }
633
+ function copyOptionalBooleans(target, record, tool, fields) {
634
+ for (const field of fields) {
635
+ if (record[field] === undefined)
636
+ continue;
637
+ if (typeof record[field] !== 'boolean')
638
+ return validationFailure(`${field} must be a boolean`, tool);
639
+ target[field] = record[field];
640
+ }
641
+ return { ok: true, value: undefined };
642
+ }
643
+ function readPreflightAgent(value, tool) {
644
+ const record = asRecord(value, tool, 'agent must be an object');
645
+ if (!record.ok)
646
+ return record;
647
+ const unexpected = Object.keys(record.value).find((key) => !['id', 'name', 'mode', 'permissions'].includes(key));
648
+ if (unexpected !== undefined)
649
+ return validationFailure(`Unexpected agent field: ${unexpected}`, tool);
650
+ const id = readNonEmptyString(record.value, 'id', tool);
651
+ if (!id.ok)
652
+ return id;
653
+ const mode = readRequiredOneOf(record.value, 'mode', agentModes, tool);
654
+ if (!mode.ok)
655
+ return mode;
656
+ const agent = { id: id.value, name: id.value, mode: mode.value, permissions: {} };
657
+ const name = copyOptionalStrings(agent, record.value, tool, ['name']);
658
+ if (!name.ok)
659
+ return name;
660
+ if (record.value.permissions !== undefined) {
661
+ const permissions = readPreflightAgentPermissions(record.value.permissions, tool);
662
+ if (!permissions.ok)
663
+ return permissions;
664
+ agent.permissions = permissions.value;
665
+ }
666
+ return { ok: true, value: agent };
667
+ }
668
+ function readPreflightAgentPermissions(value, tool) {
669
+ const record = asRecord(value, tool, 'agent.permissions must be an object');
670
+ if (!record.ok)
671
+ return record;
672
+ const permissions = {};
673
+ for (const [category, decision] of Object.entries(record.value)) {
674
+ if (!permissionCategories.includes(category))
675
+ return validationFailure(`agent.permissions category must be one of: ${permissionCategories.join(', ')}`, tool);
676
+ if (typeof decision !== 'string' || !permissionDecisions.includes(decision))
677
+ return validationFailure(`agent.permissions.${category} must be one of: ${permissionDecisions.join(', ')}`, tool);
678
+ permissions[category] = decision;
679
+ }
680
+ return { ok: true, value: permissions };
681
+ }
682
+ function copyOptionalLimitedStrings(target, record, tool, fields, maxLength) {
683
+ for (const field of fields) {
684
+ if (record[field] === undefined)
685
+ continue;
686
+ const value = readLimitedNonEmptyString(record, field, tool, maxLength);
687
+ if (!value.ok)
688
+ return value;
689
+ target[field] = value.value;
690
+ }
691
+ return { ok: true, value: undefined };
692
+ }
693
+ function readLimitedNonEmptyString(record, field, tool, maxLength) {
694
+ const value = readNonEmptyString(record, field, tool);
695
+ if (!value.ok)
696
+ return value;
697
+ if (maxLength !== undefined && value.value.length > maxLength)
698
+ return validationFailure(`${field} must be ${maxLength} characters or fewer`, tool);
699
+ return value;
700
+ }
701
+ function readRequiredOneOf(record, field, values, tool) {
702
+ const value = readNonEmptyString(record, field, tool);
703
+ if (!value.ok)
704
+ return value;
705
+ if (!values.includes(value.value))
706
+ return validationFailure(`${field} must be one of: ${values.join(', ')}`, tool);
707
+ return { ok: true, value: value.value };
708
+ }
709
+ function readOptionalOneOf(record, field, values, tool) {
710
+ if (record[field] === undefined)
711
+ return { ok: true, value: undefined };
712
+ const value = readNonEmptyString(record, field, tool);
713
+ if (!value.ok)
714
+ return value;
715
+ if (!values.includes(value.value))
716
+ return validationFailure(`${field} must be one of: ${values.join(', ')}`, tool);
717
+ return { ok: true, value: value.value };
718
+ }
719
+ function readOptionalTopicKey(record, tool) {
720
+ if (record.topicKey === undefined)
721
+ return { ok: true, value: undefined };
722
+ const topicKey = readLimitedNonEmptyString(record, 'topicKey', tool, maxMemoryTopicKeyLength);
723
+ if (!topicKey.ok)
724
+ return topicKey;
725
+ if (!validMemoryTopicKeyPattern.test(topicKey.value))
726
+ return validationFailure('topicKey must contain only letters, numbers, dots, underscores, slashes, or hyphens', tool);
727
+ return topicKey;
728
+ }
729
+ function readMemorySearchLimit(record, tool) {
730
+ return readBoundedLimit(record, tool);
731
+ }
732
+ function readBoundedLimit(record, tool) {
733
+ if (record.limit === undefined)
734
+ return validationFailure('limit is required', tool);
735
+ const limit = record.limit;
736
+ if (typeof limit !== 'number' || !Number.isSafeInteger(limit) || limit < 1 || limit > 100)
737
+ return validationFailure('limit must be between 1 and 100', tool);
738
+ return { ok: true, value: limit };
739
+ }
740
+ function readOptionalStringArray(record, field, tool) {
741
+ if (record[field] === undefined)
742
+ return { ok: true, value: undefined };
743
+ if (!Array.isArray(record[field]))
744
+ return validationFailure(`${field} must be an array`, tool);
745
+ const values = record[field];
746
+ const result = [];
747
+ for (const [index, item] of values.entries()) {
748
+ if (typeof item !== 'string')
749
+ return validationFailure(`${field}[${index}] must be a string`, tool);
750
+ if (item.trim().length === 0)
751
+ return validationFailure(`${field}[${index}] must not be empty`, tool);
752
+ result.push(item);
753
+ }
754
+ return { ok: true, value: result };
755
+ }
756
+ function validationFailure(message, tool) {
757
+ return errorEnvelope('validation_failed', message, tool);
758
+ }
759
+ function toValidationResultFailure(failure) {
760
+ return failure;
761
+ }