@lesliechan721/aw 0.1.0-beta.10 → 0.1.0-beta.12
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/authoring/assets/aw-config.d.mts +1 -50
- package/dist/authoring/assets/aw-config.mjs +58 -928
- package/dist/authoring/assets/aw-config.mjs.map +1 -1
- package/dist/authoring/scripts/init-plugin.mjs +28 -33
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/lib/plugin-version-check.d.mts +1 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +229 -8
- package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +159 -48
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
- package/dist/scripts/bundle-plugins.js +18 -4
- package/dist/scripts/bundle-plugins.js.map +1 -1
- package/dist/scripts/test-plugin-scripts.d.ts +2 -0
- package/dist/scripts/test-plugin-scripts.js +21 -5
- package/dist/scripts/test-plugin-scripts.js.map +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +1 -1
- package/dist/src/commands/aw-capabilities.js +1 -1
- package/dist/src/commands/aw-capabilities.js.map +1 -1
- package/dist/src/commands/catalog-dev-source.d.ts +6 -3
- package/dist/src/commands/catalog-dev-source.js +96 -35
- package/dist/src/commands/catalog-dev-source.js.map +1 -1
- package/dist/src/commands/catalog-publication-inspection.d.ts +1 -1
- package/dist/src/commands/catalog-publication-inspection.js +54 -8
- package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
- package/dist/src/commands/catalog-publication-journal.js +1 -1
- package/dist/src/commands/catalog-publication-journal.js.map +1 -1
- package/dist/src/commands/catalog-source.d.ts +19 -4
- package/dist/src/commands/catalog-source.js +121 -12
- package/dist/src/commands/catalog-source.js.map +1 -1
- package/dist/src/commands/catalog-store.d.ts +26 -7
- package/dist/src/commands/catalog-store.js +361 -42
- package/dist/src/commands/catalog-store.js.map +1 -1
- package/dist/src/commands/console.js +28 -17
- package/dist/src/commands/console.js.map +1 -1
- package/dist/src/commands/operation-plan.d.ts +2 -1
- package/dist/src/commands/operation-plan.js +24 -0
- package/dist/src/commands/operation-plan.js.map +1 -1
- package/dist/src/commands/operation-planner.d.ts +2 -2
- package/dist/src/commands/operation-planner.js +22 -20
- package/dist/src/commands/operation-planner.js.map +1 -1
- package/dist/src/commands/options.d.ts +2 -2
- package/dist/src/commands/options.js +18 -4
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/plugin-capabilities.js +2 -2
- package/dist/src/commands/plugin-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +19 -0
- package/dist/src/commands/rebuild-command.js +828 -283
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +25 -47
- package/dist/src/commands/rebuild-integration.js +1176 -1016
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/rebuild-operations.d.ts +50 -12
- package/dist/src/commands/rebuild-operations.js +207 -101
- package/dist/src/commands/rebuild-operations.js.map +1 -1
- package/dist/src/commands/status-v6.d.ts +21 -2
- package/dist/src/commands/status-v6.js +163 -31
- package/dist/src/commands/status-v6.js.map +1 -1
- package/dist/src/commands/sync-command.d.ts +17 -0
- package/dist/src/commands/sync-command.js +45 -37
- package/dist/src/commands/sync-command.js.map +1 -1
- package/dist/src/commands/write-commands.d.ts +5 -0
- package/dist/src/commands/write-commands.js +50 -3
- package/dist/src/commands/write-commands.js.map +1 -1
- package/dist/src/generators/local-plugin.js +14 -4
- package/dist/src/generators/local-plugin.js.map +1 -1
- package/dist/src/index.js +260 -91
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/command-receipt.js +1 -3
- package/dist/src/output/command-receipt.js.map +1 -1
- package/dist/src/output/rebuild-progress.js +1 -3
- package/dist/src/output/rebuild-progress.js.map +1 -1
- package/dist/src/portable/materializer.js +10 -8
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/tui/catalog-generation.js +41 -1
- package/dist/src/tui/catalog-generation.js.map +1 -1
- package/dist/src/tui/catalog-sources/session.d.ts +1 -0
- package/dist/src/tui/catalog-sources/session.js +16 -3
- package/dist/src/tui/catalog-sources/session.js.map +1 -1
- package/dist/src/tui/catalog-sources/types.d.ts +3 -2
- package/dist/src/tui/components.d.ts +4 -0
- package/dist/src/tui/components.js +36 -24
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/console-app-v4.d.ts +13 -4
- package/dist/src/tui/console-app-v4.js +2065 -857
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.js +731 -62
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +156 -10
- package/dist/src/tui/controller.js +1187 -163
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/diagnostic-projection.d.ts +22 -0
- package/dist/src/tui/diagnostic-projection.js +437 -0
- package/dist/src/tui/diagnostic-projection.js.map +1 -0
- package/dist/src/tui/diagnostics.d.ts +1 -1
- package/dist/src/tui/diagnostics.js +7 -2
- package/dist/src/tui/diagnostics.js.map +1 -1
- package/dist/src/tui/glossary.d.ts +23 -0
- package/dist/src/tui/glossary.js +42 -0
- package/dist/src/tui/glossary.js.map +1 -0
- package/dist/src/tui/index.d.ts +4 -1
- package/dist/src/tui/index.js +4 -1
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/keys.d.ts +44 -0
- package/dist/src/tui/keys.js +43 -15
- package/dist/src/tui/keys.js.map +1 -1
- package/dist/src/tui/lifecycle-action-view.d.ts +6 -0
- package/dist/src/tui/lifecycle-action-view.js +34 -0
- package/dist/src/tui/lifecycle-action-view.js.map +1 -0
- package/dist/src/tui/model.d.ts +12 -2
- package/dist/src/tui/model.js +128 -52
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-diagnostic-screens.d.ts +21 -0
- package/dist/src/tui/operation-diagnostic-screens.js +101 -0
- package/dist/src/tui/operation-diagnostic-screens.js.map +1 -0
- package/dist/src/tui/operation-history.d.ts +80 -0
- package/dist/src/tui/operation-history.js +130 -0
- package/dist/src/tui/operation-history.js.map +1 -0
- package/dist/src/tui/operation-review-planner.js +366 -99
- package/dist/src/tui/operation-review-planner.js.map +1 -1
- package/dist/src/tui/router.d.ts +82 -17
- package/dist/src/tui/router.js +186 -38
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/screen-registry.d.ts +546 -0
- package/dist/src/tui/screen-registry.js +179 -0
- package/dist/src/tui/screen-registry.js.map +1 -0
- package/dist/src/tui/session-console-app.d.ts +6 -0
- package/dist/src/tui/session-console-app.js +13 -0
- package/dist/src/tui/session-console-app.js.map +1 -0
- package/dist/src/tui/session-host.d.ts +44 -0
- package/dist/src/tui/session-host.js +197 -0
- package/dist/src/tui/session-host.js.map +1 -0
- package/dist/src/types.d.ts +64 -3
- package/dist/src/types.js +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/agent-version.js +1 -1
- package/dist/src/utils/agent-version.js.map +1 -1
- package/dist/src/utils/artifact-plan.d.ts +2 -2
- package/dist/src/utils/artifact-plan.js +8 -6
- package/dist/src/utils/artifact-plan.js.map +1 -1
- package/dist/src/utils/artifact-renderer.d.ts +2 -1
- package/dist/src/utils/artifact-renderer.js +139 -120
- package/dist/src/utils/artifact-renderer.js.map +1 -1
- package/dist/src/utils/artifact-request.d.ts +5 -0
- package/dist/src/utils/artifact-request.js +40 -0
- package/dist/src/utils/artifact-request.js.map +1 -1
- package/dist/src/utils/bundle-layout.js +4 -4
- package/dist/src/utils/bundle-layout.js.map +1 -1
- package/dist/src/utils/catalog-capability-projection.d.ts +8 -0
- package/dist/src/utils/catalog-capability-projection.js +14 -0
- package/dist/src/utils/catalog-capability-projection.js.map +1 -0
- package/dist/src/utils/catalog-generation-resolver.d.ts +14 -2
- package/dist/src/utils/catalog-generation-resolver.js +49 -27
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
- package/dist/src/utils/catalog-generation-service.d.ts +8 -1
- package/dist/src/utils/catalog-generation-service.js +81 -47
- package/dist/src/utils/catalog-generation-service.js.map +1 -1
- package/dist/src/utils/catalog-generation-store.d.ts +1 -0
- package/dist/src/utils/catalog-generation-store.js +60 -5
- package/dist/src/utils/catalog-generation-store.js.map +1 -1
- package/dist/src/utils/catalog-operation-context.js +1 -0
- package/dist/src/utils/catalog-operation-context.js.map +1 -1
- package/dist/src/utils/catalog-public-error.js +4 -0
- package/dist/src/utils/catalog-public-error.js.map +1 -1
- package/dist/src/utils/catalog-source-impact.d.ts +3 -2
- package/dist/src/utils/catalog-source-impact.js +142 -20
- package/dist/src/utils/catalog-source-impact.js.map +1 -1
- package/dist/src/utils/catalog-source-references.js +95 -9
- package/dist/src/utils/catalog-source-references.js.map +1 -1
- package/dist/src/utils/catalog-sources.d.ts +1 -1
- package/dist/src/utils/catalog-sources.js +19 -3
- package/dist/src/utils/catalog-sources.js.map +1 -1
- package/dist/src/utils/codex-manager.js +8 -0
- package/dist/src/utils/codex-manager.js.map +1 -1
- package/dist/src/utils/codex-native-observation.d.ts +34 -1
- package/dist/src/utils/codex-native-observation.js +132 -0
- package/dist/src/utils/codex-native-observation.js.map +1 -1
- package/dist/src/utils/codex-reconciler.d.ts +0 -2
- package/dist/src/utils/codex-reconciler.js.map +1 -1
- package/dist/src/utils/codex-shared-native.d.ts +2 -26
- package/dist/src/utils/codex-shared-native.js +8 -82
- package/dist/src/utils/codex-shared-native.js.map +1 -1
- package/dist/src/utils/git-catalog-provider.d.ts +3 -0
- package/dist/src/utils/git-catalog-provider.js +40 -1
- package/dist/src/utils/git-catalog-provider.js.map +1 -1
- package/dist/src/utils/local-marketplace.d.ts +1 -0
- package/dist/src/utils/local-marketplace.js +69 -73
- package/dist/src/utils/local-marketplace.js.map +1 -1
- package/dist/src/utils/multi-source-catalog.js +1 -0
- package/dist/src/utils/multi-source-catalog.js.map +1 -1
- package/dist/src/utils/native-cli.d.ts +9 -4
- package/dist/src/utils/native-cli.js +280 -34
- package/dist/src/utils/native-cli.js.map +1 -1
- package/dist/src/utils/path-catalog-provider.js +2 -0
- package/dist/src/utils/path-catalog-provider.js.map +1 -1
- package/dist/src/utils/plugin-config-impact.d.ts +33 -0
- package/dist/src/utils/plugin-config-impact.js +298 -0
- package/dist/src/utils/plugin-config-impact.js.map +1 -0
- package/dist/src/utils/plugin-config-write.d.ts +36 -14
- package/dist/src/utils/plugin-config-write.js +709 -225
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/plugin-config.d.ts +58 -4
- package/dist/src/utils/plugin-config.js +328 -60
- package/dist/src/utils/plugin-config.js.map +1 -1
- package/dist/src/utils/plugin-scripts.d.ts +20 -12
- package/dist/src/utils/plugin-scripts.js +389 -114
- package/dist/src/utils/plugin-scripts.js.map +1 -1
- package/dist/src/utils/process-tree.d.ts +2 -2
- package/dist/src/utils/process-tree.js +1 -1
- package/dist/src/utils/process-tree.js.map +1 -1
- package/dist/src/utils/project-boundary.d.ts +11 -1
- package/dist/src/utils/project-boundary.js +33 -11
- package/dist/src/utils/project-boundary.js.map +1 -1
- package/dist/src/utils/safe-operation-diagnostic.d.ts +15 -0
- package/dist/src/utils/safe-operation-diagnostic.js +33 -0
- package/dist/src/utils/safe-operation-diagnostic.js.map +1 -0
- package/dist/src/utils/sensitive-content.d.ts +4 -0
- package/dist/src/utils/sensitive-content.js +36 -0
- package/dist/src/utils/sensitive-content.js.map +1 -0
- package/dist/src/utils/windows-claude-shim.d.ts +9 -0
- package/dist/src/utils/windows-claude-shim.js +141 -0
- package/dist/src/utils/windows-claude-shim.js.map +1 -0
- package/dist/vitest.config.js +91 -10
- package/dist/vitest.config.js.map +1 -1
- package/package.json +9 -9
- package/dist/authoring/templates/aw-config-runtime.d.mts +0 -2
- package/dist/authoring/templates/aw-config-runtime.mjs +0 -407
- package/dist/authoring/templates/aw-config-runtime.mjs.map +0 -1
|
@@ -6,6 +6,7 @@ import { canonicalizePluginConfigValues, formatPluginConfigIssue, matchPluginCon
|
|
|
6
6
|
import { assertTestReadablePath, assertTestWritablePath, } from './test-path-fence.js';
|
|
7
7
|
import { canonicalizePathThroughExistingAncestor, resolveAwHome, resolveRepoRootSync, } from './paths.js';
|
|
8
8
|
import { assertRealFileParentWithinRoot, assertSafeFileMutationPath, atomicReplaceSafeFile, } from './safe-fs.js';
|
|
9
|
+
import { assertProjectSharedConfigPathVisible, PROJECT_CONFIG_SHAREABILITY_UNVERIFIED_WARNING, } from './project-boundary.js';
|
|
9
10
|
export function codexNativeRefreshKeys(manifest) {
|
|
10
11
|
return new Set((manifest.artifacts?.targets ?? []).flatMap((target) => target.platform === 'codex'
|
|
11
12
|
&& target.target === 'codex.skill'
|
|
@@ -13,6 +14,51 @@ export function codexNativeRefreshKeys(manifest) {
|
|
|
13
14
|
? target.refreshKeys
|
|
14
15
|
: []));
|
|
15
16
|
}
|
|
17
|
+
function readPluginConfigBinding(value, scope) {
|
|
18
|
+
if (!isRecord(value))
|
|
19
|
+
return null;
|
|
20
|
+
if (scope === 'user') {
|
|
21
|
+
return value.kind === 'source'
|
|
22
|
+
&& typeof value.sourceIdentity === 'string'
|
|
23
|
+
&& /^sha256:[0-9a-f]{64}$/u.test(value.sourceIdentity)
|
|
24
|
+
&& Object.keys(value).every((key) => ['kind', 'sourceIdentity'].includes(key))
|
|
25
|
+
? { kind: 'source', sourceIdentity: value.sourceIdentity }
|
|
26
|
+
: null;
|
|
27
|
+
}
|
|
28
|
+
return value.kind === 'catalog'
|
|
29
|
+
&& typeof value.logicalIdentity === 'string'
|
|
30
|
+
&& value.logicalIdentity.trim().length > 0
|
|
31
|
+
&& Object.keys(value).every((key) => ['kind', 'logicalIdentity'].includes(key))
|
|
32
|
+
? { kind: 'catalog', logicalIdentity: value.logicalIdentity }
|
|
33
|
+
: null;
|
|
34
|
+
}
|
|
35
|
+
const PLUGIN_CONFIG_ENVELOPE_V4_KEYS = new Set([
|
|
36
|
+
'schemaVersion',
|
|
37
|
+
'sourceId',
|
|
38
|
+
'pluginName',
|
|
39
|
+
'binding',
|
|
40
|
+
'values',
|
|
41
|
+
]);
|
|
42
|
+
function readPluginConfigEnvelopeV4(value, scope) {
|
|
43
|
+
if (!isRecord(value)
|
|
44
|
+
|| value.schemaVersion !== 4
|
|
45
|
+
|| typeof value.sourceId !== 'string'
|
|
46
|
+
|| typeof value.pluginName !== 'string'
|
|
47
|
+
|| !isRecord(value.values)
|
|
48
|
+
|| Object.keys(value).some((key) => !PLUGIN_CONFIG_ENVELOPE_V4_KEYS.has(key))) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const binding = readPluginConfigBinding(value.binding, scope);
|
|
52
|
+
if (!binding)
|
|
53
|
+
return null;
|
|
54
|
+
return {
|
|
55
|
+
schemaVersion: 4,
|
|
56
|
+
sourceId: value.sourceId,
|
|
57
|
+
pluginName: value.pluginName,
|
|
58
|
+
binding,
|
|
59
|
+
values: value.values,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
16
62
|
export class PluginConfigResetError extends Error {
|
|
17
63
|
code;
|
|
18
64
|
osCode;
|
|
@@ -356,17 +402,33 @@ async function readNamespacedStoreFile(options) {
|
|
|
356
402
|
if (parsed.state === 'invalidJson')
|
|
357
403
|
return parsed.store;
|
|
358
404
|
const raw = parsed.value;
|
|
359
|
-
if (!isRecord(raw) || raw.schemaVersion !==
|
|
360
|
-
return invalidStore(options.filePath, 'schemaVersionUnsupported', 'Only plugin config store schemaVersion
|
|
405
|
+
if (!isRecord(raw) || raw.schemaVersion !== 4) {
|
|
406
|
+
return invalidStore(options.filePath, 'schemaVersionUnsupported', 'Only plugin config store schemaVersion 4 is supported.', parsed.rawDigest);
|
|
361
407
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
408
|
+
const envelope = readPluginConfigEnvelopeV4(raw, options.scope);
|
|
409
|
+
if (!envelope) {
|
|
410
|
+
return invalidStore(options.filePath, 'schemaVersionUnsupported', 'The plugin config store schemaVersion 4 envelope is invalid.', parsed.rawDigest);
|
|
411
|
+
}
|
|
412
|
+
if (envelope.sourceId !== options.sourceId
|
|
413
|
+
|| envelope.pluginName !== options.pluginName) {
|
|
365
414
|
return invalidStore(options.filePath, 'identityMismatch', 'The store identity does not match its source and namespaced path.', parsed.rawDigest);
|
|
366
415
|
}
|
|
416
|
+
const binding = envelope.binding;
|
|
417
|
+
const matchesBinding = options.scope === 'user'
|
|
418
|
+
? binding?.kind === 'source'
|
|
419
|
+
&& typeof options.sourceIdentity === 'string'
|
|
420
|
+
&& binding.sourceIdentity === options.sourceIdentity
|
|
421
|
+
: binding?.kind === 'catalog'
|
|
422
|
+
&& typeof options.logicalIdentity === 'string'
|
|
423
|
+
&& binding.logicalIdentity === options.logicalIdentity;
|
|
424
|
+
if (!matchesBinding) {
|
|
425
|
+
return invalidStore(options.filePath, 'identityMismatch', options.scope === 'user'
|
|
426
|
+
? 'The user store is not bound to the requested source identity.'
|
|
427
|
+
: 'The project store is not bound to the requested Catalog logical identity.', parsed.rawDigest);
|
|
428
|
+
}
|
|
367
429
|
return validateStoreValues({
|
|
368
430
|
filePath: options.filePath,
|
|
369
|
-
values:
|
|
431
|
+
values: envelope.values,
|
|
370
432
|
rawDigest: parsed.rawDigest,
|
|
371
433
|
});
|
|
372
434
|
}
|
|
@@ -374,14 +436,18 @@ function namespacedConfigContent(options) {
|
|
|
374
436
|
const values = canonicalizePluginConfigValues(options.values);
|
|
375
437
|
if (!options.sourceId)
|
|
376
438
|
return `${JSON.stringify(values, null, 2)}\n`;
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
439
|
+
const binding = options.scope === 'user'
|
|
440
|
+
? options.sourceIdentity
|
|
441
|
+
? { kind: 'source', sourceIdentity: options.sourceIdentity }
|
|
442
|
+
: (() => { throw new Error('sourceChanged: user plugin config requires a source identity.'); })()
|
|
443
|
+
: options.logicalIdentity
|
|
444
|
+
? { kind: 'catalog', logicalIdentity: options.logicalIdentity }
|
|
445
|
+
: (() => { throw new Error('catalogUnavailable: project plugin config requires verified Catalog logical identity evidence.'); })();
|
|
380
446
|
const envelope = {
|
|
381
|
-
schemaVersion:
|
|
447
|
+
schemaVersion: 4,
|
|
382
448
|
sourceId: options.sourceId,
|
|
383
|
-
sourceIdentity: options.sourceIdentity,
|
|
384
449
|
pluginName: options.pluginName,
|
|
450
|
+
binding,
|
|
385
451
|
values,
|
|
386
452
|
};
|
|
387
453
|
return `${JSON.stringify(envelope, null, 2)}\n`;
|
|
@@ -431,7 +497,9 @@ export async function readPluginConfigStore(options) {
|
|
|
431
497
|
? readNamespacedStoreFile({
|
|
432
498
|
filePath,
|
|
433
499
|
sourceId: options.sourceId,
|
|
500
|
+
scope: options.scope,
|
|
434
501
|
sourceIdentity: options.sourceIdentity,
|
|
502
|
+
logicalIdentity: options.logicalIdentity,
|
|
435
503
|
pluginName: options.pluginName,
|
|
436
504
|
})
|
|
437
505
|
: readStoreFile(filePath);
|
|
@@ -447,16 +515,16 @@ export async function readNamespacedPluginConfigStoreIdentity(options) {
|
|
|
447
515
|
if (parsed.state === 'invalidJson') {
|
|
448
516
|
throw new Error(`${parsed.store.invalidCode}: invalid namespaced plugin config store.`);
|
|
449
517
|
}
|
|
450
|
-
const
|
|
451
|
-
if (!
|
|
452
|
-
||
|
|
453
|
-
||
|
|
518
|
+
const envelope = readPluginConfigEnvelopeV4(parsed.value, options.scope);
|
|
519
|
+
if (!envelope
|
|
520
|
+
|| envelope.sourceId !== options.sourceId
|
|
521
|
+
|| envelope.pluginName !== options.pluginName) {
|
|
454
522
|
throw new Error('schemaVersionUnsupported: invalid namespaced plugin config store.');
|
|
455
523
|
}
|
|
456
|
-
const store = validateStoreValues({ filePath, values:
|
|
524
|
+
const store = validateStoreValues({ filePath, values: envelope.values });
|
|
457
525
|
assertReadyPluginConfigStore(store);
|
|
458
526
|
return {
|
|
459
|
-
|
|
527
|
+
binding: envelope.binding,
|
|
460
528
|
store,
|
|
461
529
|
};
|
|
462
530
|
}
|
|
@@ -496,6 +564,64 @@ export async function listPluginConfigStorePluginNames(options) {
|
|
|
496
564
|
const pluginNames = (await Promise.all(storeRoots.map((storeRoot) => listConfigStoreDirectoryPluginNames(storeRoot)))).flat();
|
|
497
565
|
return [...new Set(pluginNames)].sort((left, right) => left.localeCompare(right));
|
|
498
566
|
}
|
|
567
|
+
export async function listNamespacedPluginConfigStoreIdentities(options) {
|
|
568
|
+
const boundaryRoot = options.scope === 'user'
|
|
569
|
+
? resolveAwHome(options.env)
|
|
570
|
+
: resolveAwProjectRoot(options.cwd);
|
|
571
|
+
if (options.scope === 'user') {
|
|
572
|
+
await canonicalizePathThroughExistingAncestor(boundaryRoot);
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
await fs.realpath(boundaryRoot);
|
|
576
|
+
}
|
|
577
|
+
const storeRoot = path.join(boundaryRoot, ...(options.scope === 'project' ? ['.agent-workflows'] : []), CONFIG_DIR);
|
|
578
|
+
if (!await inspectConfigInventoryStoreRoot(boundaryRoot, storeRoot))
|
|
579
|
+
return [];
|
|
580
|
+
const output = [];
|
|
581
|
+
for (const sourceEntry of await fs.readdir(storeRoot, { withFileTypes: true })) {
|
|
582
|
+
if (!sourceEntry.isDirectory() || sourceEntry.isSymbolicLink())
|
|
583
|
+
continue;
|
|
584
|
+
let sourceId;
|
|
585
|
+
try {
|
|
586
|
+
sourceId = assertSafePluginConfigSegment(sourceEntry.name);
|
|
587
|
+
}
|
|
588
|
+
catch {
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
const sourceRoot = path.join(storeRoot, sourceId);
|
|
592
|
+
let pluginEntries;
|
|
593
|
+
try {
|
|
594
|
+
await assertNoConfigSymlink(boundaryRoot, sourceRoot);
|
|
595
|
+
pluginEntries = await fs.readdir(sourceRoot, { withFileTypes: true });
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
for (const pluginEntry of pluginEntries) {
|
|
601
|
+
if (!pluginEntry.isDirectory() || pluginEntry.isSymbolicLink())
|
|
602
|
+
continue;
|
|
603
|
+
let pluginName;
|
|
604
|
+
try {
|
|
605
|
+
pluginName = assertSafePluginConfigSegment(pluginEntry.name);
|
|
606
|
+
await assertNoConfigSymlink(boundaryRoot, path.join(sourceRoot, pluginName));
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
let target;
|
|
612
|
+
try {
|
|
613
|
+
target = await lstatIfExists(path.join(sourceRoot, pluginName, CONFIG_FILE));
|
|
614
|
+
}
|
|
615
|
+
catch {
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (!target)
|
|
619
|
+
continue;
|
|
620
|
+
output.push({ sourceId, pluginName, pluginId: `${sourceId}/${pluginName}` });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return output.sort((left, right) => left.pluginId.localeCompare(right.pluginId));
|
|
624
|
+
}
|
|
499
625
|
export async function listNamespacedPluginConfigStores(options) {
|
|
500
626
|
const boundaryRoot = options.scope === 'user'
|
|
501
627
|
? resolveAwHome(options.env)
|
|
@@ -532,17 +658,17 @@ export async function listNamespacedPluginConfigStores(options) {
|
|
|
532
658
|
if (parsed.state === 'invalidJson') {
|
|
533
659
|
throw new Error(`${parsed.store.invalidCode}: invalid namespaced plugin config store "${filePath}".`);
|
|
534
660
|
}
|
|
535
|
-
const
|
|
536
|
-
if (!
|
|
537
|
-
||
|
|
538
|
-
||
|
|
661
|
+
const envelope = readPluginConfigEnvelopeV4(parsed.value, options.scope);
|
|
662
|
+
if (!envelope
|
|
663
|
+
|| envelope.sourceId !== sourceId
|
|
664
|
+
|| envelope.pluginName !== pluginName) {
|
|
539
665
|
throw new Error(`schemaVersionUnsupported: invalid namespaced plugin config store "${filePath}".`);
|
|
540
666
|
}
|
|
541
|
-
const store = validateStoreValues({ filePath, values:
|
|
667
|
+
const store = validateStoreValues({ filePath, values: envelope.values });
|
|
542
668
|
assertReadyPluginConfigStore(store);
|
|
543
669
|
output.push({
|
|
544
670
|
sourceId,
|
|
545
|
-
|
|
671
|
+
binding: envelope.binding,
|
|
546
672
|
pluginName,
|
|
547
673
|
pluginId: `${sourceId}/${pluginName}`,
|
|
548
674
|
values: store.values,
|
|
@@ -560,22 +686,37 @@ export async function writePluginConfigStore(options) {
|
|
|
560
686
|
const allowedRoot = resolvePluginConfigAllowedRoot(options);
|
|
561
687
|
const validated = validateStoreValues({ filePath, values: options.values });
|
|
562
688
|
assertReadyPluginConfigStore(validated);
|
|
689
|
+
const warnings = [];
|
|
563
690
|
await withConfigFileMutation({
|
|
564
691
|
filePath,
|
|
565
692
|
allowedRoot,
|
|
566
|
-
action: async () =>
|
|
567
|
-
|
|
568
|
-
|
|
693
|
+
action: async () => {
|
|
694
|
+
if (Object.keys(validated.values).length === 0) {
|
|
695
|
+
return atomicRemoveConfigFile({ filePath, allowedRoot });
|
|
696
|
+
}
|
|
697
|
+
if (options.scope === 'project') {
|
|
698
|
+
const visibility = await assertProjectSharedConfigPathVisible({
|
|
699
|
+
cwd: options.cwd,
|
|
700
|
+
targetPath: filePath,
|
|
701
|
+
env: options.env,
|
|
702
|
+
});
|
|
703
|
+
if (visibility?.state === 'unverified') {
|
|
704
|
+
warnings.push(PROJECT_CONFIG_SHAREABILITY_UNVERIFIED_WARNING);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return atomicReplaceConfigFile({
|
|
569
708
|
filePath,
|
|
570
709
|
allowedRoot,
|
|
571
710
|
content: namespacedConfigContent({ ...options, values: validated.values }),
|
|
572
711
|
mode: 0o600,
|
|
573
|
-
})
|
|
712
|
+
});
|
|
713
|
+
},
|
|
574
714
|
});
|
|
575
715
|
return {
|
|
576
716
|
pluginName: options.pluginName,
|
|
577
717
|
scope: options.scope,
|
|
578
718
|
path: filePath,
|
|
719
|
+
warnings,
|
|
579
720
|
};
|
|
580
721
|
}
|
|
581
722
|
export async function patchPluginConfigStore(options) {
|
|
@@ -586,6 +727,7 @@ export async function patchPluginConfigStore(options) {
|
|
|
586
727
|
});
|
|
587
728
|
const allowedRoot = resolvePluginConfigAllowedRoot(options);
|
|
588
729
|
const removedKeys = options.removeKeys ?? [];
|
|
730
|
+
const warnings = [];
|
|
589
731
|
await withConfigFileMutation({
|
|
590
732
|
filePath,
|
|
591
733
|
allowedRoot,
|
|
@@ -596,7 +738,9 @@ export async function patchPluginConfigStore(options) {
|
|
|
596
738
|
? await readNamespacedStoreFile({
|
|
597
739
|
filePath,
|
|
598
740
|
sourceId: options.sourceId,
|
|
741
|
+
scope: options.scope,
|
|
599
742
|
sourceIdentity: options.sourceIdentity,
|
|
743
|
+
logicalIdentity: options.logicalIdentity,
|
|
600
744
|
pluginName: options.pluginName,
|
|
601
745
|
})
|
|
602
746
|
: await readStoreFile(filePath)
|
|
@@ -618,6 +762,16 @@ export async function patchPluginConfigStore(options) {
|
|
|
618
762
|
await atomicRemoveConfigFile({ filePath, allowedRoot });
|
|
619
763
|
}
|
|
620
764
|
else {
|
|
765
|
+
if (options.scope === 'project') {
|
|
766
|
+
const visibility = await assertProjectSharedConfigPathVisible({
|
|
767
|
+
cwd: options.cwd,
|
|
768
|
+
targetPath: filePath,
|
|
769
|
+
env: options.env,
|
|
770
|
+
});
|
|
771
|
+
if (visibility?.state === 'unverified') {
|
|
772
|
+
warnings.push(PROJECT_CONFIG_SHAREABILITY_UNVERIFIED_WARNING);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
621
775
|
await atomicReplaceConfigFile({
|
|
622
776
|
filePath,
|
|
623
777
|
allowedRoot,
|
|
@@ -631,6 +785,7 @@ export async function patchPluginConfigStore(options) {
|
|
|
631
785
|
pluginName: options.pluginName,
|
|
632
786
|
scope: options.scope,
|
|
633
787
|
path: filePath,
|
|
788
|
+
warnings,
|
|
634
789
|
updatedKeys: Object.keys(options.updates),
|
|
635
790
|
removedKeys,
|
|
636
791
|
};
|
|
@@ -847,6 +1002,13 @@ function coerceConfigValue(key, field, value) {
|
|
|
847
1002
|
export async function coercePluginConfigValue(options) {
|
|
848
1003
|
return coerceConfigValue(options.key, options.field, options.value);
|
|
849
1004
|
}
|
|
1005
|
+
function validateConfigReadValue(key, field, value) {
|
|
1006
|
+
const issues = validateCorePluginConfigValue(field, value, key);
|
|
1007
|
+
if (issues.length > 0) {
|
|
1008
|
+
throw new Error(formatPluginConfigIssue(issues[0]));
|
|
1009
|
+
}
|
|
1010
|
+
return value;
|
|
1011
|
+
}
|
|
850
1012
|
function redactValue(field, value) {
|
|
851
1013
|
return redactPluginConfigValue(field, value);
|
|
852
1014
|
}
|
|
@@ -897,6 +1059,7 @@ export async function resolveEffectivePluginConfig(options) {
|
|
|
897
1059
|
const userStore = await readPluginConfigStore({
|
|
898
1060
|
sourceId: options.sourceId,
|
|
899
1061
|
sourceIdentity: options.sourceIdentity,
|
|
1062
|
+
logicalIdentity: options.logicalIdentity,
|
|
900
1063
|
pluginName,
|
|
901
1064
|
scope: 'user',
|
|
902
1065
|
cwd: options.cwd,
|
|
@@ -907,12 +1070,38 @@ export async function resolveEffectivePluginConfig(options) {
|
|
|
907
1070
|
: await readPluginConfigStore({
|
|
908
1071
|
sourceId: options.sourceId,
|
|
909
1072
|
sourceIdentity: options.sourceIdentity,
|
|
1073
|
+
logicalIdentity: options.logicalIdentity,
|
|
910
1074
|
pluginName,
|
|
911
1075
|
scope: 'project',
|
|
912
1076
|
cwd: options.cwd,
|
|
913
1077
|
env: options.env,
|
|
914
1078
|
});
|
|
915
1079
|
assertReadyPluginConfigStore(userStore);
|
|
1080
|
+
if (projectStore)
|
|
1081
|
+
assertReadyPluginConfigStore(projectStore);
|
|
1082
|
+
return resolveEffectivePluginConfigFromStores({
|
|
1083
|
+
pluginName,
|
|
1084
|
+
manifest: options.manifest,
|
|
1085
|
+
targetScope: options.targetScope,
|
|
1086
|
+
projectRoot,
|
|
1087
|
+
stores: {
|
|
1088
|
+
user: userStore,
|
|
1089
|
+
...(projectStore ? { project: projectStore } : {}),
|
|
1090
|
+
},
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
export async function resolveEffectivePluginConfigFromStores(options) {
|
|
1094
|
+
const pluginName = assertSafePluginConfigSegment(options.pluginName ?? options.manifest.name);
|
|
1095
|
+
const schema = options.manifest.config?.fields;
|
|
1096
|
+
if (!schema) {
|
|
1097
|
+
throw new Error(`Plugin "${pluginName}" does not declare an AW config schema.`);
|
|
1098
|
+
}
|
|
1099
|
+
const userStore = options.stores.user;
|
|
1100
|
+
const projectStore = options.targetScope === 'user' ? undefined : options.stores.project;
|
|
1101
|
+
assertReadyPluginConfigStore(userStore);
|
|
1102
|
+
if (!projectStore && options.targetScope !== 'user') {
|
|
1103
|
+
throw new Error(`Project plugin config store is required for ${pluginName}.`);
|
|
1104
|
+
}
|
|
916
1105
|
if (projectStore)
|
|
917
1106
|
assertReadyPluginConfigStore(projectStore);
|
|
918
1107
|
const values = {};
|
|
@@ -920,8 +1109,10 @@ export async function resolveEffectivePluginConfig(options) {
|
|
|
920
1109
|
const sources = {};
|
|
921
1110
|
const fieldStates = {};
|
|
922
1111
|
const ignoredUnknownKeys = [];
|
|
1112
|
+
const unsupportedLayerOverrides = [];
|
|
923
1113
|
const dangerousKeyIssues = [];
|
|
924
1114
|
const schemaKeys = new Set(Object.keys(schema));
|
|
1115
|
+
const userOnlyKeys = codexNativeRefreshKeys(options.manifest);
|
|
925
1116
|
for (const key of schemaKeys) {
|
|
926
1117
|
sources[key] = 'missing';
|
|
927
1118
|
}
|
|
@@ -967,13 +1158,26 @@ export async function resolveEffectivePluginConfig(options) {
|
|
|
967
1158
|
}
|
|
968
1159
|
}
|
|
969
1160
|
}
|
|
1161
|
+
const supportedEntries = scope === 'project'
|
|
1162
|
+
? Object.fromEntries(Object.entries(plainEntries).filter(([key]) => {
|
|
1163
|
+
if (!schemaKeys.has(key) || !userOnlyKeys.has(key))
|
|
1164
|
+
return true;
|
|
1165
|
+
unsupportedLayerOverrides.push({
|
|
1166
|
+
type: 'configLayerUnsupported',
|
|
1167
|
+
key,
|
|
1168
|
+
scope: 'project',
|
|
1169
|
+
source: 'project',
|
|
1170
|
+
});
|
|
1171
|
+
return false;
|
|
1172
|
+
}))
|
|
1173
|
+
: plainEntries;
|
|
970
1174
|
await applyConfigLayer({
|
|
971
1175
|
values,
|
|
972
1176
|
redactedValues,
|
|
973
1177
|
sources,
|
|
974
1178
|
fieldStates,
|
|
975
1179
|
schema,
|
|
976
|
-
entries:
|
|
1180
|
+
entries: supportedEntries,
|
|
977
1181
|
source,
|
|
978
1182
|
});
|
|
979
1183
|
}
|
|
@@ -993,12 +1197,13 @@ export async function resolveEffectivePluginConfig(options) {
|
|
|
993
1197
|
}
|
|
994
1198
|
return {
|
|
995
1199
|
pluginName,
|
|
996
|
-
projectRoot,
|
|
1200
|
+
projectRoot: options.projectRoot,
|
|
997
1201
|
values,
|
|
998
1202
|
redactedValues,
|
|
999
1203
|
sources,
|
|
1000
1204
|
fieldStates,
|
|
1001
1205
|
issues,
|
|
1206
|
+
unsupportedLayerOverrides,
|
|
1002
1207
|
ignoredUnknownKeys,
|
|
1003
1208
|
schema,
|
|
1004
1209
|
stores: {
|
|
@@ -1030,6 +1235,7 @@ export async function resolveProjectArtifactRenderConfig(options) {
|
|
|
1030
1235
|
readPluginConfigStore({
|
|
1031
1236
|
sourceId: options.sourceId,
|
|
1032
1237
|
sourceIdentity: options.sourceIdentity,
|
|
1238
|
+
logicalIdentity: options.logicalIdentity,
|
|
1033
1239
|
pluginName,
|
|
1034
1240
|
scope: 'user',
|
|
1035
1241
|
cwd: options.cwd,
|
|
@@ -1038,6 +1244,7 @@ export async function resolveProjectArtifactRenderConfig(options) {
|
|
|
1038
1244
|
readPluginConfigStore({
|
|
1039
1245
|
sourceId: options.sourceId,
|
|
1040
1246
|
sourceIdentity: options.sourceIdentity,
|
|
1247
|
+
logicalIdentity: options.logicalIdentity,
|
|
1041
1248
|
pluginName,
|
|
1042
1249
|
scope: 'project',
|
|
1043
1250
|
cwd: options.cwd,
|
|
@@ -1052,6 +1259,7 @@ export async function resolveProjectArtifactRenderConfig(options) {
|
|
|
1052
1259
|
values: {},
|
|
1053
1260
|
sources: {},
|
|
1054
1261
|
issues: [],
|
|
1262
|
+
unsupportedLayerOverrides: [],
|
|
1055
1263
|
ignoredUnknownKeys: [],
|
|
1056
1264
|
schema: {},
|
|
1057
1265
|
stores: { user: userStore, project: projectStore },
|
|
@@ -1067,6 +1275,7 @@ export async function resolveProjectArtifactRenderConfig(options) {
|
|
|
1067
1275
|
values: effective.values,
|
|
1068
1276
|
sources: effective.sources,
|
|
1069
1277
|
issues: effective.issues,
|
|
1278
|
+
unsupportedLayerOverrides: effective.unsupportedLayerOverrides,
|
|
1070
1279
|
ignoredUnknownKeys: effective.ignoredUnknownKeys,
|
|
1071
1280
|
schema: effective.schema,
|
|
1072
1281
|
stores: {
|
|
@@ -1077,13 +1286,9 @@ export async function resolveProjectArtifactRenderConfig(options) {
|
|
|
1077
1286
|
}
|
|
1078
1287
|
async function resolveRedactedLayerValue(options) {
|
|
1079
1288
|
try {
|
|
1080
|
-
const
|
|
1081
|
-
key: options.key,
|
|
1082
|
-
field: options.field,
|
|
1083
|
-
value: options.value,
|
|
1084
|
-
});
|
|
1289
|
+
const value = validateConfigReadValue(options.key, options.field, options.value);
|
|
1085
1290
|
return {
|
|
1086
|
-
value: redactValue(options.field,
|
|
1291
|
+
value: redactValue(options.field, value),
|
|
1087
1292
|
};
|
|
1088
1293
|
}
|
|
1089
1294
|
catch (error) {
|
|
@@ -1155,6 +1360,7 @@ export async function resolveProjectScopedPluginConfigView(options) {
|
|
|
1155
1360
|
sources: effective.sources,
|
|
1156
1361
|
entries,
|
|
1157
1362
|
issues: effective.issues,
|
|
1363
|
+
unsupportedLayerOverrides: effective.unsupportedLayerOverrides,
|
|
1158
1364
|
ignoredUnknownKeys: effective.ignoredUnknownKeys,
|
|
1159
1365
|
};
|
|
1160
1366
|
}
|
|
@@ -1196,6 +1402,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1196
1402
|
const userStore = await readPluginConfigStore({
|
|
1197
1403
|
sourceId: options.plugin.sourceId,
|
|
1198
1404
|
sourceIdentity: options.plugin.sourceIdentity,
|
|
1405
|
+
logicalIdentity: options.plugin.catalogLogicalIdentity,
|
|
1199
1406
|
pluginName: options.plugin.manifest.name,
|
|
1200
1407
|
scope: 'user',
|
|
1201
1408
|
cwd: options.cwd,
|
|
@@ -1207,6 +1414,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1207
1414
|
: await readPluginConfigStore({
|
|
1208
1415
|
sourceId: options.plugin.sourceId,
|
|
1209
1416
|
sourceIdentity: options.plugin.sourceIdentity,
|
|
1417
|
+
logicalIdentity: options.plugin.catalogLogicalIdentity,
|
|
1210
1418
|
pluginName: options.plugin.manifest.name,
|
|
1211
1419
|
scope: 'project',
|
|
1212
1420
|
cwd: options.cwd,
|
|
@@ -1221,6 +1429,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1221
1429
|
const effective = await resolveEffectivePluginConfig({
|
|
1222
1430
|
sourceId: options.plugin.sourceId,
|
|
1223
1431
|
sourceIdentity: options.plugin.sourceIdentity,
|
|
1432
|
+
logicalIdentity: options.plugin.catalogLogicalIdentity,
|
|
1224
1433
|
pluginName: options.plugin.manifest.name,
|
|
1225
1434
|
manifest: options.plugin.manifest,
|
|
1226
1435
|
targetScope: options.scope === 'user' ? 'user' : 'project',
|
|
@@ -1228,12 +1437,65 @@ async function buildManifestFieldEntries(options) {
|
|
|
1228
1437
|
env: options.env,
|
|
1229
1438
|
});
|
|
1230
1439
|
const userOnlyKeys = codexNativeRefreshKeys(options.plugin.manifest);
|
|
1440
|
+
const projectRemovalFallback = (key) => {
|
|
1441
|
+
const field = schema[key];
|
|
1442
|
+
if (Object.hasOwn(userPlainEntries, key)) {
|
|
1443
|
+
const value = userPlainEntries[key];
|
|
1444
|
+
const validationIssues = validateCorePluginConfigValue(field, value, key);
|
|
1445
|
+
if (validationIssues.length > 0) {
|
|
1446
|
+
return {
|
|
1447
|
+
state: 'invalid',
|
|
1448
|
+
sourceLayer: 'user',
|
|
1449
|
+
issues: validationIssues.map((issue) => ({
|
|
1450
|
+
type: 'invalid-config',
|
|
1451
|
+
key,
|
|
1452
|
+
source: 'user',
|
|
1453
|
+
message: formatPluginConfigIssue(issue),
|
|
1454
|
+
})),
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
return {
|
|
1458
|
+
state: 'valid',
|
|
1459
|
+
effectiveValue: redactValue(field, value),
|
|
1460
|
+
sourceLayer: 'user',
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
if (field.default === undefined)
|
|
1464
|
+
return { state: 'missing' };
|
|
1465
|
+
const validationIssues = validateCorePluginConfigValue(field, field.default, key);
|
|
1466
|
+
if (validationIssues.length > 0) {
|
|
1467
|
+
return {
|
|
1468
|
+
state: 'invalid',
|
|
1469
|
+
sourceLayer: 'default',
|
|
1470
|
+
issues: validationIssues.map((issue) => ({
|
|
1471
|
+
type: 'invalid-config',
|
|
1472
|
+
key,
|
|
1473
|
+
source: 'default',
|
|
1474
|
+
message: formatPluginConfigIssue(issue),
|
|
1475
|
+
})),
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
return {
|
|
1479
|
+
state: 'valid',
|
|
1480
|
+
effectiveValue: redactValue(field, field.default),
|
|
1481
|
+
sourceLayer: 'default',
|
|
1482
|
+
};
|
|
1483
|
+
};
|
|
1231
1484
|
const effectiveFieldState = (key) => {
|
|
1232
1485
|
const source = effective.sources[key];
|
|
1233
1486
|
const sourceLayer = toConfigSourceLayer(source);
|
|
1234
1487
|
const field = schema[key];
|
|
1235
1488
|
const fieldIssues = effective.issues.filter((entry) => entry.key === key);
|
|
1236
1489
|
const fieldState = effective.fieldStates[key];
|
|
1490
|
+
const fallback = options.scope === 'project'
|
|
1491
|
+
? projectRemovalFallback(key)
|
|
1492
|
+
: fieldState?.fallback
|
|
1493
|
+
? {
|
|
1494
|
+
state: 'valid',
|
|
1495
|
+
effectiveValue: fieldState.fallback.redactedValue,
|
|
1496
|
+
sourceLayer: fieldState.fallback.source,
|
|
1497
|
+
}
|
|
1498
|
+
: undefined;
|
|
1237
1499
|
if (source === undefined || source === 'missing') {
|
|
1238
1500
|
return {
|
|
1239
1501
|
valueState: fieldIssues.length > 0 ? 'invalid' : 'default',
|
|
@@ -1253,12 +1515,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1253
1515
|
issues: fieldState.invalidOverride.issues,
|
|
1254
1516
|
},
|
|
1255
1517
|
} : {}),
|
|
1256
|
-
...(
|
|
1257
|
-
fallback: {
|
|
1258
|
-
effectiveValue: fieldState.fallback.redactedValue,
|
|
1259
|
-
sourceLayer: fieldState.fallback.source,
|
|
1260
|
-
},
|
|
1261
|
-
} : {}),
|
|
1518
|
+
...(fallback ? { fallback } : {}),
|
|
1262
1519
|
...configFieldProjection({
|
|
1263
1520
|
field,
|
|
1264
1521
|
value: issue ? undefined : effective.values[key],
|
|
@@ -1269,12 +1526,18 @@ async function buildManifestFieldEntries(options) {
|
|
|
1269
1526
|
};
|
|
1270
1527
|
const fields = [];
|
|
1271
1528
|
for (const [key, field] of Object.entries(schema)) {
|
|
1529
|
+
const canSet = options.scope !== 'project'
|
|
1530
|
+
|| (!userOnlyKeys.has(key) && field.sensitive !== true);
|
|
1272
1531
|
const base = {
|
|
1273
1532
|
key,
|
|
1274
1533
|
title: field.title ?? key,
|
|
1275
1534
|
kind: 'manifest',
|
|
1276
1535
|
reserved: false,
|
|
1277
|
-
writable:
|
|
1536
|
+
writable: canSet,
|
|
1537
|
+
canSet,
|
|
1538
|
+
canUnset: options.scope === 'user'
|
|
1539
|
+
? Object.hasOwn(userPlainEntries, key)
|
|
1540
|
+
: options.scope === 'project' && Object.hasOwn(projectPlainEntries, key),
|
|
1278
1541
|
valueState: 'default',
|
|
1279
1542
|
effectiveValue: null,
|
|
1280
1543
|
sourceLayer: null,
|
|
@@ -1283,11 +1546,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1283
1546
|
if (options.scope === 'user') {
|
|
1284
1547
|
if (Object.hasOwn(userPlainEntries, key)) {
|
|
1285
1548
|
try {
|
|
1286
|
-
const value =
|
|
1287
|
-
key,
|
|
1288
|
-
field,
|
|
1289
|
-
value: userPlainEntries[key],
|
|
1290
|
-
});
|
|
1549
|
+
const value = validateConfigReadValue(key, field, userPlainEntries[key]);
|
|
1291
1550
|
fields.push({
|
|
1292
1551
|
...base,
|
|
1293
1552
|
valueState: 'configured',
|
|
@@ -1303,6 +1562,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1303
1562
|
...base,
|
|
1304
1563
|
valueState: 'invalid',
|
|
1305
1564
|
sourceLayer: 'user',
|
|
1565
|
+
source: 'user',
|
|
1306
1566
|
storedSourceLayer: 'user',
|
|
1307
1567
|
valid: false,
|
|
1308
1568
|
issues: [{ type: 'invalid-config', key, source: 'user' }],
|
|
@@ -1312,11 +1572,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1312
1572
|
}
|
|
1313
1573
|
if (field.default !== undefined) {
|
|
1314
1574
|
try {
|
|
1315
|
-
const value =
|
|
1316
|
-
key,
|
|
1317
|
-
field,
|
|
1318
|
-
value: field.default,
|
|
1319
|
-
});
|
|
1575
|
+
const value = validateConfigReadValue(key, field, field.default);
|
|
1320
1576
|
fields.push({
|
|
1321
1577
|
...base,
|
|
1322
1578
|
effectiveValue: redactValue(field, value),
|
|
@@ -1342,11 +1598,7 @@ async function buildManifestFieldEntries(options) {
|
|
|
1342
1598
|
let storedProjectValue;
|
|
1343
1599
|
if (options.scope === 'project' && Object.hasOwn(projectPlainEntries, key)) {
|
|
1344
1600
|
try {
|
|
1345
|
-
const value =
|
|
1346
|
-
key,
|
|
1347
|
-
field,
|
|
1348
|
-
value: projectPlainEntries[key],
|
|
1349
|
-
});
|
|
1601
|
+
const value = validateConfigReadValue(key, field, projectPlainEntries[key]);
|
|
1350
1602
|
storedProjectValue = {
|
|
1351
1603
|
storedValue: redactValue(field, value),
|
|
1352
1604
|
storedSourceLayer: 'project',
|
|
@@ -1375,6 +1627,7 @@ async function buildLegacyStoreFieldEntries(options) {
|
|
|
1375
1627
|
const store = await readPluginConfigStore({
|
|
1376
1628
|
sourceId: options.sourceId,
|
|
1377
1629
|
sourceIdentity: options.sourceIdentity,
|
|
1630
|
+
logicalIdentity: options.logicalIdentity,
|
|
1378
1631
|
pluginName: options.pluginName,
|
|
1379
1632
|
scope: location.scope,
|
|
1380
1633
|
cwd: options.cwd,
|
|
@@ -1387,6 +1640,8 @@ async function buildLegacyStoreFieldEntries(options) {
|
|
|
1387
1640
|
kind: 'manifest',
|
|
1388
1641
|
reserved: false,
|
|
1389
1642
|
writable: false,
|
|
1643
|
+
canSet: false,
|
|
1644
|
+
canUnset: false,
|
|
1390
1645
|
valueState: 'configured',
|
|
1391
1646
|
effectiveValue: '[redacted]',
|
|
1392
1647
|
sourceLayer: location.sourceLayer,
|
|
@@ -1437,6 +1692,7 @@ export async function resolveConfigRead(options) {
|
|
|
1437
1692
|
: await buildLegacyStoreFieldEntries({
|
|
1438
1693
|
sourceId: options.sourceId,
|
|
1439
1694
|
sourceIdentity: options.sourceIdentity,
|
|
1695
|
+
logicalIdentity: options.logicalIdentity,
|
|
1440
1696
|
pluginName,
|
|
1441
1697
|
scope: options.scope,
|
|
1442
1698
|
cwd: options.cwd,
|
|
@@ -1446,6 +1702,9 @@ export async function resolveConfigRead(options) {
|
|
|
1446
1702
|
pluginName,
|
|
1447
1703
|
scope: options.scope,
|
|
1448
1704
|
...(schemaAccess.schema ? { schema: schemaAccess.schema } : {}),
|
|
1705
|
+
...(schemaAccess.plugin?.manifest.config?.fields
|
|
1706
|
+
? { fieldDefinitions: schemaAccess.plugin.manifest.config.fields }
|
|
1707
|
+
: {}),
|
|
1449
1708
|
fields: manifestFields,
|
|
1450
1709
|
};
|
|
1451
1710
|
}
|
|
@@ -1588,13 +1847,21 @@ export function toCliConfigPromptOptions(model) {
|
|
|
1588
1847
|
requiredKeys: [...model.requiredKeys],
|
|
1589
1848
|
};
|
|
1590
1849
|
}
|
|
1591
|
-
function
|
|
1850
|
+
export function formatPluginConfigSetRecoveryCommand(pluginName, key, field, scope) {
|
|
1851
|
+
return field.sensitive === true
|
|
1852
|
+
? `aw config set ${pluginName} ${key} --scope user --value-stdin`
|
|
1853
|
+
: `aw config set ${pluginName} ${key} --scope ${scope} --value-json '<json>'`;
|
|
1854
|
+
}
|
|
1855
|
+
function formatRequiredConfigSetCommands(pluginName, issues, defaultScope, schema) {
|
|
1592
1856
|
const commands = new Set();
|
|
1593
1857
|
for (const issue of issues) {
|
|
1594
1858
|
const scope = issue.source === 'user' || issue.source === 'project'
|
|
1595
1859
|
? issue.source
|
|
1596
1860
|
: defaultScope;
|
|
1597
|
-
|
|
1861
|
+
const field = schema[issue.key];
|
|
1862
|
+
if (!field)
|
|
1863
|
+
continue;
|
|
1864
|
+
commands.add(formatPluginConfigSetRecoveryCommand(pluginName, issue.key, field, scope));
|
|
1598
1865
|
}
|
|
1599
1866
|
return [...commands].map((command) => `\`${command}\``).join(' 或 ');
|
|
1600
1867
|
}
|
|
@@ -1620,6 +1887,7 @@ export async function preflightRequiredPluginConfigs(options) {
|
|
|
1620
1887
|
let effective = await resolveEffectivePluginConfig({
|
|
1621
1888
|
sourceId: target.sourceId,
|
|
1622
1889
|
sourceIdentity: target.sourceIdentity,
|
|
1890
|
+
logicalIdentity: target.logicalIdentity,
|
|
1623
1891
|
pluginName,
|
|
1624
1892
|
manifest: target.manifest,
|
|
1625
1893
|
cwd: options.cwd,
|
|
@@ -1630,7 +1898,7 @@ export async function preflightRequiredPluginConfigs(options) {
|
|
|
1630
1898
|
continue;
|
|
1631
1899
|
}
|
|
1632
1900
|
const details = blockingIssues.map((issue) => issue.key).join(', ');
|
|
1633
|
-
const setCommands = formatRequiredConfigSetCommands(pluginName, blockingIssues, options.defaultScope);
|
|
1901
|
+
const setCommands = formatRequiredConfigSetCommands(pluginName, blockingIssues, options.defaultScope, target.manifest.config.fields);
|
|
1634
1902
|
throw new Error(`${pluginName} requires valid AW config before install/upgrade: ${details}. ` +
|
|
1635
1903
|
`Run ${setCommands}, or open \`aw\` to complete setup.`);
|
|
1636
1904
|
}
|