@lesliechan721/aw 0.1.0-beta.18 → 0.1.0-beta.19
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/src/commands/operation-planner.d.ts +3 -3
- package/dist/src/commands/status-v6.d.ts +81 -31
- package/dist/src/commands/status-v6.js +494 -183
- package/dist/src/commands/status-v6.js.map +1 -1
- package/dist/src/commands/wizard.d.ts +2 -2
- package/dist/src/index.js +2 -2
- package/dist/src/tui/catalog-sources/projection.d.ts +2 -2
- package/dist/src/tui/catalog-sources/screens.js +17 -10
- package/dist/src/tui/catalog-sources/screens.js.map +1 -1
- package/dist/src/tui/console-app-v4.js +1291 -435
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.d.ts +3 -3
- package/dist/src/tui/controller-runtime.js +85 -27
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +17 -7
- package/dist/src/tui/controller.js +265 -24
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/dependency-graph.d.ts +3 -0
- package/dist/src/tui/dependency-graph.js +37 -1
- package/dist/src/tui/dependency-graph.js.map +1 -1
- package/dist/src/tui/diagnostic-projection.d.ts +1 -0
- package/dist/src/tui/diagnostic-projection.js +51 -4
- package/dist/src/tui/diagnostic-projection.js.map +1 -1
- package/dist/src/tui/model.d.ts +22 -12
- package/dist/src/tui/model.js +251 -86
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-history.d.ts +1 -0
- package/dist/src/tui/operation-history.js +5 -0
- package/dist/src/tui/operation-history.js.map +1 -1
- package/dist/src/tui/operation-review-planner.js +67 -2
- package/dist/src/tui/operation-review-planner.js.map +1 -1
- package/dist/src/tui/plugin-write-task.d.ts +2 -0
- package/dist/src/tui/plugin-write-task.js.map +1 -1
- package/dist/src/tui/router.d.ts +6 -0
- package/dist/src/tui/router.js +56 -12
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/screen-registry.d.ts +7 -0
- package/dist/src/utils/plugin-config-write.js +3 -3
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/target-eligibility.d.ts +2 -2
- package/dist/src/utils/target-eligibility.js.map +1 -1
- package/package.json +3 -3
|
@@ -24,6 +24,25 @@ import { IMPLEMENTED_AW_CAPABILITIES } from './aw-capabilities.js';
|
|
|
24
24
|
import { createDependencyPlacementPlan } from './dependency-operation-plan.js';
|
|
25
25
|
import { getCodexOperationRequirement } from '../utils/agent-version.js';
|
|
26
26
|
import { inspectSystemCodex, } from '../utils/codex-manager.js';
|
|
27
|
+
export function statusTargetPlacements(target) {
|
|
28
|
+
if (target.platform === 'claude')
|
|
29
|
+
return [target];
|
|
30
|
+
return target.placements.map((placement) => ({
|
|
31
|
+
pluginName: target.pluginName,
|
|
32
|
+
sourceId: target.sourceId,
|
|
33
|
+
sourceIdentity: target.sourceIdentity,
|
|
34
|
+
pluginId: target.pluginId,
|
|
35
|
+
...(target.version ? { version: target.version } : {}),
|
|
36
|
+
platform: target.platform,
|
|
37
|
+
cwd: target.cwd,
|
|
38
|
+
...placement,
|
|
39
|
+
sharedComponents: target.components.filter((component) => component.kind !== 'systemConsumer' || component.key === `codex:${placement.scope}`),
|
|
40
|
+
sharedReasons: target.reasons.filter((reason) => reason.code.startsWith('codexSharedNative') || reason.code === 'staleCacheObserved'),
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
export function flattenStatusTargets(targets) {
|
|
44
|
+
return targets.flatMap(statusTargetPlacements);
|
|
45
|
+
}
|
|
27
46
|
export function projectStatusSharedNativeReasons(sharedNative, existingReasonCodes = [], desiredEnabled = false) {
|
|
28
47
|
if (!sharedNative)
|
|
29
48
|
return [];
|
|
@@ -64,7 +83,7 @@ export function projectStatusSharedNativeReasons(sharedNative, existingReasonCod
|
|
|
64
83
|
];
|
|
65
84
|
}
|
|
66
85
|
function statusComponent(target, kind, key) {
|
|
67
|
-
return target.components.find((component) => component.kind === kind && (key === undefined || component.key === key));
|
|
86
|
+
return [...target.components, ...(target.sharedComponents ?? [])].find((component) => component.kind === kind && (key === undefined || component.key === key));
|
|
68
87
|
}
|
|
69
88
|
export function statusTargetIntent(target) {
|
|
70
89
|
const metadata = statusComponent(target, 'intent', 'desired')?.metadata;
|
|
@@ -121,7 +140,7 @@ export function statusTargetSharedNative(target) {
|
|
|
121
140
|
export function statusTargetActivation(target) {
|
|
122
141
|
const user = statusComponent(target, 'activation', 'user');
|
|
123
142
|
const project = statusComponent(target, 'activation', 'project');
|
|
124
|
-
const consumer = statusComponent(target, 'systemConsumer'
|
|
143
|
+
const consumer = statusComponent(target, 'systemConsumer');
|
|
125
144
|
if (!user && !project && !consumer)
|
|
126
145
|
return undefined;
|
|
127
146
|
const activation = user ?? project ?? consumer;
|
|
@@ -181,7 +200,7 @@ export function setStatusDependencyInspectionHookForTests(hook) {
|
|
|
181
200
|
dependencyInspectionHookForTests = hook;
|
|
182
201
|
}
|
|
183
202
|
export async function loadConsoleItemsResult(options = {}, runtime = {}) {
|
|
184
|
-
const result = await
|
|
203
|
+
const result = await statusCommandV8({
|
|
185
204
|
cwd: options.cwd ?? process.cwd(),
|
|
186
205
|
env: runtime.env,
|
|
187
206
|
platform: options.platform,
|
|
@@ -203,7 +222,7 @@ export async function loadConsoleItemsResult(options = {}, runtime = {}) {
|
|
|
203
222
|
...(pluginSummary ? { pluginSummary } : {}),
|
|
204
223
|
targets: [],
|
|
205
224
|
};
|
|
206
|
-
current.targets.push(target);
|
|
225
|
+
current.targets.push(...statusTargetPlacements(target));
|
|
207
226
|
groups.set(target.pluginId, current);
|
|
208
227
|
}
|
|
209
228
|
const allSourcesFailed = result.payload.catalog.sources.length > 0
|
|
@@ -251,6 +270,7 @@ function finalizeTargetError(error, targetState) {
|
|
|
251
270
|
return {
|
|
252
271
|
...error,
|
|
253
272
|
severity: error.code === 'artifactCollision'
|
|
273
|
+
|| error.code === 'dependencyGraphInvalid'
|
|
254
274
|
|| (targetState === 'error'
|
|
255
275
|
&& error.dependencyPluginId === undefined)
|
|
256
276
|
? 'blocking'
|
|
@@ -416,7 +436,7 @@ function projectDependencyClosureForTarget(options) {
|
|
|
416
436
|
visit(options.pluginId);
|
|
417
437
|
return closure;
|
|
418
438
|
}
|
|
419
|
-
function statusRecovery(options) {
|
|
439
|
+
export function statusRecovery(options) {
|
|
420
440
|
if (options.errorCodes?.some((code) => code === 'codexProjectPluginVersionTooLow'
|
|
421
441
|
|| code === 'codexProjectPluginUnsupported'
|
|
422
442
|
|| code === 'codexSystemCliUnsupported')) {
|
|
@@ -431,8 +451,29 @@ function statusRecovery(options) {
|
|
|
431
451
|
description: '升级 AW CLI 到支持插件所需 capability 的版本后重试。',
|
|
432
452
|
}];
|
|
433
453
|
}
|
|
454
|
+
if (options.errorCodes?.includes('dependencyGraphInvalid')) {
|
|
455
|
+
return [{
|
|
456
|
+
command: 'manual',
|
|
457
|
+
description: '修复 Catalog 中的插件依赖循环后重试。',
|
|
458
|
+
}];
|
|
459
|
+
}
|
|
434
460
|
if (options.state === 'ready' || options.state === 'absent')
|
|
435
461
|
return [];
|
|
462
|
+
if (options.desired.scopes.length === 0
|
|
463
|
+
&& options.sharedNative?.state === 'replaceable'
|
|
464
|
+
&& options.sharedNative.reason === 'damaged') {
|
|
465
|
+
return [
|
|
466
|
+
...(options.actualEnabled ? [{
|
|
467
|
+
command: 'cleanup',
|
|
468
|
+
...(options.scope ? { scope: options.scope } : {}),
|
|
469
|
+
description: `仅清理 ${options.scope ?? '当前'} scope 的激活;不会修复或删除损坏的共享内容。`,
|
|
470
|
+
}] : []),
|
|
471
|
+
{
|
|
472
|
+
command: 'manual',
|
|
473
|
+
description: `共享内容已损坏。先明确选择 user 或 project 使用范围,再运行 aw install ${options.pluginId} --platform codex --scope <user|project> 重建。`,
|
|
474
|
+
},
|
|
475
|
+
];
|
|
476
|
+
}
|
|
436
477
|
if (options.state === 'orphaned') {
|
|
437
478
|
return [{ command: 'cleanup', description: '清理可证明属于 AW 的遗留输出。' }];
|
|
438
479
|
}
|
|
@@ -556,7 +597,7 @@ export function projectTargetRevision(availableVersion, installedVersion) {
|
|
|
556
597
|
return { state: 'upgradeAvailable', availableVersion, installedVersion };
|
|
557
598
|
return { state: 'unknown', availableVersion, installedVersion };
|
|
558
599
|
}
|
|
559
|
-
function
|
|
600
|
+
function renderStatusV8(payload, verbose) {
|
|
560
601
|
const lines = [`Catalog sources: ${payload.catalog.sources.length}`];
|
|
561
602
|
for (const source of payload.catalog.sources) {
|
|
562
603
|
lines.push(`${source.primary ? '*' : '-'} ${source.id}: ${source.error ?? source.freshness ?? 'unavailable'}`);
|
|
@@ -566,11 +607,41 @@ function renderStatusV7(payload, verbose) {
|
|
|
566
607
|
? ` [${target.reasons.map((reason) => reason.message.startsWith(`${reason.code}:`)
|
|
567
608
|
? reason.message : `${reason.code}: ${reason.message}`).join('; ')}]`
|
|
568
609
|
: '';
|
|
569
|
-
|
|
610
|
+
if (target.platform === 'claude') {
|
|
611
|
+
lines.push(`${target.pluginId} ${target.platform} (${target.scope}): ${target.state}${reasons}`);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
lines.push(`${target.pluginId} ${target.platform}: ${target.state}${reasons}`);
|
|
615
|
+
const desiredScopes = target.placements.filter((placement) => placement.components.some((component) => component.kind === 'intent' && component.metadata?.enabled === true))
|
|
616
|
+
.map((placement) => placement.scope);
|
|
617
|
+
const actualScopes = target.placements.filter((placement) => placement.components.some((component) => component.kind === 'activation'
|
|
618
|
+
&& component.key === placement.scope
|
|
619
|
+
&& component.state === 'enabled'))
|
|
620
|
+
.map((placement) => placement.scope);
|
|
621
|
+
const usage = (scopes) => scopes.length === 0
|
|
622
|
+
? 'disabled'
|
|
623
|
+
: scopes.length === 2 ? 'user+project' : scopes[0];
|
|
624
|
+
lines.push(` desired use: ${usage(desiredScopes)}`);
|
|
625
|
+
lines.push(` actual use: ${usage(actualScopes)}`);
|
|
626
|
+
const shared = target.components.find((component) => component.kind === 'sharedNative');
|
|
627
|
+
if (shared)
|
|
628
|
+
lines.push(` shared content: ${shared.state} (${shared.key})`);
|
|
629
|
+
for (const placement of target.placements) {
|
|
630
|
+
lines.push(` ${placement.scope}: ${placement.state}`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
570
633
|
if (verbose) {
|
|
571
634
|
for (const component of target.components) {
|
|
572
635
|
lines.push(` component ${component.kind}/${component.key}: ${component.state}`);
|
|
573
636
|
}
|
|
637
|
+
if (target.platform === 'codex') {
|
|
638
|
+
for (const placement of target.placements) {
|
|
639
|
+
lines.push(` placement ${placement.scope}: ${placement.state}`);
|
|
640
|
+
for (const component of placement.components) {
|
|
641
|
+
lines.push(` component ${component.kind}/${component.key}: ${component.state}`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
574
645
|
for (const action of target.recoveryActions) {
|
|
575
646
|
lines.push(` recovery ${action.command}: ${action.description}`);
|
|
576
647
|
}
|
|
@@ -601,7 +672,7 @@ function collisionRootIssueId(options) {
|
|
|
601
672
|
options.collision.artifactKey,
|
|
602
673
|
].join(':');
|
|
603
674
|
}
|
|
604
|
-
async function
|
|
675
|
+
async function statusCommandV8InSession(options) {
|
|
605
676
|
const env = options.env ?? process.env;
|
|
606
677
|
const dependencyPluginCache = new Map();
|
|
607
678
|
const dependencyInspectionCache = new Map();
|
|
@@ -732,9 +803,9 @@ async function statusCommandV7InSession(options) {
|
|
|
732
803
|
if (!userCodexConfig || (probe.scope === 'project' && !projectCodexConfig)) {
|
|
733
804
|
return 'partial';
|
|
734
805
|
}
|
|
735
|
-
const configEnabled =
|
|
736
|
-
|
|
737
|
-
|
|
806
|
+
const configEnabled = (probe.scope === 'user'
|
|
807
|
+
? userCodexConfig
|
|
808
|
+
: projectCodexConfig)?.snapshot.plugins[`${probe.pluginName}@${probe.marketplaceName}`]?.enabled === true;
|
|
738
809
|
return configEnabled
|
|
739
810
|
? 'present'
|
|
740
811
|
: 'partial';
|
|
@@ -865,6 +936,35 @@ async function statusCommandV7InSession(options) {
|
|
|
865
936
|
};
|
|
866
937
|
}
|
|
867
938
|
try {
|
|
939
|
+
const catalogEntriesByName = new Map(item.resolution.manifest.entries.map((entry) => [
|
|
940
|
+
entry.name,
|
|
941
|
+
entry,
|
|
942
|
+
]));
|
|
943
|
+
const cyclicDependencyPluginNames = new Set();
|
|
944
|
+
const dependencyVisitState = new Map();
|
|
945
|
+
const dependencyVisitStack = [];
|
|
946
|
+
const visitDependencyGraph = (pluginName) => {
|
|
947
|
+
const state = dependencyVisitState.get(pluginName);
|
|
948
|
+
if (state === 'visited')
|
|
949
|
+
return;
|
|
950
|
+
if (state === 'visiting') {
|
|
951
|
+
const cycleStart = dependencyVisitStack.lastIndexOf(pluginName);
|
|
952
|
+
for (const name of dependencyVisitStack.slice(cycleStart)) {
|
|
953
|
+
cyclicDependencyPluginNames.add(name);
|
|
954
|
+
}
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
dependencyVisitState.set(pluginName, 'visiting');
|
|
958
|
+
dependencyVisitStack.push(pluginName);
|
|
959
|
+
for (const dependencyName of catalogEntriesByName.get(pluginName)?.dependencies ?? []) {
|
|
960
|
+
if (catalogEntriesByName.has(dependencyName))
|
|
961
|
+
visitDependencyGraph(dependencyName);
|
|
962
|
+
}
|
|
963
|
+
dependencyVisitStack.pop();
|
|
964
|
+
dependencyVisitState.set(pluginName, 'visited');
|
|
965
|
+
};
|
|
966
|
+
for (const pluginName of catalogEntriesByName.keys())
|
|
967
|
+
visitDependencyGraph(pluginName);
|
|
868
968
|
const placementEntries = item.resolution.manifest.entries.map((entry) => {
|
|
869
969
|
const supportedPlatforms = resolveCatalogEntrySupportedPlatforms(entry.policy);
|
|
870
970
|
return {
|
|
@@ -1125,8 +1225,238 @@ async function statusCommandV7InSession(options) {
|
|
|
1125
1225
|
const dependencyErrors = [];
|
|
1126
1226
|
const dependencyReadiness = [];
|
|
1127
1227
|
const directDependencies = plugin.manifest.dependencies ?? [];
|
|
1228
|
+
const desiredInScope = sourceDesired.get(desiredTargetKey(plugin.pluginId, platform))?.scopes.includes(scope) === true;
|
|
1229
|
+
const codexPluginId = `${entry.name}@${marketplaceName}`;
|
|
1230
|
+
const actualCodexActivation = platform === 'codex'
|
|
1231
|
+
&& (scope === 'user' ? userCodexConfig : projectCodexConfig)
|
|
1232
|
+
?.snapshot.plugins[codexPluginId]?.enabled === true;
|
|
1233
|
+
const hasScopedExtensionResidue = platform === 'codex'
|
|
1234
|
+
&& inspected.inspection.components.some((component) => component.component.kind !== 'native-plugin'
|
|
1235
|
+
&& !component.component.identity.artifactKey.startsWith('activation-')
|
|
1236
|
+
&& !component.component.identity.artifactKey.startsWith('marketplace-')
|
|
1237
|
+
&& (component.state !== 'absent' || component.collision !== undefined));
|
|
1238
|
+
const dependencyPriority = {
|
|
1239
|
+
ready: 5,
|
|
1240
|
+
blockedByCollision: 4,
|
|
1241
|
+
incomplete: 3,
|
|
1242
|
+
error: 2,
|
|
1243
|
+
absent: 1,
|
|
1244
|
+
};
|
|
1245
|
+
function dependencyPlacementsFor(dependencyId, consumerScope) {
|
|
1246
|
+
const dependencyOverride = (consumerScope === 'project'
|
|
1247
|
+
? projectIntent
|
|
1248
|
+
: userIntent).dependencyScopeOverrides.find((override) => override.pluginId === dependencyId
|
|
1249
|
+
&& (override.platform === undefined || override.platform === platform));
|
|
1250
|
+
return dependencyOverride
|
|
1251
|
+
? [dependencyOverride.scope]
|
|
1252
|
+
: consumerScope === 'project' ? ['project', 'user'] : ['user'];
|
|
1253
|
+
}
|
|
1254
|
+
async function inspectDependencyAtScope(dependencyName, dependencyScope) {
|
|
1255
|
+
const dependencyId = formatPluginId({
|
|
1256
|
+
sourceId: item.resolution.sourceId,
|
|
1257
|
+
pluginName: dependencyName,
|
|
1258
|
+
});
|
|
1259
|
+
const inspectionCacheKey = [
|
|
1260
|
+
item.resolution.sourceIdentity,
|
|
1261
|
+
dependencyId,
|
|
1262
|
+
platform,
|
|
1263
|
+
dependencyScope,
|
|
1264
|
+
dependencyScope === 'project' ? currentProjectKey : '',
|
|
1265
|
+
].join('\0');
|
|
1266
|
+
if (cyclicDependencyPluginNames.has(dependencyName)) {
|
|
1267
|
+
return {
|
|
1268
|
+
state: 'error',
|
|
1269
|
+
dependencyScope,
|
|
1270
|
+
rootIssueId: `dependencyGraphInvalid:${dependencyId}`,
|
|
1271
|
+
rootIssueCode: 'dependencyGraphInvalid',
|
|
1272
|
+
issuePluginId: dependencyId,
|
|
1273
|
+
issueScope: dependencyScope,
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
const cached = dependencyInspectionCache.get(inspectionCacheKey);
|
|
1277
|
+
if (cached)
|
|
1278
|
+
return cached;
|
|
1279
|
+
const inspection = (async () => {
|
|
1280
|
+
const dependencyEntry = item.resolution.manifest.entries.find((candidate) => candidate.name === dependencyName);
|
|
1281
|
+
if (!dependencyEntry) {
|
|
1282
|
+
return {
|
|
1283
|
+
state: 'absent',
|
|
1284
|
+
dependencyScope,
|
|
1285
|
+
rootIssueId: `dependencyMissing:${dependencyId}:${platform}:${dependencyScope}`,
|
|
1286
|
+
rootIssueCode: 'dependencyMissing',
|
|
1287
|
+
issuePluginId: dependencyId,
|
|
1288
|
+
issueScope: dependencyScope,
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
const dependencySupport = checkAwCapabilitySupport(dependencyEntry.requires.aw.capabilities ?? [], IMPLEMENTED_AW_CAPABILITIES);
|
|
1292
|
+
if (!dependencySupport.supported) {
|
|
1293
|
+
return {
|
|
1294
|
+
state: 'error',
|
|
1295
|
+
dependencyScope,
|
|
1296
|
+
rootIssueId: `awCapabilityUnsupported:${dependencyId}`,
|
|
1297
|
+
rootIssueCode: 'awCapabilityUnsupported',
|
|
1298
|
+
issuePluginId: dependencyId,
|
|
1299
|
+
issueScope: dependencyScope,
|
|
1300
|
+
missingCapabilities: dependencySupport.missing,
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
const pluginCacheKey = [item.resolution.sourceIdentity, dependencyId].join('\0');
|
|
1304
|
+
let dependencyPluginPromise = dependencyPluginCache.get(pluginCacheKey);
|
|
1305
|
+
if (!dependencyPluginPromise) {
|
|
1306
|
+
dependencyPluginPromise = readPluginManifest(path.join(item.resolution.rootDir, 'plugins', dependencyName), { mode: 'bundle' }).then((dependencyPlugin) => {
|
|
1307
|
+
dependencyPlugin.sourceId = item.resolution.sourceId;
|
|
1308
|
+
dependencyPlugin.sourceIdentity = item.resolution.sourceIdentity;
|
|
1309
|
+
dependencyPlugin.catalogLogicalIdentity = item.resolution.logicalIdentity;
|
|
1310
|
+
dependencyPlugin.pluginId = dependencyId;
|
|
1311
|
+
return dependencyPlugin;
|
|
1312
|
+
});
|
|
1313
|
+
dependencyPluginCache.set(pluginCacheKey, dependencyPluginPromise);
|
|
1314
|
+
}
|
|
1315
|
+
const dependencyPlugin = await dependencyPluginPromise;
|
|
1316
|
+
dependencyInspectionHookForTests?.();
|
|
1317
|
+
const dependencyMarketplaceName = marketplaceNameFor(dependencyName, platform, dependencyScope);
|
|
1318
|
+
const dependencyInspected = await inspectRebuildTarget({
|
|
1319
|
+
sourceId: item.resolution.sourceId,
|
|
1320
|
+
sourceIdentity: item.resolution.sourceIdentity,
|
|
1321
|
+
pluginId: dependencyId,
|
|
1322
|
+
marketplaceName: dependencyMarketplaceName,
|
|
1323
|
+
marketplaceRoot,
|
|
1324
|
+
plugin: dependencyPlugin,
|
|
1325
|
+
platform,
|
|
1326
|
+
scope: dependencyScope,
|
|
1327
|
+
cwd: options.cwd,
|
|
1328
|
+
catalog: { rootDir: item.resolution.rootDir, source: 'local' },
|
|
1329
|
+
context: {
|
|
1330
|
+
env,
|
|
1331
|
+
nativeCliRunner,
|
|
1332
|
+
reporter: createNoopReporter(),
|
|
1333
|
+
debugLogger: createNoopDebugLogger(),
|
|
1334
|
+
codexObservationSession: options.codexObservationSession,
|
|
1335
|
+
},
|
|
1336
|
+
userActivationDesired: codexDesiredUserActivationIds,
|
|
1337
|
+
nativeProbe: readOnlyNativeProbe({
|
|
1338
|
+
pluginName: dependencyName,
|
|
1339
|
+
sourceId: item.resolution.sourceId,
|
|
1340
|
+
sourceIdentity: item.resolution.sourceIdentity,
|
|
1341
|
+
platform,
|
|
1342
|
+
scope: dependencyScope,
|
|
1343
|
+
marketplaceName: dependencyMarketplaceName,
|
|
1344
|
+
marketplaceRoot,
|
|
1345
|
+
desired: sourceDesired.get(desiredTargetKey(dependencyId, platform))
|
|
1346
|
+
?.scopes.includes(dependencyScope) === true,
|
|
1347
|
+
}),
|
|
1348
|
+
shallow: true,
|
|
1349
|
+
});
|
|
1350
|
+
const dependencyLiveState = projectedLiveState({
|
|
1351
|
+
inspection: dependencyInspected.inspection,
|
|
1352
|
+
required: dependencyInspected.target.desiredOwnedComponents
|
|
1353
|
+
?? dependencyInspected.target.ownedComponents,
|
|
1354
|
+
optional: dependencyInspected.target.optionalOwnedComponents ?? [],
|
|
1355
|
+
});
|
|
1356
|
+
const collision = dependencyInspected.inspection.components.find((component) => component.collision)?.collision;
|
|
1357
|
+
if (collision) {
|
|
1358
|
+
return {
|
|
1359
|
+
state: 'blockedByCollision',
|
|
1360
|
+
dependencyScope,
|
|
1361
|
+
rootIssueId: collisionRootIssueId({
|
|
1362
|
+
pluginId: dependencyId,
|
|
1363
|
+
platform,
|
|
1364
|
+
scope: dependencyScope,
|
|
1365
|
+
collision,
|
|
1366
|
+
}),
|
|
1367
|
+
rootIssueCode: 'artifactCollision',
|
|
1368
|
+
issuePluginId: dependencyId,
|
|
1369
|
+
issueScope: dependencyScope,
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
const requiredDependencyComponents = dependencyInspected.target
|
|
1373
|
+
.desiredOwnedComponents ?? dependencyInspected.target.ownedComponents;
|
|
1374
|
+
const desiredDependency = sourceDesired.get(desiredTargetKey(dependencyId, platform));
|
|
1375
|
+
const projectMigrationPending = dependencyScope === 'project'
|
|
1376
|
+
&& projectIntent.dependencyScopeOverrides.some((override) => override.pluginId === dependencyId
|
|
1377
|
+
&& override.scope === 'project'
|
|
1378
|
+
&& (override.platform === undefined || override.platform === platform))
|
|
1379
|
+
&& desiredDependency?.scopes.includes('project') === true
|
|
1380
|
+
&& desiredDependency.scopes.includes('user') === false
|
|
1381
|
+
&& ownerInventory.references.some((reference) => reference.kind === 'namespacedOwner'
|
|
1382
|
+
&& reference.sourceId === item.resolution.sourceId
|
|
1383
|
+
&& reference.pluginName === dependencyName
|
|
1384
|
+
&& reference.platform === platform
|
|
1385
|
+
&& reference.scope === 'user');
|
|
1386
|
+
const migrationOnlyPartial = dependencyLiveState === 'partial'
|
|
1387
|
+
&& projectMigrationPending
|
|
1388
|
+
&& dependencyInspected.inspection.components.every((component) => component.state === 'present' || component.state === 'absent')
|
|
1389
|
+
&& requiredDependencyComponents.every((required) => dependencyInspected.inspection.components.some((component) => component.component === required
|
|
1390
|
+
&& (component.state === 'present'
|
|
1391
|
+
|| component.state === 'absent'
|
|
1392
|
+
&& component.component.kind !== 'native-plugin'
|
|
1393
|
+
&& 'locator' in component.component
|
|
1394
|
+
&& component.component.locator.kind === 'codex-activation'
|
|
1395
|
+
&& component.component.locator.desired === false)));
|
|
1396
|
+
const effectiveDependencyLiveState = migrationOnlyPartial
|
|
1397
|
+
? 'present'
|
|
1398
|
+
: dependencyLiveState;
|
|
1399
|
+
if (effectiveDependencyLiveState !== 'present') {
|
|
1400
|
+
const state = effectiveDependencyLiveState === 'absent' ? 'absent'
|
|
1401
|
+
: effectiveDependencyLiveState === 'partial' ? 'incomplete'
|
|
1402
|
+
: 'error';
|
|
1403
|
+
return {
|
|
1404
|
+
state,
|
|
1405
|
+
dependencyScope,
|
|
1406
|
+
rootIssueId: state === 'absent'
|
|
1407
|
+
? `dependencyMissing:${dependencyId}:${platform}:${dependencyScope}`
|
|
1408
|
+
: state === 'incomplete'
|
|
1409
|
+
? `incompleteInstallation:${dependencyId}:${platform}:${dependencyScope}`
|
|
1410
|
+
: `diagnostic:${dependencyId}:${platform}:${dependencyScope}`,
|
|
1411
|
+
rootIssueCode: state === 'absent' ? 'dependencyMissing'
|
|
1412
|
+
: state === 'incomplete' ? 'incompleteInstallation' : 'diagnostic',
|
|
1413
|
+
issuePluginId: dependencyId,
|
|
1414
|
+
issueScope: dependencyScope,
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
for (const childName of dependencyPlugin.manifest.dependencies ?? []) {
|
|
1418
|
+
const childId = formatPluginId({
|
|
1419
|
+
sourceId: item.resolution.sourceId,
|
|
1420
|
+
pluginName: childName,
|
|
1421
|
+
});
|
|
1422
|
+
let childResult;
|
|
1423
|
+
for (const childScope of dependencyPlacementsFor(childId, dependencyScope)) {
|
|
1424
|
+
const candidate = await inspectDependencyAtScope(childName, childScope);
|
|
1425
|
+
if (candidate.state === 'ready') {
|
|
1426
|
+
childResult = candidate;
|
|
1427
|
+
break;
|
|
1428
|
+
}
|
|
1429
|
+
if (!childResult
|
|
1430
|
+
|| dependencyPriority[candidate.state]
|
|
1431
|
+
> dependencyPriority[childResult.state]) {
|
|
1432
|
+
childResult = candidate;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
if (childResult?.state !== 'ready') {
|
|
1436
|
+
return {
|
|
1437
|
+
...childResult,
|
|
1438
|
+
dependencyScope,
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
return { state: 'ready', dependencyScope };
|
|
1443
|
+
})().catch(() => ({
|
|
1444
|
+
state: 'error',
|
|
1445
|
+
dependencyScope,
|
|
1446
|
+
rootIssueId: `diagnostic:${dependencyId}:${platform}:${dependencyScope}`,
|
|
1447
|
+
rootIssueCode: 'diagnostic',
|
|
1448
|
+
issuePluginId: dependencyId,
|
|
1449
|
+
issueScope: dependencyScope,
|
|
1450
|
+
}));
|
|
1451
|
+
dependencyInspectionCache.set(inspectionCacheKey, inspection);
|
|
1452
|
+
return inspection;
|
|
1453
|
+
}
|
|
1128
1454
|
if (directDependencies.length > 0
|
|
1129
|
-
&& (
|
|
1455
|
+
&& (desiredInScope
|
|
1456
|
+
|| actualCodexActivation
|
|
1457
|
+
|| hasScopedExtensionResidue
|
|
1458
|
+
|| (platform !== 'codex'
|
|
1459
|
+
&& (liveState === 'present' || liveState === 'partial')))) {
|
|
1130
1460
|
for (const dependencyName of directDependencies) {
|
|
1131
1461
|
const dependencyId = formatPluginId({
|
|
1132
1462
|
sourceId: item.resolution.sourceId,
|
|
@@ -1180,120 +1510,12 @@ async function statusCommandV7InSession(options) {
|
|
|
1180
1510
|
}, 'partial'));
|
|
1181
1511
|
continue;
|
|
1182
1512
|
}
|
|
1183
|
-
const
|
|
1184
|
-
let dependencyPluginPromise = dependencyPluginCache.get(pluginCacheKey);
|
|
1185
|
-
if (!dependencyPluginPromise) {
|
|
1186
|
-
dependencyPluginPromise = readPluginManifest(path.join(item.resolution.rootDir, 'plugins', dependencyName), { mode: 'bundle' }).then((dependencyPlugin) => {
|
|
1187
|
-
dependencyPlugin.sourceId = item.resolution.sourceId;
|
|
1188
|
-
dependencyPlugin.sourceIdentity = item.resolution.sourceIdentity;
|
|
1189
|
-
dependencyPlugin.catalogLogicalIdentity = item.resolution.logicalIdentity;
|
|
1190
|
-
dependencyPlugin.pluginId = dependencyId;
|
|
1191
|
-
return dependencyPlugin;
|
|
1192
|
-
});
|
|
1193
|
-
dependencyPluginCache.set(pluginCacheKey, dependencyPluginPromise);
|
|
1194
|
-
}
|
|
1195
|
-
const dependencyOverride = (scope === 'project'
|
|
1196
|
-
? projectIntent
|
|
1197
|
-
: userIntent).dependencyScopeOverrides.find((override) => override.pluginId === dependencyId
|
|
1198
|
-
&& (override.platform === undefined || override.platform === platform));
|
|
1199
|
-
const placements = dependencyOverride
|
|
1200
|
-
? [dependencyOverride.scope]
|
|
1201
|
-
: scope === 'project' ? ['project', 'user'] : ['user'];
|
|
1513
|
+
const placements = dependencyPlacementsFor(dependencyId, scope);
|
|
1202
1514
|
let dependencyResult = {
|
|
1203
1515
|
state: 'absent',
|
|
1204
1516
|
};
|
|
1205
1517
|
for (const dependencyScope of placements) {
|
|
1206
|
-
const
|
|
1207
|
-
item.resolution.sourceIdentity,
|
|
1208
|
-
dependencyId,
|
|
1209
|
-
platform,
|
|
1210
|
-
dependencyScope,
|
|
1211
|
-
dependencyScope === 'project' ? currentProjectKey : '',
|
|
1212
|
-
].join('\0');
|
|
1213
|
-
let dependencyInspection = dependencyInspectionCache.get(inspectionCacheKey);
|
|
1214
|
-
if (!dependencyInspection) {
|
|
1215
|
-
dependencyInspection = dependencyPluginPromise.then(async (dependencyPlugin) => {
|
|
1216
|
-
dependencyInspectionHookForTests?.();
|
|
1217
|
-
const dependencyMarketplaceName = marketplaceNameFor(dependencyName, platform, dependencyScope);
|
|
1218
|
-
const dependencyInspected = await inspectRebuildTarget({
|
|
1219
|
-
sourceId: item.resolution.sourceId,
|
|
1220
|
-
sourceIdentity: item.resolution.sourceIdentity,
|
|
1221
|
-
pluginId: dependencyId,
|
|
1222
|
-
marketplaceName: dependencyMarketplaceName,
|
|
1223
|
-
marketplaceRoot,
|
|
1224
|
-
plugin: dependencyPlugin,
|
|
1225
|
-
platform,
|
|
1226
|
-
scope: dependencyScope,
|
|
1227
|
-
cwd: options.cwd,
|
|
1228
|
-
catalog: { rootDir: item.resolution.rootDir, source: 'local' },
|
|
1229
|
-
context: {
|
|
1230
|
-
env,
|
|
1231
|
-
nativeCliRunner,
|
|
1232
|
-
reporter: createNoopReporter(),
|
|
1233
|
-
debugLogger: createNoopDebugLogger(),
|
|
1234
|
-
codexObservationSession: options.codexObservationSession,
|
|
1235
|
-
},
|
|
1236
|
-
userActivationDesired: codexDesiredUserActivationIds,
|
|
1237
|
-
nativeProbe: readOnlyNativeProbe({
|
|
1238
|
-
pluginName: dependencyName,
|
|
1239
|
-
sourceId: item.resolution.sourceId,
|
|
1240
|
-
sourceIdentity: item.resolution.sourceIdentity,
|
|
1241
|
-
platform,
|
|
1242
|
-
scope: dependencyScope,
|
|
1243
|
-
marketplaceName: dependencyMarketplaceName,
|
|
1244
|
-
marketplaceRoot,
|
|
1245
|
-
desired: sourceDesired.get(desiredTargetKey(dependencyId, platform))
|
|
1246
|
-
?.scopes.includes(dependencyScope) === true,
|
|
1247
|
-
}),
|
|
1248
|
-
shallow: true,
|
|
1249
|
-
});
|
|
1250
|
-
const dependencyLiveState = projectedLiveState({
|
|
1251
|
-
inspection: dependencyInspected.inspection,
|
|
1252
|
-
required: dependencyInspected.target.desiredOwnedComponents
|
|
1253
|
-
?? dependencyInspected.target.ownedComponents,
|
|
1254
|
-
optional: dependencyInspected.target.optionalOwnedComponents ?? [],
|
|
1255
|
-
});
|
|
1256
|
-
const collision = dependencyInspected.inspection.components.find((component) => component.collision)?.collision;
|
|
1257
|
-
if (collision) {
|
|
1258
|
-
return {
|
|
1259
|
-
state: 'blockedByCollision',
|
|
1260
|
-
dependencyScope,
|
|
1261
|
-
rootIssueId: collisionRootIssueId({
|
|
1262
|
-
pluginId: dependencyId,
|
|
1263
|
-
platform,
|
|
1264
|
-
scope: dependencyScope,
|
|
1265
|
-
collision,
|
|
1266
|
-
}),
|
|
1267
|
-
rootIssueCode: 'artifactCollision',
|
|
1268
|
-
};
|
|
1269
|
-
}
|
|
1270
|
-
return {
|
|
1271
|
-
state: dependencyLiveState === 'present' ? 'ready'
|
|
1272
|
-
: dependencyLiveState === 'absent' ? 'absent'
|
|
1273
|
-
: dependencyLiveState === 'partial' ? 'incomplete'
|
|
1274
|
-
: 'error',
|
|
1275
|
-
dependencyScope,
|
|
1276
|
-
...(dependencyLiveState === 'partial'
|
|
1277
|
-
? {
|
|
1278
|
-
rootIssueId: `incompleteInstallation:${dependencyId}:${platform}:${dependencyScope}`,
|
|
1279
|
-
rootIssueCode: 'incompleteInstallation',
|
|
1280
|
-
}
|
|
1281
|
-
: dependencyLiveState === 'error'
|
|
1282
|
-
? {
|
|
1283
|
-
rootIssueId: `diagnostic:${dependencyId}:${platform}:${dependencyScope}`,
|
|
1284
|
-
rootIssueCode: 'diagnostic',
|
|
1285
|
-
}
|
|
1286
|
-
: {}),
|
|
1287
|
-
};
|
|
1288
|
-
}).catch(() => ({
|
|
1289
|
-
state: 'error',
|
|
1290
|
-
dependencyScope,
|
|
1291
|
-
rootIssueId: `diagnostic:${dependencyId}:${platform}:${dependencyScope}`,
|
|
1292
|
-
rootIssueCode: 'diagnostic',
|
|
1293
|
-
}));
|
|
1294
|
-
dependencyInspectionCache.set(inspectionCacheKey, dependencyInspection);
|
|
1295
|
-
}
|
|
1296
|
-
const candidate = await dependencyInspection;
|
|
1518
|
+
const candidate = await inspectDependencyAtScope(dependencyName, dependencyScope);
|
|
1297
1519
|
if (candidate.state === 'ready') {
|
|
1298
1520
|
dependencyResult = candidate;
|
|
1299
1521
|
break;
|
|
@@ -1309,7 +1531,7 @@ async function statusCommandV7InSession(options) {
|
|
|
1309
1531
|
dependencyResult = candidate;
|
|
1310
1532
|
}
|
|
1311
1533
|
}
|
|
1312
|
-
if (dependencyResult.state === 'absent') {
|
|
1534
|
+
if (dependencyResult.state === 'absent' && !dependencyResult.rootIssueId) {
|
|
1313
1535
|
const dependencyScope = dependencyResult.dependencyScope ?? placements[0];
|
|
1314
1536
|
dependencyResult = {
|
|
1315
1537
|
state: 'absent',
|
|
@@ -1324,28 +1546,46 @@ async function statusCommandV7InSession(options) {
|
|
|
1324
1546
|
dependencyPlatform: platform,
|
|
1325
1547
|
dependencyScope,
|
|
1326
1548
|
dependencyProject: dependencyScope === 'project' ? 'current' : null,
|
|
1327
|
-
|
|
1549
|
+
state: dependencyResult.state,
|
|
1550
|
+
...(dependencyResult.rootIssueId
|
|
1551
|
+
? { rootIssueId: dependencyResult.rootIssueId }
|
|
1552
|
+
: {}),
|
|
1553
|
+
...(dependencyResult.rootIssueCode
|
|
1554
|
+
? { rootIssueCode: dependencyResult.rootIssueCode }
|
|
1555
|
+
: {}),
|
|
1328
1556
|
});
|
|
1557
|
+
const issuePluginId = dependencyResult.issuePluginId ?? dependencyId;
|
|
1558
|
+
const issueScope = dependencyResult.issueScope ?? dependencyScope;
|
|
1329
1559
|
if (dependencyResult.state === 'absent') {
|
|
1330
1560
|
dependencyErrors.push(finalizeTargetError({
|
|
1331
1561
|
code: 'dependencyMissing',
|
|
1332
|
-
message: `dependencyMissing: ${
|
|
1333
|
-
dependencyPluginId:
|
|
1562
|
+
message: `dependencyMissing: ${issuePluginId} is absent from its required live placement.`,
|
|
1563
|
+
dependencyPluginId: issuePluginId,
|
|
1334
1564
|
dependencyPlatform: platform,
|
|
1335
|
-
dependencyScope,
|
|
1336
|
-
dependencyProject:
|
|
1565
|
+
dependencyScope: issueScope,
|
|
1566
|
+
dependencyProject: issueScope === 'project' ? 'current' : null,
|
|
1337
1567
|
rootIssueId: dependencyResult.rootIssueId,
|
|
1338
1568
|
rootIssueCode: dependencyResult.rootIssueCode,
|
|
1339
1569
|
}, 'partial'));
|
|
1340
1570
|
}
|
|
1341
1571
|
else if (dependencyResult.state !== 'ready') {
|
|
1572
|
+
const code = dependencyResult.rootIssueCode === 'awCapabilityUnsupported'
|
|
1573
|
+
? 'awCapabilityUnsupported'
|
|
1574
|
+
: dependencyResult.rootIssueCode === 'dependencyGraphInvalid'
|
|
1575
|
+
? 'dependencyGraphInvalid'
|
|
1576
|
+
: 'dependencyNotReady';
|
|
1577
|
+
const message = code === 'awCapabilityUnsupported'
|
|
1578
|
+
? `${code}: ${issuePluginId} requires unsupported AW capabilities: ${(dependencyResult.missingCapabilities ?? []).join(', ')}.`
|
|
1579
|
+
: code === 'dependencyGraphInvalid'
|
|
1580
|
+
? `${code}: dependency cycle includes ${issuePluginId}.`
|
|
1581
|
+
: `${code}: ${issuePluginId} is not ready at its required live placement.`;
|
|
1342
1582
|
dependencyErrors.push(finalizeTargetError({
|
|
1343
|
-
code
|
|
1344
|
-
message
|
|
1345
|
-
dependencyPluginId:
|
|
1583
|
+
code,
|
|
1584
|
+
message,
|
|
1585
|
+
dependencyPluginId: issuePluginId,
|
|
1346
1586
|
dependencyPlatform: platform,
|
|
1347
|
-
dependencyScope,
|
|
1348
|
-
dependencyProject:
|
|
1587
|
+
dependencyScope: issueScope,
|
|
1588
|
+
dependencyProject: issueScope === 'project' ? 'current' : null,
|
|
1349
1589
|
...(dependencyResult.rootIssueId
|
|
1350
1590
|
? { rootIssueId: dependencyResult.rootIssueId }
|
|
1351
1591
|
: {}),
|
|
@@ -1924,12 +2164,10 @@ async function statusCommandV7InSession(options) {
|
|
|
1924
2164
|
const codex = target.platform === 'codex' ? entry?.codex : undefined;
|
|
1925
2165
|
const desiredAll = desiredTargetStates.get(desiredTargetKey(target.pluginId, target.platform))
|
|
1926
2166
|
?? { scopes: [], relation: 'none' };
|
|
1927
|
-
const desired =
|
|
1928
|
-
?
|
|
1929
|
-
:
|
|
1930
|
-
|
|
1931
|
-
relation: desiredAll.relation,
|
|
1932
|
-
};
|
|
2167
|
+
const desired = {
|
|
2168
|
+
scopes: desiredAll.scopes.includes(target.scope) ? [target.scope] : [],
|
|
2169
|
+
relation: desiredAll.relation,
|
|
2170
|
+
};
|
|
1933
2171
|
const sharedNative = codex?.sharedNative ?? target.sharedNative;
|
|
1934
2172
|
const baseActivation = codex?.activation ?? target.activation;
|
|
1935
2173
|
const consumerScope = desired.scopes.includes('project')
|
|
@@ -1952,9 +2190,7 @@ async function statusCommandV7InSession(options) {
|
|
|
1952
2190
|
systemConsumer,
|
|
1953
2191
|
}
|
|
1954
2192
|
: baseActivation;
|
|
1955
|
-
const observationScopes =
|
|
1956
|
-
? [explicitScope]
|
|
1957
|
-
: desired.scopes.length > 0 ? desired.scopes : groupedScopes;
|
|
2193
|
+
const observationScopes = [target.scope];
|
|
1958
2194
|
const scopedTargets = groupedTargets.filter((candidate) => observationScopes.includes(candidate.scope));
|
|
1959
2195
|
const observedTargets = scopedTargets.length > 0 ? scopedTargets : groupedTargets;
|
|
1960
2196
|
const ownershipState = observedTargets.some((candidate) => candidate.state === 'error')
|
|
@@ -1966,6 +2202,8 @@ async function statusCommandV7InSession(options) {
|
|
|
1966
2202
|
: sharedNative?.staleCacheObserved
|
|
1967
2203
|
? 'partial'
|
|
1968
2204
|
: 'absent';
|
|
2205
|
+
const actualScopeEnabled = target.platform === 'codex'
|
|
2206
|
+
&& baseActivation?.[target.scope] === true;
|
|
1969
2207
|
const hasSourceError = observedTargets.some((candidate) => candidate.errors.some((error) => error.code === 'sourceMissing'
|
|
1970
2208
|
|| error.code === 'catalogSourceUnavailable'
|
|
1971
2209
|
|| error.code === 'bundleUnavailable'
|
|
@@ -1974,18 +2212,16 @@ async function statusCommandV7InSession(options) {
|
|
|
1974
2212
|
&& (codex?.extensionKinds.length ?? 0) > 0
|
|
1975
2213
|
&& desired.scopes.includes('user')
|
|
1976
2214
|
&& desired.scopes.includes('project');
|
|
1977
|
-
const
|
|
1978
|
-
const expectedProject = desired.scopes.includes('project');
|
|
2215
|
+
const expectedEnabled = desired.scopes.includes(target.scope);
|
|
1979
2216
|
const activationDrift = target.platform === 'codex'
|
|
1980
2217
|
&& (codexConfigErrors.some((error) => error.scope === 'user' || observationScopes.includes(error.scope))
|
|
1981
2218
|
|| ((codex?.nativeKinds.length ?? 0) > 0
|
|
1982
|
-
&& (
|
|
1983
|
-
||
|
|
1984
|
-
|| (expectedProject && activation?.project !== true)
|
|
1985
|
-
|| (!expectedProject && activation?.project === true))));
|
|
2219
|
+
&& (expectedEnabled && activation?.[target.scope] !== true
|
|
2220
|
+
|| !expectedEnabled && activation?.[target.scope] === true)));
|
|
1986
2221
|
const extensionComponents = observedTargets.flatMap((candidate) => candidate.components).filter((component) => component.key !== 'native'
|
|
1987
2222
|
&& !component.key.startsWith('activation-')
|
|
1988
2223
|
&& !component.key.startsWith('marketplace-'));
|
|
2224
|
+
const hasScopedExtensionResidue = extensionComponents.some((component) => component.state !== 'absent' || component.error !== undefined);
|
|
1989
2225
|
const extensions = target.platform !== 'codex'
|
|
1990
2226
|
|| (codex?.extensionKinds.length ?? 0) === 0
|
|
1991
2227
|
? undefined
|
|
@@ -2041,6 +2277,7 @@ async function statusCommandV7InSession(options) {
|
|
|
2041
2277
|
const baseTargetErrors = observedTargets.flatMap((candidate) => candidate.errors);
|
|
2042
2278
|
const hasBlockingBaseReason = baseTargetErrors.some((reason) => reason.severity === 'blocking');
|
|
2043
2279
|
const capabilityUnsupported = baseTargetErrors.some((reason) => reason.code === 'awCapabilityUnsupported');
|
|
2280
|
+
const dependencyNotReady = (target.dependencyReadiness ?? []).some((dependency) => dependency.state !== 'ready');
|
|
2044
2281
|
const state = hasSourceError && desiredEnabled
|
|
2045
2282
|
? 'blocked'
|
|
2046
2283
|
: consumerBlocking && desiredEnabled
|
|
@@ -2049,23 +2286,31 @@ async function statusCommandV7InSession(options) {
|
|
|
2049
2286
|
? 'blocked'
|
|
2050
2287
|
: sharedNative?.state === 'blocked' || hasBlockingBaseReason || capabilityUnsupported
|
|
2051
2288
|
? 'blocked'
|
|
2052
|
-
:
|
|
2053
|
-
?
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2289
|
+
: sharedNative?.state === 'replaceable' && sharedNative.reason === 'damaged'
|
|
2290
|
+
? 'needsSync'
|
|
2291
|
+
: !desiredEnabled
|
|
2292
|
+
? (target.platform === 'codex'
|
|
2293
|
+
? actualScopeEnabled || hasScopedExtensionResidue
|
|
2294
|
+
: ownershipState !== 'absent')
|
|
2295
|
+
|| desired.relation === 'managed'
|
|
2296
|
+
? 'orphaned'
|
|
2297
|
+
: 'absent'
|
|
2298
|
+
: dependencyMoves.length > 0
|
|
2061
2299
|
? 'needsSync'
|
|
2062
|
-
:
|
|
2300
|
+
: dependencyNotReady
|
|
2063
2301
|
? 'needsSync'
|
|
2064
|
-
:
|
|
2302
|
+
: sharedNative?.state === 'missing'
|
|
2303
|
+
|| sharedNative?.state === 'replaceable'
|
|
2304
|
+
|| sharedNative?.state === 'unobserved'
|
|
2065
2305
|
? 'needsSync'
|
|
2066
|
-
:
|
|
2306
|
+
: activationDrift || extensions?.state === 'drifted'
|
|
2067
2307
|
? 'needsSync'
|
|
2068
|
-
: '
|
|
2308
|
+
: extensions?.state === 'missing'
|
|
2309
|
+
|| (target.platform !== 'codex' && ownershipState === 'absent')
|
|
2310
|
+
? 'needsSync'
|
|
2311
|
+
: ownershipState === 'partial' || ownershipState === 'error'
|
|
2312
|
+
? 'needsSync'
|
|
2313
|
+
: 'ready';
|
|
2069
2314
|
const stableErrors = [
|
|
2070
2315
|
...projectStatusSharedNativeReasons(sharedNative, baseTargetErrors.map((error) => error.code), desiredEnabled),
|
|
2071
2316
|
...(desiredOverlapConflict
|
|
@@ -2073,8 +2318,8 @@ async function statusCommandV7InSession(options) {
|
|
|
2073
2318
|
: []),
|
|
2074
2319
|
...(activationDrift && sharedNative?.state !== 'missing' && sharedNative?.state !== 'unobserved'
|
|
2075
2320
|
? [warning('codexActivationDrift', `${target.pluginId} activation differs from desired intent: `
|
|
2076
|
-
+
|
|
2077
|
-
+ `
|
|
2321
|
+
+ `${target.scope} expected=${expectedEnabled}, `
|
|
2322
|
+
+ `actual=${activation?.[target.scope] ?? 'unset'}.`)]
|
|
2078
2323
|
: []),
|
|
2079
2324
|
...(extensions?.state === 'drifted'
|
|
2080
2325
|
? [warning('codexExtensionDrift', `${target.pluginId} extension projection has drifted.`)]
|
|
@@ -2100,11 +2345,7 @@ async function statusCommandV7InSession(options) {
|
|
|
2100
2345
|
])).values()];
|
|
2101
2346
|
const ownershipComponents = [...new Map(observedTargets.flatMap((candidate) => candidate.components)
|
|
2102
2347
|
.map((component) => [component.key, component])).values()];
|
|
2103
|
-
const representativeScope =
|
|
2104
|
-
?? (desired.scopes.length === 1
|
|
2105
|
-
? desired.scopes[0]
|
|
2106
|
-
: observedTargets.find((candidate) => candidate.state !== 'absent')?.scope
|
|
2107
|
-
?? (groupedScopes.includes('user') ? 'user' : groupedScopes[0] ?? target.scope));
|
|
2348
|
+
const representativeScope = target.scope;
|
|
2108
2349
|
const representativeTarget = observedTargets.find((candidate) => candidate.scope === representativeScope) ?? target;
|
|
2109
2350
|
const components = [
|
|
2110
2351
|
{
|
|
@@ -2151,7 +2392,7 @@ async function statusCommandV7InSession(options) {
|
|
|
2151
2392
|
}]),
|
|
2152
2393
|
...(activation?.systemConsumer ? [{
|
|
2153
2394
|
kind: 'systemConsumer',
|
|
2154
|
-
key:
|
|
2395
|
+
key: `codex:${representativeScope}`,
|
|
2155
2396
|
state: activation.systemConsumer.state,
|
|
2156
2397
|
metadata: {
|
|
2157
2398
|
evidence: activation.evidence,
|
|
@@ -2198,6 +2439,8 @@ async function statusCommandV7InSession(options) {
|
|
|
2198
2439
|
pluginId: target.pluginId,
|
|
2199
2440
|
...(dependencyMoves.length > 0 ? { dependencyMoves } : {}),
|
|
2200
2441
|
...(sharedNative ? { sharedNative } : {}),
|
|
2442
|
+
scope: target.scope,
|
|
2443
|
+
actualEnabled: actualScopeEnabled,
|
|
2201
2444
|
conflictRoots: rootIntentsForTarget({
|
|
2202
2445
|
pluginId: target.pluginId,
|
|
2203
2446
|
platform: target.platform,
|
|
@@ -2206,7 +2449,9 @@ async function statusCommandV7InSession(options) {
|
|
|
2206
2449
|
available,
|
|
2207
2450
|
}),
|
|
2208
2451
|
errorCodes: dedupedErrors.map((error) => error.code),
|
|
2209
|
-
})
|
|
2452
|
+
}).map((action) => action.command === 'manual' || action.scope
|
|
2453
|
+
? action
|
|
2454
|
+
: { ...action, scope: representativeScope }),
|
|
2210
2455
|
};
|
|
2211
2456
|
};
|
|
2212
2457
|
const codexGroups = new Map();
|
|
@@ -2221,18 +2466,84 @@ async function statusCommandV7InSession(options) {
|
|
|
2221
2466
|
codexGroups.set(target.pluginId, group);
|
|
2222
2467
|
}
|
|
2223
2468
|
for (const group of codexGroups.values()) {
|
|
2224
|
-
const
|
|
2225
|
-
|
|
2469
|
+
const decorated = await Promise.all(group.map((target) => decorateTarget(target, [target.scope], [target])));
|
|
2470
|
+
const first = decorated[0];
|
|
2471
|
+
const entry = selectedByPluginId.get(first.pluginId);
|
|
2472
|
+
const desired = desiredTargetStates.get(desiredTargetKey(first.pluginId, 'codex'))
|
|
2473
|
+
?? { scopes: [], relation: 'none' };
|
|
2474
|
+
const returnedScopes = new Set(decorated.map((target) => target.scope));
|
|
2475
|
+
const desiredOverlapConflict = (entry?.codex?.extensionKinds.length ?? 0) > 0
|
|
2476
|
+
&& desired.scopes.includes('user')
|
|
2477
|
+
&& desired.scopes.includes('project')
|
|
2478
|
+
&& returnedScopes.has('user')
|
|
2479
|
+
&& returnedScopes.has('project');
|
|
2480
|
+
const sharedComponents = [...new Map(decorated.flatMap((target) => target.components)
|
|
2481
|
+
.filter((component) => component.kind === 'sharedNative' || component.kind === 'systemConsumer')
|
|
2482
|
+
.map((component) => [`${component.kind}\0${component.key}`, component])).values()];
|
|
2483
|
+
const sharedReason = (reason) => reason.code.startsWith('codexSharedNative') || reason.code === 'staleCacheObserved';
|
|
2484
|
+
const sharedReasons = decorated.flatMap((target) => target.reasons.filter(sharedReason));
|
|
2485
|
+
const placements = decorated.map((target) => ({
|
|
2486
|
+
scope: target.scope,
|
|
2487
|
+
state: target.state,
|
|
2488
|
+
components: target.components.filter((component) => component.kind !== 'sharedNative' && component.kind !== 'systemConsumer'),
|
|
2489
|
+
reasons: target.reasons.filter((reason) => !sharedReason(reason)),
|
|
2490
|
+
recoveryActions: target.recoveryActions,
|
|
2491
|
+
})).sort((left, right) => left.scope.localeCompare(right.scope, 'en'));
|
|
2492
|
+
const reasons = [...new Map([
|
|
2493
|
+
...placements.flatMap((placement) => placement.reasons),
|
|
2494
|
+
...sharedReasons,
|
|
2495
|
+
...(desiredOverlapConflict ? [blocking('codexExtensionScopeConflict', `${first.pluginId} has AW extensions desired at user and project scope.`)] : []),
|
|
2496
|
+
]
|
|
2497
|
+
.map((reason) => [`${reason.code}\0${reason.message}`, reason])).values()];
|
|
2498
|
+
const conflictRecovery = desiredOverlapConflict ? statusRecovery({
|
|
2499
|
+
state: 'blocked',
|
|
2500
|
+
desired,
|
|
2501
|
+
platform: 'codex',
|
|
2502
|
+
pluginId: first.pluginId,
|
|
2503
|
+
conflictRoots: rootIntentsForTarget({
|
|
2504
|
+
pluginId: first.pluginId,
|
|
2505
|
+
platform: 'codex',
|
|
2506
|
+
userIntent,
|
|
2507
|
+
projectIntent,
|
|
2508
|
+
available,
|
|
2509
|
+
}),
|
|
2510
|
+
errorCodes: ['codexExtensionScopeConflict'],
|
|
2511
|
+
}) : [];
|
|
2512
|
+
const recoveryActions = [...new Map((desiredOverlapConflict
|
|
2513
|
+
? conflictRecovery
|
|
2514
|
+
: placements.flatMap((placement) => placement.recoveryActions))
|
|
2515
|
+
.map((action) => [
|
|
2516
|
+
`${action.command}\0${action.scope ?? ''}\0${action.description}`,
|
|
2517
|
+
action,
|
|
2518
|
+
])).values()];
|
|
2519
|
+
const state = desiredOverlapConflict ? 'blocked'
|
|
2520
|
+
: ['blocked', 'needsSync', 'orphaned', 'ready', 'absent']
|
|
2521
|
+
.find((candidate) => placements.some((placement) => placement.state === candidate));
|
|
2522
|
+
projectedTargets.push({
|
|
2523
|
+
pluginName: first.pluginName,
|
|
2524
|
+
sourceId: first.sourceId,
|
|
2525
|
+
sourceIdentity: first.sourceIdentity,
|
|
2526
|
+
pluginId: first.pluginId,
|
|
2527
|
+
...(first.version ? { version: first.version } : {}),
|
|
2528
|
+
platform: 'codex',
|
|
2529
|
+
cwd: first.cwd,
|
|
2530
|
+
state,
|
|
2531
|
+
components: sharedComponents,
|
|
2532
|
+
reasons,
|
|
2533
|
+
recoveryActions,
|
|
2534
|
+
placements,
|
|
2535
|
+
});
|
|
2226
2536
|
}
|
|
2227
|
-
projectedTargets.sort((left, right) => `${left.pluginId}\0${left.platform}
|
|
2228
|
-
const targetRevisions = projectedTargets.
|
|
2537
|
+
projectedTargets.sort((left, right) => `${left.pluginId}\0${left.platform}`.localeCompare(`${right.pluginId}\0${right.platform}`, 'en'));
|
|
2538
|
+
const targetRevisions = projectedTargets.flatMap((target) => {
|
|
2229
2539
|
const entry = selectedByPluginId.get(target.pluginId);
|
|
2230
|
-
|
|
2540
|
+
const placements = target.platform === 'codex' ? target.placements : [target];
|
|
2541
|
+
return placements.map((placement) => ({
|
|
2231
2542
|
pluginId: target.pluginId,
|
|
2232
2543
|
platform: target.platform,
|
|
2233
|
-
scope:
|
|
2234
|
-
revision: projectTargetRevision(entry?.version, entry?.states[target.platform]?.[
|
|
2235
|
-
};
|
|
2544
|
+
scope: placement.scope,
|
|
2545
|
+
revision: projectTargetRevision(entry?.version, entry?.states[target.platform]?.[placement.scope]?.installedVersion),
|
|
2546
|
+
}));
|
|
2236
2547
|
});
|
|
2237
2548
|
const publicConfigIssues = available.flatMap((entry) => (entry.configIssues ?? [])
|
|
2238
2549
|
.filter((issue) => issue.type === 'configLayerUnsupported')
|
|
@@ -2242,7 +2553,7 @@ async function statusCommandV7InSession(options) {
|
|
|
2242
2553
|
...issue,
|
|
2243
2554
|
})));
|
|
2244
2555
|
const payload = {
|
|
2245
|
-
schemaVersion:
|
|
2556
|
+
schemaVersion: 8,
|
|
2246
2557
|
catalog: {
|
|
2247
2558
|
primarySourceId: catalog.primarySourceId,
|
|
2248
2559
|
configDigest: catalog.configDigest,
|
|
@@ -2272,7 +2583,7 @@ async function statusCommandV7InSession(options) {
|
|
|
2272
2583
|
|| payload.targets.some((target) => target.reasons.some((reason) => reason.severity === 'blocking'));
|
|
2273
2584
|
return {
|
|
2274
2585
|
payload,
|
|
2275
|
-
output: options.json ? JSON.stringify(payload) :
|
|
2586
|
+
output: options.json ? JSON.stringify(payload) : renderStatusV8(payload, options.verbose === true),
|
|
2276
2587
|
hasErrors,
|
|
2277
2588
|
targetRevisions,
|
|
2278
2589
|
pluginSummaries: available.map((entry) => {
|
|
@@ -2319,9 +2630,9 @@ async function statusCommandV7InSession(options) {
|
|
|
2319
2630
|
}),
|
|
2320
2631
|
};
|
|
2321
2632
|
}
|
|
2322
|
-
export async function
|
|
2633
|
+
export async function statusCommandV8(options) {
|
|
2323
2634
|
if (options.codexObservationSession) {
|
|
2324
|
-
return
|
|
2635
|
+
return statusCommandV8InSession({
|
|
2325
2636
|
...options,
|
|
2326
2637
|
codexObservationSession: options.codexObservationSession,
|
|
2327
2638
|
});
|
|
@@ -2333,7 +2644,7 @@ export async function statusCommandV7(options) {
|
|
|
2333
2644
|
runner: options.nativeCliRunner ?? getDefaultNativeCliRunner(),
|
|
2334
2645
|
});
|
|
2335
2646
|
try {
|
|
2336
|
-
return await
|
|
2647
|
+
return await statusCommandV8InSession({ ...options, codexObservationSession: session });
|
|
2337
2648
|
}
|
|
2338
2649
|
finally {
|
|
2339
2650
|
await session.dispose();
|