@lesliechan721/aw 0.1.0-beta.34 → 0.1.0-beta.36
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/scripts/test-plugin-scripts.js +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +1 -1
- package/dist/src/commands/aw-capabilities.js +1 -0
- package/dist/src/commands/aw-capabilities.js.map +1 -1
- package/dist/src/commands/operation-plan.d.ts +19 -0
- package/dist/src/commands/operation-plan.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +1 -0
- package/dist/src/commands/rebuild-command.js +890 -8
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +12 -0
- package/dist/src/commands/rebuild-integration.js +88 -2
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/status-v6.js +109 -19
- package/dist/src/commands/status-v6.js.map +1 -1
- package/dist/src/commands/wizard.d.ts +5 -1
- package/dist/src/commands/wizard.js +4 -2
- package/dist/src/commands/wizard.js.map +1 -1
- package/dist/src/commands/write-commands.js +3 -0
- package/dist/src/commands/write-commands.js.map +1 -1
- package/dist/src/index.js +57 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/portable/materializer.js +19 -3
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/review/review-profile.js +19 -2
- package/dist/src/review/review-profile.js.map +1 -1
- package/dist/src/tui/components.d.ts +39 -0
- package/dist/src/tui/components.js +51 -18
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/config-array-draft.d.ts +29 -0
- package/dist/src/tui/config-array-draft.js +48 -0
- package/dist/src/tui/config-array-draft.js.map +1 -0
- package/dist/src/tui/config-value-presentation.d.ts +1 -0
- package/dist/src/tui/config-value-presentation.js +17 -1
- package/dist/src/tui/config-value-presentation.js.map +1 -1
- package/dist/src/tui/console-app-v4.js +1742 -1368
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/content-item-card.d.ts +13 -0
- package/dist/src/tui/content-item-card.js +51 -0
- package/dist/src/tui/content-item-card.js.map +1 -0
- package/dist/src/tui/controller-runtime.js +45 -4
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +18 -0
- package/dist/src/tui/controller.js +168 -12
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/dependency-graph-view.d.ts +39 -0
- package/dist/src/tui/dependency-graph-view.js +121 -0
- package/dist/src/tui/dependency-graph-view.js.map +1 -0
- package/dist/src/tui/dependency-graph.js +16 -19
- package/dist/src/tui/dependency-graph.js.map +1 -1
- package/dist/src/tui/entity-cards.d.ts +55 -0
- package/dist/src/tui/entity-cards.js +220 -0
- package/dist/src/tui/entity-cards.js.map +1 -0
- package/dist/src/tui/input-display.js +10 -1
- package/dist/src/tui/input-display.js.map +1 -1
- package/dist/src/tui/model.d.ts +11 -0
- package/dist/src/tui/model.js +20 -4
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-diagnostic-screens.d.ts +2 -18
- package/dist/src/tui/operation-diagnostic-screens.js +16 -69
- package/dist/src/tui/operation-diagnostic-screens.js.map +1 -1
- package/dist/src/tui/operation-review-planner.js +44 -3
- package/dist/src/tui/operation-review-planner.js.map +1 -1
- package/dist/src/tui/plugin-content.d.ts +8 -0
- package/dist/src/tui/plugin-content.js +409 -65
- package/dist/src/tui/plugin-content.js.map +1 -1
- package/dist/src/tui/plugin-detail.d.ts +52 -0
- package/dist/src/tui/plugin-detail.js +165 -0
- package/dist/src/tui/plugin-detail.js.map +1 -0
- package/dist/src/tui/project-inventory.d.ts +68 -0
- package/dist/src/tui/project-inventory.js +203 -0
- package/dist/src/tui/project-inventory.js.map +1 -0
- package/dist/src/tui/query-header.d.ts +30 -0
- package/dist/src/tui/query-header.js +40 -0
- package/dist/src/tui/query-header.js.map +1 -0
- package/dist/src/tui/reader.d.ts +37 -0
- package/dist/src/tui/reader.js +47 -0
- package/dist/src/tui/reader.js.map +1 -0
- package/dist/src/tui/router.d.ts +26 -3
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/screen-registry.d.ts +9 -1
- package/dist/src/tui/screen-registry.js +1 -1
- package/dist/src/tui/screen-registry.js.map +1 -1
- package/dist/src/tui/source-detail-card.d.ts +29 -0
- package/dist/src/tui/source-detail-card.js +45 -0
- package/dist/src/tui/source-detail-card.js.map +1 -0
- package/dist/src/tui/theme.d.ts +12 -0
- package/dist/src/tui/theme.js +12 -0
- package/dist/src/tui/theme.js.map +1 -1
- package/dist/src/tui/wizard.js +26 -4
- package/dist/src/tui/wizard.js.map +1 -1
- package/dist/src/types.d.ts +2 -0
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/catalog-source-references.js +2 -2
- package/dist/src/utils/local-marketplace.d.ts +1 -0
- package/dist/src/utils/local-marketplace.js +22 -0
- package/dist/src/utils/local-marketplace.js.map +1 -1
- package/dist/src/utils/plugin-config-write.js +3 -1
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/plugin-config.d.ts +5 -5
- package/dist/src/utils/plugin-config.js +47 -23
- package/dist/src/utils/plugin-config.js.map +1 -1
- package/package.json +4 -4
|
@@ -11,7 +11,9 @@ import type { OperationPlan } from '../commands/operation-plan.js';
|
|
|
11
11
|
import type { RebuildProgressFeed, RebuildProgressSnapshot } from '../output/rebuild-progress.js';
|
|
12
12
|
import { type ConfigPageViewModel, type ConfigGroupViewModel, type InstallPlacementDraftViewModel, type PluginListItemViewModel, type PluginDependencyOverviewViewModel, type PortableSkillSelectionViewModel, type SourceHealthViewModel, type SourceDetailViewModel, type TuiViewModel, type UserIssueCategory, type UserIssueViewModel } from './model.js';
|
|
13
13
|
import type { PluginContentOverview } from './plugin-content.js';
|
|
14
|
+
import { type PluginDetailSubject } from './plugin-detail.js';
|
|
14
15
|
import { OperationHistoryStore, type OperationDiagnosticDetail, type OperationEffectFacts, type OperationHistorySummary, type OperationReportPreview, type SafeOperationDiagnostic, type SaveOperationReportResult } from './operation-history.js';
|
|
16
|
+
import { type ProjectInventoryRoot, type ProjectInventoryViewModel } from './project-inventory.js';
|
|
15
17
|
import { type ConfigInvalidStoreEvidence, type PluginInstallFilter, type PortableBlockerCode, type TuiPageContext, type TuiRoute, type TuiRouterSnapshot } from './router.js';
|
|
16
18
|
import { type CatalogSourceGenerationViewModel } from './catalog-generation.js';
|
|
17
19
|
import type { CatalogSourceFreshnessViewModel } from './catalog-freshness.js';
|
|
@@ -136,6 +138,7 @@ export interface ConfigOperationChange {
|
|
|
136
138
|
}>;
|
|
137
139
|
}
|
|
138
140
|
export interface ConfigSaveBatchGroup {
|
|
141
|
+
editEvidence?: Record<string, import('./model.js').ConfigEditEvidence>;
|
|
139
142
|
scope: Scope;
|
|
140
143
|
updates?: Record<string, unknown>;
|
|
141
144
|
removeKeys?: string[];
|
|
@@ -290,6 +293,7 @@ export interface OperationEvidence {
|
|
|
290
293
|
targetFingerprint?: string;
|
|
291
294
|
offlineCleanup?: OfflineCleanupTargetEvidence;
|
|
292
295
|
offlineCleanupPlans?: OfflineCleanupTargetEvidence[];
|
|
296
|
+
removedPluginCleanupIds?: string[];
|
|
293
297
|
dependencyPlan?: ReconcileOperationPlan;
|
|
294
298
|
codexReconcilePlans?: CodexReconcilePlan[];
|
|
295
299
|
operationPlan?: OperationPlan;
|
|
@@ -382,6 +386,10 @@ export interface OperationReviewModel {
|
|
|
382
386
|
version?: string;
|
|
383
387
|
};
|
|
384
388
|
changes: OperationReviewChange[];
|
|
389
|
+
configImpact?: {
|
|
390
|
+
state: 'known' | 'unknown';
|
|
391
|
+
affectedTargetCount: number;
|
|
392
|
+
};
|
|
385
393
|
confirmationDetails?: string[];
|
|
386
394
|
technicalDetails?: string[];
|
|
387
395
|
equivalentCommand?: string;
|
|
@@ -778,6 +786,12 @@ export interface TuiControllerSnapshot {
|
|
|
778
786
|
operationRecordId?: string;
|
|
779
787
|
};
|
|
780
788
|
projectIntentReminder?: ProjectIntentReminder;
|
|
789
|
+
projectInventory?: ProjectInventoryViewModel;
|
|
790
|
+
projectInventoryRefresh: {
|
|
791
|
+
state: 'idle' | 'checking' | 'error';
|
|
792
|
+
checkedAtMs?: number;
|
|
793
|
+
errorCode?: string;
|
|
794
|
+
};
|
|
781
795
|
projectDeclarationAbsent?: boolean;
|
|
782
796
|
projectIntentIssue?: {
|
|
783
797
|
state: 'invalid' | 'unavailable';
|
|
@@ -833,6 +847,9 @@ export declare class TuiController {
|
|
|
833
847
|
discardDrafts?: boolean;
|
|
834
848
|
}): boolean;
|
|
835
849
|
load(): Promise<void>;
|
|
850
|
+
listProjectInventoryRoots(section?: 'declared' | 'extraInstalled'): ProjectInventoryRoot[];
|
|
851
|
+
getProjectInventoryRoot(pluginId: string): ProjectInventoryRoot | undefined;
|
|
852
|
+
refreshProjectInventory(): Promise<boolean>;
|
|
836
853
|
push(route: TuiRoute, context?: TuiPageContext): void;
|
|
837
854
|
hasPortableSkills(pluginId: string): boolean;
|
|
838
855
|
preparePortableInstall(pluginId: string, navigation?: 'push' | 'replace'): Promise<PortableSkillSelectionViewModel>;
|
|
@@ -881,6 +898,7 @@ export declare class TuiController {
|
|
|
881
898
|
installFilter?: PluginInstallFilter;
|
|
882
899
|
}): PluginListItemViewModel[];
|
|
883
900
|
getPluginOverview(pluginId: string): PluginListItemViewModel | undefined;
|
|
901
|
+
getPluginDetailSubject(pluginId: string): PluginDetailSubject | undefined;
|
|
884
902
|
getPluginContentOverview(pluginId: string): PluginContentOverview | undefined;
|
|
885
903
|
getPluginContentState(pluginId: string): 'idle' | 'loading' | 'ready';
|
|
886
904
|
loadPluginContent(pluginId: string): Promise<void>;
|
|
@@ -5,11 +5,13 @@ import { flattenStatusTargets, statusTargetActivation, statusTargetExtensions, s
|
|
|
5
5
|
import { buildRebuildReceiptJson, requestedIntentAction } from '../output/command-receipt.js';
|
|
6
6
|
import { buildOperationResultModel } from '../commands/operation-planner.js';
|
|
7
7
|
import { buildOperationReviewProjection } from './operation-review-planner.js';
|
|
8
|
-
import { buildTuiViewModel, dependencyPlacementTargets,
|
|
8
|
+
import { buildTuiViewModel, dependencyPlacementTargets, } from './model.js';
|
|
9
|
+
import { buildPluginDetailSubject } from './plugin-detail.js';
|
|
9
10
|
import { safeDiagnosticCode, sanitizeDiagnosticText } from './diagnostics.js';
|
|
10
11
|
import { projectExecutionDiagnostics, projectThrownOperationDiagnostic } from './diagnostic-projection.js';
|
|
11
12
|
import { OperationHistoryStore, } from './operation-history.js';
|
|
12
13
|
import { targetHasArtifactCollision } from '../utils/target-eligibility.js';
|
|
14
|
+
import { buildProjectInventory, hasStatusInstallationEvidence, } from './project-inventory.js';
|
|
13
15
|
import { TuiRouter, } from './router.js';
|
|
14
16
|
import { normalizeTuiRoute } from './screen-registry.js';
|
|
15
17
|
import { CatalogSourcesSession } from './catalog-sources/session.js';
|
|
@@ -36,7 +38,10 @@ export function pluginWriteBatchTargets(action, pluginIds, statusTargets) {
|
|
|
36
38
|
const activation = statusTargetActivation(target);
|
|
37
39
|
const hasManagedOutput = ownership !== 'absent';
|
|
38
40
|
const hasCleanupEvidence = ownership === 'present' || ownership === 'partial'
|
|
39
|
-
|| intent.relation === 'managed'
|
|
41
|
+
|| intent.relation === 'managed'
|
|
42
|
+
|| target.reasons.some((reason) => reason.code === 'removedPluginCleanupRequired')
|
|
43
|
+
|| (target.platform === 'codex' && activation?.evidence === 'observed'
|
|
44
|
+
&& (activation.user !== undefined || activation.project !== undefined));
|
|
40
45
|
if (action === 'sync' || action === 'reinstall') {
|
|
41
46
|
intent.scopes.forEach((scope) => add(target, scope));
|
|
42
47
|
if (hasManagedOutput)
|
|
@@ -61,9 +66,9 @@ export function pluginWriteBatchTargets(action, pluginIds, statusTargets) {
|
|
|
61
66
|
else if (hasCleanupEvidence) {
|
|
62
67
|
add(target, target.scope);
|
|
63
68
|
if (target.platform === 'codex') {
|
|
64
|
-
if (activation?.user
|
|
69
|
+
if (activation?.user !== undefined)
|
|
65
70
|
add(target, 'user');
|
|
66
|
-
if (activation?.project
|
|
71
|
+
if (activation?.project !== undefined)
|
|
67
72
|
add(target, 'project');
|
|
68
73
|
}
|
|
69
74
|
}
|
|
@@ -731,6 +736,9 @@ export class TuiController {
|
|
|
731
736
|
#portableResultRecheck;
|
|
732
737
|
#completionNotice;
|
|
733
738
|
#projectIntentReminder;
|
|
739
|
+
#projectInventory;
|
|
740
|
+
#projectInventoryRefresh = { state: 'idle' };
|
|
741
|
+
#projectInventoryRefreshToken = 0;
|
|
734
742
|
#loadError;
|
|
735
743
|
#portableDraft;
|
|
736
744
|
#recoverablePortableDraft;
|
|
@@ -850,6 +858,8 @@ export class TuiController {
|
|
|
850
858
|
...(this.#projectIntentReminder
|
|
851
859
|
? { projectIntentReminder: this.#projectIntentReminder }
|
|
852
860
|
: {}),
|
|
861
|
+
...(this.#projectInventory ? { projectInventory: this.#projectInventory } : {}),
|
|
862
|
+
projectInventoryRefresh: this.#projectInventoryRefresh,
|
|
853
863
|
...(this.#status?.projectIntent?.state === 'absent' ? { projectDeclarationAbsent: true } : {}),
|
|
854
864
|
...(this.#status?.projectIntent?.state === 'invalid'
|
|
855
865
|
|| this.#status?.projectIntent?.state === 'unavailable'
|
|
@@ -1197,13 +1207,34 @@ export class TuiController {
|
|
|
1197
1207
|
portablePluginIds: this.#status.portablePluginIds,
|
|
1198
1208
|
configStoreInventory: this.#status.configStoreInventory,
|
|
1199
1209
|
});
|
|
1210
|
+
this.#projectInventory = buildProjectInventory({
|
|
1211
|
+
projectRoot: this.#status.projectRoot,
|
|
1212
|
+
projectIntent: this.#status.projectIntent,
|
|
1213
|
+
status: this.#status.payload,
|
|
1214
|
+
pluginSummaries: this.#viewModel.plugins,
|
|
1215
|
+
targetRevisions: this.#status.targetRevisions,
|
|
1216
|
+
dependencyOverviews: this.#status.dependencyOverviews,
|
|
1217
|
+
actionableTargets: this.#projectIntentReminder?.actionableTargets,
|
|
1218
|
+
});
|
|
1200
1219
|
}
|
|
1201
1220
|
#normalizeRoute(route) {
|
|
1202
|
-
|
|
1221
|
+
const state = this.#routeEntityState();
|
|
1222
|
+
if (route.name === 'pluginDetail' || route.name === 'pluginPreview'
|
|
1223
|
+
|| route.name === 'pluginDependencies' && route.view !== 'removeBlocked'
|
|
1224
|
+
|| route.name === 'pluginDependencyNode') {
|
|
1225
|
+
return normalizeTuiRoute(route, {
|
|
1226
|
+
...state,
|
|
1227
|
+
hasPlugin: (pluginId) => this.getPluginDetailSubject(pluginId) !== undefined,
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
return normalizeTuiRoute(route, state);
|
|
1203
1231
|
}
|
|
1204
1232
|
#routeEntityState() {
|
|
1205
1233
|
return {
|
|
1206
|
-
hasPlugin: (pluginId) => this.#viewModel?.plugins.some((plugin) => plugin.pluginId === pluginId)
|
|
1234
|
+
hasPlugin: (pluginId) => this.#viewModel?.plugins.some((plugin) => plugin.pluginId === pluginId)
|
|
1235
|
+
|| this.#projectInventory?.declaredRoots.some((root) => root.pluginId === pluginId)
|
|
1236
|
+
|| this.#projectInventory?.extraInstalledRoots.some((root) => root.pluginId === pluginId)
|
|
1237
|
+
|| false,
|
|
1207
1238
|
hasSource: (sourceId) => this.#viewModel?.sourceTabs.some((source) => source.id === sourceId) ?? false,
|
|
1208
1239
|
hasIssue: (issueId) => this.#viewModel?.issues.some((issue) => issue.issueId === issueId) ?? false,
|
|
1209
1240
|
hasHistoryRecord: (recordId) => this.#operationHistory.get(recordId) !== undefined,
|
|
@@ -1527,6 +1558,8 @@ export class TuiController {
|
|
|
1527
1558
|
this.#assertAcceptingActions();
|
|
1528
1559
|
this.dependencies.beginCatalogSession?.();
|
|
1529
1560
|
const generation = ++this.#generation;
|
|
1561
|
+
this.#projectInventoryRefreshToken += 1;
|
|
1562
|
+
this.#projectInventoryRefresh = { state: 'idle' };
|
|
1530
1563
|
this.#pluginContentEpoch += 1;
|
|
1531
1564
|
this.#pluginContent.clear();
|
|
1532
1565
|
this.#pluginContentInflight.clear();
|
|
@@ -1554,6 +1587,49 @@ export class TuiController {
|
|
|
1554
1587
|
this.#loadError = undefined;
|
|
1555
1588
|
this.#publish();
|
|
1556
1589
|
}
|
|
1590
|
+
listProjectInventoryRoots(section = 'declared') {
|
|
1591
|
+
return cloneFrozen(section === 'declared'
|
|
1592
|
+
? this.#projectInventory?.declaredRoots ?? []
|
|
1593
|
+
: this.#projectInventory?.extraInstalledRoots ?? []);
|
|
1594
|
+
}
|
|
1595
|
+
getProjectInventoryRoot(pluginId) {
|
|
1596
|
+
const root = [...(this.#projectInventory?.declaredRoots ?? []),
|
|
1597
|
+
...(this.#projectInventory?.extraInstalledRoots ?? [])]
|
|
1598
|
+
.find((entry) => entry.pluginId === pluginId);
|
|
1599
|
+
return root ? cloneFrozen(root) : undefined;
|
|
1600
|
+
}
|
|
1601
|
+
async refreshProjectInventory() {
|
|
1602
|
+
this.#assertAcceptingActions();
|
|
1603
|
+
if (!this.#status || this.#phase !== 'ready')
|
|
1604
|
+
return false;
|
|
1605
|
+
const token = ++this.#projectInventoryRefreshToken;
|
|
1606
|
+
const generation = this.#generation;
|
|
1607
|
+
this.#projectInventoryRefresh = { state: 'checking' };
|
|
1608
|
+
this.#publish();
|
|
1609
|
+
try {
|
|
1610
|
+
const status = await this.#trackRead(this.dependencies.loadStatus(this.#abort.signal));
|
|
1611
|
+
if (this.#disposed || generation !== this.#generation
|
|
1612
|
+
|| token !== this.#projectInventoryRefreshToken)
|
|
1613
|
+
return false;
|
|
1614
|
+
this.#applyStatus(status);
|
|
1615
|
+
this.#projectInventoryRefresh = {
|
|
1616
|
+
state: 'idle',
|
|
1617
|
+
checkedAtMs: this.#statusReadAtMs,
|
|
1618
|
+
};
|
|
1619
|
+
this.#publish();
|
|
1620
|
+
return true;
|
|
1621
|
+
}
|
|
1622
|
+
catch (error) {
|
|
1623
|
+
if (this.#disposed || generation !== this.#generation
|
|
1624
|
+
|| token !== this.#projectInventoryRefreshToken)
|
|
1625
|
+
return false;
|
|
1626
|
+
const code = issueCode(error);
|
|
1627
|
+
await this.#logErrorSafe(error, code);
|
|
1628
|
+
this.#projectInventoryRefresh = { state: 'error', errorCode: code };
|
|
1629
|
+
this.#publish();
|
|
1630
|
+
return false;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1557
1633
|
push(route, context) {
|
|
1558
1634
|
if (this.#router.snapshot.current.route.name === 'result') {
|
|
1559
1635
|
this.#invalidatePortableResultRecheck();
|
|
@@ -2433,10 +2509,39 @@ export class TuiController {
|
|
|
2433
2509
|
}
|
|
2434
2510
|
listPlugins(options) {
|
|
2435
2511
|
const query = options.query?.trim().toLocaleLowerCase('en');
|
|
2512
|
+
const actualScopes = new Map();
|
|
2513
|
+
const statusTargets = flattenStatusTargets(this.#status?.payload.targets ?? []);
|
|
2514
|
+
const targetsByPlugin = new Map();
|
|
2515
|
+
for (const target of statusTargets) {
|
|
2516
|
+
targetsByPlugin.set(target.pluginId, [...(targetsByPlugin.get(target.pluginId) ?? []), target]);
|
|
2517
|
+
const owned = target.platform === 'claude'
|
|
2518
|
+
? ['present', 'partial'].includes(statusTargetOwnershipState(target))
|
|
2519
|
+
: target.components.some((component) => component.kind === 'ownership'
|
|
2520
|
+
&& component.key !== 'native'
|
|
2521
|
+
&& !component.key.startsWith('activation-')
|
|
2522
|
+
&& !component.key.startsWith('marketplace-')
|
|
2523
|
+
&& (component.state === 'present' || component.state === 'partial'));
|
|
2524
|
+
const activation = target.platform === 'codex' ? statusTargetActivation(target) : undefined;
|
|
2525
|
+
if (!owned && !(activation?.evidence === 'observed'
|
|
2526
|
+
&& activation[target.scope] === true)
|
|
2527
|
+
&& !hasStatusInstallationEvidence(target))
|
|
2528
|
+
continue;
|
|
2529
|
+
const scopes = actualScopes.get(target.pluginId) ?? new Set();
|
|
2530
|
+
scopes.add(target.scope);
|
|
2531
|
+
actualScopes.set(target.pluginId, scopes);
|
|
2532
|
+
}
|
|
2436
2533
|
return cloneFrozen((this.#viewModel?.plugins ?? []).filter((plugin) => (!options.sourceId || plugin.sourceId === options.sourceId)
|
|
2437
2534
|
&& (options.installFilter !== 'installed'
|
|
2438
|
-
||
|
|
2439
|
-
&& (options.installFilter !== 'uninstalled'
|
|
2535
|
+
|| (actualScopes.get(plugin.pluginId)?.size ?? 0) > 0)
|
|
2536
|
+
&& (options.installFilter !== 'uninstalled'
|
|
2537
|
+
|| plugin.aggregateStatus === 'available'
|
|
2538
|
+
&& (targetsByPlugin.get(plugin.pluginId)?.length ?? 0) > 0
|
|
2539
|
+
&& targetsByPlugin.get(plugin.pluginId).every((target) => target.state === 'absent')
|
|
2540
|
+
&& (actualScopes.get(plugin.pluginId)?.size ?? 0) === 0)
|
|
2541
|
+
&& (options.installFilter !== 'project'
|
|
2542
|
+
|| actualScopes.get(plugin.pluginId)?.has('project') === true)
|
|
2543
|
+
&& (options.installFilter !== 'user'
|
|
2544
|
+
|| actualScopes.get(plugin.pluginId)?.has('user') === true)
|
|
2440
2545
|
&& (options.installFilter !== 'updateAvailable' || plugin.update?.state === 'available')
|
|
2441
2546
|
&& (options.installFilter !== 'attention'
|
|
2442
2547
|
|| plugin.aggregateStatus === 'needsAttention' || plugin.aggregateStatus === 'unavailable'
|
|
@@ -2448,6 +2553,20 @@ export class TuiController {
|
|
|
2448
2553
|
const plugin = this.#viewModel?.plugins.find((entry) => entry.pluginId === pluginId);
|
|
2449
2554
|
return plugin ? cloneFrozen(plugin) : undefined;
|
|
2450
2555
|
}
|
|
2556
|
+
getPluginDetailSubject(pluginId) {
|
|
2557
|
+
if (!this.#status || !this.#viewModel)
|
|
2558
|
+
return undefined;
|
|
2559
|
+
const subject = buildPluginDetailSubject({
|
|
2560
|
+
pluginId,
|
|
2561
|
+
status: this.#status.payload,
|
|
2562
|
+
pluginSummaries: this.#status.pluginSummaries,
|
|
2563
|
+
targetRevisions: this.#status.targetRevisions,
|
|
2564
|
+
plugins: this.#viewModel.plugins,
|
|
2565
|
+
projectInventory: this.#projectInventory,
|
|
2566
|
+
dependencyOverviews: this.#status.dependencyOverviews,
|
|
2567
|
+
});
|
|
2568
|
+
return subject ? cloneFrozen(subject) : undefined;
|
|
2569
|
+
}
|
|
2451
2570
|
getPluginContentOverview(pluginId) {
|
|
2452
2571
|
const overview = this.#viewModel?.contentOverviews[pluginId];
|
|
2453
2572
|
return overview ? cloneFrozen(overview) : undefined;
|
|
@@ -2485,6 +2604,10 @@ export class TuiController {
|
|
|
2485
2604
|
pluginVersion: '待确认',
|
|
2486
2605
|
catalogVersion: '待确认',
|
|
2487
2606
|
evidence: 'unavailable',
|
|
2607
|
+
coverage: 'unavailable',
|
|
2608
|
+
coverageIssue: {
|
|
2609
|
+
code: 'unreadable', message: '当前无法安全读取这个插件的内容。',
|
|
2610
|
+
},
|
|
2488
2611
|
items: [],
|
|
2489
2612
|
notices: ['当前无法安全读取这个插件的内容。'],
|
|
2490
2613
|
});
|
|
@@ -2511,7 +2634,20 @@ export class TuiController {
|
|
|
2511
2634
|
}))].sort((left, right) => left.localeCompare(right, 'en')));
|
|
2512
2635
|
}
|
|
2513
2636
|
listPluginWriteBatchTargets(action, pluginIds) {
|
|
2514
|
-
|
|
2637
|
+
const targets = pluginWriteBatchTargets(action, pluginIds, flattenStatusTargets(this.#status?.payload.targets ?? []));
|
|
2638
|
+
if (action === 'cleanup') {
|
|
2639
|
+
for (const plugin of this.#viewModel?.plugins ?? []) {
|
|
2640
|
+
if (!pluginIds.includes(plugin.pluginId) || !plugin.configOnly
|
|
2641
|
+
|| targets.some((target) => target.pluginId === plugin.pluginId))
|
|
2642
|
+
continue;
|
|
2643
|
+
targets.push({
|
|
2644
|
+
pluginId: plugin.pluginId,
|
|
2645
|
+
platform: 'codex',
|
|
2646
|
+
scope: plugin.savedConfigScopes[0] ?? 'user',
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
return cloneFrozen(targets);
|
|
2515
2651
|
}
|
|
2516
2652
|
listPluginInstallBatchTargets(pluginIds, platform, scope) {
|
|
2517
2653
|
const platforms = platform === 'both' ? ['codex', 'claude'] : [platform];
|
|
@@ -2529,14 +2665,14 @@ export class TuiController {
|
|
|
2529
2665
|
&& activation[scope] === true);
|
|
2530
2666
|
});
|
|
2531
2667
|
const exactOwnership = exactTarget ? statusTargetOwnershipState(exactTarget) : 'absent';
|
|
2668
|
+
if (plugin?.catalogEntryMissing) {
|
|
2669
|
+
return { ...target, state: 'blocked', reason: '来源中没有可信插件定义' };
|
|
2670
|
+
}
|
|
2532
2671
|
if (alreadyConfigured || exactOwnership === 'present' || exactOwnership === 'partial') {
|
|
2533
2672
|
return { ...target, state: 'existing' };
|
|
2534
2673
|
}
|
|
2535
2674
|
if (!plugin)
|
|
2536
2675
|
return { ...target, state: 'blocked', reason: '插件已不在当前状态中' };
|
|
2537
|
-
if (plugin.configOnly) {
|
|
2538
|
-
return { ...target, state: 'blocked', reason: '来源中没有可信插件定义' };
|
|
2539
|
-
}
|
|
2540
2676
|
if (plugin.sourceUnavailable) {
|
|
2541
2677
|
return { ...target, state: 'blocked', reason: '插件来源不可用' };
|
|
2542
2678
|
}
|
|
@@ -2617,6 +2753,11 @@ export class TuiController {
|
|
|
2617
2753
|
const plugin = this.#viewModel?.plugins.find((entry) => entry.pluginId === pluginId);
|
|
2618
2754
|
if (!plugin)
|
|
2619
2755
|
return [];
|
|
2756
|
+
if (plugin.catalogEntryMissing) {
|
|
2757
|
+
return plugin.supportedPlatforms.map((platform) => ({
|
|
2758
|
+
platform, compatible: false, disabled: '来源中没有可信插件定义',
|
|
2759
|
+
}));
|
|
2760
|
+
}
|
|
2620
2761
|
if (plugin.aggregateStatus === 'unavailable') {
|
|
2621
2762
|
return plugin.supportedPlatforms.map((platform) => ({
|
|
2622
2763
|
platform,
|
|
@@ -3277,6 +3418,20 @@ export class TuiController {
|
|
|
3277
3418
|
assertPluginWriteTaskEvidence(intent, evidence);
|
|
3278
3419
|
if (this.#router.snapshot.current.route.name === 'result')
|
|
3279
3420
|
navigation = 'replace';
|
|
3421
|
+
const configEvidence = intent.kind === 'configSave'
|
|
3422
|
+
? evidence.config ? [evidence.config] : undefined
|
|
3423
|
+
: intent.kind === 'configSaveBatch'
|
|
3424
|
+
? evidence.configBatch?.groups.map((group) => group.config)
|
|
3425
|
+
: undefined;
|
|
3426
|
+
if ((intent.kind === 'configSave' || intent.kind === 'configSaveBatch')
|
|
3427
|
+
&& (!configEvidence || configEvidence.length !== (intent.kind === 'configSave' ? 1 : intent.groups.length))) {
|
|
3428
|
+
throw new TuiOperationBlockedError('configImpactUnavailable', '设置确认缺少完整的应用影响证据。');
|
|
3429
|
+
}
|
|
3430
|
+
const configImpact = configEvidence ? {
|
|
3431
|
+
state: configEvidence.some((group) => group.impactState !== 'known') ? 'unknown' : 'known',
|
|
3432
|
+
affectedTargetCount: new Set(configEvidence.flatMap((group) => group.affectedTargets
|
|
3433
|
+
.map((target) => `${target.platform}\0${target.scope}`))).size,
|
|
3434
|
+
} : undefined;
|
|
3280
3435
|
const projection = buildOperationReviewProjection({
|
|
3281
3436
|
intent,
|
|
3282
3437
|
evidence,
|
|
@@ -3349,6 +3504,7 @@ export class TuiController {
|
|
|
3349
3504
|
? { originIssue: intent.originIssue }
|
|
3350
3505
|
: {}),
|
|
3351
3506
|
...projection,
|
|
3507
|
+
...(configImpact ? { configImpact } : {}),
|
|
3352
3508
|
subject: {
|
|
3353
3509
|
name: 'pluginId' in intent
|
|
3354
3510
|
? this.#viewModel?.plugins.find((plugin) => plugin.pluginId === intent.pluginId)?.displayName
|