@lesliechan721/aw 0.1.0-beta.32 → 0.1.0-beta.33

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.
@@ -54,6 +54,7 @@ export interface PluginInstallBatchTarget extends PluginWriteBatchTarget {
54
54
  export declare function pluginWriteBatchTargets(action: Exclude<BatchPluginWriteAction, 'install'>, pluginIds: readonly string[], statusTargets: readonly StatusScopedTarget[]): PluginWriteBatchTarget[];
55
55
  export interface PluginWriteBatchIntent {
56
56
  kind: 'pluginWriteBatch';
57
+ dependencyScopeOverrides?: DependencyScopeOverride[];
57
58
  action: BatchPluginWriteAction;
58
59
  selection: PluginWriteBatchSelection;
59
60
  platform: PlatformName | 'both';
@@ -757,6 +758,7 @@ export interface TuiControllerSnapshot {
757
758
  activeReview?: OperationReviewModel;
758
759
  reviewPreparation?: ReviewPreparationSnapshot;
759
760
  result?: OperationExecuteResult;
761
+ canResumeInstallDraft?: boolean;
760
762
  operationHistorySummaries: OperationHistorySummary[];
761
763
  portableResultSkills?: string[];
762
764
  loadError?: {
@@ -865,11 +867,12 @@ export declare class TuiController {
865
867
  beginInstallFlow(pluginId: string, rootScope: Scope): void;
866
868
  setInstallRootScope(rootScope: Scope): void;
867
869
  setInstallPlatforms(platforms: PlatformName[]): void;
870
+ setInstallRootTargets(targets: PluginWriteBatchTarget[]): void;
868
871
  prepareInstallDependencyPlacement(): Promise<boolean>;
869
872
  setDependencyScope(pluginId: string, platform: PlatformName, scope: Scope): Promise<void>;
870
873
  resetDependencyScopes(): Promise<void>;
871
874
  installPlacementIntent(): Extract<OperationIntent, {
872
- kind: 'pluginWrite';
875
+ kind: 'pluginWrite' | 'pluginWriteBatch';
873
876
  }>;
874
877
  listPlugins(options: {
875
878
  mode: 'browse' | 'installed';
@@ -825,6 +825,7 @@ export class TuiController {
825
825
  ? { reviewPreparation: this.#reviewPreparation.snapshot }
826
826
  : {}),
827
827
  ...(this.#result ? { result: this.#result } : {}),
828
+ ...(this.#recoverableInstallPlacementDraft ? { canResumeInstallDraft: true } : {}),
828
829
  operationHistorySummaries: this.#operationHistory.list(),
829
830
  ...(this.#portableResultSkills ? { portableResultSkills: this.#portableResultSkills } : {}),
830
831
  ...(this.#loadError ? { loadError: this.#loadError } : {}),
@@ -833,6 +834,8 @@ export class TuiController {
833
834
  ? { installPlacementDraft: {
834
835
  pluginId: this.#installPlacementDraft.pluginId,
835
836
  rootScope: this.#installPlacementDraft.rootScope,
837
+ ...(this.#installPlacementDraft.exactRootTargets
838
+ ? { exactRootTargets: this.#installPlacementDraft.exactRootTargets } : {}),
836
839
  platforms: this.#installPlacementDraft.platforms,
837
840
  dependencyScopeOverrides: this.#installPlacementDraft.dependencyScopeOverrides,
838
841
  state: this.#installPlacementDraft.state,
@@ -1232,6 +1235,10 @@ export class TuiController {
1232
1235
  if (intent.kind === 'pluginWriteBatch') {
1233
1236
  if (active?.kind === 'batchWrite')
1234
1237
  return;
1238
+ if (active?.kind === 'pluginInstall' && intent.action === 'install'
1239
+ && intent.selection.kind === 'targets' && this.#installPlacementDraft
1240
+ && intent.selection.targets.every((target) => target.pluginId === this.#installPlacementDraft.pluginId))
1241
+ return;
1235
1242
  this.#router.beginFlow('batchWrite', { name: 'pluginList', mode: 'installed' });
1236
1243
  return;
1237
1244
  }
@@ -1356,10 +1363,17 @@ export class TuiController {
1356
1363
  this.#cancelReviewPreparation();
1357
1364
  this.#progress = { messages: [] };
1358
1365
  this.#progressTargets = [];
1366
+ const installDraft = this.#installPlacementDraft;
1367
+ const ownsInstallDraft = installDraft && (intent.kind === 'pluginWrite'
1368
+ && intent.action === 'install' && installDraft.pluginId === intent.pluginId
1369
+ || intent.kind === 'pluginWriteBatch' && intent.action === 'install'
1370
+ && this.#router.activeFlow()?.kind === 'pluginInstall'
1371
+ && intent.selection.kind === 'targets' && installDraft.exactRootTargets
1372
+ && JSON.stringify(canonicalBatchTargets(intent.selection.targets))
1373
+ === JSON.stringify(installDraft.exactRootTargets));
1359
1374
  this.#recoverableInstallPlacementDraft = result.state === 'blocked'
1360
- && intent.kind === 'pluginWrite' && intent.action === 'install'
1361
- && this.#installPlacementDraft?.pluginId === intent.pluginId
1362
- ? structuredClone(this.#installPlacementDraft)
1375
+ && 'returnRoute' in result && result.returnRoute && ownsInstallDraft
1376
+ ? structuredClone(installDraft)
1363
1377
  : undefined;
1364
1378
  this.#installPlacementDraft = undefined;
1365
1379
  this.#recoverablePortableDraft = result.state !== 'succeeded'
@@ -2097,21 +2111,31 @@ export class TuiController {
2097
2111
  if (this.#router.snapshot.current.route.name !== 'result' || !result
2098
2112
  || !('returnRoute' in result) || !result.returnRoute)
2099
2113
  return;
2114
+ if (result.operationKind === 'pluginWriteBatch' && !this.#recoverableInstallPlacementDraft)
2115
+ return;
2100
2116
  this.#invalidatePortableResultRecheck();
2101
2117
  const returnRoute = this.#normalizeRoute(result.returnRoute);
2102
2118
  this.#router.back();
2103
- const kind = result.operationKind === 'configSave' || result.operationKind === 'configSaveBatch'
2104
- || result.operationKind === 'configReset'
2105
- ? 'configEdit'
2106
- : result.operationKind === 'portableInstall'
2107
- ? 'portableInstall'
2108
- : result.operationKind === 'sourceMutation' || result.operationKind === 'catalogGeneration'
2109
- || result.operationKind === 'catalogSourcesRecovery'
2110
- ? 'sourceEdit'
2111
- : 'pluginMaintenance';
2119
+ const kind = this.#recoverableInstallPlacementDraft
2120
+ ? 'pluginInstall'
2121
+ : result.operationKind === 'configSave' || result.operationKind === 'configSaveBatch'
2122
+ || result.operationKind === 'configReset'
2123
+ ? 'configEdit'
2124
+ : result.operationKind === 'portableInstall'
2125
+ ? 'portableInstall'
2126
+ : result.operationKind === 'sourceMutation' || result.operationKind === 'catalogGeneration'
2127
+ || result.operationKind === 'catalogSourcesRecovery'
2128
+ ? 'sourceEdit'
2129
+ : 'pluginMaintenance';
2112
2130
  this.#router.beginFlow(kind, this.#router.snapshot.current.route);
2113
- if (result.operationKind === 'pluginWrite') {
2131
+ if (this.#recoverableInstallPlacementDraft) {
2114
2132
  this.#installPlacementDraft = this.#recoverableInstallPlacementDraft;
2133
+ if (this.#installPlacementDraft.exactRootTargets) {
2134
+ this.#installPlacementDraft.state = 'selecting';
2135
+ this.#installPlacementDraft.targets = [];
2136
+ this.#installPlacementDraft.canContinue = false;
2137
+ this.#installPlacementDraft.error = undefined;
2138
+ }
2115
2139
  }
2116
2140
  if (result.operationKind === 'portableInstall') {
2117
2141
  this.#portableDraft = this.#recoverablePortableDraft;
@@ -2232,8 +2256,9 @@ export class TuiController {
2232
2256
  return;
2233
2257
  this.#cancelInstallPlacementRequest();
2234
2258
  draft.rootScope = rootScope;
2259
+ draft.exactRootTargets = undefined;
2260
+ draft.dependencyScopeOverrides = draft.dependencyScopeOverrides.filter((override) => rootScope !== 'user' || override.scope === 'user');
2235
2261
  draft.platforms = [];
2236
- draft.plan = undefined;
2237
2262
  draft.targets = [];
2238
2263
  draft.state = 'selecting';
2239
2264
  draft.canContinue = false;
@@ -2247,21 +2272,41 @@ export class TuiController {
2247
2272
  this.#cancelInstallPlacementRequest();
2248
2273
  const selected = [...new Set(platforms)].sort();
2249
2274
  draft.platforms = selected;
2275
+ draft.exactRootTargets = undefined;
2250
2276
  draft.dependencyScopeOverrides = draft.dependencyScopeOverrides.filter((override) => selected.includes(override.platform));
2251
- draft.plan = undefined;
2252
2277
  draft.targets = [];
2253
2278
  draft.state = 'selecting';
2254
2279
  draft.canContinue = selected.length > 0;
2255
2280
  draft.error = undefined;
2256
2281
  this.#publish();
2257
2282
  }
2283
+ setInstallRootTargets(targets) {
2284
+ const draft = this.#installPlacementDraft;
2285
+ if (!draft)
2286
+ return;
2287
+ const selected = canonicalBatchTargets(structuredClone(targets));
2288
+ if (selected.length === 0 || selected.some((target) => target.pluginId !== draft.pluginId)
2289
+ || new Set(selected.map((target) => target.platform)).size !== selected.length) {
2290
+ throw new TuiOperationBlockedError('installPlacementIncomplete', '请为每个所选平台确定一个根插件位置。');
2291
+ }
2292
+ this.#cancelInstallPlacementRequest();
2293
+ draft.exactRootTargets = selected;
2294
+ draft.rootScope = selected[0].scope;
2295
+ draft.platforms = selected.map((target) => target.platform);
2296
+ draft.dependencyScopeOverrides = draft.dependencyScopeOverrides.filter((override) => selected.some((target) => target.platform === override.platform
2297
+ && (target.scope === 'project' || override.scope === 'user')));
2298
+ draft.targets = [];
2299
+ draft.state = 'selecting';
2300
+ draft.canContinue = true;
2301
+ draft.error = undefined;
2302
+ this.#publish();
2303
+ }
2258
2304
  #cancelInstallPlacementRequest() {
2259
2305
  const cancelled = this.#installPlacementRequestAbort !== undefined;
2260
2306
  this.#installPlacementRequestToken += 1;
2261
2307
  this.#installPlacementRequestAbort?.abort();
2262
2308
  this.#installPlacementRequestAbort = undefined;
2263
2309
  if (cancelled && this.#installPlacementDraft?.state === 'loading') {
2264
- this.#installPlacementDraft.plan = undefined;
2265
2310
  this.#installPlacementDraft.targets = [];
2266
2311
  this.#installPlacementDraft.state = 'selecting';
2267
2312
  this.#installPlacementDraft.canContinue = false;
@@ -2273,6 +2318,16 @@ export class TuiController {
2273
2318
  if (!draft || draft.platforms.length === 0) {
2274
2319
  throw new TuiOperationBlockedError('installPlacementIncomplete', '请先明确选择目标平台。');
2275
2320
  }
2321
+ if (draft.exactRootTargets)
2322
+ return {
2323
+ kind: 'pluginWriteBatch',
2324
+ action: 'install',
2325
+ selection: { kind: 'targets', targets: structuredClone(draft.exactRootTargets) },
2326
+ platform: draft.platforms.length === 2 ? 'both' : draft.platforms[0],
2327
+ scope: draft.rootScope,
2328
+ ...(draft.dependencyScopeOverrides.length > 0
2329
+ ? { dependencyScopeOverrides: structuredClone(draft.dependencyScopeOverrides) } : {}),
2330
+ };
2276
2331
  return {
2277
2332
  kind: 'pluginWrite',
2278
2333
  action: 'install',
@@ -2307,19 +2362,22 @@ export class TuiController {
2307
2362
  throw new DOMException('Dependency placement preview was cancelled.', 'AbortError');
2308
2363
  }
2309
2364
  };
2310
- const plan = await this.#trackRead(preview(this.#installPlacementIntent()));
2311
- throwIfCancelled();
2312
- if (!plan) {
2313
- draft.state = 'ready';
2314
- draft.plan = undefined;
2315
- draft.targets = [];
2316
- draft.canContinue = true;
2317
- this.#publish();
2318
- return false;
2365
+ const placementIntent = this.#installPlacementIntent();
2366
+ const intents = placementIntent.kind === 'pluginWrite'
2367
+ ? [placementIntent]
2368
+ : (draft.exactRootTargets ?? []).map((target) => ({
2369
+ kind: 'pluginWrite', action: 'install', ...target,
2370
+ dependencyScopeOverrides: draft.dependencyScopeOverrides.filter((override) => override.platform === target.platform),
2371
+ }));
2372
+ const plans = [];
2373
+ for (const intent of intents) {
2374
+ const plan = await this.#trackRead(preview(intent));
2375
+ throwIfCancelled();
2376
+ if (plan)
2377
+ plans.push(plan);
2319
2378
  }
2320
- draft.plan = structuredClone(plan);
2321
- draft.targets = dependencyPlacementTargets(plan);
2322
- const blocker = plan.targets.find((target) => target.action === 'block');
2379
+ draft.targets = plans.flatMap(dependencyPlacementTargets);
2380
+ const blocker = plans.flatMap((plan) => plan.targets).find((target) => target.action === 'block');
2323
2381
  draft.state = blocker ? 'blocked' : 'ready';
2324
2382
  draft.canContinue = !blocker;
2325
2383
  draft.error = blocker