@lesliechan721/aw-plugin-core 0.1.0-beta.6 → 0.1.0-beta.61
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/aw-capabilities.d.ts +27 -0
- package/dist/aw-capabilities.js +117 -0
- package/dist/aw-capabilities.js.map +1 -0
- package/dist/catalog-file-modes.d.ts +5 -0
- package/dist/catalog-file-modes.js +67 -0
- package/dist/catalog-file-modes.js.map +1 -0
- package/dist/catalog-workspace-resolution.d.ts +3 -0
- package/dist/catalog-workspace-resolution.js +34 -0
- package/dist/catalog-workspace-resolution.js.map +1 -0
- package/dist/generated/plugin-manifest-v3.d.ts +1532 -0
- package/dist/generated/{plugin-manifest-v1.js → plugin-manifest-v3.js} +1 -1
- package/dist/generated/plugin-manifest-v3.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/managed-commands.d.ts +167 -0
- package/dist/managed-commands.js +463 -0
- package/dist/managed-commands.js.map +1 -0
- package/dist/manifest-contract.d.ts +3 -6
- package/dist/manifest-contract.js +271 -407
- package/dist/manifest-contract.js.map +1 -1
- package/dist/manifest-type-contract.d.ts +2 -2
- package/dist/manifest.d.ts +12 -8
- package/dist/manifest.js +18 -7
- package/dist/manifest.js.map +1 -1
- package/dist/native-runtime/reader-runtime.mjs +34 -0
- package/dist/native-runtime/reader.d.mts +6 -0
- package/dist/native-runtime/reader.mjs +11 -0
- package/dist/native-tools.d.ts +48 -0
- package/dist/native-tools.js +192 -0
- package/dist/native-tools.js.map +1 -0
- package/dist/plugin-authoring-capabilities.d.ts +1 -1
- package/dist/plugin-authoring-capabilities.js +133 -26
- package/dist/plugin-authoring-capabilities.js.map +1 -1
- package/dist/plugin-config.d.ts +47 -0
- package/dist/plugin-config.js +1355 -0
- package/dist/plugin-config.js.map +1 -0
- package/dist/plugin-requirements.d.ts +34 -0
- package/dist/plugin-requirements.js +300 -0
- package/dist/plugin-requirements.js.map +1 -0
- package/dist/plugin-script-contract.d.ts +11 -12
- package/dist/plugin-script-contract.js +44 -71
- package/dist/plugin-script-contract.js.map +1 -1
- package/dist/runtime-config.d.ts +38 -0
- package/dist/runtime-config.js +31 -0
- package/dist/runtime-config.js.map +1 -0
- package/dist/types.d.ts +266 -73
- package/dist/workspace.d.ts +37 -9
- package/dist/workspace.js +436 -195
- package/dist/workspace.js.map +1 -1
- package/package.json +16 -6
- package/schemas/plugin-manifest-v3.json +2655 -0
- package/dist/generated/plugin-manifest-v1.d.ts +0 -368
- package/dist/generated/plugin-manifest-v1.js.map +0 -1
- package/dist/plugin-release.d.ts +0 -30
- package/dist/plugin-release.js +0 -187
- package/dist/plugin-release.js.map +0 -1
- package/schemas/plugin-manifest-v1.json +0 -329
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
3
|
import fs from 'fs-extra';
|
|
4
|
+
import { computeAwCapabilitySetDigest, normalizeAwCapabilities, } from './aw-capabilities.js';
|
|
4
5
|
import { normalizePluginManifestSchemaVersion, PLUGIN_MANIFEST_SCHEMA_VERSION, SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION, } from './manifest.js';
|
|
6
|
+
import { getPluginConfigDependencyKeys, normalizePluginConfigDefinition } from './plugin-config.js';
|
|
5
7
|
import { readJsonFile } from './read-json.js';
|
|
8
|
+
import { loadPluginNativeToolClosure, normalizeNativeTools, validateNativeToolClosureFiles, validateNativeToolsManifest } from './native-tools.js';
|
|
6
9
|
import { parsePermissionCommand } from './permission-command.js';
|
|
10
|
+
import { normalizeManagedCommands, normalizeManagedCommandPermission, validateManagedCommandManifest, validateManagedCommandSources } from './managed-commands.js';
|
|
7
11
|
import { applyFileRules } from './file-rules.js';
|
|
8
12
|
import { resolvePlatformEntries } from './platform-entries.js';
|
|
9
13
|
import { validatePortableSkillDirectoriesRoot, validatePortableSkillName, } from './portable-skill-validation.js';
|
|
10
14
|
import { assertHookMatcherAllowed, assertNativeHookEvent, assertPublicHookEvent, normalizeRenderedHookGroupIdentity, renderHookDefinitionGroup, resolvePlatformHookDefinitions, } from './hooks-contract.js';
|
|
11
|
-
import {
|
|
15
|
+
import { PLUGIN_SCRIPT_TIMEOUT_MAX_MS, PLUGIN_SCRIPT_TIMEOUT_MIN_MS, } from './plugin-script-contract.js';
|
|
12
16
|
import { DEFAULT_SLASH_COMMANDS_PATH, resolveSlashCommands, } from './slash-commands.js';
|
|
13
17
|
import { isSkillAuthorOnlyPath } from './skill-authoring.js';
|
|
14
18
|
import { assertPluginInputTree, validateRuntimeExportSource } from './runtime-export-source.js';
|
|
@@ -29,7 +33,6 @@ const PLATFORM_PRODUCT_BY_NAME = {
|
|
|
29
33
|
};
|
|
30
34
|
const PLUGIN_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
31
35
|
const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
32
|
-
export const DEFAULT_SOURCE_PLUGIN_AW_MIN_VERSION = '0.0.0';
|
|
33
36
|
const STRICT_SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|(?:[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))(?:\.(?:0|[1-9]\d*|(?:[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
34
37
|
export const STRICT_SEMVER_VALIDATION_CODE = 'invalidStrictSemVer';
|
|
35
38
|
export class StrictSemVerValidationError extends Error {
|
|
@@ -220,14 +223,18 @@ function ensureStringArray(value, fieldName) {
|
|
|
220
223
|
return value.map((entry, index) => ensureString(entry, `${fieldName}[${index}]`));
|
|
221
224
|
}
|
|
222
225
|
function normalizePermissionCommandArray(value, fieldName) {
|
|
223
|
-
if (value === undefined)
|
|
226
|
+
if (value === undefined)
|
|
224
227
|
return undefined;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
if (!Array.isArray(value))
|
|
229
|
+
throw new Error(`Invalid ${fieldName}: expected an array.`);
|
|
230
|
+
return value.map((entry, index) => {
|
|
231
|
+
const label = `${fieldName}[${index}]`;
|
|
232
|
+
if (typeof entry === 'string') {
|
|
233
|
+
parsePermissionCommand(entry, label);
|
|
234
|
+
return entry;
|
|
235
|
+
}
|
|
236
|
+
return normalizeManagedCommandPermission(entry, label);
|
|
237
|
+
});
|
|
231
238
|
}
|
|
232
239
|
function normalizeComparableStringArray(value) {
|
|
233
240
|
if (!value) {
|
|
@@ -265,30 +272,26 @@ function assertCatalogChannel(value, fieldName) {
|
|
|
265
272
|
}
|
|
266
273
|
return channel;
|
|
267
274
|
}
|
|
268
|
-
function
|
|
269
|
-
return {
|
|
270
|
-
aw: {
|
|
271
|
-
minVersion,
|
|
272
|
-
},
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
function normalizePluginCompatibility(value, fieldName, options) {
|
|
275
|
+
function normalizePluginRequirements(value, fieldName, options) {
|
|
276
276
|
if (value === undefined) {
|
|
277
|
-
if (options.allowMissing)
|
|
278
|
-
return
|
|
279
|
-
}
|
|
280
|
-
throw new Error(`Invalid ${fieldName}.aw.minVersion: expected a strict SemVer 2.0.0 string. Received undefined.`);
|
|
277
|
+
if (options.allowMissing)
|
|
278
|
+
return undefined;
|
|
279
|
+
throw new Error(`Invalid ${fieldName}: expected an object.`);
|
|
281
280
|
}
|
|
282
281
|
const input = assertObject(value, fieldName);
|
|
283
282
|
assertAllowedKeys(input, fieldName, ['aw']);
|
|
284
283
|
const aw = assertObject(input.aw, `${fieldName}.aw`);
|
|
285
|
-
assertAllowedKeys(aw, `${fieldName}.aw`, ['
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
function assertPluginMinVersionWithinCatalogBounds(options) {
|
|
289
|
-
if (compareStrictSemVer(options.pluginMinVersion, options.catalogMinVersion) > 0) {
|
|
290
|
-
throw new Error(`Invalid ${options.fieldName}: plugin "${options.pluginName}" requires aw ${options.pluginMinVersion}, which is higher than catalog minimum ${options.catalogMinVersion}.`);
|
|
284
|
+
assertAllowedKeys(aw, `${fieldName}.aw`, ['capabilities']);
|
|
285
|
+
if (aw.capabilities !== undefined && !Array.isArray(aw.capabilities)) {
|
|
286
|
+
throw new Error(`Invalid ${fieldName}.aw.capabilities: expected an array.`);
|
|
291
287
|
}
|
|
288
|
+
return {
|
|
289
|
+
aw: {
|
|
290
|
+
...(aw.capabilities === undefined
|
|
291
|
+
? {}
|
|
292
|
+
: { capabilities: normalizeAwCapabilities(aw.capabilities, `${fieldName}.aw.capabilities`) }),
|
|
293
|
+
},
|
|
294
|
+
};
|
|
292
295
|
}
|
|
293
296
|
function normalizeMarketplaceProducts(value, fieldName) {
|
|
294
297
|
if (value === undefined) {
|
|
@@ -619,15 +622,20 @@ function normalizeRuntimeExports(pluginRoot, value, fieldName) {
|
|
|
619
622
|
return value.map((entry, index) => {
|
|
620
623
|
const entryField = `${fieldName}[${index}]`;
|
|
621
624
|
const input = assertObject(entry, entryField);
|
|
622
|
-
assertAllowedKeys(input, entryField, ['name', 'source']);
|
|
625
|
+
assertAllowedKeys(input, entryField, ['name', 'source', 'requires']);
|
|
623
626
|
const name = normalizeRuntimeExportName(input.name, `${entryField}.name`);
|
|
624
627
|
if (names.has(name)) {
|
|
625
628
|
throw new Error(`Invalid ${fieldName}: duplicate export name "${name}".`);
|
|
626
629
|
}
|
|
627
630
|
names.add(name);
|
|
631
|
+
const requires = normalizePluginRequirements(input.requires, `${entryField}.requires`, { allowMissing: false });
|
|
632
|
+
if (requires.aw.capabilities === undefined) {
|
|
633
|
+
throw new Error(`Invalid ${entryField}.requires.aw.capabilities: expected an array.`);
|
|
634
|
+
}
|
|
628
635
|
return {
|
|
629
636
|
name,
|
|
630
637
|
source: normalizeCanonicalPluginFilePath(pluginRoot, input.source, `${entryField}.source`),
|
|
638
|
+
requires: { aw: { capabilities: requires.aw.capabilities } },
|
|
631
639
|
};
|
|
632
640
|
});
|
|
633
641
|
}
|
|
@@ -838,12 +846,6 @@ function ensureBoolean(value, fieldName) {
|
|
|
838
846
|
}
|
|
839
847
|
return value;
|
|
840
848
|
}
|
|
841
|
-
function ensureFiniteNumber(value, fieldName) {
|
|
842
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
843
|
-
throw new Error(`Invalid ${fieldName}: expected a number.`);
|
|
844
|
-
}
|
|
845
|
-
return value;
|
|
846
|
-
}
|
|
847
849
|
function normalizeScriptTimeout(value, fieldName) {
|
|
848
850
|
if (typeof value !== 'number' ||
|
|
849
851
|
!Number.isInteger(value) ||
|
|
@@ -859,11 +861,6 @@ function assertNodeRunnablePath(value, fieldName) {
|
|
|
859
861
|
throw new Error(`Invalid ${fieldName}: expected a Node runnable file extension (.js, .mjs, or .cjs).`);
|
|
860
862
|
}
|
|
861
863
|
}
|
|
862
|
-
function assertAutoRunnablePath(value, fieldName) {
|
|
863
|
-
if (!inferLifecycleScriptRunnerFromPath(value)) {
|
|
864
|
-
throw new Error(`Invalid ${fieldName}: runner "auto" requires one of these file extensions: ${PLUGIN_AUTO_RUNNER_EXTENSIONS.join(', ')}.`);
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
864
|
function assertNotInlineCommandLike(value, fieldName) {
|
|
868
865
|
if (/\s|[;&|<>`]/.test(value) || value.includes('$(')) {
|
|
869
866
|
throw new Error(`Invalid ${fieldName}: inline command strings are not allowed.`);
|
|
@@ -874,7 +871,7 @@ function normalizePluginScriptPath(pluginRoot, value, fieldName) {
|
|
|
874
871
|
assertNotInlineCommandLike(rawPath, fieldName);
|
|
875
872
|
return normalizePluginRelativePath(pluginRoot, rawPath, fieldName);
|
|
876
873
|
}
|
|
877
|
-
function normalizeScriptEntry(pluginRoot, value, fieldName
|
|
874
|
+
function normalizeScriptEntry(pluginRoot, value, fieldName) {
|
|
878
875
|
const input = assertObject(value, fieldName);
|
|
879
876
|
if ('command' in input) {
|
|
880
877
|
throw new Error(`Invalid ${fieldName}: inline command strings are not allowed.`);
|
|
@@ -884,69 +881,29 @@ function normalizeScriptEntry(pluginRoot, value, fieldName, options = {}) {
|
|
|
884
881
|
}
|
|
885
882
|
assertAllowedKeys(input, fieldName, ['runner', 'path', 'args']);
|
|
886
883
|
const runner = ensureString(input.runner, `${fieldName}.runner`);
|
|
887
|
-
if (
|
|
888
|
-
throw new Error(`Invalid ${fieldName}.runner: unsupported runner "${runner}".`);
|
|
889
|
-
}
|
|
890
|
-
if (options.requireNodeRunner && runner !== 'node') {
|
|
884
|
+
if (runner !== 'node') {
|
|
891
885
|
throw new Error(`Invalid ${fieldName}.runner: expected "node".`);
|
|
892
886
|
}
|
|
893
887
|
const scriptPath = normalizePluginScriptPath(pluginRoot, input.path, `${fieldName}.path`);
|
|
894
|
-
if (runner === 'auto') {
|
|
895
|
-
assertAutoRunnablePath(scriptPath, `${fieldName}.path`);
|
|
896
|
-
}
|
|
897
888
|
return {
|
|
898
|
-
runner,
|
|
889
|
+
runner: 'node',
|
|
899
890
|
path: scriptPath,
|
|
900
891
|
args: input.args === undefined
|
|
901
892
|
? undefined
|
|
902
893
|
: ensureStringArray(input.args, `${fieldName}.args`),
|
|
903
894
|
};
|
|
904
895
|
}
|
|
905
|
-
function
|
|
906
|
-
if (typeof value === 'string') {
|
|
907
|
-
const scriptPath = normalizePluginScriptPath(pluginRoot, value, fieldName);
|
|
908
|
-
assertAutoRunnablePath(scriptPath, fieldName);
|
|
909
|
-
return {
|
|
910
|
-
default: {
|
|
911
|
-
runner: 'auto',
|
|
912
|
-
path: scriptPath,
|
|
913
|
-
},
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
|
-
const input = assertObject(value, fieldName);
|
|
917
|
-
if ('runner' in input || 'path' in input || 'command' in input) {
|
|
918
|
-
throw new Error(`Invalid ${fieldName}: lifecycle scripts must be declared under OS selectors.`);
|
|
919
|
-
}
|
|
920
|
-
if ('timeoutMs' in input || 'timeout' in input) {
|
|
921
|
-
throw new Error(`Invalid ${fieldName}: per-event and per-selector timeouts are not supported.`);
|
|
922
|
-
}
|
|
923
|
-
for (const key of Object.keys(input)) {
|
|
924
|
-
if (!isPluginLifecycleOsSelector(key)) {
|
|
925
|
-
throw new Error(`Invalid ${fieldName}: unknown OS selector "${key}".`);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
const output = {};
|
|
929
|
-
for (const [selector, entry] of Object.entries(input)) {
|
|
930
|
-
output[selector] = normalizeScriptEntry(pluginRoot, entry, `${fieldName}.${selector}`);
|
|
931
|
-
}
|
|
932
|
-
for (const osName of ['linux', 'darwin', 'win32']) {
|
|
933
|
-
if (!resolveLifecycleScriptForOs(output, osName)) {
|
|
934
|
-
throw new Error(`Invalid ${fieldName}: no lifecycle entry resolves on ${osName}.`);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
return output;
|
|
938
|
-
}
|
|
939
|
-
function normalizeLifecycleScripts(pluginRoot, value, fieldName) {
|
|
896
|
+
function normalizePreApplyScript(pluginRoot, value, fieldName) {
|
|
940
897
|
const input = assertObject(value, fieldName);
|
|
941
|
-
assertAllowedKeys(input, fieldName, [
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
898
|
+
assertAllowedKeys(input, fieldName, ['path', 'timeoutMs']);
|
|
899
|
+
const scriptPath = normalizePluginScriptPath(pluginRoot, input.path, `${fieldName}.path`);
|
|
900
|
+
assertNodeRunnablePath(scriptPath, `${fieldName}.path`);
|
|
901
|
+
return {
|
|
902
|
+
path: scriptPath,
|
|
903
|
+
...(input.timeoutMs === undefined
|
|
904
|
+
? {}
|
|
905
|
+
: { timeoutMs: normalizeScriptTimeout(input.timeoutMs, `${fieldName}.timeoutMs`) }),
|
|
906
|
+
};
|
|
950
907
|
}
|
|
951
908
|
function normalizeScriptHelpers(pluginRoot, value, fieldName) {
|
|
952
909
|
const input = assertObject(value, fieldName);
|
|
@@ -959,9 +916,7 @@ function normalizeScriptHelpers(pluginRoot, value, fieldName) {
|
|
|
959
916
|
return { config };
|
|
960
917
|
}
|
|
961
918
|
function normalizeNodeBuildScript(pluginRoot, value, fieldName) {
|
|
962
|
-
const entry = normalizeScriptEntry(pluginRoot, value, fieldName
|
|
963
|
-
requireNodeRunner: true,
|
|
964
|
-
});
|
|
919
|
+
const entry = normalizeScriptEntry(pluginRoot, value, fieldName);
|
|
965
920
|
assertNodeRunnablePath(entry.path, `${fieldName}.path`);
|
|
966
921
|
return {
|
|
967
922
|
runner: 'node',
|
|
@@ -1060,9 +1015,7 @@ function normalizeScriptTests(value, fieldName) {
|
|
|
1060
1015
|
};
|
|
1061
1016
|
}
|
|
1062
1017
|
function normalizeArtifactRenderScript(pluginRoot, value, fieldName) {
|
|
1063
|
-
const entry = normalizeScriptEntry(pluginRoot, value, fieldName
|
|
1064
|
-
requireNodeRunner: true,
|
|
1065
|
-
});
|
|
1018
|
+
const entry = normalizeScriptEntry(pluginRoot, value, fieldName);
|
|
1066
1019
|
assertNodeRunnablePath(entry.path, `${fieldName}.path`);
|
|
1067
1020
|
return {
|
|
1068
1021
|
runner: 'node',
|
|
@@ -1081,14 +1034,10 @@ function normalizeArtifactScripts(pluginRoot, value, fieldName) {
|
|
|
1081
1034
|
}
|
|
1082
1035
|
function normalizePluginScripts(pluginRoot, value, fieldName) {
|
|
1083
1036
|
const input = assertObject(value, fieldName);
|
|
1084
|
-
assertAllowedKeys(input, fieldName, ['
|
|
1085
|
-
const output = {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
: normalizeScriptTimeout(input.timeoutMs, `${fieldName}.timeoutMs`),
|
|
1089
|
-
};
|
|
1090
|
-
if (input.lifecycle !== undefined) {
|
|
1091
|
-
output.lifecycle = normalizeLifecycleScripts(pluginRoot, input.lifecycle, `${fieldName}.lifecycle`);
|
|
1037
|
+
assertAllowedKeys(input, fieldName, ['preApply', 'helpers', 'node', 'artifacts', 'tests']);
|
|
1038
|
+
const output = {};
|
|
1039
|
+
if (input.preApply !== undefined) {
|
|
1040
|
+
output.preApply = normalizePreApplyScript(pluginRoot, input.preApply, `${fieldName}.preApply`);
|
|
1092
1041
|
}
|
|
1093
1042
|
if (input.helpers !== undefined) {
|
|
1094
1043
|
output.helpers = normalizeScriptHelpers(pluginRoot, input.helpers, `${fieldName}.helpers`);
|
|
@@ -1104,254 +1053,6 @@ function normalizePluginScripts(pluginRoot, value, fieldName) {
|
|
|
1104
1053
|
}
|
|
1105
1054
|
return output;
|
|
1106
1055
|
}
|
|
1107
|
-
function validateConfigKey(key, fieldName) {
|
|
1108
|
-
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(key)) {
|
|
1109
|
-
throw new Error(`Invalid ${fieldName}: config key "${key}" is not valid.`);
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
function validateConfigDefault(type, value, values, min, max, fieldName) {
|
|
1113
|
-
if (type === 'string' || type === 'file' || type === 'directory') {
|
|
1114
|
-
return ensureString(value, fieldName);
|
|
1115
|
-
}
|
|
1116
|
-
if (type === 'boolean') {
|
|
1117
|
-
return ensureBoolean(value, fieldName);
|
|
1118
|
-
}
|
|
1119
|
-
if (type === 'number') {
|
|
1120
|
-
const numberValue = ensureFiniteNumber(value, fieldName);
|
|
1121
|
-
if (min !== undefined && numberValue < min) {
|
|
1122
|
-
throw new Error(`Invalid ${fieldName}: default is smaller than min.`);
|
|
1123
|
-
}
|
|
1124
|
-
if (max !== undefined && numberValue > max) {
|
|
1125
|
-
throw new Error(`Invalid ${fieldName}: default is greater than max.`);
|
|
1126
|
-
}
|
|
1127
|
-
return numberValue;
|
|
1128
|
-
}
|
|
1129
|
-
if (type === 'enum') {
|
|
1130
|
-
const enumValue = ensureString(value, fieldName);
|
|
1131
|
-
if (!values?.includes(enumValue)) {
|
|
1132
|
-
throw new Error(`Invalid ${fieldName}: enum default must be one of values.`);
|
|
1133
|
-
}
|
|
1134
|
-
return enumValue;
|
|
1135
|
-
}
|
|
1136
|
-
throw new Error(`Invalid ${fieldName}: unsupported config type "${type}".`);
|
|
1137
|
-
}
|
|
1138
|
-
function normalizePluginConfigPresentation(value, schema, fieldName) {
|
|
1139
|
-
const input = assertObject(value, fieldName);
|
|
1140
|
-
assertAllowedKeys(input, fieldName, ['groups', 'fields', 'presets']);
|
|
1141
|
-
const schemaKeys = new Set(Object.keys(schema));
|
|
1142
|
-
const presentation = {};
|
|
1143
|
-
if (input.groups !== undefined) {
|
|
1144
|
-
if (!Array.isArray(input.groups)) {
|
|
1145
|
-
throw new Error(`Invalid ${fieldName}.groups: expected an array.`);
|
|
1146
|
-
}
|
|
1147
|
-
const groupIds = new Set();
|
|
1148
|
-
const groupedFields = new Set();
|
|
1149
|
-
presentation.groups = input.groups.map((rawGroup, index) => {
|
|
1150
|
-
const groupFieldName = `${fieldName}.groups[${index}]`;
|
|
1151
|
-
const group = assertObject(rawGroup, groupFieldName);
|
|
1152
|
-
assertAllowedKeys(group, groupFieldName, [
|
|
1153
|
-
'id',
|
|
1154
|
-
'title',
|
|
1155
|
-
'description',
|
|
1156
|
-
'fields',
|
|
1157
|
-
'advanced',
|
|
1158
|
-
]);
|
|
1159
|
-
const id = ensureString(group.id, `${groupFieldName}.id`);
|
|
1160
|
-
if (groupIds.has(id)) {
|
|
1161
|
-
throw new Error(`Invalid ${groupFieldName}.id: duplicate group id "${id}".`);
|
|
1162
|
-
}
|
|
1163
|
-
groupIds.add(id);
|
|
1164
|
-
const fields = ensureStringArray(group.fields, `${groupFieldName}.fields`);
|
|
1165
|
-
for (const [fieldIndex, key] of fields.entries()) {
|
|
1166
|
-
if (!schemaKeys.has(key)) {
|
|
1167
|
-
throw new Error(`Invalid ${groupFieldName}.fields[${fieldIndex}]: unknown config key "${key}".`);
|
|
1168
|
-
}
|
|
1169
|
-
if (groupedFields.has(key)) {
|
|
1170
|
-
throw new Error(`Invalid ${groupFieldName}.fields[${fieldIndex}]: config key "${key}" is assigned to more than one group.`);
|
|
1171
|
-
}
|
|
1172
|
-
groupedFields.add(key);
|
|
1173
|
-
}
|
|
1174
|
-
return {
|
|
1175
|
-
id,
|
|
1176
|
-
title: ensureString(group.title, `${groupFieldName}.title`),
|
|
1177
|
-
description: group.description === undefined
|
|
1178
|
-
? undefined
|
|
1179
|
-
: ensureString(group.description, `${groupFieldName}.description`),
|
|
1180
|
-
fields,
|
|
1181
|
-
advanced: group.advanced === undefined
|
|
1182
|
-
? undefined
|
|
1183
|
-
: ensureBoolean(group.advanced, `${groupFieldName}.advanced`),
|
|
1184
|
-
};
|
|
1185
|
-
});
|
|
1186
|
-
}
|
|
1187
|
-
if (input.fields !== undefined) {
|
|
1188
|
-
const fieldsInput = assertObject(input.fields, `${fieldName}.fields`);
|
|
1189
|
-
presentation.fields = {};
|
|
1190
|
-
for (const [key, rawPresentationField] of Object.entries(fieldsInput)) {
|
|
1191
|
-
if (!schemaKeys.has(key)) {
|
|
1192
|
-
throw new Error(`Invalid ${fieldName}.fields: unknown config key "${key}".`);
|
|
1193
|
-
}
|
|
1194
|
-
const presentationFieldName = `${fieldName}.fields.${key}`;
|
|
1195
|
-
const presentationField = assertObject(rawPresentationField, presentationFieldName);
|
|
1196
|
-
assertAllowedKeys(presentationField, presentationFieldName, [
|
|
1197
|
-
'valueLabels',
|
|
1198
|
-
'recommendedValue',
|
|
1199
|
-
'placeholder',
|
|
1200
|
-
'unit',
|
|
1201
|
-
'advanced',
|
|
1202
|
-
]);
|
|
1203
|
-
const schemaField = schema[key];
|
|
1204
|
-
let valueLabels;
|
|
1205
|
-
if (presentationField.valueLabels !== undefined) {
|
|
1206
|
-
if (schemaField.type !== 'enum') {
|
|
1207
|
-
throw new Error(`Invalid ${presentationFieldName}.valueLabels: valueLabels are only supported for enum config.`);
|
|
1208
|
-
}
|
|
1209
|
-
const labelsInput = assertObject(presentationField.valueLabels, `${presentationFieldName}.valueLabels`);
|
|
1210
|
-
valueLabels = {};
|
|
1211
|
-
for (const [token, rawLabel] of Object.entries(labelsInput)) {
|
|
1212
|
-
if (!schemaField.values?.includes(token)) {
|
|
1213
|
-
throw new Error(`Invalid ${presentationFieldName}.valueLabels: unknown enum token "${token}".`);
|
|
1214
|
-
}
|
|
1215
|
-
valueLabels[token] = ensureString(rawLabel, `${presentationFieldName}.valueLabels.${token}`);
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
presentation.fields[key] = {
|
|
1219
|
-
valueLabels,
|
|
1220
|
-
recommendedValue: presentationField.recommendedValue === undefined
|
|
1221
|
-
? undefined
|
|
1222
|
-
: validateConfigDefault(schemaField.type, presentationField.recommendedValue, schemaField.values, schemaField.min, schemaField.max, `${presentationFieldName}.recommendedValue`),
|
|
1223
|
-
placeholder: presentationField.placeholder === undefined
|
|
1224
|
-
? undefined
|
|
1225
|
-
: ensureString(presentationField.placeholder, `${presentationFieldName}.placeholder`),
|
|
1226
|
-
unit: presentationField.unit === undefined
|
|
1227
|
-
? undefined
|
|
1228
|
-
: ensureString(presentationField.unit, `${presentationFieldName}.unit`),
|
|
1229
|
-
advanced: presentationField.advanced === undefined
|
|
1230
|
-
? undefined
|
|
1231
|
-
: ensureBoolean(presentationField.advanced, `${presentationFieldName}.advanced`),
|
|
1232
|
-
};
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
if (input.presets !== undefined) {
|
|
1236
|
-
if (!Array.isArray(input.presets)) {
|
|
1237
|
-
throw new Error(`Invalid ${fieldName}.presets: expected an array.`);
|
|
1238
|
-
}
|
|
1239
|
-
const presetIds = new Set();
|
|
1240
|
-
presentation.presets = input.presets.map((rawPreset, index) => {
|
|
1241
|
-
const presetFieldName = `${fieldName}.presets[${index}]`;
|
|
1242
|
-
const preset = assertObject(rawPreset, presetFieldName);
|
|
1243
|
-
assertAllowedKeys(preset, presetFieldName, ['id', 'title', 'description', 'values']);
|
|
1244
|
-
const id = ensureString(preset.id, `${presetFieldName}.id`);
|
|
1245
|
-
if (presetIds.has(id)) {
|
|
1246
|
-
throw new Error(`Invalid ${presetFieldName}.id: duplicate preset id "${id}".`);
|
|
1247
|
-
}
|
|
1248
|
-
presetIds.add(id);
|
|
1249
|
-
const valuesInput = assertObject(preset.values, `${presetFieldName}.values`);
|
|
1250
|
-
const values = {};
|
|
1251
|
-
for (const [key, rawValue] of Object.entries(valuesInput)) {
|
|
1252
|
-
const schemaField = schema[key];
|
|
1253
|
-
if (!schemaField) {
|
|
1254
|
-
throw new Error(`Invalid ${presetFieldName}.values: unknown config key "${key}".`);
|
|
1255
|
-
}
|
|
1256
|
-
if (schemaField.sensitive === true
|
|
1257
|
-
|| schemaField.type === 'file'
|
|
1258
|
-
|| schemaField.type === 'directory') {
|
|
1259
|
-
throw new Error(`Invalid ${presetFieldName}.values.${key}: presets cannot contain sensitive, file, or directory config values.`);
|
|
1260
|
-
}
|
|
1261
|
-
values[key] = validateConfigDefault(schemaField.type, rawValue, schemaField.values, schemaField.min, schemaField.max, `${presetFieldName}.values.${key}`);
|
|
1262
|
-
}
|
|
1263
|
-
return {
|
|
1264
|
-
id,
|
|
1265
|
-
title: ensureString(preset.title, `${presetFieldName}.title`),
|
|
1266
|
-
description: preset.description === undefined
|
|
1267
|
-
? undefined
|
|
1268
|
-
: ensureString(preset.description, `${presetFieldName}.description`),
|
|
1269
|
-
values,
|
|
1270
|
-
};
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
return presentation;
|
|
1274
|
-
}
|
|
1275
|
-
function normalizePluginConfigSchema(value, fieldName) {
|
|
1276
|
-
const input = assertObject(value, fieldName);
|
|
1277
|
-
assertAllowedKeys(input, fieldName, ['schema', 'presentation']);
|
|
1278
|
-
const schemaInput = assertObject(input.schema, `${fieldName}.schema`);
|
|
1279
|
-
const schema = {};
|
|
1280
|
-
const supportedTypes = new Set(['string', 'number', 'boolean', 'enum', 'file', 'directory']);
|
|
1281
|
-
for (const [key, rawField] of Object.entries(schemaInput)) {
|
|
1282
|
-
validateConfigKey(key, `${fieldName}.schema`);
|
|
1283
|
-
const schemaFieldName = `${fieldName}.schema.${key}`;
|
|
1284
|
-
const configField = assertObject(rawField, schemaFieldName);
|
|
1285
|
-
assertAllowedKeys(configField, schemaFieldName, [
|
|
1286
|
-
'type',
|
|
1287
|
-
'title',
|
|
1288
|
-
'description',
|
|
1289
|
-
'default',
|
|
1290
|
-
'required',
|
|
1291
|
-
'sensitive',
|
|
1292
|
-
'values',
|
|
1293
|
-
'min',
|
|
1294
|
-
'max',
|
|
1295
|
-
]);
|
|
1296
|
-
const type = ensureString(configField.type, `${schemaFieldName}.type`);
|
|
1297
|
-
if (!supportedTypes.has(type)) {
|
|
1298
|
-
throw new Error(`Invalid ${schemaFieldName}.type: expected string, number, boolean, enum, file, or directory.`);
|
|
1299
|
-
}
|
|
1300
|
-
const required = configField.required === undefined
|
|
1301
|
-
? undefined
|
|
1302
|
-
: ensureBoolean(configField.required, `${schemaFieldName}.required`);
|
|
1303
|
-
const sensitive = configField.sensitive === undefined
|
|
1304
|
-
? undefined
|
|
1305
|
-
: ensureBoolean(configField.sensitive, `${schemaFieldName}.sensitive`);
|
|
1306
|
-
const values = configField.values === undefined
|
|
1307
|
-
? undefined
|
|
1308
|
-
: ensureStringArray(configField.values, `${schemaFieldName}.values`);
|
|
1309
|
-
if (type !== 'enum' && values !== undefined) {
|
|
1310
|
-
throw new Error(`Invalid ${schemaFieldName}.values: values are only supported for enum config.`);
|
|
1311
|
-
}
|
|
1312
|
-
if (type === 'enum' && (!values || values.length === 0)) {
|
|
1313
|
-
throw new Error(`Invalid ${schemaFieldName}.values: enum config requires at least one value.`);
|
|
1314
|
-
}
|
|
1315
|
-
if (values && new Set(values).size !== values.length) {
|
|
1316
|
-
throw new Error(`Invalid ${schemaFieldName}.values: enum values must be unique.`);
|
|
1317
|
-
}
|
|
1318
|
-
const min = configField.min === undefined
|
|
1319
|
-
? undefined
|
|
1320
|
-
: ensureFiniteNumber(configField.min, `${schemaFieldName}.min`);
|
|
1321
|
-
const max = configField.max === undefined
|
|
1322
|
-
? undefined
|
|
1323
|
-
: ensureFiniteNumber(configField.max, `${schemaFieldName}.max`);
|
|
1324
|
-
if (type !== 'number' && (min !== undefined || max !== undefined)) {
|
|
1325
|
-
throw new Error(`Invalid ${schemaFieldName}: min/max are only supported for number config.`);
|
|
1326
|
-
}
|
|
1327
|
-
if (min !== undefined && max !== undefined && min > max) {
|
|
1328
|
-
throw new Error(`Invalid ${schemaFieldName}: min must be less than or equal to max.`);
|
|
1329
|
-
}
|
|
1330
|
-
schema[key] = {
|
|
1331
|
-
type: type,
|
|
1332
|
-
title: configField.title === undefined
|
|
1333
|
-
? undefined
|
|
1334
|
-
: ensureString(configField.title, `${schemaFieldName}.title`),
|
|
1335
|
-
description: configField.description === undefined
|
|
1336
|
-
? undefined
|
|
1337
|
-
: ensureString(configField.description, `${schemaFieldName}.description`),
|
|
1338
|
-
default: configField.default === undefined
|
|
1339
|
-
? undefined
|
|
1340
|
-
: validateConfigDefault(type, configField.default, values, min, max, `${schemaFieldName}.default`),
|
|
1341
|
-
required,
|
|
1342
|
-
sensitive,
|
|
1343
|
-
values,
|
|
1344
|
-
min,
|
|
1345
|
-
max,
|
|
1346
|
-
};
|
|
1347
|
-
}
|
|
1348
|
-
return {
|
|
1349
|
-
schema,
|
|
1350
|
-
presentation: input.presentation === undefined
|
|
1351
|
-
? undefined
|
|
1352
|
-
: normalizePluginConfigPresentation(input.presentation, schema, `${fieldName}.presentation`),
|
|
1353
|
-
};
|
|
1354
|
-
}
|
|
1355
1056
|
const ARTIFACT_TARGETS = new Set([
|
|
1356
1057
|
'codex.developerInstructionsBlock',
|
|
1357
1058
|
'codex.agentRole',
|
|
@@ -1372,6 +1073,8 @@ const ARTIFACT_KIND_BY_TARGET = {
|
|
|
1372
1073
|
'codex.skill': 'skill',
|
|
1373
1074
|
'claude.skill': 'skill',
|
|
1374
1075
|
'agent-skills.skill': 'skill',
|
|
1076
|
+
'aw.command-set': 'commandSet',
|
|
1077
|
+
'aw.command-package': 'commandPackage',
|
|
1375
1078
|
};
|
|
1376
1079
|
function normalizeArtifactRuntimeImports(value, fieldName, reservedImports) {
|
|
1377
1080
|
if (value === undefined)
|
|
@@ -1394,13 +1097,24 @@ function normalizeArtifactRuntimeImports(value, fieldName, reservedImports) {
|
|
|
1394
1097
|
const resolvedInput = assertObject(input.resolved, `${entryField}.resolved`);
|
|
1395
1098
|
assertAllowedKeys(resolvedInput, `${entryField}.resolved`, [
|
|
1396
1099
|
'path', 'digest', 'providerPluginId', 'providerVersion', 'source',
|
|
1100
|
+
'requiredCapabilities', 'capabilitySetDigest',
|
|
1397
1101
|
]);
|
|
1102
|
+
if (!Array.isArray(resolvedInput.requiredCapabilities)) {
|
|
1103
|
+
throw new Error(`Invalid ${entryField}.resolved.requiredCapabilities: expected an array.`);
|
|
1104
|
+
}
|
|
1105
|
+
const requiredCapabilities = normalizeAwCapabilities(resolvedInput.requiredCapabilities, `${entryField}.resolved.requiredCapabilities`);
|
|
1106
|
+
const capabilitySetDigest = ensureDigestString(resolvedInput.capabilitySetDigest, `${entryField}.resolved.capabilitySetDigest`);
|
|
1107
|
+
if (capabilitySetDigest !== computeAwCapabilitySetDigest(requiredCapabilities)) {
|
|
1108
|
+
throw new Error(`Invalid ${entryField}.resolved.capabilitySetDigest: digest does not match requiredCapabilities.`);
|
|
1109
|
+
}
|
|
1398
1110
|
resolved = {
|
|
1399
1111
|
path: normalizePluginChildPath('', ensureString(resolvedInput.path, `${entryField}.resolved.path`), `${entryField}.resolved.path`),
|
|
1400
1112
|
digest: ensureDigestString(resolvedInput.digest, `${entryField}.resolved.digest`),
|
|
1401
1113
|
providerPluginId: ensureString(resolvedInput.providerPluginId, `${entryField}.resolved.providerPluginId`),
|
|
1402
1114
|
providerVersion: assertStrictSemVer(resolvedInput.providerVersion, `${entryField}.resolved.providerVersion`),
|
|
1403
1115
|
source: ensureString(resolvedInput.source, `${entryField}.resolved.source`),
|
|
1116
|
+
requiredCapabilities,
|
|
1117
|
+
capabilitySetDigest,
|
|
1404
1118
|
};
|
|
1405
1119
|
}
|
|
1406
1120
|
return {
|
|
@@ -1458,7 +1172,7 @@ function normalizeArtifactStates(value, fieldName) {
|
|
|
1458
1172
|
}
|
|
1459
1173
|
function normalizeArtifactRefreshKeys(value, fieldName, schema) {
|
|
1460
1174
|
const refreshKeys = ensureStringArray(value, fieldName);
|
|
1461
|
-
const schemaKeys = new Set(Object.keys(schema?.
|
|
1175
|
+
const schemaKeys = new Set(Object.keys(schema?.fields ?? {}));
|
|
1462
1176
|
const normalized = [];
|
|
1463
1177
|
for (const [index, key] of refreshKeys.entries()) {
|
|
1464
1178
|
if (!schemaKeys.has(key)) {
|
|
@@ -1470,6 +1184,51 @@ function normalizeArtifactRefreshKeys(value, fieldName, schema) {
|
|
|
1470
1184
|
}
|
|
1471
1185
|
return normalized;
|
|
1472
1186
|
}
|
|
1187
|
+
function configFieldContainsSensitiveValue(field) {
|
|
1188
|
+
if (field.sensitive === true)
|
|
1189
|
+
return true;
|
|
1190
|
+
if (field.type !== 'object')
|
|
1191
|
+
return false;
|
|
1192
|
+
return ((field.properties
|
|
1193
|
+
? Object.values(field.properties).some((child) => child.sensitive === true)
|
|
1194
|
+
: false)
|
|
1195
|
+
|| (field.additionalProperties !== false && field.additionalProperties?.sensitive === true));
|
|
1196
|
+
}
|
|
1197
|
+
function assertSkillRefreshKeysAreNotSensitive(options) {
|
|
1198
|
+
const skillTarget = options.target === 'codex.skill'
|
|
1199
|
+
|| options.target === 'claude.skill'
|
|
1200
|
+
|| options.target === 'agent-skills.skill';
|
|
1201
|
+
if (!skillTarget)
|
|
1202
|
+
return;
|
|
1203
|
+
for (const [index, key] of options.refreshKeys.entries()) {
|
|
1204
|
+
const field = options.schema?.fields[key];
|
|
1205
|
+
if (field && configFieldContainsSensitiveValue(field)) {
|
|
1206
|
+
const native = options.delivery?.mode === 'codex-native';
|
|
1207
|
+
throw new Error(`${native ? 'codexNativeRenderSensitiveRefreshKey' : 'skillRenderSensitiveRefreshKey'}: ` +
|
|
1208
|
+
`Invalid ${options.fieldName}[${index}]: ` +
|
|
1209
|
+
`${native ? 'codex-native renderers' : 'Skill renderers'} cannot read sensitive config field "${key}".`);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function normalizeCodexSkillDelivery(value, fieldName) {
|
|
1214
|
+
const input = assertObject(value, fieldName);
|
|
1215
|
+
const mode = ensureString(input.mode, `${fieldName}.mode`);
|
|
1216
|
+
if (mode === 'aw-extension') {
|
|
1217
|
+
assertAllowedKeys(input, fieldName, ['mode']);
|
|
1218
|
+
return { mode };
|
|
1219
|
+
}
|
|
1220
|
+
if (mode === 'codex-native') {
|
|
1221
|
+
assertAllowedKeys(input, fieldName, ['mode', 'identity', 'renderProfile']);
|
|
1222
|
+
if (input.identity !== 'shared') {
|
|
1223
|
+
throw new Error(`Invalid ${fieldName}.identity: expected "shared".`);
|
|
1224
|
+
}
|
|
1225
|
+
if (input.renderProfile !== 'user') {
|
|
1226
|
+
throw new Error(`Invalid ${fieldName}.renderProfile: expected "user".`);
|
|
1227
|
+
}
|
|
1228
|
+
return { mode, identity: 'shared', renderProfile: 'user' };
|
|
1229
|
+
}
|
|
1230
|
+
throw new Error(`Invalid ${fieldName}.mode: expected "codex-native" or "aw-extension".`);
|
|
1231
|
+
}
|
|
1473
1232
|
function normalizeDynamicArtifactKind(value, fieldName) {
|
|
1474
1233
|
const kind = ensureString(value, fieldName);
|
|
1475
1234
|
if (!DYNAMIC_ARTIFACT_KINDS.has(kind)) {
|
|
@@ -1510,16 +1269,27 @@ function normalizeArtifactTargetEntry(pluginRoot, entry, fieldName, schema, rese
|
|
|
1510
1269
|
'projectManagedKind',
|
|
1511
1270
|
'states',
|
|
1512
1271
|
'refreshKeys',
|
|
1272
|
+
'delivery',
|
|
1513
1273
|
'requiresCodexProjectConfig',
|
|
1514
1274
|
'roleKey',
|
|
1515
1275
|
'skillKey',
|
|
1516
1276
|
'sourceDirs',
|
|
1517
1277
|
'distribution',
|
|
1518
1278
|
'runtimeImports',
|
|
1279
|
+
'runtimeConfig',
|
|
1519
1280
|
]);
|
|
1520
1281
|
const id = ensureString(input.id, `${fieldName}.id`);
|
|
1521
1282
|
validateArtifactId(id, `${fieldName}.id`);
|
|
1283
|
+
if (/^command-(?:set|package)\./u.test(id)) {
|
|
1284
|
+
throw new Error(`Invalid ${fieldName}.id: reserved managed command target prefix.`);
|
|
1285
|
+
}
|
|
1522
1286
|
const target = normalizeArtifactTarget(input.target, `${fieldName}.target`);
|
|
1287
|
+
const delivery = target === 'codex.skill'
|
|
1288
|
+
? normalizeCodexSkillDelivery(input.delivery, `${fieldName}.delivery`)
|
|
1289
|
+
: undefined;
|
|
1290
|
+
if (target !== 'codex.skill' && input.delivery !== undefined) {
|
|
1291
|
+
throw new Error(`Invalid ${fieldName}.delivery: delivery is only supported for codex.skill targets.`);
|
|
1292
|
+
}
|
|
1523
1293
|
const portable = target === 'agent-skills.skill';
|
|
1524
1294
|
const platform = portable ? undefined : normalizePlatformName(input.platform, `${fieldName}.platform`);
|
|
1525
1295
|
const distribution = portable
|
|
@@ -1615,6 +1385,30 @@ function normalizeArtifactTargetEntry(pluginRoot, entry, fieldName, schema, rese
|
|
|
1615
1385
|
if (!portable && input.runtimeImports !== undefined) {
|
|
1616
1386
|
throw new Error(`Invalid ${fieldName}.runtimeImports: runtimeImports are only supported for agent-skills.skill targets.`);
|
|
1617
1387
|
}
|
|
1388
|
+
const refreshKeys = normalizeArtifactRefreshKeys(input.refreshKeys, `${fieldName}.refreshKeys`, schema);
|
|
1389
|
+
assertSkillRefreshKeysAreNotSensitive({
|
|
1390
|
+
target,
|
|
1391
|
+
delivery,
|
|
1392
|
+
refreshKeys,
|
|
1393
|
+
schema,
|
|
1394
|
+
fieldName: `${fieldName}.refreshKeys`,
|
|
1395
|
+
});
|
|
1396
|
+
let runtimeConfig;
|
|
1397
|
+
if (input.runtimeConfig !== undefined) {
|
|
1398
|
+
if (target !== 'codex.skill' && target !== 'claude.skill') {
|
|
1399
|
+
throw new Error(`Invalid ${fieldName}.runtimeConfig: only native platform Skill targets support installed runtime config.`);
|
|
1400
|
+
}
|
|
1401
|
+
const runtime = assertObject(input.runtimeConfig, `${fieldName}.runtimeConfig`);
|
|
1402
|
+
assertAllowedKeys(runtime, `${fieldName}.runtimeConfig`, ['keys']);
|
|
1403
|
+
const keys = ensureStringArray(runtime.keys, `${fieldName}.runtimeConfig.keys`);
|
|
1404
|
+
if (keys.length === 0 || new Set(keys).size !== keys.length || keys.some((key) => !refreshKeys.includes(key))) {
|
|
1405
|
+
throw new Error(`Invalid ${fieldName}.runtimeConfig.keys: expected unique non-empty keys from refreshKeys.`);
|
|
1406
|
+
}
|
|
1407
|
+
if (!schema || getPluginConfigDependencyKeys(schema, keys).some((key) => !schema.fields[key] || configFieldContainsSensitiveValue(schema.fields[key]))) {
|
|
1408
|
+
throw new Error(`runtimeConfigKeyDenied: Invalid ${fieldName}.runtimeConfig.keys: dependency fields must be declared and non-sensitive.`);
|
|
1409
|
+
}
|
|
1410
|
+
runtimeConfig = { keys: [keys[0], ...keys.slice(1)] };
|
|
1411
|
+
}
|
|
1618
1412
|
return {
|
|
1619
1413
|
id,
|
|
1620
1414
|
platform,
|
|
@@ -1624,12 +1418,14 @@ function normalizeArtifactTargetEntry(pluginRoot, entry, fieldName, schema, rese
|
|
|
1624
1418
|
kind,
|
|
1625
1419
|
projectManagedKind,
|
|
1626
1420
|
states: normalizeArtifactStates(input.states, `${fieldName}.states`),
|
|
1627
|
-
refreshKeys
|
|
1421
|
+
refreshKeys,
|
|
1422
|
+
delivery,
|
|
1628
1423
|
requiresCodexProjectConfig: input.requiresCodexProjectConfig === undefined
|
|
1629
1424
|
? undefined
|
|
1630
1425
|
: ensureBoolean(input.requiresCodexProjectConfig, `${fieldName}.requiresCodexProjectConfig`),
|
|
1631
1426
|
roleKey,
|
|
1632
1427
|
skillKey,
|
|
1428
|
+
runtimeConfig,
|
|
1633
1429
|
sourceDirs,
|
|
1634
1430
|
runtimeImports: normalizeArtifactRuntimeImports(input.runtimeImports, `${fieldName}.runtimeImports`, reservedImports),
|
|
1635
1431
|
};
|
|
@@ -1644,15 +1440,19 @@ function normalizeArtifacts(pluginRoot, value, fieldName, schema, reservedImport
|
|
|
1644
1440
|
if (!Array.isArray(targetsInput)) {
|
|
1645
1441
|
throw new Error(`Invalid ${fieldName}.targets: expected an array.`);
|
|
1646
1442
|
}
|
|
1647
|
-
const
|
|
1443
|
+
const seenIdsBySurfaceScope = new Set();
|
|
1648
1444
|
const seenSkillOwners = new Set();
|
|
1445
|
+
const seenNativeIds = new Set();
|
|
1446
|
+
const seenNativeSkillKeys = new Set();
|
|
1649
1447
|
return targetsInput.map((entry, index) => {
|
|
1650
1448
|
const target = normalizeArtifactTargetEntry(pluginRoot, entry, `${fieldName}.targets[${index}]`, schema, reservedImports);
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
|
|
1449
|
+
for (const scope of target.scopes) {
|
|
1450
|
+
const surfaceScopeId = `${target.platform ?? target.distribution}:${scope}:${target.id}`;
|
|
1451
|
+
if (seenIdsBySurfaceScope.has(surfaceScopeId)) {
|
|
1452
|
+
throw new Error(`Invalid ${fieldName}.targets[${index}]: duplicate artifact id "${target.id}" for surface/scope "${target.platform ?? target.distribution}:${scope}".`);
|
|
1453
|
+
}
|
|
1454
|
+
seenIdsBySurfaceScope.add(surfaceScopeId);
|
|
1654
1455
|
}
|
|
1655
|
-
seen.add(key);
|
|
1656
1456
|
if ((target.target === 'codex.skill' || target.target === 'claude.skill' || target.target === 'agent-skills.skill') && target.skillKey) {
|
|
1657
1457
|
for (const scope of target.scopes) {
|
|
1658
1458
|
const ownerKey = `${target.platform ?? target.distribution}:${scope}:${target.skillKey}`;
|
|
@@ -1662,11 +1462,60 @@ function normalizeArtifacts(pluginRoot, value, fieldName, schema, reservedImport
|
|
|
1662
1462
|
seenSkillOwners.add(ownerKey);
|
|
1663
1463
|
}
|
|
1664
1464
|
}
|
|
1465
|
+
if (target.delivery?.mode === 'codex-native') {
|
|
1466
|
+
if (seenNativeIds.has(target.id)) {
|
|
1467
|
+
throw new Error(`Invalid ${fieldName}.targets[${index}]: duplicate codex-native artifact id "${target.id}" in the shared projection.`);
|
|
1468
|
+
}
|
|
1469
|
+
if (target.skillKey && seenNativeSkillKeys.has(target.skillKey)) {
|
|
1470
|
+
throw new Error(`Invalid ${fieldName}.targets[${index}]: duplicate codex-native skillKey "${target.skillKey}" in the shared projection.`);
|
|
1471
|
+
}
|
|
1472
|
+
seenNativeIds.add(target.id);
|
|
1473
|
+
if (target.skillKey)
|
|
1474
|
+
seenNativeSkillKeys.add(target.skillKey);
|
|
1475
|
+
}
|
|
1665
1476
|
return target;
|
|
1666
1477
|
});
|
|
1667
1478
|
})();
|
|
1668
1479
|
return { targets };
|
|
1669
1480
|
}
|
|
1481
|
+
function canonicalScopeSet(scopes) {
|
|
1482
|
+
return [...scopes].sort().join(',');
|
|
1483
|
+
}
|
|
1484
|
+
function assertCodexSharedNativeScopeConsistency(manifest) {
|
|
1485
|
+
if (!supportsPlatform(manifest, 'codex'))
|
|
1486
|
+
return;
|
|
1487
|
+
const nativeComponents = [];
|
|
1488
|
+
if (manifest.skills) {
|
|
1489
|
+
nativeComponents.push({ key: 'skills', scopes: ['project', 'user'] });
|
|
1490
|
+
}
|
|
1491
|
+
if (manifest.mcpServers) {
|
|
1492
|
+
nativeComponents.push({ key: 'mcpServers', scopes: ['project', 'user'] });
|
|
1493
|
+
}
|
|
1494
|
+
if (resolvePlatformHookDefinitions(manifest, 'codex').length > 0) {
|
|
1495
|
+
nativeComponents.push({ key: 'hooks', scopes: ['project', 'user'] });
|
|
1496
|
+
}
|
|
1497
|
+
if (manifest.apps) {
|
|
1498
|
+
nativeComponents.push({ key: 'apps', scopes: ['project', 'user'] });
|
|
1499
|
+
}
|
|
1500
|
+
for (const [index, target] of (manifest.artifacts?.targets ?? []).entries()) {
|
|
1501
|
+
if (target.delivery?.mode === 'codex-native') {
|
|
1502
|
+
nativeComponents.push({
|
|
1503
|
+
key: `artifacts.targets[${index}]`,
|
|
1504
|
+
scopes: [...target.scopes],
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
const expected = nativeComponents[0];
|
|
1509
|
+
if (!expected)
|
|
1510
|
+
return;
|
|
1511
|
+
const expectedScopes = canonicalScopeSet(expected.scopes);
|
|
1512
|
+
const mismatch = nativeComponents.find((component) => canonicalScopeSet(component.scopes) !== expectedScopes);
|
|
1513
|
+
if (mismatch) {
|
|
1514
|
+
throw new Error(`codexSharedNativeScopeMismatch: Codex native component scope sets must match exactly; ` +
|
|
1515
|
+
`${expected.key} has {${expectedScopes}} but ${mismatch.key} has ` +
|
|
1516
|
+
`{${canonicalScopeSet(mismatch.scopes)}}.`);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1670
1519
|
function normalizePlatformAgentOverrides(value, fieldName, normalizer) {
|
|
1671
1520
|
const input = assertObject(value, fieldName);
|
|
1672
1521
|
assertAllowedKeys(input, fieldName, ['claude', 'codex']);
|
|
@@ -1726,7 +1575,7 @@ function normalizePermissionEntry(entry, fieldName) {
|
|
|
1726
1575
|
agentOverrides: input.agentOverrides === undefined
|
|
1727
1576
|
? undefined
|
|
1728
1577
|
: normalizePlatformAgentOverrides(input.agentOverrides, `${fieldName}.agentOverrides`, (overrideInput, overrideFieldName) => {
|
|
1729
|
-
assertAllowedKeys(overrideInput, overrideFieldName, ['name', 'allow', 'ask', 'deny']);
|
|
1578
|
+
assertAllowedKeys(overrideInput, overrideFieldName, overrideFieldName.endsWith('.claude') ? ['name', 'allow', 'ask', 'deny', 'sandbox'] : ['name', 'allow', 'ask', 'deny']);
|
|
1730
1579
|
return {
|
|
1731
1580
|
name: overrideInput.name === undefined
|
|
1732
1581
|
? undefined
|
|
@@ -1734,6 +1583,15 @@ function normalizePermissionEntry(entry, fieldName) {
|
|
|
1734
1583
|
allow: normalizePermissionCommandArray(overrideInput.allow, `${overrideFieldName}.allow`),
|
|
1735
1584
|
ask: normalizePermissionCommandArray(overrideInput.ask, `${overrideFieldName}.ask`),
|
|
1736
1585
|
deny: normalizePermissionCommandArray(overrideInput.deny, `${overrideFieldName}.deny`),
|
|
1586
|
+
...(overrideInput.sandbox === undefined ? {} : {
|
|
1587
|
+
sandbox: (() => {
|
|
1588
|
+
const sandbox = assertObject(overrideInput.sandbox, `${overrideFieldName}.sandbox`);
|
|
1589
|
+
assertAllowedKeys(sandbox, `${overrideFieldName}.sandbox`, ['excludedCommands']);
|
|
1590
|
+
if (!Array.isArray(sandbox.excludedCommands))
|
|
1591
|
+
throw new Error(`Invalid ${overrideFieldName}.sandbox.excludedCommands: expected an array.`);
|
|
1592
|
+
return { excludedCommands: sandbox.excludedCommands.map((value, index) => normalizeManagedCommandPermission(value, `${overrideFieldName}.sandbox.excludedCommands[${index}]`)) };
|
|
1593
|
+
})(),
|
|
1594
|
+
}),
|
|
1737
1595
|
};
|
|
1738
1596
|
}),
|
|
1739
1597
|
};
|
|
@@ -2006,7 +1864,7 @@ export async function assertActualNativePluginCapability(pluginRoot, manifest, m
|
|
|
2006
1864
|
}
|
|
2007
1865
|
}
|
|
2008
1866
|
if (!skills && !slashCommands && !mcpServers && !apps && !bundled) {
|
|
2009
|
-
throw new Error('Invalid plugin manifest: portable-only plugins are not supported
|
|
1867
|
+
throw new Error('Invalid plugin manifest: portable-only plugins are not supported. Declare at least one non-empty native capability.');
|
|
2010
1868
|
}
|
|
2011
1869
|
}
|
|
2012
1870
|
export function validatePluginManifest(pluginRoot, rawManifest, options = {}) {
|
|
@@ -2020,7 +1878,7 @@ export function validatePluginManifest(pluginRoot, rawManifest, options = {}) {
|
|
|
2020
1878
|
'version',
|
|
2021
1879
|
'description',
|
|
2022
1880
|
'dependencies',
|
|
2023
|
-
'
|
|
1881
|
+
'requires',
|
|
2024
1882
|
'skills',
|
|
2025
1883
|
'slashCommands',
|
|
2026
1884
|
'mcpServers',
|
|
@@ -2033,18 +1891,19 @@ export function validatePluginManifest(pluginRoot, rawManifest, options = {}) {
|
|
|
2033
1891
|
'buildConfig',
|
|
2034
1892
|
'scripts',
|
|
2035
1893
|
'config',
|
|
1894
|
+
'managedCommands',
|
|
1895
|
+
'nativeTools',
|
|
2036
1896
|
]);
|
|
2037
1897
|
const manifest = {
|
|
2038
1898
|
schemaVersion: PLUGIN_MANIFEST_SCHEMA_VERSION,
|
|
2039
1899
|
name: ensureString(input.name, 'name'),
|
|
2040
1900
|
version: assertStrictSemVer(input.version, 'plugin manifest.version'),
|
|
2041
1901
|
description: ensureString(input.description, 'description'),
|
|
2042
|
-
compatibility: normalizePluginCompatibility(input.compatibility, 'compatibility', {
|
|
2043
|
-
allowMissing: (options.compatibilityMode ?? 'defaulted') === 'defaulted',
|
|
2044
|
-
defaultMinVersion: options.defaultMinVersion,
|
|
2045
|
-
}),
|
|
2046
1902
|
marketplace: normalizeMarketplaceMeta(input.marketplace, 'marketplace'),
|
|
2047
1903
|
};
|
|
1904
|
+
const requires = normalizePluginRequirements(input.requires, 'requires', { allowMissing: true });
|
|
1905
|
+
if (requires !== undefined)
|
|
1906
|
+
manifest.requires = requires;
|
|
2048
1907
|
if (input.dependencies !== undefined) {
|
|
2049
1908
|
const dependencies = ensureStringArray(input.dependencies, 'dependencies');
|
|
2050
1909
|
if (dependencies.length > 64) {
|
|
@@ -2115,7 +1974,7 @@ export function validatePluginManifest(pluginRoot, rawManifest, options = {}) {
|
|
|
2115
1974
|
throw new Error('Invalid buildConfig.cacheable: true requires scripts.node.build.');
|
|
2116
1975
|
}
|
|
2117
1976
|
if (input.config !== undefined) {
|
|
2118
|
-
manifest.config =
|
|
1977
|
+
manifest.config = normalizePluginConfigDefinition(input.config, 'config');
|
|
2119
1978
|
}
|
|
2120
1979
|
if (input.artifacts !== undefined) {
|
|
2121
1980
|
manifest.artifacts = normalizeArtifacts(pluginRoot, input.artifacts, 'artifacts', manifest.config, options.reservedImports);
|
|
@@ -2124,7 +1983,16 @@ export function validatePluginManifest(pluginRoot, rawManifest, options = {}) {
|
|
|
2124
1983
|
&& !manifest.distributions?.agentSkills) {
|
|
2125
1984
|
throw new Error('Invalid artifacts.targets: agent-skills targets require distributions.agentSkills declaration.');
|
|
2126
1985
|
}
|
|
1986
|
+
if (input.managedCommands !== undefined) {
|
|
1987
|
+
manifest.managedCommands = normalizeManagedCommands(input.managedCommands);
|
|
1988
|
+
validateManagedCommandManifest(manifest);
|
|
1989
|
+
}
|
|
1990
|
+
if (input.nativeTools !== undefined) {
|
|
1991
|
+
manifest.nativeTools = normalizeNativeTools(input.nativeTools);
|
|
1992
|
+
validateNativeToolsManifest(manifest);
|
|
1993
|
+
}
|
|
2127
1994
|
assertManifestPlatformSupport(manifest.name, manifest);
|
|
1995
|
+
assertCodexSharedNativeScopeConsistency(manifest);
|
|
2128
1996
|
return manifest;
|
|
2129
1997
|
}
|
|
2130
1998
|
async function validateDeclaredNativeAssets(pluginRoot, manifest) {
|
|
@@ -2204,6 +2072,14 @@ async function validateSourceSkillInventory(pluginRoot, manifest) {
|
|
|
2204
2072
|
.filter((skillKey) => Boolean(skillKey))
|
|
2205
2073
|
.sort();
|
|
2206
2074
|
const dynamicSkillNameSet = new Set(dynamicSkillNames);
|
|
2075
|
+
for (const [index, target] of (manifest.artifacts?.targets ?? []).entries()) {
|
|
2076
|
+
if (target.target === 'codex.skill'
|
|
2077
|
+
&& target.delivery?.mode === 'codex-native'
|
|
2078
|
+
&& target.skillKey
|
|
2079
|
+
&& staticSkillNameSet.has(target.skillKey)) {
|
|
2080
|
+
throw new Error(`Invalid artifacts.targets[${index}].skillKey: native dynamic Skill "${target.skillKey}" conflicts with a static Skill of the same name.`);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2207
2083
|
const portableSkillsRoot = manifest.distributions?.agentSkills?.skills
|
|
2208
2084
|
? path.join(pluginRoot, stripDotSlash(manifest.distributions.agentSkills.skills))
|
|
2209
2085
|
: null;
|
|
@@ -2289,18 +2165,7 @@ async function validateSourceJsonNativeAsset(pluginRoot, manifest, field) {
|
|
|
2289
2165
|
}
|
|
2290
2166
|
export async function validateSourcePluginManifest(pluginRoot, rawManifest, options = {}) {
|
|
2291
2167
|
await assertPluginInputTree(pluginRoot);
|
|
2292
|
-
const distributionsInput = rawManifest !== null
|
|
2293
|
-
&& typeof rawManifest === 'object'
|
|
2294
|
-
&& !Array.isArray(rawManifest)
|
|
2295
|
-
? rawManifest.distributions
|
|
2296
|
-
: undefined;
|
|
2297
|
-
const requiresExplicitMinVersion = distributionsInput !== null
|
|
2298
|
-
&& typeof distributionsInput === 'object'
|
|
2299
|
-
&& !Array.isArray(distributionsInput)
|
|
2300
|
-
&& Object.hasOwn(distributionsInput, 'agentSkills');
|
|
2301
2168
|
const manifest = validatePluginManifest(pluginRoot, rawManifest, {
|
|
2302
|
-
compatibilityMode: requiresExplicitMinVersion ? 'required' : 'defaulted',
|
|
2303
|
-
defaultMinVersion: DEFAULT_SOURCE_PLUGIN_AW_MIN_VERSION,
|
|
2304
2169
|
reservedImports: options.reservedImports,
|
|
2305
2170
|
});
|
|
2306
2171
|
const parsedVersion = parseStrictSemVer(manifest.version, 'plugin manifest.version');
|
|
@@ -2312,6 +2177,9 @@ export async function validateSourcePluginManifest(pluginRoot, rawManifest, opti
|
|
|
2312
2177
|
}
|
|
2313
2178
|
await validateDeclaredNativeAssets(pluginRoot, manifest);
|
|
2314
2179
|
await validateDeclaredAssetPathsExist(pluginRoot, manifest);
|
|
2180
|
+
await validateManagedCommandSources(pluginRoot, manifest);
|
|
2181
|
+
validateNativeToolsManifest(manifest, { source: true });
|
|
2182
|
+
await loadPluginNativeToolClosure(pluginRoot, manifest);
|
|
2315
2183
|
await Promise.all([
|
|
2316
2184
|
validateSourceJsonNativeAsset(pluginRoot, manifest, 'mcpServers'),
|
|
2317
2185
|
validateSourceJsonNativeAsset(pluginRoot, manifest, 'apps'),
|
|
@@ -2337,12 +2205,14 @@ export async function readPluginManifest(pluginRoot, options = {}) {
|
|
|
2337
2205
|
? await validateSourcePluginManifest(pluginRoot, rawManifest, {
|
|
2338
2206
|
reservedImports: options.reservedImports,
|
|
2339
2207
|
})
|
|
2340
|
-
: validatePluginManifest(pluginRoot, rawManifest, {
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2208
|
+
: validatePluginManifest(pluginRoot, rawManifest, { reservedImports: options.reservedImports });
|
|
2209
|
+
if (mode === 'bundle') {
|
|
2210
|
+
await validateManagedCommandSources(pluginRoot, manifest);
|
|
2211
|
+
const nativeTools = await loadPluginNativeToolClosure(pluginRoot, manifest);
|
|
2212
|
+
if (nativeTools)
|
|
2213
|
+
await validateNativeToolClosureFiles(pluginRoot, nativeTools);
|
|
2345
2214
|
await assertActualNativePluginCapability(pluginRoot, manifest, 'bundle');
|
|
2215
|
+
}
|
|
2346
2216
|
return {
|
|
2347
2217
|
rootDir: pluginRoot,
|
|
2348
2218
|
manifestPath,
|
|
@@ -2438,9 +2308,6 @@ function assertCatalogChannelVersionContract(options) {
|
|
|
2438
2308
|
}
|
|
2439
2309
|
function normalizeCatalogManifestEntry(value, fieldName) {
|
|
2440
2310
|
const input = assertObject(value, fieldName);
|
|
2441
|
-
if (Object.hasOwn(input, 'dependencies')) {
|
|
2442
|
-
throw new Error(`Invalid ${fieldName}: "dependencies" is unsupported.`);
|
|
2443
|
-
}
|
|
2444
2311
|
assertAllowedKeys(input, fieldName, [
|
|
2445
2312
|
'name',
|
|
2446
2313
|
'version',
|
|
@@ -2450,7 +2317,8 @@ function normalizeCatalogManifestEntry(value, fieldName) {
|
|
|
2450
2317
|
'tags',
|
|
2451
2318
|
'strict',
|
|
2452
2319
|
'policy',
|
|
2453
|
-
'
|
|
2320
|
+
'dependencies',
|
|
2321
|
+
'requires',
|
|
2454
2322
|
'source',
|
|
2455
2323
|
'artifactDigest',
|
|
2456
2324
|
'manifestDigest',
|
|
@@ -2462,7 +2330,11 @@ function normalizeCatalogManifestEntry(value, fieldName) {
|
|
|
2462
2330
|
category: ensureString(input.category, `${fieldName}.category`),
|
|
2463
2331
|
strict: ensureBoolean(input.strict, `${fieldName}.strict`),
|
|
2464
2332
|
policy: normalizeMarketplacePolicy(input.policy, `${fieldName}.policy`),
|
|
2465
|
-
|
|
2333
|
+
dependencies: input.dependencies === undefined
|
|
2334
|
+
? []
|
|
2335
|
+
: normalizeComparableStringArray(ensureStringArray(input.dependencies, `${fieldName}.dependencies`))
|
|
2336
|
+
.map((dependency, index) => ensurePluginName(dependency, `${fieldName}.dependencies[${index}]`)),
|
|
2337
|
+
requires: normalizePluginRequirements(input.requires, `${fieldName}.requires`, {
|
|
2466
2338
|
allowMissing: false,
|
|
2467
2339
|
}),
|
|
2468
2340
|
source: normalizeCatalogRelativePath(input.source, `${fieldName}.source`),
|
|
@@ -2486,8 +2358,8 @@ export function normalizeCatalogManifestBase(input, fieldName) {
|
|
|
2486
2358
|
fieldName: `${fieldName}.catalogVersion`,
|
|
2487
2359
|
kind: 'catalog',
|
|
2488
2360
|
});
|
|
2489
|
-
const
|
|
2490
|
-
return { catalogVersion, channel,
|
|
2361
|
+
const requires = normalizePluginRequirements(input.requires, `${fieldName}.requires`, { allowMissing: false });
|
|
2362
|
+
return { catalogVersion, channel, requires };
|
|
2491
2363
|
}
|
|
2492
2364
|
export function normalizeCatalogManifestEntries(rawEntries, base, fieldName) {
|
|
2493
2365
|
if (!Array.isArray(rawEntries)) {
|
|
@@ -2508,16 +2380,10 @@ export function normalizeCatalogManifestEntries(rawEntries, base, fieldName) {
|
|
|
2508
2380
|
kind: 'plugin',
|
|
2509
2381
|
});
|
|
2510
2382
|
}
|
|
2511
|
-
assertPluginMinVersionWithinCatalogBounds({
|
|
2512
|
-
pluginName: entry.name,
|
|
2513
|
-
pluginMinVersion: entry.compatibility.aw.minVersion,
|
|
2514
|
-
catalogMinVersion: base.compatibility.aw.minVersion,
|
|
2515
|
-
fieldName: `${fieldName}.entries.${entry.name}.compatibility.aw.minVersion`,
|
|
2516
|
-
});
|
|
2517
2383
|
}
|
|
2518
2384
|
return entries;
|
|
2519
2385
|
}
|
|
2520
|
-
export function createBundleSourceManifest(plugin) {
|
|
2386
|
+
export function createBundleSourceManifest(plugin, requiredCapabilities) {
|
|
2521
2387
|
const scripts = plugin.manifest.scripts
|
|
2522
2388
|
? structuredClone(plugin.manifest.scripts)
|
|
2523
2389
|
: undefined;
|
|
@@ -2543,9 +2409,12 @@ export function createBundleSourceManifest(plugin) {
|
|
|
2543
2409
|
return {
|
|
2544
2410
|
...plugin.manifest,
|
|
2545
2411
|
buildConfig,
|
|
2546
|
-
|
|
2547
|
-
? structuredClone(plugin.manifest.
|
|
2548
|
-
:
|
|
2412
|
+
distributions: plugin.manifest.distributions
|
|
2413
|
+
? structuredClone(plugin.manifest.distributions)
|
|
2414
|
+
: undefined,
|
|
2415
|
+
requires: requiredCapabilities === undefined
|
|
2416
|
+
? structuredClone(plugin.manifest.requires)
|
|
2417
|
+
: { aw: { capabilities: normalizeAwCapabilities(requiredCapabilities) } },
|
|
2549
2418
|
extensions: plugin.manifest.extensions
|
|
2550
2419
|
? {
|
|
2551
2420
|
instructions: plugin.manifest.extensions.instructions
|
|
@@ -2580,11 +2449,6 @@ export function createPlatformManifestBase(plugin) {
|
|
|
2580
2449
|
name: plugin.manifest.name,
|
|
2581
2450
|
version: plugin.manifest.version,
|
|
2582
2451
|
description: plugin.manifest.description,
|
|
2583
|
-
compatibility: structuredClone(plugin.manifest.compatibility ?? {
|
|
2584
|
-
aw: {
|
|
2585
|
-
minVersion: '0.0.0',
|
|
2586
|
-
},
|
|
2587
|
-
}),
|
|
2588
2452
|
interface: plugin.manifest.interface,
|
|
2589
2453
|
};
|
|
2590
2454
|
}
|