vgxness 1.17.2 → 1.18.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.
- package/dist/mcp/control-plane.js +55 -0
- package/dist/mcp/schema.js +253 -0
- package/dist/mcp/stdio-server.js +6 -0
- package/dist/mcp/validation.js +662 -0
- package/dist/memory/sqlite/migrations/018_skill_system_v2.sql +112 -0
- package/dist/skills/repositories/skill-evaluation-requests.js +190 -0
- package/dist/skills/repositories/skill-improvement-proposals.js +55 -4
- package/dist/skills/repositories/skills.js +630 -3
- package/dist/skills/skill-payload.js +9 -2
- package/dist/skills/skill-registry-service.js +554 -4
- package/dist/skills/skill-status-service.js +4 -1
- package/package.json +1 -1
package/dist/mcp/validation.js
CHANGED
|
@@ -14,6 +14,12 @@ const runOutcomes = ['success', 'partial', 'failure', 'blocked', 'cancelled'];
|
|
|
14
14
|
const permissionDecisions = ['allow', 'ask', 'deny'];
|
|
15
15
|
const payloadModes = ['compact', 'verbose'];
|
|
16
16
|
const contextCockpitLevels = ['compact', 'expanded', 'verbose'];
|
|
17
|
+
const skillVersionStatuses = ['draft', 'active', 'deprecated', 'archived'];
|
|
18
|
+
const skillImprovementProposalStatuses = ['draft', 'pending-approval', 'approved', 'rejected', 'cancelled', 'applied'];
|
|
19
|
+
const skillEvaluationRequestStatuses = ['requested', 'planned', 'running', 'completed', 'failed', 'cancelled', 'skipped'];
|
|
20
|
+
const skillSourceKinds = ['path', 'url', 'inline'];
|
|
21
|
+
const skillUsageOutcomes = ['selected', 'injected', 'helped', 'failed', 'neutral'];
|
|
22
|
+
const skillAttachmentTargetTypes = ['agent', 'subagent', 'workflow-phase', 'provider-adapter', 'intent-signal'];
|
|
17
23
|
const providerChangePlanProviders = ['opencode', 'claude', 'antigravity', 'custom'];
|
|
18
24
|
const providerChangePlanTypes = ['opencode-mcp-install', 'claude-mcp-install', 'setup', 'install', 'config-preparation'];
|
|
19
25
|
const providerInstallTargets = ['user-global'];
|
|
@@ -86,8 +92,34 @@ export function validateVgxMcpToolCall(call) {
|
|
|
86
92
|
return validationSuccess(tool.value, validateManagerProfileSetInput(input, tool.value));
|
|
87
93
|
case 'vgxness_skill_index':
|
|
88
94
|
return validationSuccess(tool.value, validateSkillIndexInput(input, tool.value));
|
|
95
|
+
case 'vgxness_skill_search':
|
|
96
|
+
return validationSuccess(tool.value, validateSkillSearchInput(input, tool.value));
|
|
97
|
+
case 'vgxness_skill_get':
|
|
98
|
+
return validationSuccess(tool.value, validateSkillGetInput(input, tool.value));
|
|
99
|
+
case 'vgxness_skill_status':
|
|
100
|
+
return validationSuccess(tool.value, validateSkillStatusInput(input, tool.value));
|
|
89
101
|
case 'vgxness_skill_payload':
|
|
90
102
|
return validationSuccess(tool.value, validateSkillPayloadInput(input, tool.value));
|
|
103
|
+
case 'vgxness_skill_activate':
|
|
104
|
+
return validationSuccess(tool.value, validateSkillActivateInput(input, tool.value));
|
|
105
|
+
case 'vgxness_skill_record_usage':
|
|
106
|
+
return validationSuccess(tool.value, validateSkillRecordUsageInput(input, tool.value));
|
|
107
|
+
case 'vgxness_skill_propose_improvement':
|
|
108
|
+
return validationSuccess(tool.value, validateSkillProposeImprovementInput(input, tool.value));
|
|
109
|
+
case 'vgxness_skill_list_improvement_proposals':
|
|
110
|
+
return validationSuccess(tool.value, validateSkillListImprovementProposalsInput(input, tool.value));
|
|
111
|
+
case 'vgxness_skill_request_evaluation':
|
|
112
|
+
return validationSuccess(tool.value, validateSkillRequestEvaluationInput(input, tool.value));
|
|
113
|
+
case 'vgxness_skill_list_evaluations':
|
|
114
|
+
return validationSuccess(tool.value, validateSkillListEvaluationsInput(input, tool.value));
|
|
115
|
+
case 'vgxness_skill_get_evaluation':
|
|
116
|
+
return validationSuccess(tool.value, validateSkillGetEvaluationInput(input, tool.value));
|
|
117
|
+
case 'vgxness_skill_create_draft':
|
|
118
|
+
return validationSuccess(tool.value, validateSkillCreateDraftInput(input, tool.value));
|
|
119
|
+
case 'vgxness_skill_update_draft':
|
|
120
|
+
return validationSuccess(tool.value, validateSkillUpdateDraftInput(input, tool.value));
|
|
121
|
+
case 'vgxness_skill_publish_version':
|
|
122
|
+
return validationSuccess(tool.value, validateSkillPublishVersionInput(input, tool.value));
|
|
91
123
|
case 'vgxness_opencode_manager_payload':
|
|
92
124
|
return validationSuccess(tool.value, validateOpenCodeManagerPayloadInput(input, tool.value));
|
|
93
125
|
case 'vgxness_opencode_handoff_preview':
|
|
@@ -601,6 +633,97 @@ function validateSkillIndexInput(input, tool) {
|
|
|
601
633
|
return scope;
|
|
602
634
|
return { ok: true, value: { project: project.value, scope: scope.value } };
|
|
603
635
|
}
|
|
636
|
+
function validateSkillSearchInput(input, tool) {
|
|
637
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'query', 'status', 'sourceKind', 'limit']);
|
|
638
|
+
if (!record.ok)
|
|
639
|
+
return record;
|
|
640
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
641
|
+
if (!project.ok)
|
|
642
|
+
return project;
|
|
643
|
+
const result = { project: project.value };
|
|
644
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
645
|
+
if (!scope.ok)
|
|
646
|
+
return scope;
|
|
647
|
+
if (scope.value !== undefined)
|
|
648
|
+
result.scope = scope.value;
|
|
649
|
+
const query = readOptionalNonEmptyString(record.value, 'query', tool);
|
|
650
|
+
if (!query.ok)
|
|
651
|
+
return query;
|
|
652
|
+
if (query.value !== undefined)
|
|
653
|
+
result.query = query.value;
|
|
654
|
+
const status = readOptionalOneOf(record.value, 'status', skillVersionStatuses, tool);
|
|
655
|
+
if (!status.ok)
|
|
656
|
+
return status;
|
|
657
|
+
if (status.value !== undefined)
|
|
658
|
+
result.status = status.value;
|
|
659
|
+
const sourceKind = readOptionalOneOf(record.value, 'sourceKind', skillSourceKinds, tool);
|
|
660
|
+
if (!sourceKind.ok)
|
|
661
|
+
return sourceKind;
|
|
662
|
+
if (sourceKind.value !== undefined)
|
|
663
|
+
result.sourceKind = sourceKind.value;
|
|
664
|
+
if (record.value.limit !== undefined) {
|
|
665
|
+
const limit = record.value.limit;
|
|
666
|
+
if (typeof limit !== 'number' || !Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
667
|
+
return validationFailure('limit must be an integer between 1 and 100', tool);
|
|
668
|
+
result.limit = limit;
|
|
669
|
+
}
|
|
670
|
+
return { ok: true, value: result };
|
|
671
|
+
}
|
|
672
|
+
function validateSkillGetInput(input, tool) {
|
|
673
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'id', 'name', 'includeUsage']);
|
|
674
|
+
if (!record.ok)
|
|
675
|
+
return record;
|
|
676
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
677
|
+
if (!project.ok)
|
|
678
|
+
return project;
|
|
679
|
+
const result = { project: project.value };
|
|
680
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
681
|
+
if (!scope.ok)
|
|
682
|
+
return scope;
|
|
683
|
+
if (scope.value !== undefined)
|
|
684
|
+
result.scope = scope.value;
|
|
685
|
+
const id = readOptionalNonEmptyString(record.value, 'id', tool);
|
|
686
|
+
if (!id.ok)
|
|
687
|
+
return id;
|
|
688
|
+
if (id.value !== undefined)
|
|
689
|
+
result.id = id.value;
|
|
690
|
+
const name = readOptionalNonEmptyString(record.value, 'name', tool);
|
|
691
|
+
if (!name.ok)
|
|
692
|
+
return name;
|
|
693
|
+
if (name.value !== undefined)
|
|
694
|
+
result.name = name.value;
|
|
695
|
+
if (result.id === undefined && result.name === undefined)
|
|
696
|
+
return validationFailure('Either id or name is required', tool);
|
|
697
|
+
if (record.value.includeUsage !== undefined) {
|
|
698
|
+
if (typeof record.value.includeUsage !== 'boolean')
|
|
699
|
+
return validationFailure('includeUsage must be boolean', tool);
|
|
700
|
+
result.includeUsage = record.value.includeUsage;
|
|
701
|
+
}
|
|
702
|
+
return { ok: true, value: result };
|
|
703
|
+
}
|
|
704
|
+
function validateSkillStatusInput(input, tool) {
|
|
705
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'provider', 'mode', 'agent']);
|
|
706
|
+
if (!record.ok)
|
|
707
|
+
return record;
|
|
708
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
709
|
+
if (!project.ok)
|
|
710
|
+
return project;
|
|
711
|
+
const result = { project: project.value };
|
|
712
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
713
|
+
if (!scope.ok)
|
|
714
|
+
return scope;
|
|
715
|
+
if (scope.value !== undefined)
|
|
716
|
+
result.scope = scope.value;
|
|
717
|
+
const mode = readOptionalOneOf(record.value, 'mode', agentModes, tool);
|
|
718
|
+
if (!mode.ok)
|
|
719
|
+
return mode;
|
|
720
|
+
if (mode.value !== undefined)
|
|
721
|
+
result.mode = mode.value;
|
|
722
|
+
const copied = copyOptionalStrings(result, record.value, tool, ['provider', 'agent']);
|
|
723
|
+
if (!copied.ok)
|
|
724
|
+
return copied;
|
|
725
|
+
return { ok: true, value: result };
|
|
726
|
+
}
|
|
604
727
|
function validateSessionStartInput(input, tool) {
|
|
605
728
|
const record = inputRecord(input, tool, ['id', 'project', 'directory']);
|
|
606
729
|
if (!record.ok)
|
|
@@ -787,6 +910,483 @@ function validateSkillPayloadInput(input, tool) {
|
|
|
787
910
|
}
|
|
788
911
|
return { ok: true, value: result };
|
|
789
912
|
}
|
|
913
|
+
function validateSkillActivateInput(input, tool) {
|
|
914
|
+
const record = inputRecord(input, tool, [
|
|
915
|
+
'project',
|
|
916
|
+
'scope',
|
|
917
|
+
'skillId',
|
|
918
|
+
'name',
|
|
919
|
+
'versionId',
|
|
920
|
+
'version',
|
|
921
|
+
'runId',
|
|
922
|
+
'agentId',
|
|
923
|
+
'workflow',
|
|
924
|
+
'phase',
|
|
925
|
+
'providerAdapter',
|
|
926
|
+
'intent',
|
|
927
|
+
'reason',
|
|
928
|
+
'workspaceRoot',
|
|
929
|
+
'maxSourceBytes',
|
|
930
|
+
'mode',
|
|
931
|
+
]);
|
|
932
|
+
if (!record.ok)
|
|
933
|
+
return record;
|
|
934
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
935
|
+
if (!project.ok)
|
|
936
|
+
return project;
|
|
937
|
+
const result = { project: project.value };
|
|
938
|
+
const copied = copyOptionalStrings(result, record.value, tool, [
|
|
939
|
+
'skillId',
|
|
940
|
+
'name',
|
|
941
|
+
'versionId',
|
|
942
|
+
'version',
|
|
943
|
+
'runId',
|
|
944
|
+
'agentId',
|
|
945
|
+
'workflow',
|
|
946
|
+
'phase',
|
|
947
|
+
'providerAdapter',
|
|
948
|
+
'reason',
|
|
949
|
+
'workspaceRoot',
|
|
950
|
+
]);
|
|
951
|
+
if (!copied.ok)
|
|
952
|
+
return copied;
|
|
953
|
+
if (result.skillId === undefined && result.name === undefined)
|
|
954
|
+
return validationFailure('Either skillId or name is required', tool);
|
|
955
|
+
if (result.versionId !== undefined && result.version !== undefined)
|
|
956
|
+
return validationFailure('Use either versionId or version, not both', tool);
|
|
957
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
958
|
+
if (!scope.ok)
|
|
959
|
+
return scope;
|
|
960
|
+
if (scope.value !== undefined)
|
|
961
|
+
result.scope = scope.value;
|
|
962
|
+
const mode = readOptionalOneOf(record.value, 'mode', payloadModes, tool);
|
|
963
|
+
if (!mode.ok)
|
|
964
|
+
return mode;
|
|
965
|
+
if (mode.value !== undefined)
|
|
966
|
+
result.mode = mode.value;
|
|
967
|
+
const intent = readOptionalJsonObject(record.value, 'intent', tool);
|
|
968
|
+
if (!intent.ok)
|
|
969
|
+
return intent;
|
|
970
|
+
if (intent.value !== undefined)
|
|
971
|
+
result.intent = intent.value;
|
|
972
|
+
if (record.value.maxSourceBytes !== undefined) {
|
|
973
|
+
const maxSourceBytes = record.value.maxSourceBytes;
|
|
974
|
+
if (typeof maxSourceBytes !== 'number' || !Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)
|
|
975
|
+
return validationFailure('maxSourceBytes must be a positive safe integer', tool);
|
|
976
|
+
result.maxSourceBytes = maxSourceBytes;
|
|
977
|
+
}
|
|
978
|
+
return { ok: true, value: result };
|
|
979
|
+
}
|
|
980
|
+
function validateSkillRecordUsageInput(input, tool) {
|
|
981
|
+
const record = inputRecord(input, tool, [
|
|
982
|
+
'skillId',
|
|
983
|
+
'versionId',
|
|
984
|
+
'runId',
|
|
985
|
+
'targetType',
|
|
986
|
+
'targetKey',
|
|
987
|
+
'outcome',
|
|
988
|
+
'notes',
|
|
989
|
+
'workflow',
|
|
990
|
+
'phase',
|
|
991
|
+
'providerAdapter',
|
|
992
|
+
'agentId',
|
|
993
|
+
'intent',
|
|
994
|
+
'evidence',
|
|
995
|
+
]);
|
|
996
|
+
if (!record.ok)
|
|
997
|
+
return record;
|
|
998
|
+
const skillId = readNonEmptyString(record.value, 'skillId', tool);
|
|
999
|
+
if (!skillId.ok)
|
|
1000
|
+
return skillId;
|
|
1001
|
+
const outcome = readRequiredOneOf(record.value, 'outcome', skillUsageOutcomes, tool);
|
|
1002
|
+
if (!outcome.ok)
|
|
1003
|
+
return outcome;
|
|
1004
|
+
const result = { skillId: skillId.value, outcome: outcome.value };
|
|
1005
|
+
const copied = copyOptionalStrings(result, record.value, tool, ['versionId', 'runId', 'targetKey', 'notes', 'workflow', 'phase', 'providerAdapter', 'agentId']);
|
|
1006
|
+
if (!copied.ok)
|
|
1007
|
+
return copied;
|
|
1008
|
+
const targetType = readOptionalOneOf(record.value, 'targetType', skillAttachmentTargetTypes, tool);
|
|
1009
|
+
if (!targetType.ok)
|
|
1010
|
+
return targetType;
|
|
1011
|
+
if (targetType.value !== undefined)
|
|
1012
|
+
result.targetType = targetType.value;
|
|
1013
|
+
if (result.targetType !== undefined && result.targetKey === undefined)
|
|
1014
|
+
return validationFailure('targetKey is required when targetType is set', tool);
|
|
1015
|
+
if (result.targetType === undefined && result.targetKey !== undefined)
|
|
1016
|
+
return validationFailure('targetType is required when targetKey is set', tool);
|
|
1017
|
+
const intent = readOptionalJsonObject(record.value, 'intent', tool);
|
|
1018
|
+
if (!intent.ok)
|
|
1019
|
+
return intent;
|
|
1020
|
+
if (intent.value !== undefined)
|
|
1021
|
+
result.intent = intent.value;
|
|
1022
|
+
const evidence = readOptionalJsonObject(record.value, 'evidence', tool);
|
|
1023
|
+
if (!evidence.ok)
|
|
1024
|
+
return evidence;
|
|
1025
|
+
if (evidence.value !== undefined)
|
|
1026
|
+
result.evidence = evidence.value;
|
|
1027
|
+
return { ok: true, value: result };
|
|
1028
|
+
}
|
|
1029
|
+
function validateSkillProposeImprovementInput(input, tool) {
|
|
1030
|
+
const record = inputRecord(input, tool, [
|
|
1031
|
+
'project',
|
|
1032
|
+
'scope',
|
|
1033
|
+
'skillId',
|
|
1034
|
+
'name',
|
|
1035
|
+
'baseVersionId',
|
|
1036
|
+
'baseVersion',
|
|
1037
|
+
'proposedVersion',
|
|
1038
|
+
'proposedSource',
|
|
1039
|
+
'proposedCompatibility',
|
|
1040
|
+
'title',
|
|
1041
|
+
'problem',
|
|
1042
|
+
'suggestedChange',
|
|
1043
|
+
'sourceContext',
|
|
1044
|
+
'runId',
|
|
1045
|
+
'agentId',
|
|
1046
|
+
'workflow',
|
|
1047
|
+
'phase',
|
|
1048
|
+
'providerAdapter',
|
|
1049
|
+
'evidenceRefs',
|
|
1050
|
+
'evidence',
|
|
1051
|
+
'actor',
|
|
1052
|
+
]);
|
|
1053
|
+
if (!record.ok)
|
|
1054
|
+
return record;
|
|
1055
|
+
const result = {};
|
|
1056
|
+
const copied = copyRequiredStrings(result, record.value, tool, ['project', 'proposedVersion', 'title', 'problem', 'suggestedChange']);
|
|
1057
|
+
if (!copied.ok)
|
|
1058
|
+
return copied;
|
|
1059
|
+
const optional = copyOptionalStrings(result, record.value, tool, ['skillId', 'name', 'baseVersionId', 'baseVersion', 'runId', 'agentId', 'workflow', 'phase', 'providerAdapter', 'actor']);
|
|
1060
|
+
if (!optional.ok)
|
|
1061
|
+
return optional;
|
|
1062
|
+
if (result.skillId === undefined && result.name === undefined)
|
|
1063
|
+
return validationFailure('Either skillId or name is required', tool);
|
|
1064
|
+
if (result.baseVersionId !== undefined && result.baseVersion !== undefined)
|
|
1065
|
+
return validationFailure('Use either baseVersionId or baseVersion, not both', tool);
|
|
1066
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1067
|
+
if (!scope.ok)
|
|
1068
|
+
return scope;
|
|
1069
|
+
if (scope.value !== undefined)
|
|
1070
|
+
result.scope = scope.value;
|
|
1071
|
+
const source = readSkillSource(record.value, 'proposedSource', tool);
|
|
1072
|
+
if (!source.ok)
|
|
1073
|
+
return source;
|
|
1074
|
+
result.proposedSource = source.value;
|
|
1075
|
+
const compatibility = readOptionalJsonObject(record.value, 'proposedCompatibility', tool);
|
|
1076
|
+
if (!compatibility.ok)
|
|
1077
|
+
return compatibility;
|
|
1078
|
+
if (compatibility.value !== undefined) {
|
|
1079
|
+
const proposedCompatibility = compatibility.value;
|
|
1080
|
+
if (proposedCompatibility !== undefined)
|
|
1081
|
+
result.proposedCompatibility = proposedCompatibility;
|
|
1082
|
+
}
|
|
1083
|
+
const sourceContext = readOptionalJsonObject(record.value, 'sourceContext', tool);
|
|
1084
|
+
if (!sourceContext.ok)
|
|
1085
|
+
return sourceContext;
|
|
1086
|
+
if (sourceContext.value !== undefined)
|
|
1087
|
+
result.sourceContext = sourceContext.value;
|
|
1088
|
+
const evidence = readOptionalJsonObject(record.value, 'evidence', tool);
|
|
1089
|
+
if (!evidence.ok)
|
|
1090
|
+
return evidence;
|
|
1091
|
+
if (evidence.value !== undefined)
|
|
1092
|
+
result.evidence = evidence.value;
|
|
1093
|
+
const evidenceRefs = readOptionalStringArray(record.value, 'evidenceRefs', tool);
|
|
1094
|
+
if (!evidenceRefs.ok)
|
|
1095
|
+
return evidenceRefs;
|
|
1096
|
+
if (evidenceRefs.value !== undefined)
|
|
1097
|
+
result.evidenceRefs = evidenceRefs.value;
|
|
1098
|
+
return { ok: true, value: result };
|
|
1099
|
+
}
|
|
1100
|
+
function validateSkillListImprovementProposalsInput(input, tool) {
|
|
1101
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'skillId', 'name', 'baseVersionId', 'status', 'runId', 'agentId', 'limit']);
|
|
1102
|
+
if (!record.ok)
|
|
1103
|
+
return record;
|
|
1104
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
1105
|
+
if (!project.ok)
|
|
1106
|
+
return project;
|
|
1107
|
+
const result = { project: project.value };
|
|
1108
|
+
const copied = copyOptionalStrings(result, record.value, tool, ['skillId', 'name', 'baseVersionId', 'runId', 'agentId']);
|
|
1109
|
+
if (!copied.ok)
|
|
1110
|
+
return copied;
|
|
1111
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1112
|
+
if (!scope.ok)
|
|
1113
|
+
return scope;
|
|
1114
|
+
if (scope.value !== undefined)
|
|
1115
|
+
result.scope = scope.value;
|
|
1116
|
+
const status = readOptionalOneOf(record.value, 'status', skillImprovementProposalStatuses, tool);
|
|
1117
|
+
if (!status.ok)
|
|
1118
|
+
return status;
|
|
1119
|
+
if (status.value !== undefined)
|
|
1120
|
+
result.status = status.value;
|
|
1121
|
+
const limit = readOptionalBoundedLimit(record.value, tool);
|
|
1122
|
+
if (!limit.ok)
|
|
1123
|
+
return limit;
|
|
1124
|
+
if (limit.value !== undefined)
|
|
1125
|
+
result.limit = limit.value;
|
|
1126
|
+
return { ok: true, value: result };
|
|
1127
|
+
}
|
|
1128
|
+
function validateSkillRequestEvaluationInput(input, tool) {
|
|
1129
|
+
const record = inputRecord(input, tool, [
|
|
1130
|
+
'project',
|
|
1131
|
+
'scope',
|
|
1132
|
+
'skillId',
|
|
1133
|
+
'name',
|
|
1134
|
+
'versionId',
|
|
1135
|
+
'version',
|
|
1136
|
+
'scenarioId',
|
|
1137
|
+
'proposalId',
|
|
1138
|
+
'requestedBy',
|
|
1139
|
+
'runId',
|
|
1140
|
+
'agentId',
|
|
1141
|
+
'workflow',
|
|
1142
|
+
'phase',
|
|
1143
|
+
'providerAdapter',
|
|
1144
|
+
'risk',
|
|
1145
|
+
'preflight',
|
|
1146
|
+
]);
|
|
1147
|
+
if (!record.ok)
|
|
1148
|
+
return record;
|
|
1149
|
+
const result = {};
|
|
1150
|
+
const copied = copyRequiredStrings(result, record.value, tool, ['project', 'requestedBy']);
|
|
1151
|
+
if (!copied.ok)
|
|
1152
|
+
return copied;
|
|
1153
|
+
const optional = copyOptionalStrings(result, record.value, tool, ['skillId', 'name', 'versionId', 'version', 'scenarioId', 'proposalId', 'runId', 'agentId', 'workflow', 'phase', 'providerAdapter']);
|
|
1154
|
+
if (!optional.ok)
|
|
1155
|
+
return optional;
|
|
1156
|
+
if (result.skillId === undefined && result.name === undefined)
|
|
1157
|
+
return validationFailure('Either skillId or name is required', tool);
|
|
1158
|
+
if (result.versionId !== undefined && result.version !== undefined)
|
|
1159
|
+
return validationFailure('Use either versionId or version, not both', tool);
|
|
1160
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1161
|
+
if (!scope.ok)
|
|
1162
|
+
return scope;
|
|
1163
|
+
if (scope.value !== undefined)
|
|
1164
|
+
result.scope = scope.value;
|
|
1165
|
+
const risk = readOptionalJsonObject(record.value, 'risk', tool);
|
|
1166
|
+
if (!risk.ok)
|
|
1167
|
+
return risk;
|
|
1168
|
+
if (risk.value !== undefined)
|
|
1169
|
+
result.risk = risk.value;
|
|
1170
|
+
const preflight = readOptionalJsonObject(record.value, 'preflight', tool);
|
|
1171
|
+
if (!preflight.ok)
|
|
1172
|
+
return preflight;
|
|
1173
|
+
if (preflight.value !== undefined)
|
|
1174
|
+
result.preflight = preflight.value;
|
|
1175
|
+
return { ok: true, value: result };
|
|
1176
|
+
}
|
|
1177
|
+
function validateSkillListEvaluationsInput(input, tool) {
|
|
1178
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'skillId', 'name', 'versionId', 'scenarioId', 'proposalId', 'status', 'runId', 'agentId', 'limit']);
|
|
1179
|
+
if (!record.ok)
|
|
1180
|
+
return record;
|
|
1181
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
1182
|
+
if (!project.ok)
|
|
1183
|
+
return project;
|
|
1184
|
+
const result = { project: project.value };
|
|
1185
|
+
const copied = copyOptionalStrings(result, record.value, tool, ['skillId', 'name', 'versionId', 'scenarioId', 'proposalId', 'runId', 'agentId']);
|
|
1186
|
+
if (!copied.ok)
|
|
1187
|
+
return copied;
|
|
1188
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1189
|
+
if (!scope.ok)
|
|
1190
|
+
return scope;
|
|
1191
|
+
if (scope.value !== undefined)
|
|
1192
|
+
result.scope = scope.value;
|
|
1193
|
+
const status = readOptionalOneOf(record.value, 'status', skillEvaluationRequestStatuses, tool);
|
|
1194
|
+
if (!status.ok)
|
|
1195
|
+
return status;
|
|
1196
|
+
if (status.value !== undefined)
|
|
1197
|
+
result.status = status.value;
|
|
1198
|
+
const limit = readOptionalBoundedLimit(record.value, tool);
|
|
1199
|
+
if (!limit.ok)
|
|
1200
|
+
return limit;
|
|
1201
|
+
if (limit.value !== undefined)
|
|
1202
|
+
result.limit = limit.value;
|
|
1203
|
+
return { ok: true, value: result };
|
|
1204
|
+
}
|
|
1205
|
+
function validateSkillGetEvaluationInput(input, tool) {
|
|
1206
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'id']);
|
|
1207
|
+
if (!record.ok)
|
|
1208
|
+
return record;
|
|
1209
|
+
const project = readNonEmptyString(record.value, 'project', tool);
|
|
1210
|
+
if (!project.ok)
|
|
1211
|
+
return project;
|
|
1212
|
+
const id = readNonEmptyString(record.value, 'id', tool);
|
|
1213
|
+
if (!id.ok)
|
|
1214
|
+
return id;
|
|
1215
|
+
const result = { project: project.value, id: id.value };
|
|
1216
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1217
|
+
if (!scope.ok)
|
|
1218
|
+
return scope;
|
|
1219
|
+
if (scope.value !== undefined)
|
|
1220
|
+
result.scope = scope.value;
|
|
1221
|
+
return { ok: true, value: result };
|
|
1222
|
+
}
|
|
1223
|
+
function validateSkillCreateDraftInput(input, tool) {
|
|
1224
|
+
const record = inputRecord(input, tool, [
|
|
1225
|
+
'project',
|
|
1226
|
+
'scope',
|
|
1227
|
+
'name',
|
|
1228
|
+
'description',
|
|
1229
|
+
'version',
|
|
1230
|
+
'source',
|
|
1231
|
+
'compatibility',
|
|
1232
|
+
'draftParentVersionId',
|
|
1233
|
+
'actor',
|
|
1234
|
+
'reason',
|
|
1235
|
+
'runId',
|
|
1236
|
+
'agentId',
|
|
1237
|
+
'evidence',
|
|
1238
|
+
'governance',
|
|
1239
|
+
]);
|
|
1240
|
+
if (!record.ok)
|
|
1241
|
+
return record;
|
|
1242
|
+
const result = {};
|
|
1243
|
+
const required = copyRequiredStrings(result, record.value, tool, ['project', 'name', 'description', 'version']);
|
|
1244
|
+
if (!required.ok)
|
|
1245
|
+
return required;
|
|
1246
|
+
const optional = copyOptionalStrings(result, record.value, tool, ['draftParentVersionId', 'reason', 'runId', 'agentId']);
|
|
1247
|
+
if (!optional.ok)
|
|
1248
|
+
return optional;
|
|
1249
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1250
|
+
if (!scope.ok)
|
|
1251
|
+
return scope;
|
|
1252
|
+
if (scope.value !== undefined)
|
|
1253
|
+
result.scope = scope.value;
|
|
1254
|
+
const source = readSkillSource(record.value, 'source', tool);
|
|
1255
|
+
if (!source.ok)
|
|
1256
|
+
return source;
|
|
1257
|
+
result.source = source.value;
|
|
1258
|
+
const actor = readSkillLifecycleActor(record.value, tool);
|
|
1259
|
+
if (!actor.ok)
|
|
1260
|
+
return actor;
|
|
1261
|
+
result.actor = actor.value;
|
|
1262
|
+
const compatibility = readOptionalJsonObject(record.value, 'compatibility', tool);
|
|
1263
|
+
if (!compatibility.ok)
|
|
1264
|
+
return compatibility;
|
|
1265
|
+
if (compatibility.value !== undefined)
|
|
1266
|
+
result.compatibility = compatibility.value;
|
|
1267
|
+
const evidence = readOptionalJsonObject(record.value, 'evidence', tool);
|
|
1268
|
+
if (!evidence.ok)
|
|
1269
|
+
return evidence;
|
|
1270
|
+
if (evidence.value !== undefined)
|
|
1271
|
+
result.evidence = evidence.value;
|
|
1272
|
+
const governance = readOptionalJsonObject(record.value, 'governance', tool);
|
|
1273
|
+
if (!governance.ok)
|
|
1274
|
+
return governance;
|
|
1275
|
+
if (governance.value !== undefined)
|
|
1276
|
+
result.governance = governance.value;
|
|
1277
|
+
return { ok: true, value: result };
|
|
1278
|
+
}
|
|
1279
|
+
function validateSkillUpdateDraftInput(input, tool) {
|
|
1280
|
+
const record = inputRecord(input, tool, [
|
|
1281
|
+
'project',
|
|
1282
|
+
'scope',
|
|
1283
|
+
'skillId',
|
|
1284
|
+
'name',
|
|
1285
|
+
'versionId',
|
|
1286
|
+
'version',
|
|
1287
|
+
'source',
|
|
1288
|
+
'compatibility',
|
|
1289
|
+
'expectedDraftRevision',
|
|
1290
|
+
'actor',
|
|
1291
|
+
'reason',
|
|
1292
|
+
'runId',
|
|
1293
|
+
'agentId',
|
|
1294
|
+
'evidence',
|
|
1295
|
+
'governance',
|
|
1296
|
+
]);
|
|
1297
|
+
if (!record.ok)
|
|
1298
|
+
return record;
|
|
1299
|
+
const result = {};
|
|
1300
|
+
const required = copyRequiredStrings(result, record.value, tool, ['project']);
|
|
1301
|
+
if (!required.ok)
|
|
1302
|
+
return required;
|
|
1303
|
+
const optional = copyOptionalStrings(result, record.value, tool, ['skillId', 'name', 'versionId', 'version', 'reason', 'runId', 'agentId']);
|
|
1304
|
+
if (!optional.ok)
|
|
1305
|
+
return optional;
|
|
1306
|
+
if (result.skillId === undefined && result.name === undefined)
|
|
1307
|
+
return validationFailure('Either skillId or name is required', tool);
|
|
1308
|
+
if (result.versionId === undefined && result.version === undefined)
|
|
1309
|
+
return validationFailure('Either versionId or version is required', tool);
|
|
1310
|
+
if (result.versionId !== undefined && result.version !== undefined)
|
|
1311
|
+
return validationFailure('Use either versionId or version, not both', tool);
|
|
1312
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1313
|
+
if (!scope.ok)
|
|
1314
|
+
return scope;
|
|
1315
|
+
if (scope.value !== undefined)
|
|
1316
|
+
result.scope = scope.value;
|
|
1317
|
+
const actor = readSkillLifecycleActor(record.value, tool);
|
|
1318
|
+
if (!actor.ok)
|
|
1319
|
+
return actor;
|
|
1320
|
+
result.actor = actor.value;
|
|
1321
|
+
if (record.value.source !== undefined) {
|
|
1322
|
+
const source = readSkillSource(record.value, 'source', tool);
|
|
1323
|
+
if (!source.ok)
|
|
1324
|
+
return source;
|
|
1325
|
+
result.source = source.value;
|
|
1326
|
+
}
|
|
1327
|
+
const compatibility = readOptionalJsonObject(record.value, 'compatibility', tool);
|
|
1328
|
+
if (!compatibility.ok)
|
|
1329
|
+
return compatibility;
|
|
1330
|
+
if (compatibility.value !== undefined)
|
|
1331
|
+
result.compatibility = compatibility.value;
|
|
1332
|
+
if (record.value.expectedDraftRevision !== undefined) {
|
|
1333
|
+
const revision = record.value.expectedDraftRevision;
|
|
1334
|
+
if (typeof revision !== 'number' || !Number.isSafeInteger(revision) || revision < 1)
|
|
1335
|
+
return validationFailure('expectedDraftRevision must be a positive safe integer', tool);
|
|
1336
|
+
result.expectedDraftRevision = revision;
|
|
1337
|
+
}
|
|
1338
|
+
const evidence = readOptionalJsonObject(record.value, 'evidence', tool);
|
|
1339
|
+
if (!evidence.ok)
|
|
1340
|
+
return evidence;
|
|
1341
|
+
if (evidence.value !== undefined)
|
|
1342
|
+
result.evidence = evidence.value;
|
|
1343
|
+
const governance = readOptionalJsonObject(record.value, 'governance', tool);
|
|
1344
|
+
if (!governance.ok)
|
|
1345
|
+
return governance;
|
|
1346
|
+
if (governance.value !== undefined)
|
|
1347
|
+
result.governance = governance.value;
|
|
1348
|
+
if (result.source === undefined && result.compatibility === undefined && result.governance === undefined)
|
|
1349
|
+
return validationFailure('At least one draft update field is required', tool);
|
|
1350
|
+
return { ok: true, value: result };
|
|
1351
|
+
}
|
|
1352
|
+
function validateSkillPublishVersionInput(input, tool) {
|
|
1353
|
+
const record = inputRecord(input, tool, ['project', 'scope', 'skillId', 'name', 'versionId', 'version', 'actor', 'reason', 'runId', 'agentId', 'evidence', 'governance']);
|
|
1354
|
+
if (!record.ok)
|
|
1355
|
+
return record;
|
|
1356
|
+
const result = {};
|
|
1357
|
+
const required = copyRequiredStrings(result, record.value, tool, ['project', 'reason']);
|
|
1358
|
+
if (!required.ok)
|
|
1359
|
+
return required;
|
|
1360
|
+
const optional = copyOptionalStrings(result, record.value, tool, ['skillId', 'name', 'versionId', 'version', 'runId', 'agentId']);
|
|
1361
|
+
if (!optional.ok)
|
|
1362
|
+
return optional;
|
|
1363
|
+
if (result.skillId === undefined && result.name === undefined)
|
|
1364
|
+
return validationFailure('Either skillId or name is required', tool);
|
|
1365
|
+
if (result.versionId === undefined && result.version === undefined)
|
|
1366
|
+
return validationFailure('Either versionId or version is required', tool);
|
|
1367
|
+
if (result.versionId !== undefined && result.version !== undefined)
|
|
1368
|
+
return validationFailure('Use either versionId or version, not both', tool);
|
|
1369
|
+
const scope = readOptionalOneOf(record.value, 'scope', scopes, tool);
|
|
1370
|
+
if (!scope.ok)
|
|
1371
|
+
return scope;
|
|
1372
|
+
if (scope.value !== undefined)
|
|
1373
|
+
result.scope = scope.value;
|
|
1374
|
+
const actor = readSkillLifecycleActor(record.value, tool);
|
|
1375
|
+
if (!actor.ok)
|
|
1376
|
+
return actor;
|
|
1377
|
+
result.actor = actor.value;
|
|
1378
|
+
const evidence = readOptionalJsonObject(record.value, 'evidence', tool);
|
|
1379
|
+
if (!evidence.ok)
|
|
1380
|
+
return evidence;
|
|
1381
|
+
if (evidence.value !== undefined)
|
|
1382
|
+
result.evidence = evidence.value;
|
|
1383
|
+
const governance = readOptionalJsonObject(record.value, 'governance', tool);
|
|
1384
|
+
if (!governance.ok)
|
|
1385
|
+
return governance;
|
|
1386
|
+
if (governance.value !== undefined)
|
|
1387
|
+
result.governance = governance.value;
|
|
1388
|
+
return { ok: true, value: result };
|
|
1389
|
+
}
|
|
790
1390
|
function validateManagerProfileGetInput(input, tool) {
|
|
791
1391
|
const record = inputRecord(input, tool, ['project', 'scope', 'managerName']);
|
|
792
1392
|
if (!record.ok)
|
|
@@ -1150,6 +1750,14 @@ function readJsonValue(record, field, tool) {
|
|
|
1150
1750
|
return validationFailure(`${field} must be JSON-compatible`, tool);
|
|
1151
1751
|
return { ok: true, value: record[field] };
|
|
1152
1752
|
}
|
|
1753
|
+
function readOptionalJsonObject(record, field, tool) {
|
|
1754
|
+
if (record[field] === undefined)
|
|
1755
|
+
return { ok: true, value: undefined };
|
|
1756
|
+
const value = record[field];
|
|
1757
|
+
if (!isJsonValue(value) || typeof value !== 'object' || value === null || Array.isArray(value))
|
|
1758
|
+
return validationFailure(`${field} must be a JSON object`, tool);
|
|
1759
|
+
return { ok: true, value: value };
|
|
1760
|
+
}
|
|
1153
1761
|
function isJsonValue(value) {
|
|
1154
1762
|
if (value === null)
|
|
1155
1763
|
return true;
|
|
@@ -1282,6 +1890,60 @@ function readBoundedLimit(record, tool) {
|
|
|
1282
1890
|
return validationFailure('limit must be between 1 and 100', tool);
|
|
1283
1891
|
return { ok: true, value: limit };
|
|
1284
1892
|
}
|
|
1893
|
+
function readOptionalBoundedLimit(record, tool) {
|
|
1894
|
+
if (record.limit === undefined)
|
|
1895
|
+
return { ok: true, value: undefined };
|
|
1896
|
+
return readBoundedLimit(record, tool);
|
|
1897
|
+
}
|
|
1898
|
+
function readSkillSource(record, field, tool) {
|
|
1899
|
+
const source = asRecord(record[field], tool, `${field} must be an object`);
|
|
1900
|
+
if (!source.ok)
|
|
1901
|
+
return source;
|
|
1902
|
+
const kind = readRequiredOneOf(source.value, 'kind', skillSourceKinds, tool);
|
|
1903
|
+
if (!kind.ok)
|
|
1904
|
+
return kind;
|
|
1905
|
+
const result = { kind: kind.value };
|
|
1906
|
+
const path = readOptionalNonEmptyString(source.value, 'path', tool);
|
|
1907
|
+
if (!path.ok)
|
|
1908
|
+
return path;
|
|
1909
|
+
if (path.value !== undefined)
|
|
1910
|
+
result.path = path.value;
|
|
1911
|
+
const url = readOptionalNonEmptyString(source.value, 'url', tool);
|
|
1912
|
+
if (!url.ok)
|
|
1913
|
+
return url;
|
|
1914
|
+
if (url.value !== undefined)
|
|
1915
|
+
result.url = url.value;
|
|
1916
|
+
const inlineMetadata = readOptionalJsonObject(source.value, 'inlineMetadata', tool);
|
|
1917
|
+
if (!inlineMetadata.ok)
|
|
1918
|
+
return inlineMetadata;
|
|
1919
|
+
if (inlineMetadata.value !== undefined)
|
|
1920
|
+
result.inlineMetadata = inlineMetadata.value;
|
|
1921
|
+
if (result.kind === 'path' && result.path === undefined)
|
|
1922
|
+
return validationFailure('proposedSource.path is required when proposedSource.kind is path', tool);
|
|
1923
|
+
if (result.kind === 'url' && result.url === undefined)
|
|
1924
|
+
return validationFailure('proposedSource.url is required when proposedSource.kind is url', tool);
|
|
1925
|
+
if (result.kind === 'inline' && (result.path !== undefined || result.url !== undefined))
|
|
1926
|
+
return validationFailure('Inline proposedSource cannot include path or url', tool);
|
|
1927
|
+
return { ok: true, value: result };
|
|
1928
|
+
}
|
|
1929
|
+
function readSkillLifecycleActor(record, tool) {
|
|
1930
|
+
const actorRecord = asRecord(record.actor, tool, 'actor must be an object');
|
|
1931
|
+
if (!actorRecord.ok)
|
|
1932
|
+
return actorRecord;
|
|
1933
|
+
const type = readRequiredOneOf(actorRecord.value, 'type', ['human', 'agent', 'system'], tool);
|
|
1934
|
+
if (!type.ok)
|
|
1935
|
+
return type;
|
|
1936
|
+
const id = readNonEmptyString(actorRecord.value, 'id', tool);
|
|
1937
|
+
if (!id.ok)
|
|
1938
|
+
return id;
|
|
1939
|
+
const actor = { type: type.value, id: id.value };
|
|
1940
|
+
const displayName = readOptionalNonEmptyString(actorRecord.value, 'displayName', tool);
|
|
1941
|
+
if (!displayName.ok)
|
|
1942
|
+
return displayName;
|
|
1943
|
+
if (displayName.value !== undefined)
|
|
1944
|
+
actor.displayName = displayName.value;
|
|
1945
|
+
return { ok: true, value: actor };
|
|
1946
|
+
}
|
|
1285
1947
|
function readOptionalStringArray(record, field, tool) {
|
|
1286
1948
|
if (record[field] === undefined)
|
|
1287
1949
|
return { ok: true, value: undefined };
|