@lesliechan721/aw 0.1.0-beta.20 → 0.1.0-beta.21

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.
Files changed (38) hide show
  1. package/dist/src/commands/status-v6.js +44 -25
  2. package/dist/src/commands/status-v6.js.map +1 -1
  3. package/dist/src/tui/components.d.ts +1 -0
  4. package/dist/src/tui/components.js +3 -1
  5. package/dist/src/tui/components.js.map +1 -1
  6. package/dist/src/tui/console-app-v4.d.ts +1 -1
  7. package/dist/src/tui/console-app-v4.js +756 -1127
  8. package/dist/src/tui/console-app-v4.js.map +1 -1
  9. package/dist/src/tui/controller-runtime.js +65 -42
  10. package/dist/src/tui/controller-runtime.js.map +1 -1
  11. package/dist/src/tui/controller.d.ts +4 -30
  12. package/dist/src/tui/controller.js +7 -219
  13. package/dist/src/tui/controller.js.map +1 -1
  14. package/dist/src/tui/dependency-graph.d.ts +3 -3
  15. package/dist/src/tui/dependency-graph.js +15 -14
  16. package/dist/src/tui/dependency-graph.js.map +1 -1
  17. package/dist/src/tui/glossary.d.ts +1 -1
  18. package/dist/src/tui/glossary.js +1 -1
  19. package/dist/src/tui/glossary.js.map +1 -1
  20. package/dist/src/tui/model.d.ts +2 -0
  21. package/dist/src/tui/model.js +63 -30
  22. package/dist/src/tui/model.js.map +1 -1
  23. package/dist/src/tui/operation-review-planner.js +8 -195
  24. package/dist/src/tui/operation-review-planner.js.map +1 -1
  25. package/dist/src/tui/plugin-write-task.js +4 -0
  26. package/dist/src/tui/plugin-write-task.js.map +1 -1
  27. package/dist/src/tui/router.d.ts +4 -16
  28. package/dist/src/tui/router.js.map +1 -1
  29. package/dist/src/tui/screen-registry.d.ts +10 -57
  30. package/dist/src/tui/screen-registry.js +1 -15
  31. package/dist/src/tui/screen-registry.js.map +1 -1
  32. package/package.json +3 -3
  33. package/dist/src/tui/catalog-management-screens.d.ts +0 -45
  34. package/dist/src/tui/catalog-management-screens.js +0 -25
  35. package/dist/src/tui/catalog-management-screens.js.map +0 -1
  36. package/dist/src/tui/catalog-management.d.ts +0 -240
  37. package/dist/src/tui/catalog-management.js +0 -856
  38. package/dist/src/tui/catalog-management.js.map +0 -1
@@ -16,7 +16,6 @@ import { safeDiagnosticCode, sanitizeDiagnosticText, } from './diagnostics.js';
16
16
  import { extractPortableError, TuiConfigInvalidStoreError, userIssueKey, } from './controller.js';
17
17
  import { pluginWriteTaskVersionEvidence } from './plugin-write-task.js';
18
18
  import { catalogSourceFreshnessLabel, catalogSourceListPresentation, } from './catalog-sources/screens.js';
19
- import { CatalogManagementIntro, CatalogPublicationSummary, CatalogStoreSummary, CatalogWorkspaceSummary, } from './catalog-management-screens.js';
20
19
  import { operationDiagnosticLineCount, operationHistoryMeta, operationHistoryState, operationReportLineCount, OperationDiagnosticScreen, OperationReportPreviewScreen, } from './operation-diagnostic-screens.js';
21
20
  import { resolveTuiSizePolicy } from './layout.js';
22
21
  import { buildDependencyGraphProjection, } from './dependency-graph.js';
@@ -34,7 +33,6 @@ function sourceOperationBlockLabel(reason) {
34
33
  case 'configDraft': return '未保存的插件设置';
35
34
  case 'sourceDraft': return '未保存的来源修改';
36
35
  case 'batchDraft': return '未完成的批量操作选择';
37
- case 'catalogDraft': return '未完成的 Catalog 管理输入';
38
36
  case 'portableDraft': return '未完成的通用 Skills 选择';
39
37
  case 'activeReview': return '等待确认的操作';
40
38
  case 'reviewPreparation': return '正在准备确认信息的操作';
@@ -69,14 +67,7 @@ function batchPluginVersionSummary(plugin) {
69
67
  ? changes[0]
70
68
  : `${updates.length} 个位置版本不同(Enter 查看)`;
71
69
  }
72
- function pluginPlacementConclusion(placement) {
73
- if (placement.state === 'notInstalled')
74
- return { text: '未添加', status: 'muted' };
75
- if (placement.state === 'blocked')
76
- return { text: '无法添加:输出位置有冲突', status: 'error' };
77
- if (placement.state === 'scopeConflict')
78
- return { text: '使用位置冲突,需要选择一个位置', status: 'warning' };
79
- const location = placement.desiredScopes?.map(scopeLabel).join('、') || scopeLabel(placement.scope);
70
+ function scopedPluginPlacementConclusion(placement, location) {
80
71
  if (placement.blockingReason === 'artifactCollision' || placement.actualState === 'blocked') {
81
72
  return { text: `${location}暂时不可用`, status: 'error' };
82
73
  }
@@ -87,6 +78,42 @@ function pluginPlacementConclusion(placement) {
87
78
  return { text: `${location}状态未知`, status: 'warning' };
88
79
  return { text: `${location}可用`, status: 'success' };
89
80
  }
81
+ function pluginPlacementConclusions(placement) {
82
+ if (placement.state === 'notInstalled')
83
+ return [{ text: '未添加', status: 'muted' }];
84
+ if (placement.state === 'blocked')
85
+ return [{ text: '无法添加:输出位置有冲突', status: 'error' }];
86
+ if (placement.state === 'scopeConflict')
87
+ return [{ text: '使用位置冲突,需要选择一个位置', status: 'warning' }];
88
+ if (!placement.scopedPlacements?.length) {
89
+ const location = placement.desiredScopes?.map(scopeLabel).join('、') || scopeLabel(placement.scope);
90
+ return [scopedPluginPlacementConclusion(placement, location)];
91
+ }
92
+ const grouped = new Map();
93
+ for (const scoped of placement.scopedPlacements) {
94
+ const conclusion = scopedPluginPlacementConclusion({
95
+ platform: placement.platform,
96
+ state: 'installed',
97
+ scope: scoped.scope,
98
+ health: scoped.health,
99
+ revision: scoped.revision,
100
+ desiredScopes: [scoped.scope],
101
+ ...(scoped.actualState ? { actualState: scoped.actualState } : {}),
102
+ ...(scoped.recovery ? { recovery: scoped.recovery } : {}),
103
+ ...(scoped.blockingReason ? { blockingReason: scoped.blockingReason } : {}),
104
+ }, '');
105
+ const key = `${conclusion.status}\0${conclusion.text}`;
106
+ const current = grouped.get(key);
107
+ if (current)
108
+ current.scopes.push(scoped.scope);
109
+ else
110
+ grouped.set(key, { scopes: [scoped.scope], status: conclusion.status, suffix: conclusion.text });
111
+ }
112
+ return [...grouped.values()].map((entry) => ({
113
+ text: `${entry.scopes.map(scopeLabel).join('、')}${entry.suffix}`,
114
+ status: entry.status,
115
+ }));
116
+ }
90
117
  function isCharacterInputMode(route, searchMode) {
91
118
  if (routeDefinition(route).keymap !== 'menuOrTextInput')
92
119
  return false;
@@ -98,13 +125,17 @@ function isCharacterInputMode(route, searchMode) {
98
125
  || route.name === 'configObjectPropertyEditor'
99
126
  && (route.stage === 'key' || route.stage === 'custom')
100
127
  || route.name === 'sourceAdd' && route.step !== 'type' && route.step !== 'refPolicy'
101
- || route.name === 'catalogWorkspace'
102
- && (route.view === 'select' || route.view === 'create'
103
- || route.view === 'version' && route.step === 'catalogVersion')
104
- || route.name === 'catalogDev' && route.step !== undefined && route.step !== 'overview'
105
- || route.name === 'catalogPublish' && route.step !== 'overview'
106
128
  || route.name === 'scriptTimeout';
107
129
  }
130
+ function supportsScriptTimeout(intent) {
131
+ return intent?.kind === 'pluginWrite'
132
+ && (intent.action === 'install' || intent.action === 'sync'
133
+ || intent.action === 'refreshAndSync' || intent.action === 'reinstall')
134
+ || intent?.kind === 'pluginWriteBatch'
135
+ && (intent.action === 'install' || intent.action === 'sync' || intent.action === 'reinstall')
136
+ || intent?.kind === 'pluginWriteTask'
137
+ || intent?.kind === 'configSave' && intent.apply;
138
+ }
108
139
  function helpRowsForRoute(route, actionCount, supportsTechnicalDetails, busy, sessionNavigation) {
109
140
  const rows = [];
110
141
  if (!busy && actionCount > 1)
@@ -354,6 +385,17 @@ function wrapConsoleText(value, columns) {
354
385
  lines.push(line);
355
386
  return lines;
356
387
  }
388
+ function changeDetailLines(changes, columns) {
389
+ const valueLines = (label, value) => [
390
+ label,
391
+ ...wrapConsoleText(value ?? '未设置', Math.max(1, columns - 4)).map((line) => ` ${line}`),
392
+ ];
393
+ return changes.flatMap((change) => [
394
+ `修改项 · ${change.title}`,
395
+ ...valueLines('修改前', change.before),
396
+ ...valueLines('修改后', change.after),
397
+ ]);
398
+ }
357
399
  function operationRiskWarnings(review) {
358
400
  return [...new Set([
359
401
  ...(review.sharedImpact.warning ? [review.sharedImpact.warning] : []),
@@ -884,7 +926,7 @@ function dependencyReferenceUsageLabel(reference, consumerName) {
884
926
  const location = reference.consumer.scope === 'user'
885
927
  ? '所有项目'
886
928
  : reference.consumer.project === 'current' ? '当前项目' : '其他项目';
887
- return `${consumerName}在${location}的${platformLabel(reference.consumer.platform)}中使用它`;
929
+ return `${consumerName} · ${location} · ${platformLabel(reference.consumer.platform)}`;
888
930
  }
889
931
  function dependencySummaryText(summary) {
890
932
  return `${summary.directCount} 个直接 · ${summary.totalCount} 个总计`;
@@ -1002,23 +1044,9 @@ export function ConsoleAppV4(props) {
1002
1044
  const [expandedDependencyPluginIds, setExpandedDependencyPluginIds] = useState();
1003
1045
  const [sourceInput, setSourceInput] = useState('');
1004
1046
  const [sourceInputError, setSourceInputError] = useState();
1005
- const [catalogInput, setCatalogInput] = useState('');
1006
- const [catalogInputError, setCatalogInputError] = useState();
1007
- const [catalogWorkspace, setCatalogWorkspace] = useState();
1008
- const [catalogValidation, setCatalogValidation] = useState();
1009
- const [catalogDev, setCatalogDev] = useState();
1010
- const [catalogStore, setCatalogStore] = useState();
1011
- const [catalogPublication, setCatalogPublication] = useState();
1012
- const [catalogLoading, setCatalogLoading] = useState(false);
1013
- const [catalogWorkspaceDraft, setCatalogWorkspaceDraft] = useState({
1014
- ownerName: '', ownerUrl: '', displayName: '', catalogVersion: '0.1.0',
1015
- });
1016
- const [catalogPublishDraft, setCatalogPublishDraft] = useState({
1017
- targetKind: 'remote', target: '', branch: 'catalog',
1018
- });
1019
- const [catalogDevSourceId, setCatalogDevSourceId] = useState('');
1020
1047
  const [pendingReviewIntent, setPendingReviewIntent] = useState();
1021
1048
  const pendingReviewIntentRef = useRef(undefined);
1049
+ const pendingActionFocus = useRef(undefined);
1022
1050
  const [scriptTimeoutInput, setScriptTimeoutInput] = useState(String(SCRIPT_TIMEOUT_DEFAULT_MS));
1023
1051
  const [scriptTimeoutError, setScriptTimeoutError] = useState();
1024
1052
  const [sourceReferenceSummary, setSourceReferenceSummary] = useState();
@@ -1033,10 +1061,9 @@ export function ConsoleAppV4(props) {
1033
1061
  const [pendingLayerFieldKey, setPendingLayerFieldKey] = useState();
1034
1062
  const dynamicMenuFocus = useRef(undefined);
1035
1063
  const dependencyGraphContexts = useRef(new Map());
1036
- const externalDraftRevision = useRef({ config: 0, source: 0, batch: 0, catalog: 0 });
1064
+ const externalDraftRevision = useRef({ config: 0, source: 0, batch: 0 });
1037
1065
  const previousExternalDraftValues = useRef({
1038
1066
  draftUpdates, draftRemoves, objectDrafts, changedObjectDraftKeys, sourceDraft, batchDraft,
1039
- catalogInput, catalogWorkspaceDraft, catalogPublishDraft, catalogDevSourceId,
1040
1067
  });
1041
1068
  const externalDraftFlowIds = useRef(new Map());
1042
1069
  const exitSent = useRef(false);
@@ -1152,23 +1179,6 @@ export function ConsoleAppV4(props) {
1152
1179
  setBatchDraft(undefined);
1153
1180
  setDirty(false);
1154
1181
  }, [batchDraft?.flowId, route.name, snapshot.result]);
1155
- useEffect(() => {
1156
- if (route.name !== 'result'
1157
- || snapshot.result?.state !== 'succeeded'
1158
- || snapshot.result.operationKind !== 'catalogManagement')
1159
- return;
1160
- const action = snapshot.result.summary.catalogManagement?.action;
1161
- if (action === 'workspaceInit') {
1162
- setCatalogInput('');
1163
- setCatalogWorkspaceDraft({
1164
- ownerName: '', ownerUrl: '', displayName: '', catalogVersion: '0.1.0',
1165
- });
1166
- }
1167
- if (action === 'publishApply') {
1168
- setCatalogInput('');
1169
- setCatalogPublishDraft({ targetKind: 'remote', target: '', branch: 'catalog' });
1170
- }
1171
- }, [route.name, snapshot.result]);
1172
1182
  useEffect(() => {
1173
1183
  if (!batchDraft || (route.name !== 'batchSelection' && route.name !== 'batchPlacement'))
1174
1184
  return;
@@ -1178,74 +1188,6 @@ export function ConsoleAppV4(props) {
1178
1188
  if (route.name !== 'sourceAdd')
1179
1189
  setSourceInput('');
1180
1190
  }, [route.name]);
1181
- useEffect(() => {
1182
- if (route.name !== 'catalogWorkspace' || route.view !== 'overview')
1183
- return;
1184
- let current = true;
1185
- setCatalogLoading(true);
1186
- setCatalogInputError(undefined);
1187
- void props.controller.getCatalogWorkspaceManagement()
1188
- .then((value) => { if (current)
1189
- setCatalogWorkspace(value); })
1190
- .catch((error) => {
1191
- if (current)
1192
- setCatalogInputError(sanitizeDiagnosticText(error instanceof Error ? error.message : String(error), [], [catalogInput]));
1193
- })
1194
- .finally(() => { if (current)
1195
- setCatalogLoading(false); });
1196
- return () => { current = false; };
1197
- }, [props.controller, route.name, route.name === 'catalogWorkspace' ? route.view : '']);
1198
- useEffect(() => {
1199
- if (route.name !== 'catalogDev' || route.step && route.step !== 'overview')
1200
- return;
1201
- let current = true;
1202
- setCatalogLoading(true);
1203
- setCatalogInputError(undefined);
1204
- void props.controller.getCatalogDevManagement()
1205
- .then((value) => { if (current)
1206
- setCatalogDev(value); })
1207
- .catch((error) => {
1208
- if (current)
1209
- setCatalogInputError(sanitizeDiagnosticText(error instanceof Error ? error.message : String(error), [], [catalogInput]));
1210
- })
1211
- .finally(() => { if (current)
1212
- setCatalogLoading(false); });
1213
- return () => { current = false; };
1214
- }, [props.controller, route.name, route.name === 'catalogDev' ? route.step : '']);
1215
- useEffect(() => {
1216
- if (route.name !== 'catalogStore')
1217
- return;
1218
- let current = true;
1219
- setCatalogLoading(true);
1220
- setCatalogInputError(undefined);
1221
- void props.controller.getCatalogStoreManagement()
1222
- .then((value) => { if (current)
1223
- setCatalogStore(value); })
1224
- .catch((error) => {
1225
- if (current)
1226
- setCatalogInputError(sanitizeDiagnosticText(error instanceof Error ? error.message : String(error), [], []));
1227
- })
1228
- .finally(() => { if (current)
1229
- setCatalogLoading(false); });
1230
- return () => { current = false; };
1231
- }, [props.controller, route.name]);
1232
- useEffect(() => {
1233
- if (route.name !== 'catalogPublish' || route.step !== 'overview')
1234
- return;
1235
- let current = true;
1236
- setCatalogLoading(true);
1237
- setCatalogInputError(undefined);
1238
- void props.controller.getCatalogPublicationManagement()
1239
- .then((value) => { if (current)
1240
- setCatalogPublication(value); })
1241
- .catch((error) => {
1242
- if (current)
1243
- setCatalogInputError(sanitizeDiagnosticText(error instanceof Error ? error.message : String(error), [], [catalogPublishDraft.target]));
1244
- })
1245
- .finally(() => { if (current)
1246
- setCatalogLoading(false); });
1247
- return () => { current = false; };
1248
- }, [props.controller, route.name, route.name === 'catalogPublish' ? route.step : '']);
1249
1191
  useEffect(() => {
1250
1192
  if (route.name === 'operationReportPreview')
1251
1193
  return;
@@ -1291,14 +1233,8 @@ export function ConsoleAppV4(props) {
1291
1233
  externalDraftRevision.current.source += 1;
1292
1234
  if (previous.batchDraft !== batchDraft)
1293
1235
  externalDraftRevision.current.batch += 1;
1294
- if (previous.catalogInput !== catalogInput
1295
- || previous.catalogWorkspaceDraft !== catalogWorkspaceDraft
1296
- || previous.catalogPublishDraft !== catalogPublishDraft
1297
- || previous.catalogDevSourceId !== catalogDevSourceId)
1298
- externalDraftRevision.current.catalog += 1;
1299
1236
  previousExternalDraftValues.current = {
1300
1237
  draftUpdates, draftRemoves, objectDrafts, changedObjectDraftKeys, sourceDraft, batchDraft,
1301
- catalogInput, catalogWorkspaceDraft, catalogPublishDraft, catalogDevSourceId,
1302
1238
  };
1303
1239
  const currentFlowId = snapshot.router.currentFlowId;
1304
1240
  if (currentFlowId && configRouteOwner) {
@@ -1327,26 +1263,10 @@ export function ConsoleAppV4(props) {
1327
1263
  flowId: batchDraft.flowId,
1328
1264
  });
1329
1265
  }
1330
- const catalogWorkspaceDirty = catalogWorkspaceDraft.ownerName !== ''
1331
- || catalogWorkspaceDraft.ownerUrl !== '' || catalogWorkspaceDraft.displayName !== '';
1332
- const catalogPublishDirty = catalogPublishDraft.target !== '';
1333
- const catalogDraftActive = route.name === 'catalogWorkspace'
1334
- && (route.view === 'create' || route.view === 'version' && route.step === 'catalogVersion')
1335
- || route.name === 'catalogPublish' && route.step !== 'overview'
1336
- || route.name === 'catalogDev' && route.step !== undefined && route.step !== 'overview'
1337
- || route.name === 'catalogWorkspace' && route.view === 'overview' && catalogWorkspaceDirty
1338
- || route.name === 'catalogPublish' && route.step === 'overview' && catalogPublishDirty;
1339
- if (catalogDraftActive)
1340
- drafts.push({
1341
- kind: 'catalogDraft', owner: 'catalog-management', revision: externalDraftRevision.current.catalog,
1342
- });
1343
1266
  props.controller.setExternalDraftState(drafts);
1344
1267
  }, [
1345
1268
  props.controller, batchDraft, changedObjectDraftKeys, configRouteOwner, dirty, draftOwner,
1346
- draftRemoves, draftUpdates, objectDrafts, snapshot.router.currentFlowId, sourceDraft,
1347
- catalogInput, catalogWorkspaceDraft, catalogPublishDraft, catalogDevSourceId, route.name,
1348
- route.name === 'catalogWorkspace' ? `${route.view}:${route.step ?? ''}` : '',
1349
- route.name === 'catalogPublish' || route.name === 'catalogDev' ? route.step : '',
1269
+ draftRemoves, draftUpdates, objectDrafts, route.name, snapshot.router.currentFlowId, sourceDraft,
1350
1270
  ]);
1351
1271
  useEffect(() => () => props.controller.setExternalDraftState(), [props.controller]);
1352
1272
  const currentConfigPage = configPageMatches(configPage, configRoute) ? configPage : undefined;
@@ -1521,7 +1441,7 @@ export function ConsoleAppV4(props) {
1521
1441
  useEffect(() => {
1522
1442
  let count;
1523
1443
  if (route.name === 'sourceList')
1524
- count = props.controller.listSources().length + 3;
1444
+ count = props.controller.listSources().length + 2;
1525
1445
  else if (route.name === 'issueList') {
1526
1446
  const issueCount = props.controller.listUserIssues().length;
1527
1447
  count = issueCount || 2;
@@ -1823,6 +1743,7 @@ export function ConsoleAppV4(props) {
1823
1743
  let content;
1824
1744
  let actions = [];
1825
1745
  let referenceDetailPagination;
1746
+ let placementConclusionPagination;
1826
1747
  let pluginRows = [];
1827
1748
  let visibleConfigTabs = [];
1828
1749
  let activeConfigTabId;
@@ -2012,16 +1933,8 @@ export function ConsoleAppV4(props) {
2012
1933
  setActionError(undefined);
2013
1934
  };
2014
1935
  const beginReview = (intent, returnRoute) => {
2015
- const supportsScriptTimeout = intent.kind === 'pluginWrite'
2016
- && (intent.action === 'install' || intent.action === 'sync'
2017
- || intent.action === 'refreshAndSync' || intent.action === 'reinstall')
2018
- || intent.kind === 'pluginWriteBatch'
2019
- && (intent.action === 'install' || intent.action === 'sync' || intent.action === 'reinstall')
2020
- || intent.kind === 'pluginWriteTask'
2021
- || intent.kind === 'configSave' && intent.apply;
2022
- const pendingIntent = supportsScriptTimeout ? intent : undefined;
2023
- pendingReviewIntentRef.current = pendingIntent;
2024
- setPendingReviewIntent(pendingIntent);
1936
+ pendingReviewIntentRef.current = intent;
1937
+ setPendingReviewIntent(intent);
2025
1938
  const underlyingResultRoute = returnRoute ?? (route.name === 'result' && snapshot.result && 'returnRoute' in snapshot.result
2026
1939
  ? snapshot.result.returnRoute
2027
1940
  : undefined);
@@ -2358,7 +2271,7 @@ export function ConsoleAppV4(props) {
2358
2271
  const beginRestrictedForceCleanup = async (pluginId, platform, selectedScope) => {
2359
2272
  const candidate = await props.controller.getForceCleanupCandidate(pluginId, platform, selectedScope);
2360
2273
  if (!candidate) {
2361
- setActionError('当前没有可安全确认的受限清理目标。共享、外来、符号链接和原生内容会保持不变。');
2274
+ setActionError('当前没有可安全确认的受限清理目标。不属于插件、被共用、符号链接和原生内容会保持不变。');
2362
2275
  return;
2363
2276
  }
2364
2277
  try {
@@ -3250,7 +3163,7 @@ export function ConsoleAppV4(props) {
3250
3163
  description = batchDraft?.stage === 'select'
3251
3164
  ? 'Space 切换选择,Enter 查看插件。选择会跨来源、搜索和筛选保留。'
3252
3165
  : batchDraft?.stage === 'task'
3253
- ? '更新和恢复使用现有精确位置;移除会明确使用已有位置。'
3166
+ ? '更新和恢复沿用已经添加的位置;移除会逐项显示已有位置。'
3254
3167
  : '同步、重新安装和普通清理使用所选插件的已有位置。';
3255
3168
  if (!batchDraft) {
3256
3169
  actions = [{ label: '返回插件列表', run: back }];
@@ -3312,9 +3225,10 @@ export function ConsoleAppV4(props) {
3312
3225
  }
3313
3226
  };
3314
3227
  const continueAction = {
3228
+ actionId: 'batch-selection-continue',
3315
3229
  label: `查看确认(${batchDraft.selectedPluginIds.length})`,
3316
3230
  description: batchDraft.selectedPluginIds.length > 0
3317
- ? batchDraft.recommendedGoal ? '重新读取更新证据并建立 Review' : '继续选择任务和确认范围'
3231
+ ? batchDraft.recommendedGoal ? '重新读取更新信息并显示操作汇总' : '继续选择任务和确认范围'
3318
3232
  : '先选择至少一个插件',
3319
3233
  disabled: batchDraft.selectedPluginIds.length === 0 ? '先选择至少一个插件' : undefined,
3320
3234
  run: continueSelection,
@@ -3434,7 +3348,7 @@ export function ConsoleAppV4(props) {
3434
3348
  actions = [
3435
3349
  { label: '同步已保存使用设置…', description: `重新应用 ${syncTargets.length} 个已保存或现场目标`, run: () => startExistingBatch('sync') },
3436
3350
  { label: '重新安装…', description: `重新生成 ${props.controller.listPluginWriteBatchTargets('reinstall', selectedIds).length} 个已保存或现场目标`, run: () => startExistingBatch('reinstall') },
3437
- { label: '清理遗留内容…', description: `${props.controller.listPluginWriteBatchTargets('cleanup', selectedIds).length} 个有受管证据的位置;保留 foreign 和 shared 内容`, run: () => startExistingBatch('cleanup') },
3351
+ { label: '清理遗留内容…', description: `${props.controller.listPluginWriteBatchTargets('cleanup', selectedIds).length} 个已核验位置;保留不属于插件或被共用的内容`, run: () => startExistingBatch('cleanup') },
3438
3352
  {
3439
3353
  label: '返回任务选择',
3440
3354
  run: () => moveBatchStage('task'),
@@ -3449,13 +3363,13 @@ export function ConsoleAppV4(props) {
3449
3363
  actions = [
3450
3364
  ...(updates.length > 0 ? [{
3451
3365
  label: `更新所选中的 ${updateRoots} 个可更新插件…`,
3452
- description: '使用已验证版本和现有精确位置',
3366
+ description: '使用已验证版本和已经添加的位置',
3453
3367
  status: 'warning',
3454
3368
  run: () => openSelectedPluginTask('update', selectedIds),
3455
3369
  }] : []),
3456
3370
  ...(restores.length > 0 ? [{
3457
3371
  label: `恢复所选中的 ${restoreRoots} 个插件…`,
3458
- description: '按当前问题和现有精确位置准备方案',
3372
+ description: '按当前问题检查已经添加的位置',
3459
3373
  status: 'warning',
3460
3374
  run: () => openSelectedPluginTask('restore', selectedIds),
3461
3375
  }] : []),
@@ -3490,8 +3404,10 @@ export function ConsoleAppV4(props) {
3490
3404
  : `设置批量${batchDraft?.action ? batchActionLabel(batchDraft.action) : ''}位置`;
3491
3405
  description = maintenanceMode
3492
3406
  ? '默认沿用进入此页时的现有位置。可以取消位置,也可以恢复本次集合中的位置。'
3493
- : '分别选择使用范围和工具。确认页会重新读取状态并冻结实际计划。';
3407
+ : '分别选择使用范围和工具。操作汇总会重新读取状态;本次安装位置变化时需要重新确认。';
3494
3408
  let installPlacementTargets = [];
3409
+ let installPlacementGroups = [];
3410
+ let installPlacementActions = [];
3495
3411
  let maintenanceTargetCount = 0;
3496
3412
  if (!batchDraft?.action && !batchDraft?.maintenanceGoal) {
3497
3413
  actions = [{ label: '返回批量选择', run: back }];
@@ -3558,6 +3474,92 @@ export function ConsoleAppV4(props) {
3558
3474
  const addTargets = installPlacementTargets.filter((target) => target.state === 'add');
3559
3475
  const blockedTargets = installPlacementTargets.filter((target) => target.state === 'blocked');
3560
3476
  const existingTargets = installPlacementTargets.filter((target) => target.state === 'existing');
3477
+ installPlacementGroups = [
3478
+ {
3479
+ kind: 'action',
3480
+ actions: [
3481
+ ...(installPlacementTargets.length > 0 ? [{
3482
+ actionId: 'batch-placement-details',
3483
+ label: '查看全部位置和受阻原因…',
3484
+ description: `${addTargets.length} 个可添加 · ${existingTargets.length} 个已有 · ${blockedTargets.length} 个受阻`,
3485
+ run: () => {
3486
+ setBatchDraft((current) => current ? { ...current, showPlacementTargets: true } : current);
3487
+ setFocus(0);
3488
+ setScrollOffset(0);
3489
+ },
3490
+ }] : []),
3491
+ {
3492
+ actionId: 'batch-placement-confirm',
3493
+ label: batchDraft.action === 'install' && blockedTargets.length > 0
3494
+ ? `仅添加可执行的 ${addTargets.length} 个位置`
3495
+ : `查看批量${batchActionLabel(batchDraft.action)}确认`,
3496
+ description: batchDraft.action === 'install'
3497
+ ? `${addTargets.length} 个可添加 · ${existingTargets.length} 个已有 · ${blockedTargets.length} 个受阻`
3498
+ : `${batchDraft.selection === 'selected' ? `${batchDraft.selectedPluginIds.length} 个所选插件` : '当前项目全部保存目标'} · ${scopeLabel(batchDraft.scope)}`,
3499
+ disabled: batchDraft.selection === 'selected' && batchDraft.selectedPluginIds.length === 0
3500
+ ? '请至少选择一个插件'
3501
+ : batchDraft.action === 'install' && addTargets.length === 0
3502
+ ? '所选工具和位置没有可添加目标'
3503
+ : undefined,
3504
+ run: () => {
3505
+ if (invalidBatchSelection(batchDraft).length > 0) {
3506
+ setActionError('已选插件状态已变化。请返回选择页检查并取消失效项。');
3507
+ return;
3508
+ }
3509
+ const intent = {
3510
+ kind: 'pluginWriteBatch',
3511
+ action: batchDraft.action,
3512
+ selection: batchDraft.action === 'install'
3513
+ ? { kind: 'targets', targets: addTargets.map(({ pluginId, platform, scope }) => ({
3514
+ pluginId, platform, scope,
3515
+ })) }
3516
+ : batchDraft.selection === 'selected'
3517
+ ? {
3518
+ kind: 'selected',
3519
+ pluginIds: [...new Set(batchDraft.selectedPluginIds)]
3520
+ .sort((left, right) => left.localeCompare(right, 'en')),
3521
+ }
3522
+ : { kind: 'currentProjectIntentRoots' },
3523
+ platform: addTargets[0]?.platform ?? batchDraft.platform,
3524
+ scope: addTargets[0]?.scope ?? batchDraft.scope,
3525
+ };
3526
+ beginReview(intent);
3527
+ setDirty(false);
3528
+ setFocus(0);
3529
+ setScrollOffset(0);
3530
+ },
3531
+ },
3532
+ ],
3533
+ },
3534
+ {
3535
+ title: '在哪里使用',
3536
+ kind: 'choice',
3537
+ actions: [
3538
+ {
3539
+ actionId: 'batch-placement-scope-project',
3540
+ label: '当前项目', selected: batchDraft.scope === 'project',
3541
+ run: () => setBatchDraft((current) => current ? { ...current, scope: 'project' } : current),
3542
+ },
3543
+ {
3544
+ actionId: 'batch-placement-scope-user',
3545
+ label: '所有项目', selected: batchDraft.scope === 'user',
3546
+ disabled: projectIntent ? '项目全部同步固定使用当前项目' : undefined,
3547
+ run: () => setBatchDraft((current) => current ? { ...current, scope: 'user' } : current),
3548
+ },
3549
+ ],
3550
+ },
3551
+ {
3552
+ title: '用于哪个工具',
3553
+ kind: 'choice',
3554
+ actions: ['codex', 'claude', 'both'].map((platform) => ({
3555
+ actionId: `batch-placement-platform-${platform}`,
3556
+ label: platform === 'both' ? 'Codex 和 Claude Code' : platformLabel(platform),
3557
+ selected: batchDraft.platform === platform,
3558
+ run: () => setBatchDraft((current) => current ? { ...current, platform } : current),
3559
+ })),
3560
+ },
3561
+ ];
3562
+ installPlacementActions = installPlacementGroups.flatMap((group) => group.actions);
3561
3563
  if (batchDraft.showPlacementTargets) {
3562
3564
  actions = [
3563
3565
  ...installPlacementTargets.map((target) => ({
@@ -3571,78 +3573,13 @@ export function ConsoleAppV4(props) {
3571
3573
  label: '返回位置选择',
3572
3574
  run: () => {
3573
3575
  setBatchDraft((current) => current ? { ...current, showPlacementTargets: false } : current);
3574
- setFocus(5);
3575
- setScrollOffset(0);
3576
+ restoreActionFocus('batch-placement-details');
3576
3577
  },
3577
3578
  },
3578
3579
  ];
3579
3580
  }
3580
3581
  else
3581
- actions = [
3582
- {
3583
- label: '当前项目', selected: batchDraft.scope === 'project',
3584
- run: () => setBatchDraft((current) => current ? { ...current, scope: 'project' } : current),
3585
- },
3586
- {
3587
- label: '所有项目', selected: batchDraft.scope === 'user',
3588
- disabled: projectIntent ? '项目全部同步固定使用当前项目' : undefined,
3589
- run: () => setBatchDraft((current) => current ? { ...current, scope: 'user' } : current),
3590
- },
3591
- ...['codex', 'claude', 'both'].map((platform) => ({
3592
- label: platform === 'both' ? 'Codex 和 Claude Code' : platformLabel(platform),
3593
- selected: batchDraft.platform === platform,
3594
- run: () => setBatchDraft((current) => current ? { ...current, platform } : current),
3595
- })),
3596
- ...(installPlacementTargets.length > 0 ? [{
3597
- label: '查看全部位置和受阻原因…',
3598
- description: `${addTargets.length} 个可添加 · ${existingTargets.length} 个已有 · ${blockedTargets.length} 个受阻`,
3599
- run: () => {
3600
- setBatchDraft((current) => current ? { ...current, showPlacementTargets: true } : current);
3601
- setFocus(0);
3602
- setScrollOffset(0);
3603
- },
3604
- }] : []),
3605
- {
3606
- label: batchDraft.action === 'install' && blockedTargets.length > 0
3607
- ? `仅添加可执行的 ${addTargets.length} 个位置`
3608
- : `查看批量${batchActionLabel(batchDraft.action)}确认`,
3609
- description: batchDraft.action === 'install'
3610
- ? `${addTargets.length} 个可添加 · ${existingTargets.length} 个已有 · ${blockedTargets.length} 个受阻`
3611
- : `${batchDraft.selection === 'selected' ? `${batchDraft.selectedPluginIds.length} 个所选插件` : '当前项目全部保存目标'} · ${scopeLabel(batchDraft.scope)}`,
3612
- disabled: batchDraft.selection === 'selected' && batchDraft.selectedPluginIds.length === 0
3613
- ? '请至少选择一个插件'
3614
- : batchDraft.action === 'install' && addTargets.length === 0
3615
- ? '所选工具和位置没有可添加目标'
3616
- : undefined,
3617
- run: () => {
3618
- if (invalidBatchSelection(batchDraft).length > 0) {
3619
- setActionError('已选插件状态已变化。请返回选择页检查并取消失效项。');
3620
- return;
3621
- }
3622
- const intent = {
3623
- kind: 'pluginWriteBatch',
3624
- action: batchDraft.action,
3625
- selection: batchDraft.action === 'install'
3626
- ? { kind: 'targets', targets: addTargets.map(({ pluginId, platform, scope }) => ({
3627
- pluginId, platform, scope,
3628
- })) }
3629
- : batchDraft.selection === 'selected'
3630
- ? {
3631
- kind: 'selected',
3632
- pluginIds: [...new Set(batchDraft.selectedPluginIds)]
3633
- .sort((left, right) => left.localeCompare(right, 'en')),
3634
- }
3635
- : { kind: 'currentProjectIntentRoots' },
3636
- platform: addTargets[0]?.platform ?? batchDraft.platform,
3637
- scope: addTargets[0]?.scope ?? batchDraft.scope,
3638
- };
3639
- beginReview(intent);
3640
- setDirty(false);
3641
- setFocus(0);
3642
- setScrollOffset(0);
3643
- },
3644
- },
3645
- ];
3582
+ actions = installPlacementActions;
3646
3583
  }
3647
3584
  context = batchDraft?.selection === 'selected'
3648
3585
  ? maintenanceMode
@@ -3662,7 +3599,14 @@ export function ConsoleAppV4(props) {
3662
3599
  content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "\u5904\u7406\u8303\u56F4", meta: `${maintenanceSelection.size} 个位置`, compact: true, children: targetLimit > 0 ? _jsx(SemanticRows, { actions: actions.slice(0, maintenanceTargetCount), focus: focus, kind: "toggle", compact: true, offset: targetOffset, limit: targetLimit }) : null }), actionLimit > 0 ? _jsx(SemanticRows, { actions: actions.slice(maintenanceTargetCount), focus: focus - maintenanceTargetCount, kind: "action", compact: policy.mode === 'compact', offset: actionOffset, limit: actionLimit }) : null] });
3663
3600
  }
3664
3601
  else if (!placementDetail && batchDraft?.action === 'install') {
3665
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions.slice(5), focus: focus - 5, kind: "action", compact: policy.mode === 'compact' }), _jsx(Text, { color: tuiTheme.colors.muted, children: "\u5728\u54EA\u91CC\u4F7F\u7528" }), _jsx(SemanticRows, { actions: actions.slice(0, 2), focus: focus, kind: "choice", compact: true }), _jsx(Text, { color: tuiTheme.colors.muted, children: "\u7528\u4E8E\u54EA\u4E2A\u5DE5\u5177" }), _jsx(SemanticRows, { actions: actions.slice(2, 5), focus: focus - 2, kind: "choice", compact: true })] });
3602
+ content = _jsx(Box, { flexDirection: "column", children: installPlacementGroups.map((group) => {
3603
+ const groupOffset = installPlacementActions.findIndex((action) => action.actionId === group.actions[0]?.actionId);
3604
+ const localOffset = Math.max(0, viewport.offset - groupOffset);
3605
+ const localLimit = Math.max(0, Math.min(group.actions.length - localOffset, viewport.offset + viewport.limit - groupOffset - localOffset));
3606
+ if (localLimit === 0)
3607
+ return null;
3608
+ return _jsxs(Box, { flexDirection: "column", children: [group.title ? _jsx(Text, { color: tuiTheme.colors.muted, children: group.title }) : null, _jsx(SemanticRows, { actions: group.actions, focus: focus - groupOffset, kind: group.kind, compact: group.kind === 'choice' || policy.mode === 'compact', offset: localOffset, limit: localLimit })] }, group.title ?? 'actions');
3609
+ }) });
3666
3610
  }
3667
3611
  else
3668
3612
  content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: placementDetail ? 'action' : 'choice', compact: placementDetail ? false : policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit });
@@ -3935,11 +3879,11 @@ export function ConsoleAppV4(props) {
3935
3879
  ...(expandedDependencyPluginIds ? { expandedPluginIds: expandedDependencyPluginIds } : {}),
3936
3880
  });
3937
3881
  const visibleRows = projection.rows;
3938
- context = direction === 'dependencies' ? '它需要的' : '谁在使用它';
3939
- title = hasInstalledPlacement(plugin) ? '依赖与被使用情况' : '安装所需插件';
3882
+ context = direction === 'dependencies' ? '它需要的' : '哪些插件依赖它';
3883
+ title = hasInstalledPlacement(plugin) ? '依赖与当前可用关系' : '安装所需插件';
3940
3884
  description = direction === 'dependencies'
3941
3885
  ? '每一层表示上面的插件需要下面的插件。'
3942
- : '每一层表示下面的插件正在使用上面的插件;只显示已确认的引用。';
3886
+ : '每一层表示下面的插件在本次检查中需要上面的插件。';
3943
3887
  const rowActions = visibleRows.map((row) => {
3944
3888
  const state = row.depth === 0
3945
3889
  ? { value: statusText(plugin), status: plugin.aggregateStatus === 'needsAttention'
@@ -3953,7 +3897,7 @@ export function ConsoleAppV4(props) {
3953
3897
  ? `${row.label}(当前插件)`
3954
3898
  : `${compactBranch}${row.label}${row.sharedWithRowId ? '(共用,见上方)' : ''}`,
3955
3899
  description: row.hiddenDescendantCount > 0
3956
- ? `另有 ${row.hiddenDescendantCount} 个${direction === 'dependencies' ? '所需插件' : '实际使用者'}`
3900
+ ? `另有 ${row.hiddenDescendantCount} 个${direction === 'dependencies' ? '所需插件' : '当前可用依赖者'}`
3957
3901
  : row.depth === 0 ? '当前插件' : undefined,
3958
3902
  meta: state.value,
3959
3903
  status: state.status,
@@ -3974,7 +3918,7 @@ export function ConsoleAppV4(props) {
3974
3918
  const declared = overview?.dependents.find((entry) => entry.pluginId === pluginId);
3975
3919
  return {
3976
3920
  label: declared?.displayName ?? pluginId,
3977
- description: '仅有依赖声明,尚未确认实际使用',
3921
+ description: '有依赖声明,但本次尚未确认依赖可用',
3978
3922
  meta: declared?.aggregateStatus === 'notInstalled' ? '仅声明 · 未安装' : '仅声明 · 未验证',
3979
3923
  status: 'muted',
3980
3924
  run: () => {
@@ -3993,7 +3937,7 @@ export function ConsoleAppV4(props) {
3993
3937
  ...rowActions,
3994
3938
  ...unverifiedConsumerActions,
3995
3939
  {
3996
- label: direction === 'dependencies' ? '切换到“谁在使用它”' : '切换到“它需要的”',
3940
+ label: direction === 'dependencies' ? '切换到“哪些插件依赖它”' : '切换到“它需要的”',
3997
3941
  description: '切换关系方向',
3998
3942
  run: () => {
3999
3943
  persistDependencyGraphContext(route, projection, expandedDependencyPluginIds ?? new Set(projection.defaultExpandedPluginIds), focus, scrollOffset);
@@ -4006,17 +3950,14 @@ export function ConsoleAppV4(props) {
4006
3950
  },
4007
3951
  { label: showTechnical ? '隐藏检查详情' : '查看检查详情', run: () => toggleTechnical() },
4008
3952
  ];
4009
- const scopeText = projection.scopeSummary.references.length > 0
4010
- ? projection.scopeSummary.references.map((entry) => `${platformLabel(entry.platform)} · ${scopeLabel(entry.scope)}`).join(';')
4011
- : '当前加载范围;其他项目引用未检查';
4012
- const relationViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, showTechnical ? responsiveBudget(3, 6) : responsiveBudget(6, 10));
3953
+ const relationViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, showTechnical ? responsiveBudget(2, 5) : responsiveBudget(5, 9));
4013
3954
  const focusedGraphRow = focus < rowActions.length ? visibleRows[focus] : undefined;
4014
3955
  help = '↑↓ 选择 · → 展开 · ← 收起 · Enter 节点详情 · Esc 返回';
4015
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StaticRow, { title: `当前检查范围 · ${scopeText}`, status: "muted", compact: true }), projection.status.state === 'invalid'
3956
+ content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StaticRow, { title: "\u68C0\u67E5\u8303\u56F4", value: "\u53EA\u68C0\u67E5\u5F53\u524D\u9879\u76EE\u548C\u4E2A\u4EBA\u4F4D\u7F6E\uFF1B\u5176\u4ED6\u9879\u76EE\u672A\u68C0\u67E5", status: "muted", compact: true }), projection.status.state === 'invalid'
4016
3957
  ? _jsx(Callout, { status: "error", title: "\u4F9D\u8D56\u5173\u7CFB\u65E0\u6548", description: projection.status.message }) : null, unverifiedConsumerActions.length > 0
4017
- ? _jsx(StaticRow, { title: `未验证声明者 · ${unverifiedConsumerActions.length} 个`, description: "\u4EE5\u4E0B\u58F0\u660E\u8005\u4E0D\u8BA1\u5165\u5B9E\u9645\u4F7F\u7528\u8005", status: "muted", compact: true })
4018
- : null, focusedGraphRow ? _jsx(StaticRow, { title: "\u7528\u9014", description: props.controller
4019
- .getPluginOverview(focusedGraphRow.pluginId)?.description ?? '当前目录没有用途说明', compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: relationViewport.offset, limit: relationViewport.limit }), showTechnical ? _jsxs(TechnicalDetails, { children: [_jsx(StaticRow, { title: `${dependencyCount} 个依赖 · ${projection.scopeSummary.actualConsumerPluginIds.length} 个实际使用者`, meta: plugin.pluginId, compact: true }), _jsx(StaticRow, { title: `未验证声明者 · ${projection.scopeSummary.unknownConsumerPluginIds.length} 个`, compact: true })] }) : null] });
3958
+ ? _jsx(StaticRow, { title: `未验证声明者 · ${unverifiedConsumerActions.length} 个`, description: "\u4EE5\u4E0B\u58F0\u660E\u8005\u4E0D\u8BA1\u5165\u5F53\u524D\u53EF\u7528\u5173\u7CFB", status: "muted", compact: true })
3959
+ : null, focusedGraphRow ? _jsx(StaticRow, { title: "\u7528\u9014", value: props.controller
3960
+ .getPluginOverview(focusedGraphRow.pluginId)?.description ?? '当前目录没有用途说明', compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: relationViewport.offset, limit: relationViewport.limit }), showTechnical ? _jsxs(TechnicalDetails, { children: [_jsx(StaticRow, { title: `${dependencyCount} 个依赖 · ${projection.scopeSummary.availableConsumerPluginIds.length} 个当前可用依赖者`, meta: plugin.pluginId, compact: true }), _jsx(StaticRow, { title: `未验证声明者 · ${projection.scopeSummary.unknownConsumerPluginIds.length} 个`, compact: true })] }) : null] });
4020
3961
  }
4021
3962
  }
4022
3963
  else if (route.name === 'pluginDependencyNode' && plugin) {
@@ -4038,10 +3979,10 @@ export function ConsoleAppV4(props) {
4038
3979
  ?.find((entry) => entry.pluginId === route.nodePluginId);
4039
3980
  const state = item ? dependencyStatus(item) : undefined;
4040
3981
  const relationship = selectedRow?.relationship
4041
- ?? ((item?.placementReferences?.length ?? 0) > 0 ? 'unknown'
3982
+ ?? ((item?.availablePlacementReferences?.length ?? 0) > 0 ? 'unknown'
4042
3983
  : item ? 'declared' : undefined);
4043
3984
  breadcrumb = `${plugin.displayName} / 依赖关系 / ${node?.displayName ?? route.nodePluginId}`;
4044
- context = route.direction === 'dependencies' ? '它需要的' : '谁在使用它';
3985
+ context = route.direction === 'dependencies' ? '它需要的' : '哪些插件依赖它';
4045
3986
  title = node?.displayName ?? route.nodePluginId;
4046
3987
  const pathPluginIds = selectedRow?.pathPluginIds ?? nodePathPluginIds;
4047
3988
  const intermediateNames = pathPluginIds.slice(1, -1).reverse().map((pluginId) => props.controller.getPluginOverview(pluginId)?.displayName ?? pluginId);
@@ -4050,37 +3991,61 @@ export function ConsoleAppV4(props) {
4050
3991
  ?? declaringPluginId;
4051
3992
  description = relationship === 'root'
4052
3993
  ? '这是当前关系图的根插件。'
4053
- : relationship === 'directVerified'
3994
+ : relationship === 'directAvailable'
4054
3995
  ? route.direction === 'dependencies'
4055
- ? `${plugin.displayName} 的已安装位置直接使用这个插件。`
4056
- : `${node?.displayName ?? route.nodePluginId} 的已安装位置直接使用当前插件。`
4057
- : relationship === 'indirectVerified'
3996
+ ? `${plugin.displayName} 在本次检查的位置需要此插件,所需依赖当前可用。`
3997
+ : `${node?.displayName ?? route.nodePluginId} 在本次检查的位置需要当前插件,所需依赖当前可用。`
3998
+ : relationship === 'indirectAvailable'
4058
3999
  ? route.direction === 'dependencies'
4059
- ? `${plugin.displayName} 通过 ${intermediateNames.join('、')} 间接使用 ${node?.displayName ?? route.nodePluginId}。`
4060
- : `${node?.displayName ?? route.nodePluginId} 通过 ${intermediateNames.join('、')} 间接使用 ${plugin.displayName}。`
4000
+ ? `${plugin.displayName} 通过 ${intermediateNames.join('、')} 需要 ${node?.displayName ?? route.nodePluginId},且各段依赖当前可用。`
4001
+ : `${node?.displayName ?? route.nodePluginId} 通过 ${intermediateNames.join('、')} 需要 ${plugin.displayName},且各段依赖当前可用。`
4061
4002
  : relationship === 'unknown'
4062
- ? '引用位置不能组成连续路径,不能确认这项间接使用。'
4003
+ ? '本次检查的位置不能组成连续路径,不能显示这项间接关系。'
4063
4004
  : relationship === 'declared'
4064
4005
  ? route.direction === 'dependencies'
4065
- ? `${declaringPluginName} 声明需要 ${node?.displayName ?? route.nodePluginId},但当前没有实际引用证据。`
4066
- : `${node?.displayName ?? route.nodePluginId} 声明依赖当前插件,但当前没有实际引用证据。`
4006
+ ? `${declaringPluginName} 声明需要 ${node?.displayName ?? route.nodePluginId},但本次尚未确认依赖可用。`
4007
+ : `${node?.displayName ?? route.nodePluginId} 声明需要当前插件,但本次尚未确认依赖可用。`
4067
4008
  : '当前数据不足,不能判断这项依赖关系。';
4068
- const references = selectedRow?.edge?.placementReferences ?? item?.placementReferences ?? [];
4009
+ const references = selectedRow?.edge?.availablePlacementReferences
4010
+ ?? item?.availablePlacementReferences ?? [];
4069
4011
  const referenceActions = references.map((reference) => {
4070
4012
  const consumerName = props.controller.getPluginOverview(reference.consumer.pluginId)?.displayName
4071
4013
  ?? reference.consumer.pluginId.split('/').at(-1);
4072
4014
  return {
4073
4015
  label: dependencyReferenceUsageLabel(reference, consumerName),
4074
- meta: '已确认使用',
4016
+ meta: '依赖当前可用',
4075
4017
  };
4076
4018
  });
4077
- if (route.view === 'references') {
4019
+ if (route.view === 'details') {
4020
+ const detailSections = [
4021
+ ['用途', node?.description ?? '当前目录没有用途说明'],
4022
+ ['为何需要', description],
4023
+ ['影响', state?.value ?? (node ? statusText(node) : '尚未检查当前状态')],
4024
+ ];
4025
+ const detailLines = detailSections.flatMap(([label, value]) => [
4026
+ label,
4027
+ ...wrapConsoleText(value, Math.max(1, size.columns - 6)).map((line) => ` ${line}`),
4028
+ ]);
4029
+ const pageRows = responsiveBudget(5, 10);
4030
+ const detailOffset = Math.min(batchTargetOffset, Math.max(0, detailLines.length - 1));
4031
+ const visibleDetailLines = detailLines.slice(detailOffset, detailOffset + pageRows);
4032
+ referenceDetailPagination = { total: detailLines.length, pageRows };
4033
+ breadcrumb = `${plugin.displayName} / 依赖关系 / ${node?.displayName ?? route.nodePluginId} / 完整说明`;
4034
+ context = `${Math.min(detailOffset + 1, detailLines.length)}–${Math.min(detailOffset + visibleDetailLines.length, detailLines.length)} / ${detailLines.length}`;
4035
+ title = `${node?.displayName ?? route.nodePluginId} 的完整说明`;
4036
+ description = '用途、关系原因和当前影响。';
4037
+ help = 'PgUp/PgDn 阅读 · Enter 返回节点详情 · Esc 返回节点详情';
4038
+ actions = [{ label: '返回节点详情', run: back }];
4039
+ content = _jsxs(Box, { flexDirection: "column", children: [detailOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${detailOffset} 行`, status: "muted", compact: true }) : null, visibleDetailLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${detailOffset + index}:${line}`)), detailOffset + visibleDetailLines.length < detailLines.length
4040
+ ? _jsx(StaticRow, { title: `↓ 后面还有 ${detailLines.length - detailOffset - visibleDetailLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
4041
+ }
4042
+ else if (route.view === 'references') {
4078
4043
  breadcrumb = `${plugin.displayName} / 依赖关系 / ${node?.displayName ?? route.nodePluginId} / 使用位置`;
4079
4044
  context = showTechnical ? '技术详情' : '使用位置';
4080
- title = `已检查的使用位置 ${references.length} 个`;
4045
+ title = `当前可用依赖位置 ${references.length} 个`;
4081
4046
  description = showTechnical
4082
4047
  ? '显示当前选择的完整引用字段。'
4083
- : '这些位置有连续、已确认的实际引用。';
4048
+ : '这些位置的所需依赖当前可用,且本次检查发现它们同时满足依赖声明和安装位置。';
4084
4049
  actions = [...referenceActions, { label: '返回节点详情', run: back }];
4085
4050
  const referenceViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(3, 6));
4086
4051
  const selectedReference = references[Math.min(focus, references.length - 1)];
@@ -4110,7 +4075,7 @@ export function ConsoleAppV4(props) {
4110
4075
  ? 'PgUp/PgDn 查看当前位置详情 · ↑↓ 查看全部位置 · d 隐藏技术详情 · Esc 返回节点详情'
4111
4076
  : '↑↓ 查看全部位置 · d 技术详情 · Enter 返回节点详情 · Esc 返回节点详情';
4112
4077
  content = _jsxs(Box, { flexDirection: "column", children: [showTechnical ? null
4113
- : _jsx(StaticRow, { title: "\u8BC1\u636E\u8FB9\u754C", description: "\u8FD9\u91CC\u53EA\u663E\u793A\u5DF2\u786E\u8BA4\u7684\u5B9E\u9645\u5F15\u7528\uFF1B\u63D2\u4EF6\u72B6\u6001\u4E0D\u4F5C\u4E3A\u5F15\u7528", status: "muted", compact: true }), showTechnical && referenceDetailOffset > 0
4078
+ : _jsx(StaticRow, { title: "\u672C\u6B21\u68C0\u67E5", value: "\u53EA\u68C0\u67E5\u5F53\u524D\u9879\u76EE\u548C\u4E2A\u4EBA\u4F4D\u7F6E\uFF1B\u5176\u4ED6\u9879\u76EE\u672A\u68C0\u67E5", status: "muted", compact: true }), showTechnical && referenceDetailOffset > 0
4114
4079
  ? _jsx(StaticRow, { title: `↑ 前面还有 ${referenceDetailOffset} 行`, status: "muted", compact: true }) : null, showTechnical ? visibleReferenceDetailLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${referenceDetailOffset + index}:${line}`)) : null, showTechnical && referenceDetailOffset + visibleReferenceDetailLines.length < referenceDetailLines.length
4115
4080
  ? _jsx(StaticRow, { title: `↓ 后面还有 ${referenceDetailLines.length - referenceDetailOffset - visibleReferenceDetailLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: referenceViewport.offset, limit: referenceViewport.limit })] });
4116
4081
  }
@@ -4118,7 +4083,7 @@ export function ConsoleAppV4(props) {
4118
4083
  actions = [
4119
4084
  ...(references.length > 0 ? [{
4120
4085
  label: `查看全部位置(${references.length})`,
4121
- description: '查看每个已检查位置及证据状态',
4086
+ description: '查看每个位置的当前可用依赖',
4122
4087
  run: () => go({ ...route, view: 'references' }),
4123
4088
  }] : []),
4124
4089
  ...(route.nodePluginId !== plugin.pluginId ? [{
@@ -4130,11 +4095,20 @@ export function ConsoleAppV4(props) {
4130
4095
  direction: route.direction,
4131
4096
  }),
4132
4097
  }] : []),
4098
+ {
4099
+ label: '阅读完整说明',
4100
+ description: '分页查看用途、为何需要和影响',
4101
+ run: () => {
4102
+ setBatchTargetOffset(0);
4103
+ go({ ...route, view: 'details' });
4104
+ },
4105
+ },
4133
4106
  { label: '返回关系图', run: back },
4134
4107
  ];
4135
- content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { title: "\u8282\u70B9\u72B6\u6001", children: [_jsx(StaticRow, { title: node?.displayName ?? route.nodePluginId, meta: state?.value ?? (node ? statusText(node) : '未检查'), status: state?.status ?? 'muted', compact: true }), _jsx(StaticRow, { title: "\u7528\u9014", description: node?.description ?? '当前目录没有用途说明', compact: true }), _jsx(StaticRow, { title: "\u4E3A\u4F55\u9700\u8981", description: description, compact: true }), _jsx(StaticRow, { title: "\u5F71\u54CD", description: state?.value ?? (node ? statusText(node) : '尚未检查当前状态'), status: state?.status ?? 'muted', compact: true }), references.length > 0
4136
- ? _jsx(StaticRow, { title: `已检查的使用位置 ${references.length} 个`, description: "\u9009\u62E9\u201C\u67E5\u770B\u5168\u90E8\u4F4D\u7F6E\u201D\u53EF\u9010\u9879\u67E5\u770B", compact: true })
4137
- : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' }), showTechnical ? _jsxs(TechnicalDetails, { children: [_jsx(StaticRow, { title: "pluginId", meta: route.nodePluginId, compact: true }), _jsx(StaticRow, { title: "relationship", meta: relationship ?? 'unknown', compact: true })] }) : null] });
4108
+ const nodeActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(2, 4));
4109
+ content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { title: "\u8282\u70B9\u72B6\u6001", children: [_jsx(StaticRow, { title: "\u7528\u9014", value: node?.description ?? '当前目录没有用途说明', compact: true }), _jsx(StaticRow, { title: "\u4E3A\u4F55\u9700\u8981", value: description, compact: true }), _jsx(StaticRow, { title: "\u5F71\u54CD", value: state?.value ?? (node ? statusText(node) : '尚未检查当前状态'), status: state?.status ?? 'muted', compact: true }), references.length > 0
4110
+ ? _jsx(StaticRow, { title: `当前可用依赖位置 ${references.length} 个`, description: "\u9009\u62E9\u201C\u67E5\u770B\u5168\u90E8\u4F4D\u7F6E\u201D\u53EF\u9010\u9879\u67E5\u770B", compact: true })
4111
+ : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: nodeActionViewport.offset, limit: nodeActionViewport.limit }), showTechnical ? _jsxs(TechnicalDetails, { children: [_jsx(StaticRow, { title: "pluginId", meta: route.nodePluginId, compact: true }), _jsx(StaticRow, { title: "relationship", meta: relationship ?? 'unknown', compact: true })] }) : null] });
4138
4112
  }
4139
4113
  }
4140
4114
  else if (route.name === 'installPlacement' && plugin) {
@@ -4143,7 +4117,7 @@ export function ConsoleAppV4(props) {
4143
4117
  title = `你希望在哪里使用 ${plugin.displayName}?`;
4144
4118
  const hasDependencies = (plugin.dependencySummary?.totalCount ?? 0) > 0;
4145
4119
  description = hasDependencies
4146
- ? '这里只选择根插件位置。依赖将采用 planner 推荐位置,并在 Review 中显示。'
4120
+ ? '这里只选择根插件的安装位置。依赖会自动安排合适位置,并在操作汇总中显示。'
4147
4121
  : '选择位置后,再选择一个或多个目标平台。';
4148
4122
  const availableScopes = ['user', 'project'].filter((candidateScope) => props.controller.listInstallTargets(plugin.pluginId, candidateScope)
4149
4123
  .some((entry) => entry.compatible));
@@ -4153,7 +4127,7 @@ export function ConsoleAppV4(props) {
4153
4127
  selected: candidateScope === scope,
4154
4128
  description: candidateScope === 'user'
4155
4129
  ? hasDependencies ? '根插件在任意项目中可用;依赖位置自动计算' : '在任意项目中可使用,适合个人常用能力'
4156
- : hasDependencies ? '根插件只在当前项目使用;Review 会说明更宽的依赖位置' : '仅在当前项目中使用,适合团队共享',
4130
+ : hasDependencies ? '根插件只在当前项目使用;操作汇总会说明依赖是否需要用于更多项目' : '仅在当前项目中使用,适合团队共享',
4157
4131
  meta: candidateScope === 'user' ? '推荐' : undefined,
4158
4132
  run: () => {
4159
4133
  const choices = props.controller.listInstallTargets(plugin.pluginId, candidateScope);
@@ -4176,7 +4150,7 @@ export function ConsoleAppV4(props) {
4176
4150
  },
4177
4151
  })),
4178
4152
  ];
4179
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' }), hasDependencies ? _jsx(SectionCard, { title: "\u4F9D\u8D56\u4F4D\u7F6E", children: _jsx(StaticRow, { title: `${plugin.dependencySummary?.totalCount ?? 0} 个依赖将采用推荐位置`, description: "Review \u4E2D\u53EF\u67E5\u770B\u6216\u8C03\u6574", status: "info" }) }) : null] });
4153
+ content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' }), hasDependencies ? _jsx(SectionCard, { title: "\u4F9D\u8D56\u4F4D\u7F6E", children: _jsx(StaticRow, { title: `${plugin.dependencySummary?.totalCount ?? 0} 个依赖将自动安排合适位置`, description: "\u53EF\u5728\u64CD\u4F5C\u6C47\u603B\u4E2D\u67E5\u770B\u6216\u8C03\u6574", status: "info" }) }) : null] });
4180
4154
  }
4181
4155
  else if (route.name === 'installTargets' && plugin) {
4182
4156
  breadcrumb = `${plugin.displayName} / 添加 / 目标平台`;
@@ -4184,8 +4158,8 @@ export function ConsoleAppV4(props) {
4184
4158
  title = '选择目标平台';
4185
4159
  const hasDependencies = (plugin.dependencySummary?.totalCount ?? 0) > 0;
4186
4160
  description = hasDependencies
4187
- ? '根插件必须支持所选位置;确认后会自动规划依赖并进入 Review。'
4188
- : '目标平台按所选位置验证;仅含平台共享内容的插件可同时启用两个位置。';
4161
+ ? '根插件必须支持所选位置;确认后会自动安排依赖并显示操作汇总。'
4162
+ : '目标平台按所选位置验证;只含由平台共用内容的插件可同时启用两个位置。';
4189
4163
  const choices = props.controller.listInstallTargets(plugin.pluginId, scope);
4190
4164
  const validSelectedTargets = selectedTargets.filter((platform) => choices.some((choice) => choice.platform === platform && choice.compatible));
4191
4165
  const allUnavailable = choices.length > 0 && choices.every((choice) => !choice.compatible);
@@ -4268,7 +4242,7 @@ export function ConsoleAppV4(props) {
4268
4242
  ...dependencyActions,
4269
4243
  {
4270
4244
  label: '继续到确认',
4271
- description: draft?.canContinue ? '使用这些最终位置准备 Review' : undefined,
4245
+ description: draft?.canContinue ? '使用这些最终位置显示操作汇总' : undefined,
4272
4246
  disabled: !draft?.canContinue ? draft?.error?.message ?? '依赖位置尚未就绪' : undefined,
4273
4247
  run: () => beginReview(props.controller.installPlacementIntent()),
4274
4248
  },
@@ -4285,7 +4259,7 @@ export function ConsoleAppV4(props) {
4285
4259
  const reusedCount = draft?.targets.filter((target) => target.assignmentSource === 'existingWiderTarget').length ?? 0;
4286
4260
  const promotedCount = draft?.targets.filter((target) => target.assignmentSource === 'consumerPromotion').length ?? 0;
4287
4261
  const reasonSummary = [
4288
- ...(defaultCount > 0 ? [`默认 project ${defaultCount} 项`] : []),
4262
+ ...(defaultCount > 0 ? [`默认当前项目 ${defaultCount} 项`] : []),
4289
4263
  ...(reusedCount > 0 ? [`复用健康的所有项目安装 ${reusedCount} 项`] : []),
4290
4264
  ...(promotedCount > 0 ? [`因依赖自动调整 ${promotedCount} 项`] : []),
4291
4265
  ].join(';');
@@ -4389,7 +4363,7 @@ export function ConsoleAppV4(props) {
4389
4363
  if (updateCandidates.length > 0 && updatePlugin) {
4390
4364
  return [[`update:${pluginWriteTaskTargetKey(candidate)}`, {
4391
4365
  label: `更新并恢复 ${targetLabel}…`,
4392
- description: '改用当前候选版本建立新任务;进入 Review 前仍会重新检查证据',
4366
+ description: '改用当前候选版本建立新任务;显示操作汇总前仍会重新检查状态',
4393
4367
  status: 'warning',
4394
4368
  run: () => props.controller.beginNestedPluginWriteTask({
4395
4369
  name: 'pluginWriteTask',
@@ -4469,7 +4443,7 @@ export function ConsoleAppV4(props) {
4469
4443
  const taskLabel = pluginWriteTaskLabel(route.goal);
4470
4444
  const startTaskReview = (executionPolicy) => {
4471
4445
  if (targetSetChanged) {
4472
- setActionError('冻结的精确位置已变化。请返回调整后重新开始。');
4446
+ setActionError('本次安装位置已变化。请返回调整后重新开始。');
4473
4447
  return;
4474
4448
  }
4475
4449
  props.controller.startPluginWriteTaskReview({
@@ -4546,7 +4520,7 @@ export function ConsoleAppV4(props) {
4546
4520
  : _jsx(StaticRow, { title: "\u5F53\u524D\u6CA1\u6709\u53EF\u6267\u884C\u76EE\u6807", status: "muted", compact: true }), candidates.length > taskTargetOffset + targetRows.length
4547
4521
  ? _jsx(StaticRow, { title: `↓ 后面还有 ${candidates.length - taskTargetOffset - targetRows.length} 个位置`, status: "muted", compact: true }) : null] }), blockedCandidates.length > 0 ? _jsx(Callout, { status: "warning", title: `${blockedCandidates.length} 个位置需要先处理或决定`, description: executable.length > 0
4548
4522
  ? '可以先处理可执行项,或进入下方对应入口处理受阻位置。'
4549
- : '请进入下方对应入口处理;返回后会重新读取当前证据。', compact: policy.mode === 'compact' }) : null, missingTargetKeys.length > 0 ? _jsx(Callout, { status: "warning", title: `${missingTargetKeys.length} 个冻结位置已失效或无需处理`, description: "\u4E0D\u4F1A\u628A\u8FD9\u4E9B\u4F4D\u7F6E\u5F53\u4F5C\u5DF2\u5B8C\u6210\uFF0C\u4E5F\u4E0D\u4F1A\u81EA\u52A8\u7F29\u5C0F\u672C\u6B21\u8303\u56F4\u3002\u8BF7\u8FD4\u56DE\u8C03\u6574\u9009\u62E9\u540E\u91CD\u65B0\u5F00\u59CB\u3002", compact: policy.mode === 'compact' }) : null, addedTargetKeys.length > 0 ? _jsx(Callout, { status: "warning", title: `${addedTargetKeys.length} 个新位置需要重新确认`, description: "\u4E0D\u4F1A\u628A\u5237\u65B0\u540E\u65B0\u589E\u7684\u4F4D\u7F6E\u81EA\u52A8\u52A0\u5165\u51BB\u7ED3\u8303\u56F4\u3002\u8BF7\u8FD4\u56DE\u8C03\u6574\u9009\u62E9\u540E\u91CD\u65B0\u5F00\u59CB\u3002", compact: policy.mode === 'compact' }) : null, versionEvidenceChanged ? _jsx(Callout, { status: "warning", title: "\u63D2\u4EF6\u76EE\u6807\u7248\u672C\u5DF2\u53D8\u5316", description: "\u4E0D\u4F1A\u6CBF\u7528\u6765\u6E90\u542F\u7528\u524D\u7684\u7248\u672C\u8BC1\u636E\uFF0C\u4E5F\u4E0D\u4F1A\u81EA\u52A8\u6267\u884C\u65B0\u7248\u672C\u3002", compact: policy.mode === 'compact' }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: taskViewport.offset, limit: taskViewport.limit })] });
4523
+ : '请进入下方对应入口处理;返回后会重新读取当前证据。', compact: policy.mode === 'compact' }) : null, missingTargetKeys.length > 0 ? _jsx(Callout, { status: "warning", title: `${missingTargetKeys.length} 个本次安装位置已失效或无需处理`, description: "\u4E0D\u4F1A\u628A\u8FD9\u4E9B\u4F4D\u7F6E\u5F53\u4F5C\u5DF2\u5B8C\u6210\uFF0C\u4E5F\u4E0D\u4F1A\u81EA\u52A8\u7F29\u5C0F\u672C\u6B21\u8303\u56F4\u3002\u8BF7\u8FD4\u56DE\u8C03\u6574\u9009\u62E9\u540E\u91CD\u65B0\u5F00\u59CB\u3002", compact: policy.mode === 'compact' }) : null, addedTargetKeys.length > 0 ? _jsx(Callout, { status: "warning", title: `${addedTargetKeys.length} 个新位置需要重新确认`, description: "\u4E0D\u4F1A\u628A\u5237\u65B0\u540E\u65B0\u589E\u7684\u4F4D\u7F6E\u81EA\u52A8\u52A0\u5165\u672C\u6B21\u64CD\u4F5C\u3002\u8BF7\u8FD4\u56DE\u8C03\u6574\u9009\u62E9\u540E\u91CD\u65B0\u5F00\u59CB\u3002", compact: policy.mode === 'compact' }) : null, versionEvidenceChanged ? _jsx(Callout, { status: "warning", title: "\u63D2\u4EF6\u76EE\u6807\u7248\u672C\u5DF2\u53D8\u5316", description: "\u4E0D\u4F1A\u6CBF\u7528\u6765\u6E90\u542F\u7528\u524D\u7684\u7248\u672C\u8BC1\u636E\uFF0C\u4E5F\u4E0D\u4F1A\u81EA\u52A8\u6267\u884C\u65B0\u7248\u672C\u3002", compact: policy.mode === 'compact' }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: taskViewport.offset, limit: taskViewport.limit })] });
4550
4524
  }
4551
4525
  else if (route.name === 'pluginDetail' && plugin) {
4552
4526
  breadcrumb = `我的插件 / ${plugin.displayName}`;
@@ -4656,21 +4630,40 @@ export function ConsoleAppV4(props) {
4656
4630
  const dependencyOverviewForDetail = dependencyOverview(plugin);
4657
4631
  const dependencyDetailText = dependencyOverviewForDetail
4658
4632
  && dependencyOverviewForDetail.summary.totalCount > 0
4659
- ? `使用 ${dependencyOverviewForDetail.summary.totalCount} 个所需插件;尚未确认它们在这些位置的实际使用状态。`
4633
+ ? `需要 ${dependencyOverviewForDetail.summary.totalCount} 个插件;当前可用关系按当前范围检查,未显示的关系尚未检查通过。`
4660
4634
  : undefined;
4661
- const placementConclusions = plugin.installedPlacements.map((placement) => ({
4635
+ const placementConclusions = plugin.installedPlacements.flatMap((placement) => pluginPlacementConclusions(placement).map((conclusion, index) => ({
4662
4636
  platform: placement.platform,
4663
- ...pluginPlacementConclusion(placement),
4664
- }));
4637
+ key: `${placement.platform}:${index}`,
4638
+ ...conclusion,
4639
+ })));
4665
4640
  const hasUnavailablePlacement = placementConclusions.some((placement) => placement.status === 'error');
4666
4641
  const hasUncertainPlacement = placementConclusions.some((placement) => placement.status === 'warning');
4667
4642
  const confirmedAvailablePlacements = placementConclusions.filter((placement) => placement.status === 'success');
4668
- const detailViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(Math.min(placementConclusions.length, 2) + 4));
4643
+ const placementPageRows = Math.min(2, placementConclusions.length);
4644
+ const placementOffset = Math.min(batchTargetOffset, Math.max(0, placementConclusions.length - placementPageRows));
4645
+ const visiblePlacementConclusions = placementConclusions.slice(placementOffset, placementOffset + placementPageRows);
4646
+ placementConclusionPagination = placementConclusions.length > placementPageRows
4647
+ ? { total: placementConclusions.length, pageRows: placementPageRows } : undefined;
4648
+ if (placementConclusionPagination) {
4649
+ help = 'PgUp/PgDn 查看全部使用位置 · ↑↓ 移动 · Enter 选择 · Esc 返回';
4650
+ }
4651
+ const detailStaticRows = 3 + visiblePlacementConclusions.length
4652
+ + (updateDescription ? policy.mode === 'compact' ? 1 : 4 : 0)
4653
+ + (dependencyDetailText ? 1 : 0)
4654
+ + 3;
4655
+ const detailViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(detailStaticRows));
4669
4656
  content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: hasUnavailablePlacement ? 'error'
4670
4657
  : hasUncertainPlacement ? 'warning'
4671
4658
  : confirmedAvailablePlacements.length > 0 ? 'success' : 'info', title: hasUnavailablePlacement ? '部分使用位置暂时不可用'
4672
4659
  : hasUncertainPlacement ? '部分使用位置需要处理'
4673
- : confirmedAvailablePlacements.length > 0 ? '已确认的使用位置可用' : '尚未确认使用位置', children: placementConclusions.map((placement) => _jsx(StaticRow, { title: platformLabel(placement.platform), meta: placement.text, status: placement.status, compact: true }, placement.platform)) }), updateDescription ? _jsx(Callout, { status: "warning", title: "\u6709\u53EF\u7528\u66F4\u65B0", description: updateDescription }) : null, dependencyDetailText ? _jsx(StaticRow, { title: dependencyDetailText, status: "muted", compact: true }) : null, _jsx(SectionCard, { title: "\u63D2\u4EF6\u64CD\u4F5C", children: _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: detailViewport.offset, limit: detailViewport.limit }) })] });
4660
+ : confirmedAvailablePlacements.length > 0 ? '已确认的使用位置可用' : '尚未确认使用位置', meta: placementConclusionPagination
4661
+ ? `${placementOffset + 1}–${placementOffset + visiblePlacementConclusions.length}/${placementConclusions.length}`
4662
+ : undefined, children: visiblePlacementConclusions.map((placement) => _jsx(StaticRow, { title: platformLabel(placement.platform), meta: placement.text, status: placement.status, compact: true }, placement.key)) }), updateDescription
4663
+ ? policy.mode === 'compact'
4664
+ ? _jsx(StaticRow, { title: "\u6709\u53EF\u7528\u66F4\u65B0", meta: updateDescription, status: "warning", compact: true })
4665
+ : _jsx(Callout, { status: "warning", title: "\u6709\u53EF\u7528\u66F4\u65B0", description: updateDescription })
4666
+ : null, dependencyDetailText ? _jsx(StaticRow, { title: dependencyDetailText, status: "muted", compact: true }) : null, _jsx(SectionCard, { title: "\u63D2\u4EF6\u64CD\u4F5C", children: _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: detailViewport.offset, limit: detailViewport.limit }) })] });
4674
4667
  }
4675
4668
  else if (route.name === 'pluginMore' && plugin) {
4676
4669
  breadcrumb = `我的插件 / ${plugin.displayName} / 更多操作`;
@@ -4727,7 +4720,7 @@ export function ConsoleAppV4(props) {
4727
4720
  };
4728
4721
  if (action.id === 'dependencies')
4729
4722
  return {
4730
- label: '依赖与被使用情况',
4723
+ label: '依赖与当前可用关系',
4731
4724
  description: dependencySummary?.issueCount ? `${dependencySummary.issueCount} 项需要处理` : '查看完整关系',
4732
4725
  meta: dependencySummary ? dependencySummaryText(dependencySummary) : undefined,
4733
4726
  run: () => go({ name: 'pluginDependencies', pluginId: plugin.pluginId }),
@@ -4762,8 +4755,8 @@ export function ConsoleAppV4(props) {
4762
4755
  };
4763
4756
  }),
4764
4757
  ...(!detailMenu.some((action) => action.id === 'dependencies') ? [{
4765
- label: '依赖与被使用情况',
4766
- description: '查看必需依赖和已知使用者;当前没有声明的必需依赖',
4758
+ label: '依赖与当前可用关系',
4759
+ description: '查看必需依赖、声明者和当前可用关系;当前没有声明的必需依赖',
4767
4760
  run: () => go({ name: 'pluginDependencies', pluginId: plugin.pluginId }),
4768
4761
  }] : []),
4769
4762
  { label: '使用说明', run: () => go({ name: 'pluginAbout', pluginId: plugin.pluginId }) },
@@ -4824,7 +4817,7 @@ export function ConsoleAppV4(props) {
4824
4817
  if (action.id === 'addScope')
4825
4818
  return {
4826
4819
  label: `在${scopeLabel(action.scope)}中启用…`,
4827
- description: '增加这个使用位置;现有共享内容保持不变',
4820
+ description: '增加这个使用位置;已被其它项目共用的内容保持不变',
4828
4821
  run: () => beginSecondScope(plugin, action.platform, action.scope),
4829
4822
  };
4830
4823
  if (action.id === 'about')
@@ -4870,7 +4863,7 @@ export function ConsoleAppV4(props) {
4870
4863
  description: placement?.state === 'installed'
4871
4864
  ? (placement.scopedPlacements?.find((entry) => entry.scope === action.scope)?.recovery
4872
4865
  ?? placement.recovery)?.find((entry) => entry.command === 'sync')?.description
4873
- ?? '进入现有 Review、进度和结果链修复 needsSync 或 drift'
4866
+ ?? '重新检查已保存位置,并在操作汇总中显示需要处理的项目'
4874
4867
  : undefined,
4875
4868
  run: () => placement?.state === 'installed'
4876
4869
  ? beginReview({ kind: 'pluginWrite', action: 'sync', pluginId: plugin.pluginId, platform: action.platform, scope: action.scope })
@@ -4913,7 +4906,7 @@ export function ConsoleAppV4(props) {
4913
4906
  && !platformMenu.some((action) => action.id === 'resolveScopeConflict')
4914
4907
  ? {
4915
4908
  label: '检查受限清理…',
4916
- description: '只在当前单一目标有精确、专属的 AW 管理恢复证据时确认;先核验,再取消使用设置并尽力清理;共享和外来内容保留。',
4909
+ description: '只在当前单一位置能确认内容只属于此插件时提供;先核验,再取消使用设置并尽力清理;被共用或不属于插件的内容保留。',
4917
4910
  status: 'warning',
4918
4911
  run: () => beginRestrictedForceCleanup(plugin.pluginId, route.platform, placement.scope),
4919
4912
  }
@@ -5105,10 +5098,10 @@ export function ConsoleAppV4(props) {
5105
5098
  ? (activeGroup?.fields ?? []).filter((field) => field.sharedNativeRender && !field.writable)
5106
5099
  : [];
5107
5100
  if (projectSharedNativeFields.length > 0) {
5108
- description += ' 此设置由个人默认控制平台共享内容;当前项目不可改。更改影响所有项目。';
5101
+ description += ' 此设置由个人默认控制被各项目共用的内容;当前项目不可改。更改影响所有项目。';
5109
5102
  }
5110
5103
  if (projectSharedNativeFields.some(configFieldCanUnset)) {
5111
- description += ' 发现不再支持的 project override;实际使用 user/default;请删除旧值。';
5104
+ description += ' 本项目旧值不再使用;当前继承个人或插件默认。请删除旧值。';
5112
5105
  }
5113
5106
  if (!readonly && configDraftIssues.length > 0) {
5114
5107
  description += ' 字段已变化;失效草稿不会保存。';
@@ -5139,7 +5132,7 @@ export function ConsoleAppV4(props) {
5139
5132
  : readonly
5140
5133
  ? field.sourceLabel === '未设置' ? '没有任何位置提供值' : `来自${field.sourceLabel}`
5141
5134
  : !configFieldCanSet(field) && configFieldCanUnset(field)
5142
- ? '不再支持的 project override · 实际使用 user/default · 可删除旧值'
5135
+ ? '本项目旧值不再使用 · 当前继承个人或插件默认 · 可删除旧值'
5143
5136
  : `${field.description ? `${field.description} · ` : ''}当前有效:${effectiveFieldDisplay(field)} · ${field.effectiveSourceLabel}`,
5144
5137
  meta: readonly ? effectiveFieldDisplay(field) : currentFieldDisplay(field),
5145
5138
  configKey: field.key,
@@ -5237,61 +5230,98 @@ export function ConsoleAppV4(props) {
5237
5230
  }
5238
5231
  else if (route.name === 'configSave' && plugin && currentConfigPage) {
5239
5232
  const changes = configChanges();
5240
- const affectedTargets = configSaveImpact?.affectedTargets ?? [];
5241
- const hasConsumers = configSaveImpact?.impactState === 'known' && affectedTargets.length > 0;
5242
- const targetSummary = affectedTargets
5243
- .map((target) => `${platformLabel(target.platform)} · ${scopeLabel(target.scope)}`)
5244
- .join('、');
5245
- breadcrumb = `${plugin.displayName} / 设置 / 保存汇总`;
5246
- context = `${changes.length} 项未保存`;
5247
- title = `保存 ${changes.length} 项设置修改?`;
5248
- description = route.layer.scope === 'project'
5249
- ? '修改将保存到当前项目。'
5250
- : '修改将保存为个人默认,并影响个人的所有项目;项目设置仍可覆盖。';
5251
- actions = configSaveImpactError ? [
5252
- {
5253
- label: '重新检查影响',
5254
- description: '重新读取当前安装位置;检查成功前不能保存',
5255
- run: () => setConfigSaveImpactAttempt((value) => value + 1),
5256
- },
5257
- { label: '返回修改', run: back },
5258
- ] : configSaveImpact ? [
5259
- hasConsumers ? {
5260
- label: '保存并生效',
5261
- description: `保存设置,并重新应用:${targetSummary}`,
5262
- status: 'success',
5263
- run: () => beginConfigSave(true),
5264
- } : configSaveImpact.impactState === 'unknown' ? {
5265
- label: '仅保存设置(应用范围尚未确认)',
5266
- description: '保存所选设置层;不扩大到未确认的安装位置',
5267
- status: 'warning',
5268
- run: () => beginConfigSave(false),
5269
- } : {
5270
- label: '保存设置',
5271
- description: '当前修改没有需要重新应用的已安装目标',
5272
- status: 'success',
5273
- run: () => beginConfigSave(false),
5274
- },
5275
- ...(hasConsumers ? [{
5276
- label: '只保存,稍后应用',
5277
- description: '保存所选设置层,不重新应用当前目标',
5278
- run: () => beginConfigSave(false),
5279
- }] : configSaveImpact.impactState === 'unknown' ? [{
5233
+ if (route.view === 'changes') {
5234
+ const lines = changeDetailLines(changes, size.columns - 4);
5235
+ const pageRows = responsiveBudget(5, 10);
5236
+ const detailOffset = Math.min(batchTargetOffset, Math.max(0, lines.length - 1));
5237
+ const visibleLines = lines.slice(detailOffset, detailOffset + pageRows);
5238
+ referenceDetailPagination = { total: lines.length, pageRows };
5239
+ breadcrumb = `${plugin.displayName} / 设置 / 完整变化`;
5240
+ context = `${Math.min(detailOffset + 1, lines.length)}–${Math.min(detailOffset + visibleLines.length, lines.length)} / ${lines.length}`;
5241
+ title = '完整设置变化';
5242
+ description = '逐项显示修改前和修改后的完整值。';
5243
+ help = 'PgUp/PgDn 阅读 · Enter 返回保存汇总 · Esc 返回保存汇总';
5244
+ actions = [{ label: '返回保存汇总', run: back }];
5245
+ content = _jsxs(Box, { flexDirection: "column", children: [detailOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${detailOffset} 行`, status: "muted", compact: true }) : null, visibleLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${detailOffset + index}:${line}`)), detailOffset + visibleLines.length < lines.length
5246
+ ? _jsx(StaticRow, { title: `↓ 后面还有 ${lines.length - detailOffset - visibleLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
5247
+ }
5248
+ else {
5249
+ const affectedTargets = configSaveImpact?.affectedTargets ?? [];
5250
+ const hasConsumers = configSaveImpact?.impactState === 'known' && affectedTargets.length > 0;
5251
+ const visibleAffectedTargets = affectedTargets.slice(0, 1);
5252
+ const impactRowCount = 2;
5253
+ const configSummaryLimit = 1;
5254
+ const visibleChanges = changes.slice(0, configSummaryLimit);
5255
+ const targetSummary = affectedTargets
5256
+ .map((target) => `${platformLabel(target.platform)} · ${scopeLabel(target.scope)}`)
5257
+ .join('、');
5258
+ breadcrumb = `${plugin.displayName} / 设置 / 保存汇总`;
5259
+ context = `${changes.length} 项未保存`;
5260
+ title = `保存 ${changes.length} 项设置修改?`;
5261
+ description = route.layer.scope === 'project'
5262
+ ? '修改将保存到当前项目。'
5263
+ : '修改将保存为个人默认,并影响个人的所有项目;项目设置仍可覆盖。';
5264
+ actions = configSaveImpactError ? [
5265
+ {
5280
5266
  label: '重新检查影响',
5281
- description: '再次读取当前安装位置和配置消费者',
5267
+ description: '重新读取当前安装位置;检查成功前不能保存',
5282
5268
  run: () => setConfigSaveImpactAttempt((value) => value + 1),
5283
- }] : []),
5284
- { label: '返回修改', run: back },
5285
- ] : [{ label: '返回修改', run: back }];
5286
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "\u8BBE\u7F6E\u53D8\u66F4", compact: policy.mode === 'compact', children: changes.map((change) => _jsx(ReviewChangeRow, { title: `~ ${draftRemoves.includes(change.key) ? `删除 ${change.title} 中的值` : change.title}`, description: `${change.before} → ${change.after}`, compact: policy.mode === 'compact' }, change.key)) }), _jsxs(SectionCard, { title: "\u5E94\u7528\u5F71\u54CD", compact: policy.mode === 'compact', children: [!configSaveImpact && !configSaveImpactError
5287
- ? _jsx(ProgressRow, { title: "\u5206\u6790\u5B9E\u9645\u914D\u7F6E\u6D88\u8D39\u8005", state: "active" })
5288
- : hasConsumers
5289
- ? affectedTargets.map((target) => _jsx(StaticRow, { title: `${platformLabel(target.platform)} · ${scopeLabel(target.scope)}`, meta: "\u9700\u8981\u91CD\u65B0\u5E94\u7528", status: "warning", compact: true }, `${target.platform}:${target.scope}`))
5290
- : _jsx(StaticRow, { title: configSaveImpactError
5291
- ? '影响检查失败;设置尚未保存'
5292
- : configSaveImpact?.impactState === 'unknown'
5293
- ? '应用范围尚未确认;可以仅保存并稍后重查'
5294
- : '没有需要重新应用的已安装目标', status: configSaveImpactError || configSaveImpact?.impactState === 'unknown' ? 'warning' : 'success', compact: true }), _jsx(StaticRow, { title: "\u5176\u4ED6\u8BBE\u7F6E\u5C42\u4FDD\u6301\u4E0D\u53D8", status: "success", compact: true })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
5269
+ },
5270
+ { label: '返回修改', run: back },
5271
+ ] : configSaveImpact ? [
5272
+ hasConsumers ? {
5273
+ label: '保存并生效',
5274
+ description: `保存设置,并重新应用:${targetSummary}`,
5275
+ status: 'success',
5276
+ run: () => beginConfigSave(true),
5277
+ } : configSaveImpact.impactState === 'unknown' ? {
5278
+ label: '仅保存设置(应用范围尚未确认)',
5279
+ description: '保存所选设置层;不扩大到未确认的安装位置',
5280
+ status: 'warning',
5281
+ run: () => beginConfigSave(false),
5282
+ } : {
5283
+ label: '保存设置',
5284
+ description: '当前修改没有需要重新应用的已安装目标',
5285
+ status: 'success',
5286
+ run: () => beginConfigSave(false),
5287
+ },
5288
+ ...(hasConsumers ? [{
5289
+ label: '只保存,稍后应用',
5290
+ description: '保存所选设置层,不重新应用当前目标',
5291
+ run: () => beginConfigSave(false),
5292
+ }] : configSaveImpact.impactState === 'unknown' ? [{
5293
+ label: '重新检查影响',
5294
+ description: '再次读取当前安装位置和配置消费者',
5295
+ run: () => setConfigSaveImpactAttempt((value) => value + 1),
5296
+ }] : []),
5297
+ { label: '返回修改', run: back },
5298
+ ] : [{ label: '返回修改', run: back }];
5299
+ actions.splice(Math.max(0, actions.length - 1), 0, {
5300
+ label: '阅读完整设置变化',
5301
+ description: '分页查看每项修改前和修改后的完整值',
5302
+ run: () => {
5303
+ setBatchTargetOffset(0);
5304
+ go({ ...route, view: 'changes' });
5305
+ },
5306
+ });
5307
+ const configSaveStaticRows = 6 + visibleChanges.length * 2 + impactRowCount;
5308
+ const configSaveActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(configSaveStaticRows));
5309
+ const changeSectionTitle = visibleChanges.length < changes.length
5310
+ ? `设置变更 · 显示 ${visibleChanges.length}/${changes.length}(另 ${changes.length - visibleChanges.length} 项)`
5311
+ : '设置变更';
5312
+ const impactSectionTitle = hasConsumers && visibleAffectedTargets.length < affectedTargets.length
5313
+ ? `应用影响 · 显示 ${visibleAffectedTargets.length}/${affectedTargets.length}(另 ${affectedTargets.length - visibleAffectedTargets.length} 个)`
5314
+ : '应用影响';
5315
+ content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: changeSectionTitle, compact: policy.mode === 'compact', children: visibleChanges.map((change) => _jsx(ReviewChangeRow, { title: `~ ${draftRemoves.includes(change.key) ? `删除 ${change.title} 中的值` : change.title}`, value: `${change.before} → ${change.after}`, compact: true }, change.key)) }), _jsxs(SectionCard, { title: impactSectionTitle, compact: policy.mode === 'compact', children: [!configSaveImpact && !configSaveImpactError
5316
+ ? _jsx(ProgressRow, { title: "\u5206\u6790\u5B9E\u9645\u914D\u7F6E\u6D88\u8D39\u8005", state: "active" })
5317
+ : hasConsumers
5318
+ ? visibleAffectedTargets.map((target) => _jsx(StaticRow, { title: `${platformLabel(target.platform)} · ${scopeLabel(target.scope)}`, meta: "\u9700\u8981\u91CD\u65B0\u5E94\u7528", status: "warning", compact: true }, `${target.platform}:${target.scope}`))
5319
+ : _jsx(StaticRow, { title: configSaveImpactError
5320
+ ? '影响检查失败;设置尚未保存'
5321
+ : configSaveImpact?.impactState === 'unknown'
5322
+ ? '应用范围尚未确认;可以仅保存并稍后重查'
5323
+ : '没有需要重新应用的已安装目标', status: configSaveImpactError || configSaveImpact?.impactState === 'unknown' ? 'warning' : 'success', compact: true }), _jsx(StaticRow, { title: "\u5176\u4ED6\u8BBE\u7F6E\u5C42\u4FDD\u6301\u4E0D\u53D8", status: "success", compact: true })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: configSaveActionViewport.offset, limit: configSaveActionViewport.limit })] });
5324
+ }
5295
5325
  }
5296
5326
  else if (route.name === 'configFieldAction' && plugin && activeField) {
5297
5327
  const layer = configLayerLabel(route.layer);
@@ -5321,7 +5351,7 @@ export function ConsoleAppV4(props) {
5321
5351
  content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { children: [activeField.invalidOverrideIssue
5322
5352
  ? _jsx(StaticRow, { title: "\u5F53\u524D\u8986\u76D6\u65E0\u6548", meta: activeField.invalidOverrideIssue, status: "warning" })
5323
5353
  : null, !configFieldCanSet(activeField) && configFieldCanUnset(activeField)
5324
- ? _jsx(StaticRow, { title: "\u4E0D\u518D\u652F\u6301\u7684 project override", meta: "\u5B9E\u9645\u4F7F\u7528 user/default\uFF1B\u5220\u9664\u65E7\u503C\u540E\u4FDD\u6301\u7EE7\u627F", status: "warning" })
5354
+ ? _jsx(StaticRow, { title: "\u672C\u9879\u76EE\u65E7\u503C\u4E0D\u518D\u4F7F\u7528", meta: "\u5F53\u524D\u7EE7\u627F\u4E2A\u4EBA\u6216\u63D2\u4EF6\u9ED8\u8BA4\uFF1B\u5220\u9664\u65E7\u503C\u540E\u4FDD\u6301\u7EE7\u627F", status: "warning" })
5325
5355
  : null, _jsx(StaticRow, { title: `${layer}中的值`, meta: currentFieldDisplay(activeField) }), _jsx(StaticRow, { title: "\u5F53\u524D\u5B9E\u9645\u751F\u6548", meta: `${effectiveFieldDisplay(activeField)} · 来自${activeField.effectiveSourceLabel}` }), !activeField.invalidOverrideIssue || activeField.invalidOverrideOwnedByLayer
5326
5356
  ? _jsx(StaticRow, { title: "\u5220\u9664\u540E\u5C06\u6062\u590D", meta: `${activeField.fallbackDisplayValue ?? '未设置'} · 来自${activeField.fallbackSourceLabel ?? '未设置'}` })
5327
5357
  : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
@@ -5598,217 +5628,6 @@ export function ConsoleAppV4(props) {
5598
5628
  ]), _jsx(StaticRow, { title: "stage", meta: safeDiagnosticCode(route.diagnosticStage, 'read-config'), compact: true })] }) : null, unsupportedRows, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] })
5599
5629
  : _jsxs(Box, { flexDirection: "column", children: [_jsx(DiagnosticSummary, { diagnostic: diagnostic, technical: showTechnical, compact: policy.mode === 'compact' }), unsupportedRows, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
5600
5630
  }
5601
- else if (route.name === 'catalogManagement') {
5602
- breadcrumb = '插件来源 / 目录管理';
5603
- title = '目录管理';
5604
- description = '选择任务后才读取对应的本地状态。';
5605
- actions = [
5606
- { label: 'Catalog 工作区', description: '选择、创建、查看状态、修改版本、构建和验证', run: () => go({ name: 'catalogWorkspace', view: 'overview' }) },
5607
- { label: '开发来源', description: '查看、启用或停用当前 Workspace 的开发来源', run: () => go({ name: 'catalogDev' }) },
5608
- { label: '本地存储', description: '查看保留项并预览可安全清理的空间', run: () => go({ name: 'catalogStore' }) },
5609
- { label: 'Catalog 发布', description: '准备计划、独立应用和恢复可信 pending 计划', run: () => go({ name: 'catalogPublish', step: 'overview' }) },
5610
- ];
5611
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(CatalogManagementIntro, {}), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "task", compact: policy.mode === 'compact' })] });
5612
- }
5613
- else if (route.name === 'catalogWorkspace' && route.view === 'overview') {
5614
- const model = catalogWorkspace ? {
5615
- label: catalogWorkspace.label,
5616
- state: catalogWorkspace.state,
5617
- workspaceIdentity: catalogWorkspace.identity ?? undefined,
5618
- catalogVersion: catalogWorkspace.catalog.version ?? undefined,
5619
- channel: catalogWorkspace.catalog.channel ?? undefined,
5620
- pluginCount: catalogWorkspace.plugins.length,
5621
- snapshotState: catalogWorkspace.snapshot.state,
5622
- gitState: !catalogWorkspace.git.checked ? '未检查'
5623
- : !catalogWorkspace.git.hasHead ? '没有 HEAD'
5624
- : catalogWorkspace.git.clean ? 'clean' : '有未提交变化',
5625
- issues: catalogWorkspace.issues.map((issue) => issue.message),
5626
- } : undefined;
5627
- breadcrumb = '目录管理 / Catalog 工作区';
5628
- title = 'Catalog 工作区';
5629
- description = '状态读取不会 build、fetch、创建生成目录或运行插件代码。';
5630
- actions = [
5631
- { label: '选择其他工作区…', description: '输入路径;界面只显示目录名', run: () => { setCatalogInput(''); go({ name: 'catalogWorkspace', view: 'select' }); } },
5632
- ...(catalogWorkspace?.state !== 'ready' ? [{
5633
- label: '在所选目录创建工作区…', description: '输入 owner、显示名称和初始 Catalog 版本',
5634
- run: () => { setCatalogInput(catalogWorkspaceDraft.ownerName); go({ name: 'catalogWorkspace', view: 'create', step: 'ownerName' }); },
5635
- }] : []),
5636
- ...(catalogWorkspace?.state === 'ready' ? [
5637
- { label: '修改 Catalog 版本…', description: '选择 bump,或输入稳定版和精确 beta 版本', run: () => go({ name: 'catalogWorkspace', view: 'version' }) },
5638
- ...(catalogWorkspace.snapshot.state === 'absent' ? [{
5639
- label: '构建 Catalog…', description: `bundle 并验证 ${catalogWorkspace.plugins.length} 个 canonical plugins;写入 .aw/catalog`,
5640
- run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceBuild' }),
5641
- }] : catalogWorkspace.snapshot.valid ? [{
5642
- label: '重新构建 Catalog…', description: '替换已证明为生成物的 .aw/catalog;不删除其他内容',
5643
- status: 'warning',
5644
- run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceBuild', force: true }),
5645
- }] : [{
5646
- label: '生成目录无效,不能自动替换', description: '请检查问题并移开无法证明为生成物的目录后再构建',
5647
- status: 'error', disabled: '现有生成目录未通过安全验证',
5648
- }]),
5649
- { label: '完整验证生成目录', description: '只读验证现有 .aw/catalog,不重新构建', run: async () => {
5650
- setCatalogLoading(true);
5651
- setCatalogValidation(undefined);
5652
- setCatalogInputError(undefined);
5653
- try {
5654
- setCatalogValidation(await props.controller.validateCatalogWorkspace());
5655
- }
5656
- catch (error) {
5657
- setCatalogInputError(sanitizeDiagnosticText(error instanceof Error ? error.message : String(error), [], []));
5658
- }
5659
- finally {
5660
- setCatalogLoading(false);
5661
- }
5662
- } },
5663
- ] : []),
5664
- ];
5665
- const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(6));
5666
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(CatalogWorkspaceSummary, { model: model, loading: catalogLoading }), catalogValidation ? _jsxs(SectionCard, { title: "\u5B8C\u6574\u9A8C\u8BC1\u7ED3\u679C", children: [_jsx(StaticRow, { title: catalogValidation.state === 'valid' ? '生成目录有效' : catalogValidation.state === 'absent' ? '生成目录不存在' : '生成目录无效', meta: catalogValidation.catalogVersion ?? undefined, status: catalogValidation.state === 'valid' ? 'success' : 'warning', compact: true }), catalogValidation.issues.map((issue) => _jsx(StaticRow, { title: issue.message, meta: issue.code, status: "warning", compact: true }, issue.code))] }) : null, catalogInputError ? _jsx(Callout, { status: "error", title: "\u65E0\u6CD5\u8BFB\u53D6\u5DE5\u4F5C\u533A", description: catalogInputError }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit })] });
5667
- }
5668
- else if (route.name === 'catalogWorkspace' && route.view === 'select') {
5669
- breadcrumb = '目录管理 / Catalog 工作区 / 选择';
5670
- title = '输入 Workspace 路径';
5671
- description = '相对路径从当前目录解析;输入保持在本地,不写入配置。';
5672
- help = '输入 · Enter 选择 · Ctrl-U 清空 · Esc 取消';
5673
- content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: privatePathInput(catalogInput), columns: Math.max(8, size.columns - 8) }), description: catalogInputError ?? '留空可恢复从当前目录自动发现。', status: catalogInputError ? 'error' : undefined });
5674
- }
5675
- else if (route.name === 'catalogWorkspace' && route.view === 'create') {
5676
- const step = route.step ?? 'ownerName';
5677
- breadcrumb = '目录管理 / Catalog 工作区 / 创建';
5678
- context = { ownerName: '第 1 步,共 4 步', ownerUrl: '第 2 步,共 4 步', displayName: '第 3 步,共 4 步', catalogVersion: '第 4 步,共 4 步' }[step];
5679
- title = { ownerName: '输入 owner 名称', ownerUrl: '输入 owner URL', displayName: '输入 Catalog 显示名称', catalogVersion: '输入初始 Catalog 版本' }[step];
5680
- description = step === 'catalogVersion' ? '允许稳定 x.y.z 或精确 x.y.z-beta.N。' : '所有字段会在创建确认中再次显示。';
5681
- help = '输入 · Enter 继续 · Ctrl-U 清空 · Esc 取消';
5682
- const displayValue = step === 'ownerUrl'
5683
- ? catalogInput ? `已输入 owner URL(${Array.from(catalogInput).length} 字符)` : ''
5684
- : catalogInput;
5685
- content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: displayValue, columns: Math.max(8, size.columns - 8) }), description: catalogInputError ?? '按 Enter 继续。', status: catalogInputError ? 'error' : undefined });
5686
- }
5687
- else if (route.name === 'catalogWorkspace' && route.view === 'version') {
5688
- breadcrumb = '目录管理 / Catalog 工作区 / 版本';
5689
- title = route.step === 'catalogVersion' ? '输入精确 Catalog 版本' : '修改 Catalog 版本';
5690
- description = route.step === 'catalogVersion' ? '允许稳定 x.y.z 或精确 x.y.z-beta.N。' : `当前版本:${catalogWorkspace?.catalog.version ?? '未知'}`;
5691
- if (route.step === 'catalogVersion') {
5692
- help = '输入 · Enter 确认 · Ctrl-U 清空 · Esc 取消';
5693
- content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: catalogInput, columns: Math.max(8, size.columns - 8) }), description: catalogInputError ?? '此动作会进入独立确认。', status: catalogInputError ? 'error' : undefined });
5694
- }
5695
- else {
5696
- actions = [
5697
- { label: '提高 patch 版本', run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceVersion', bump: 'patch' }, { name: 'catalogWorkspace', view: 'overview' }) },
5698
- { label: '提高 minor 版本', run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceVersion', bump: 'minor' }, { name: 'catalogWorkspace', view: 'overview' }) },
5699
- { label: '提高 major 版本', run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceVersion', bump: 'major' }, { name: 'catalogWorkspace', view: 'overview' }) },
5700
- { label: '输入精确版本…', description: '用于指定稳定版或精确 beta.N', run: () => { setCatalogInput(''); go({ name: 'catalogWorkspace', view: 'version', step: 'catalogVersion' }); } },
5701
- ];
5702
- content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' });
5703
- }
5704
- }
5705
- else if (route.name === 'catalogDev' && (!route.step || route.step === 'overview')) {
5706
- const snapshotReady = catalogDev?.snapshot.state === 'current' && catalogDev.snapshot.valid;
5707
- breadcrumb = '目录管理 / 开发来源';
5708
- title = '开发来源';
5709
- description = '状态只读取所选 Workspace、managed Path source 和 Active digest。';
5710
- actions = [
5711
- { label: '设置开发来源 ID…', description: catalogDevSourceId || '使用安全默认值', run: () => { setCatalogInput(catalogDevSourceId); go({ name: 'catalogDev', step: 'sourceId' }); } },
5712
- ...!snapshotReady ? catalogDev?.snapshot.state === 'absent' ? [
5713
- { label: '先构建 Catalog…', description: '先完成独立构建确认;构建成功后返回此页再确认启用',
5714
- run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceBuild' }, { name: 'catalogDev' }) },
5715
- ] : catalogDev?.snapshot.state === 'stale' && catalogDev.snapshot.valid ? [
5716
- { label: '先重新构建 Catalog…', description: '独立确认替换受管的旧 .aw/catalog;成功后返回此页再确认启用',
5717
- status: 'warning',
5718
- run: () => beginReview({ kind: 'catalogManagement', action: 'workspaceBuild', force: true }, { name: 'catalogDev' }) },
5719
- ] : [
5720
- { label: '生成目录无效,不能自动替换', description: '请先在 Workspace 管理页检查问题;移开无法证明为生成物的目录后再构建',
5721
- status: 'error', disabled: '现有生成目录未通过安全验证' },
5722
- ] : catalogDev?.source.exists ? [
5723
- ...!catalogDev.ready && snapshotReady ? [{
5724
- label: '重新启用并同步开发来源…', description: '来源配置已存在;重新使用当前有效 snapshot 完成 sync 和 Active 切换',
5725
- status: 'warning',
5726
- run: () => beginReview({ kind: 'catalogManagement', action: 'devActivate',
5727
- ...(catalogDevSourceId ? { sourceId: catalogDevSourceId } : {}) }, { name: 'catalogDev' }),
5728
- }] : [],
5729
- { label: '停用开发来源…', description: '保留 .aw/catalog;检查安装、设置和 Marketplace 引用', run: () => beginReview({ kind: 'catalogManagement', action: 'devDeactivate' }) },
5730
- { label: '停用并选择替代主来源…', description: '开发来源为主来源时使用', run: () => { setCatalogInput(''); go({ name: 'catalogDev', step: 'replacementPrimary' }); } },
5731
- ] : [
5732
- { label: '启用开发来源…', description: '使用当前有效 snapshot 注册 managed Path source 并 sync', run: () => beginReview({ kind: 'catalogManagement', action: 'devActivate', ...(catalogDevSourceId ? { sourceId: catalogDevSourceId } : {}) }) },
5733
- { label: '启用并设为主来源…', description: '将来源启用和主来源变化放在同一影响确认中', run: () => beginReview({ kind: 'catalogManagement', action: 'devActivate', primary: true, ...(catalogDevSourceId ? { sourceId: catalogDevSourceId } : {}) }) },
5734
- ],
5735
- ];
5736
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: catalogDev?.ready ? 'success' : catalogDev?.state === 'needsAttention' ? 'warning' : 'info', title: catalogLoading ? '正在读取开发来源' : catalogDev?.ready ? '开发来源可用' : catalogDev?.state === 'inactive' ? '开发来源未启用' : '开发来源需要处理', children: catalogDev ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u751F\u6210\u76EE\u5F55", meta: catalogDev.snapshot.state, compact: true }), _jsx(StaticRow, { title: "\u6765\u6E90", meta: catalogDev.source.id ?? '未注册', compact: true }), _jsx(StaticRow, { title: "Active", meta: catalogDev.active.ready ? '可用' : catalogDev.active.exists ? '需要处理' : '不存在', compact: true })] }) : null }), catalogInputError ? _jsx(Callout, { status: "error", title: "\u65E0\u6CD5\u8BFB\u53D6\u5F00\u53D1\u6765\u6E90", description: catalogInputError }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
5737
- }
5738
- else if (route.name === 'catalogDev') {
5739
- const replacement = route.step === 'replacementPrimary';
5740
- breadcrumb = '目录管理 / 开发来源 / 输入';
5741
- title = replacement ? '输入替代主来源 ID' : '输入开发来源 ID';
5742
- description = replacement ? '停用和主来源变化会进入同一次影响确认。' : '留空可使用安全默认 ID。';
5743
- help = '输入 · Enter 继续 · Ctrl-U 清空 · Esc 取消';
5744
- content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: catalogInput, columns: Math.max(8, size.columns - 8) }), description: catalogInputError ?? '按 Enter 继续。', status: catalogInputError ? 'error' : undefined });
5745
- }
5746
- else if (route.name === 'catalogStore') {
5747
- const entries = catalogStore?.entries ?? [];
5748
- const pageRows = responsiveBudget(3, 7);
5749
- const entryOffset = Math.min(batchTargetOffset, Math.max(0, entries.length - 1));
5750
- const entryEnd = Math.min(entries.length, entryOffset + pageRows);
5751
- const reclaimable = entries.filter((entry) => entry.status === 'reclaimable');
5752
- breadcrumb = '目录管理 / 本地存储';
5753
- title = '本地 Catalog Store';
5754
- description = '只清理已确认且执行时仍安全的弱状态;未知、foreign 和 Active 内容始终保留。';
5755
- if (entries.length > pageRows)
5756
- help = 'PgUp/PgDn 查看全部条目 · ↑↓ 移动 · Enter 选择 · Esc 返回';
5757
- actions = [{
5758
- label: '预览并清理可安全释放的空间…',
5759
- description: `${reclaimable.length} 项;确认后新增候选不进入本次删除集合`,
5760
- disabled: reclaimable.length ? undefined : '当前没有可安全清理的条目',
5761
- run: () => beginReview({ kind: 'catalogManagement', action: 'storePrune', items: reclaimable.map((entry) => entry.item) }),
5762
- }];
5763
- content = _jsxs(Box, { flexDirection: "column", children: [catalogStore ? _jsx(CatalogStoreSummary, { reclaimableCount: catalogStore.totals.reclaimableEntries, reclaimableBytes: catalogStore.totals.reclaimableBytes ?? 0, retainedCount: catalogStore.totals.retainedEntries, entries: entries.map((entry) => ({ key: entry.itemKey, title: `${entry.category} · ${entry.itemKey}`, meta: `${entry.reason}${entry.reclaimableBytes === null ? '' : ` · ${entry.reclaimableBytes} bytes`}`, status: entry.status === 'error' ? 'unsafe' : entry.status === 'active' ? 'retained' : entry.status })), before: entryOffset, after: entryEnd }) : _jsx(StatusCard, { status: "info", title: "\u6B63\u5728\u8BFB\u53D6\u672C\u5730 Catalog Store" }), catalogInputError ? _jsx(Callout, { status: "error", title: "\u65E0\u6CD5\u8BFB\u53D6 Store", description: catalogInputError }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
5764
- }
5765
- else if (route.name === 'catalogPublish' && route.step === 'overview') {
5766
- const records = catalogPublication?.records ?? [];
5767
- const pageRows = responsiveBudget(3, 7);
5768
- const recordOffset = Math.min(batchTargetOffset, Math.max(0, records.length - 1));
5769
- const recordEnd = Math.min(records.length, recordOffset + pageRows);
5770
- breadcrumb = '目录管理 / Catalog 发布';
5771
- title = 'Catalog 发布';
5772
- description = '准备计划与应用计划是两个独立写入动作。';
5773
- if (records.length > pageRows)
5774
- help = 'PgUp/PgDn 查看全部记录 · ↑↓ 移动 · Enter 选择 · Esc 返回';
5775
- actions = [
5776
- { label: '准备新发布计划…', description: '下一步输入 remote 或 URL 与 branch;执行 plan 会写 version-scoped journal 和隔离仓库', run: () => { setCatalogInput(catalogPublishDraft.expectedPlanDigest ? '' : catalogPublishDraft.target); setCatalogPublishDraft((draft) => draft.expectedPlanDigest ? { targetKind: 'remote', target: '', branch: 'catalog' } : draft); go({ name: 'catalogPublish', step: 'target' }); } },
5777
- ...records.filter((record) => record.canApply && record.planDigest).map((record) => ({
5778
- label: `${record.state === 'uncertain' ? '对账或继续' : '应用'} ${record.catalogVersion}…`,
5779
- description: record.requiresRemoteInput
5780
- ? '重新输入原 remote 名称或 URL;只恢复现有可信 plan digest'
5781
- : '只使用现有可信 plan digest;不会从当前源码重建计划',
5782
- status: record.state === 'uncertain' ? 'warning' : undefined,
5783
- run: () => record.requiresRemoteInput
5784
- ? (() => {
5785
- setCatalogPublishDraft({ targetKind: 'remote', target: '', branch: record.branch ?? 'catalog', expectedPlanDigest: record.planDigest });
5786
- setCatalogInput('');
5787
- go({ name: 'catalogPublish', step: 'target' });
5788
- })()
5789
- : beginReview({ kind: 'catalogManagement', action: 'publishApply', expectedPlanDigest: record.planDigest, ...(record.remote ? { remote: record.remote } : {}), ...(record.branch ? { branch: record.branch } : {}) }, { name: 'catalogPublish', step: 'overview' }),
5790
- })),
5791
- ...records.filter((record) => record.mustIncreaseVersion).map((record) => ({
5792
- label: `${record.catalogVersion} 无法恢复`, description: 'journal 或 pending repository 缺失或损坏;请提高 Catalog 版本后创建新计划', status: 'error', disabled: '不能重建或复用此版本',
5793
- })),
5794
- ];
5795
- const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(5));
5796
- content = _jsxs(Box, { flexDirection: "column", children: [catalogPublication ? _jsx(CatalogPublicationSummary, { records: records.map((record) => ({ key: `${record.catalogVersion}:${record.state}`, catalogVersion: record.catalogVersion, state: record.state, branch: record.branch ?? undefined, message: record.issue?.message })), before: recordOffset, after: recordEnd }) : _jsx(StatusCard, { status: "info", title: "\u6B63\u5728\u8BFB\u53D6\u672C\u5730\u53D1\u5E03\u8BB0\u5F55" }), catalogInputError ? _jsx(Callout, { status: "error", title: "\u65E0\u6CD5\u8BFB\u53D6\u53D1\u5E03\u8BB0\u5F55", description: catalogInputError }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit })] });
5797
- }
5798
- else if (route.name === 'catalogPublish') {
5799
- breadcrumb = '目录管理 / Catalog 发布 / 准备计划';
5800
- title = route.step === 'target' ? '输入 remote 名称或 remote URL' : '输入发布 branch';
5801
- description = route.step === 'target'
5802
- ? catalogPublishDraft.expectedPlanDigest
5803
- ? '重新输入原目标。后端会与现有 plan digest 中的目标身份核对。'
5804
- : 'URL 只显示脱敏摘要;remote 名称按原样使用。'
5805
- : '留空使用固定默认 branch:catalog。';
5806
- help = '输入 · Enter 继续 · Ctrl-U 清空 · Esc 取消';
5807
- const displayValue = route.step === 'target'
5808
- ? catalogInput ? `已输入远程目标(${Array.from(catalogInput).length} 字符)` : ''
5809
- : catalogInput;
5810
- content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: displayValue, columns: Math.max(8, size.columns - 8) }), description: catalogInputError ?? (route.step === 'branch' ? '执行 plan 会写 publication journal 和隔离仓库;取消 Review 不写入。' : '按 Enter 继续。'), status: catalogInputError ? 'error' : undefined });
5811
- }
5812
5631
  else if (route.name === 'sourceList') {
5813
5632
  breadcrumb = '插件来源';
5814
5633
  title = '插件来源';
@@ -5843,14 +5662,9 @@ export function ConsoleAppV4(props) {
5843
5662
  description: '并行检查各来源;结果不会自动启用待检查版本',
5844
5663
  run: () => props.controller.recheckAllCatalogSources(),
5845
5664
  },
5846
- {
5847
- label: '目录管理…',
5848
- description: 'Catalog 工作区、开发来源、本地存储和发布',
5849
- run: () => go({ name: 'catalogManagement' }),
5850
- },
5851
5665
  ];
5852
5666
  const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(8, 12));
5853
- const sourceCount = Math.max(0, actions.length - 3);
5667
+ const sourceCount = Math.max(0, actions.length - 2);
5854
5668
  content = _jsx(Box, { flexDirection: "column", children: _jsx(SemanticRows, { actions: actions, focus: focus, kind: focus < sourceCount ? 'section' : 'action', compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit }) });
5855
5669
  }
5856
5670
  else if (route.name === 'sourceDetail') {
@@ -6240,13 +6054,13 @@ export function ConsoleAppV4(props) {
6240
6054
  setSourceTransportOverlay({ owner: active.owner });
6241
6055
  setOverlayFocus(officialTransport === 'HTTPS' ? 0 : 1);
6242
6056
  },
6243
- }] : [{ label: draft?.type === 'path' || detail?.type === 'path' ? '本地目录' : 'Git 仓库地址', description: locationSummary, run: () => startDraftField('location') }]),
6057
+ }] : [{ label: draft?.type === 'path' || detail?.type === 'path' ? '本地目录' : 'Git 仓库地址', meta: locationSummary, run: () => startDraftField('location') }]),
6244
6058
  ...(draft?.type === 'git' || !draft && detail?.type === 'git' ? [
6245
- { label: '版本引用', description: draft ? draft.refPolicy === 'explicit' ? `固定:${draft.ref}` : '跟随 AW 版本通道' : detail?.refPolicy === 'explicit' ? `固定:${detail.explicitRef}` : '跟随 AW 版本通道', run: () => startDraftField('refPolicy') },
6246
- { label: '高级:Catalog 子目录', description: catalogSubdir === '' || catalogSubdir === undefined
6059
+ { label: '版本引用', meta: draft ? draft.refPolicy === 'explicit' ? `固定:${draft.ref}` : '跟随 AW 版本通道' : detail?.refPolicy === 'explicit' ? `固定:${detail.explicitRef}` : '跟随 AW 版本通道', run: () => startDraftField('refPolicy') },
6060
+ { label: '高级:Catalog 子目录', meta: catalogSubdir === '' || catalogSubdir === undefined
6247
6061
  ? '仓库根目录' : catalogSubdir, run: () => startDraftField('subdir') },
6248
6062
  ] : []),
6249
- { label: '自动检查更新', description: (draft?.autoCheck ?? detail?.autoCheck) ? '已开启' : '已关闭', selected: draft?.autoCheck ?? detail?.autoCheck, run: () => {
6063
+ { label: '自动检查更新', meta: (draft?.autoCheck ?? detail?.autoCheck) ? '已开启' : '已关闭', selected: draft?.autoCheck ?? detail?.autoCheck, run: () => {
6250
6064
  if (!draft) {
6251
6065
  const source = props.controller.getConfiguredSource(route.sourceId);
6252
6066
  if (!source)
@@ -6273,32 +6087,59 @@ export function ConsoleAppV4(props) {
6273
6087
  }
6274
6088
  else if (route.name === 'sourceSave' && sourceDraft?.owner === route.owner) {
6275
6089
  const changes = sourceDraftChanges(sourceDraft);
6276
- const savedSource = props.controller.getConfiguredSource(sourceDraft.sourceId);
6277
- const protocolOnly = changes.length === 1 && changes[0]?.title === 'Git 仓库地址'
6278
- && savedSource?.type === 'git'
6279
- && (savedSource.url === OFFICIAL_CATALOG_SOURCE_URL
6280
- || savedSource.url === OFFICIAL_CATALOG_SOURCE_SSH_URL)
6281
- && (sourceDraft.location === OFFICIAL_CATALOG_SOURCE_URL
6282
- || sourceDraft.location === OFFICIAL_CATALOG_SOURCE_SSH_URL);
6283
- breadcrumb = `插件来源 / ${sourceDraft.sourceId} / 修改汇总`;
6284
- context = `${changes.length} 项未保存`;
6285
- title = sourceDraft.mode === 'add' ? `保存新来源 ${sourceDraft.sourceId}?` : `保存 ${sourceDraft.sourceId} 的修改?`;
6286
- description = '选择是否在保存后验证候选并启用。保存成功与启用成功会分别报告。';
6287
- actions = [
6288
- ...(protocolOnly ? [] : [{ label: '保存并启用', description: '保存来源配置,再验证并切换当前目录版本', status: 'success', run: () => beginSourceReview(sourceDraft, true) }]),
6289
- { label: protocolOnly ? '只保存下载方式' : '只保存', description: '只保存来源配置;当前目录版本保持不变', status: protocolOnly ? 'success' : undefined, run: () => beginSourceReview(sourceDraft, false) },
6290
- ...(protocolOnly ? [{ label: '保存并启用…', description: '保存后验证并切换当前目录版本', run: () => beginSourceReview(sourceDraft, true) }] : []),
6291
- { label: '返回修改', run: back },
6292
- ];
6293
- content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "\u6765\u6E90\u53D8\u5316", compact: policy.mode === 'compact', children: changes.map((change) => _jsx(ReviewChangeRow, { title: `~ ${change.title}`, description: `${change.before ?? '未设置'} → ${change.after}`, compact: policy.mode === 'compact' }, change.title)) }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
6090
+ if (route.view === 'changes') {
6091
+ const lines = changeDetailLines(changes, size.columns - 4);
6092
+ const pageRows = responsiveBudget(5, 10);
6093
+ const detailOffset = Math.min(batchTargetOffset, Math.max(0, lines.length - 1));
6094
+ const visibleLines = lines.slice(detailOffset, detailOffset + pageRows);
6095
+ referenceDetailPagination = { total: lines.length, pageRows };
6096
+ breadcrumb = `插件来源 / ${sourceDraft.sourceId} / 完整变化`;
6097
+ context = `${Math.min(detailOffset + 1, lines.length)}–${Math.min(detailOffset + visibleLines.length, lines.length)} / ${lines.length}`;
6098
+ title = '完整来源变化';
6099
+ description = '逐项显示修改前和修改后的完整值。';
6100
+ help = 'PgUp/PgDn 阅读 · Enter 返回修改汇总 · Esc 返回修改汇总';
6101
+ actions = [{ label: '返回修改汇总', run: back }];
6102
+ content = _jsxs(Box, { flexDirection: "column", children: [detailOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${detailOffset} 行`, status: "muted", compact: true }) : null, visibleLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${detailOffset + index}:${line}`)), detailOffset + visibleLines.length < lines.length
6103
+ ? _jsx(StaticRow, { title: `↓ 后面还有 ${lines.length - detailOffset - visibleLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
6104
+ }
6105
+ else {
6106
+ const savedSource = props.controller.getConfiguredSource(sourceDraft.sourceId);
6107
+ const protocolOnly = changes.length === 1 && changes[0]?.title === 'Git 仓库地址'
6108
+ && savedSource?.type === 'git'
6109
+ && (savedSource.url === OFFICIAL_CATALOG_SOURCE_URL
6110
+ || savedSource.url === OFFICIAL_CATALOG_SOURCE_SSH_URL)
6111
+ && (sourceDraft.location === OFFICIAL_CATALOG_SOURCE_URL
6112
+ || sourceDraft.location === OFFICIAL_CATALOG_SOURCE_SSH_URL);
6113
+ breadcrumb = `插件来源 / ${sourceDraft.sourceId} / 修改汇总`;
6114
+ context = `${changes.length} 项未保存`;
6115
+ title = sourceDraft.mode === 'add' ? `保存新来源 ${sourceDraft.sourceId}?` : `保存 ${sourceDraft.sourceId} 的修改?`;
6116
+ description = '选择是否在保存后验证候选并启用。保存成功与启用成功会分别报告。';
6117
+ actions = [
6118
+ ...(protocolOnly ? [] : [{ label: '保存并启用', description: '保存来源配置,再验证并切换当前目录版本', status: 'success', run: () => beginSourceReview(sourceDraft, true) }]),
6119
+ { label: protocolOnly ? '只保存下载方式' : '只保存', description: '只保存来源配置;当前目录版本保持不变', status: protocolOnly ? 'success' : undefined, run: () => beginSourceReview(sourceDraft, false) },
6120
+ ...(protocolOnly ? [{ label: '保存并启用…', description: '保存后验证并切换当前目录版本', run: () => beginSourceReview(sourceDraft, true) }] : []),
6121
+ { label: '阅读完整来源变化', description: '分页查看每项修改前和修改后的完整值', run: () => {
6122
+ setBatchTargetOffset(0);
6123
+ go({ ...route, view: 'changes' });
6124
+ } },
6125
+ { label: '返回修改', run: back },
6126
+ ];
6127
+ const sourceSummaryLimit = 1;
6128
+ const visibleChanges = changes.slice(0, sourceSummaryLimit);
6129
+ const sourceSaveActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(3 + visibleChanges.length * 2));
6130
+ const changeSectionTitle = visibleChanges.length < changes.length
6131
+ ? `来源变化 · 显示 ${visibleChanges.length}/${changes.length}(另 ${changes.length - visibleChanges.length} 项)`
6132
+ : '来源变化';
6133
+ content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: changeSectionTitle, compact: policy.mode === 'compact', children: visibleChanges.map((change) => _jsx(ReviewChangeRow, { title: `~ ${change.title}`, value: `${change.before ?? '未设置'} → ${change.after}`, compact: true }, change.title)) }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: sourceSaveActionViewport.offset, limit: sourceSaveActionViewport.limit })] });
6134
+ }
6294
6135
  }
6295
6136
  else if (route.name === 'scriptTimeout' && pendingReviewIntent) {
6296
6137
  breadcrumb = '高级选项 / 安装前检查脚本';
6297
6138
  context = '毫秒';
6298
6139
  title = '设置脚本超时';
6299
6140
  description = `输入 ${SCRIPT_TIMEOUT_MIN_MS}–${SCRIPT_TIMEOUT_MAX_MS} 毫秒。默认 ${SCRIPT_TIMEOUT_DEFAULT_MS} 毫秒。`;
6300
- help = '输入 · Enter 应用并重新准备 Review · Ctrl-U 清空 · Esc 取消';
6301
- content = _jsx(Box, { flexDirection: "column", children: _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: scriptTimeoutInput, columns: Math.max(8, size.columns - 8) }), description: scriptTimeoutError ?? '此值将绑定本次 Review。', status: scriptTimeoutError ? 'error' : undefined }) });
6141
+ help = '输入 · Enter 应用并重新显示操作汇总 · Ctrl-U 清空 · Esc 取消';
6142
+ content = _jsx(Box, { flexDirection: "column", children: _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: scriptTimeoutInput, columns: Math.max(8, size.columns - 8) }), description: scriptTimeoutError ?? '此值只用于本次操作汇总。', status: scriptTimeoutError ? 'error' : undefined }) });
6302
6143
  }
6303
6144
  else if (route.name === 'sourceRemoveBlocked') {
6304
6145
  breadcrumb = `插件来源 / ${route.sourceId} / 移除`;
@@ -6619,6 +6460,17 @@ export function ConsoleAppV4(props) {
6619
6460
  ? 'Esc 取消 · Ctrl-C 完成后退出'
6620
6461
  : '↑↓ 移动 · Enter 选择 · Esc 返回';
6621
6462
  actions = preparation.state === 'failed' ? [
6463
+ ...[...new Map((preparation.operationRecordId
6464
+ ? props.controller.getOperationDiagnostic(preparation.operationRecordId)?.diagnostics ?? []
6465
+ : []).flatMap((diagnostic) => diagnostic.stage === 'dependencyPlan'
6466
+ && diagnostic.target?.pluginId
6467
+ && props.controller.getPluginOverview(diagnostic.target.pluginId)
6468
+ ? [[`${diagnostic.target.pluginId}:${diagnostic.target.platform}`, diagnostic.target]]
6469
+ : [])).values()].map((target) => ({
6470
+ label: `处理 ${props.controller.getPluginOverview(target.pluginId).displayName}`,
6471
+ description: '查看这个依赖的问题和可用的恢复操作',
6472
+ run: () => go({ name: 'platform', pluginId: target.pluginId, platform: target.platform }),
6473
+ })),
6622
6474
  { label: '重试', description: '重新读取和验证当前状态', run: () => {
6623
6475
  props.controller.retryReviewPreparation();
6624
6476
  setFocus(0);
@@ -6639,7 +6491,6 @@ export function ConsoleAppV4(props) {
6639
6491
  : review.pluginAction === 'install' ? snapshot.installPlacementDraft?.pluginId : undefined;
6640
6492
  const batchReview = review.operationKind === 'pluginWriteBatch';
6641
6493
  const taskReview = review.operationKind === 'pluginWriteTask';
6642
- const catalogManagementReview = review.operationKind === 'catalogManagement';
6643
6494
  breadcrumb = `${review.subject.name} / ${review.title}`;
6644
6495
  title = `${snapshot.result?.state === 'stale' ? '状态已变化 · ' : ''}${review.operationKind === 'portableInstall' || taskReview
6645
6496
  ? review.title : `确认${review.title}`} ${review.subject.name}`;
@@ -6647,7 +6498,7 @@ export function ConsoleAppV4(props) {
6647
6498
  ? '当前状态已变化。请检查新的变化后再次确认。'
6648
6499
  : review.description;
6649
6500
  if (taskReview) {
6650
- context = '精确目标 · 用户任务';
6501
+ context = '本次选择 · 用户任务';
6651
6502
  help = 'PgUp/PgDn 查看全部影响 · ↑↓ 移动 · Enter 选择 · Esc 返回';
6652
6503
  }
6653
6504
  else if (batchReview) {
@@ -6684,7 +6535,7 @@ export function ConsoleAppV4(props) {
6684
6535
  && batchDraft?.frozenPluginIds ? [{
6685
6536
  label: `调整选择(${new Set(pendingReviewIntent.targets
6686
6537
  .map((target) => target.pluginId)).size})`,
6687
- description: '只可删减或恢复本次冻结的推荐插件;调整后重新读取证据并建立 Review',
6538
+ description: '只可删减或恢复本次推荐插件;调整后重新读取状态并显示操作汇总',
6688
6539
  run: () => {
6689
6540
  if (!props.controller.returnToPluginWriteTaskBatchSelection(batchDraft.flowId)) {
6690
6541
  setActionError('推荐选择已失效。请返回我的插件重新开始。');
@@ -6740,7 +6591,7 @@ export function ConsoleAppV4(props) {
6740
6591
  ...(installReviewPluginId
6741
6592
  && (snapshot.installPlacementDraft?.targets.length ?? 0) > 0 ? [{
6742
6593
  label: '查看/调整依赖位置',
6743
- description: '当前已采用 planner 推荐位置;调整后会重新建立 Review',
6594
+ description: '当前已自动安排依赖位置;调整后会重新显示操作汇总',
6744
6595
  run: () => {
6745
6596
  props.controller.push({
6746
6597
  name: 'dependencyPlacement',
@@ -6750,17 +6601,7 @@ export function ConsoleAppV4(props) {
6750
6601
  setScrollOffset(0);
6751
6602
  },
6752
6603
  }] : []),
6753
- ...((pendingReviewIntent?.kind === 'pluginWrite'
6754
- && (pendingReviewIntent.action === 'install'
6755
- || pendingReviewIntent.action === 'refreshAndSync'
6756
- || pendingReviewIntent.action === 'reinstall'
6757
- || pendingReviewIntent.action === 'sync')
6758
- || pendingReviewIntent?.kind === 'pluginWriteBatch'
6759
- && (pendingReviewIntent.action === 'install'
6760
- || pendingReviewIntent.action === 'sync'
6761
- || pendingReviewIntent.action === 'reinstall')
6762
- || pendingReviewIntent?.kind === 'pluginWriteTask'
6763
- || pendingReviewIntent?.kind === 'configSave' && pendingReviewIntent.apply) ? [{
6604
+ ...(supportsScriptTimeout(pendingReviewIntent) ? [{
6764
6605
  label: '高级选项:脚本超时',
6765
6606
  description: `${pendingReviewIntent.scriptTimeoutMs ?? SCRIPT_TIMEOUT_DEFAULT_MS} 毫秒`,
6766
6607
  run: () => {
@@ -6907,11 +6748,10 @@ export function ConsoleAppV4(props) {
6907
6748
  && (review.changes.length > technicalChangeBudget || technicalDetails.length > technicalDetailLimit)) {
6908
6749
  help = 'PgUp/PgDn 查看全部确认信息 · ↑↓ 移动 · Enter 选择 · Esc 返回';
6909
6750
  }
6910
- content = _jsx(Box, { flexDirection: "column", children: _jsxs(ReviewCard, { title: review.subject.name, meta: `${review.subject.sourceLabel ?? ''} ${review.subject.version ?? ''}`, description: showEquivalentCommand ? review.description : undefined, children: [showEquivalentCommand ? _jsxs(Text, { children: ["\u7B49\u4EF7\u547D\u4EE4\uFF1A", review.equivalentCommand] }) : null, showTechnical && review.catalogBinding ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `Catalog:${review.catalogBinding.sourceId} ${review.catalogBinding.catalogVersion} · 当前使用`, meta: `generation ${review.catalogBinding.generationDigestShort}`, status: "success", compact: true }), _jsx(StaticRow, { title: "\u64CD\u4F5C\u671F\u95F4\u4E0D\u68C0\u67E5\u8FDC\u7AEF Catalog", status: "success", compact: true })] }) : null, installDependencyPluginIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `需要 ${installDependencyPluginIds.size} 个额外插件;${reusedDependencyPluginIds.size} 个复用、${newDependencyCount} 个新增`, status: "info", compact: true }), _jsx(StaticRow, { title: widenedDependencyCount > 0 ? `${widenedDependencyCount} 个依赖会扩大到所有项目` : '没有依赖会扩大到所有项目', status: widenedDependencyCount > 0 ? 'warning' : 'success', compact: true })] }) : null, review.requiresConfirmation ? _jsx(StaticRow, { title: catalogManagementReview ? '! 需要确认本次写入' : '! 需要确认共享影响', meta: !catalogManagementReview && review.sharedImpact.pluginIds.length > 0 ? `${review.sharedImpact.pluginIds.length} 个插件` : undefined, description: catalogManagementReview ? review.description : review.sharedImpact.warning, status: "warning", compact: true }) : null, showTechnical ? technicalChanges : changeGroups, _jsx(SemanticRows, { actions: actions, focus: operationConfirmation ? -1 : focus, kind: "action", compact: true }), compressedReview || showTechnical ? null : _jsx(StaticRow, { title: "\u6280\u672F\u8BE6\u60C5\uFF08d\uFF09", status: "muted" }), showTechnical ? _jsx(TechnicalDetails, { children: visibleTechnicalDetails.map((detail, index) => _jsx(StaticRow, { title: detail, meta: index === visibleTechnicalDetails.length - 1 && hiddenTechnicalDetails > 0 ? `另有 ${hiddenTechnicalDetails} 项` : undefined, compact: true }, detail)) }) : null] }) });
6751
+ content = _jsx(Box, { flexDirection: "column", children: _jsxs(ReviewCard, { title: review.subject.name, meta: `${review.subject.sourceLabel ?? ''} ${review.subject.version ?? ''}`, description: showEquivalentCommand ? review.description : undefined, children: [showEquivalentCommand ? _jsxs(Text, { children: ["\u7B49\u4EF7\u547D\u4EE4\uFF1A", review.equivalentCommand] }) : null, showTechnical && review.catalogBinding ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `Catalog:${review.catalogBinding.sourceId} ${review.catalogBinding.catalogVersion} · 当前使用`, meta: `generation ${review.catalogBinding.generationDigestShort}`, status: "success", compact: true }), _jsx(StaticRow, { title: "\u64CD\u4F5C\u671F\u95F4\u4E0D\u68C0\u67E5\u8FDC\u7AEF Catalog", status: "success", compact: true })] }) : null, installDependencyPluginIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `需要 ${installDependencyPluginIds.size} 个额外插件;${reusedDependencyPluginIds.size} 个复用、${newDependencyCount} 个新增`, status: "info", compact: true }), _jsx(StaticRow, { title: widenedDependencyCount > 0 ? `${widenedDependencyCount} 个依赖会扩大到所有项目` : '没有依赖会扩大到所有项目', status: widenedDependencyCount > 0 ? 'warning' : 'success', compact: true })] }) : null, review.requiresConfirmation ? _jsx(StaticRow, { title: "! \u9700\u8981\u786E\u8BA4\u4F1A\u5F71\u54CD\u5176\u4ED6\u9879\u76EE\u7684\u5185\u5BB9", meta: review.sharedImpact.pluginIds.length > 0 ? `${review.sharedImpact.pluginIds.length} 个插件` : undefined, description: review.sharedImpact.warning, status: "warning", compact: true }) : null, showTechnical ? technicalChanges : changeGroups, _jsx(SemanticRows, { actions: actions, focus: operationConfirmation ? -1 : focus, kind: "action", compact: true }), compressedReview || showTechnical ? null : _jsx(StaticRow, { title: "\u6280\u672F\u8BE6\u60C5\uFF08d\uFF09", status: "muted" }), showTechnical ? _jsx(TechnicalDetails, { children: visibleTechnicalDetails.map((detail, index) => _jsx(StaticRow, { title: detail, meta: index === visibleTechnicalDetails.length - 1 && hiddenTechnicalDetails > 0 ? `另有 ${hiddenTechnicalDetails} 项` : undefined, compact: true }, detail)) }) : null] }) });
6911
6752
  }
6912
6753
  else if (route.name === 'progress') {
6913
6754
  const taskOperation = snapshot.activeReview?.operationKind === 'pluginWriteTask';
6914
- const catalogManagementOperation = snapshot.activeReview?.operationKind === 'catalogManagement';
6915
6755
  const portableOperation = snapshot.activeReview?.operationKind === 'portableInstall';
6916
6756
  const configOperation = snapshot.activeReview?.operationKind === 'configSave'
6917
6757
  || snapshot.activeReview?.operationKind === 'configReset';
@@ -6919,7 +6759,7 @@ export function ConsoleAppV4(props) {
6919
6759
  || snapshot.activeReview?.operationKind === 'catalogGeneration'
6920
6760
  || snapshot.activeReview?.operationKind === 'catalogSourcesRecovery';
6921
6761
  const issueOperation = snapshot.activeReview?.originIssue;
6922
- breadcrumb = catalogManagementOperation ? '目录管理 / 进度' : taskOperation ? '插件任务 / 进度' : portableOperation ? '通用 Skills / 进度' : issueOperation ? '需要处理 / 进度' : sourceOperation ? '插件来源 / 保存' : configOperation ? '设置 / 进度' : '插件操作 / 进度';
6762
+ breadcrumb = taskOperation ? '插件任务 / 进度' : portableOperation ? '通用 Skills / 进度' : issueOperation ? '需要处理 / 进度' : sourceOperation ? '插件来源 / 保存' : configOperation ? '设置 / 进度' : '插件操作 / 进度';
6923
6763
  const configApply = snapshot.activeReview?.operationKind === 'configSave'
6924
6764
  && snapshot.activeReview.changes.some((change) => change.group === 'configImpact' && change.kind === 'change');
6925
6765
  const progressAction = snapshot.activeReview?.taskGoal === 'restore' ? '恢复'
@@ -6933,21 +6773,18 @@ export function ConsoleAppV4(props) {
6933
6773
  : snapshot.activeReview?.pluginAction === 'sync' ? '同步' : '处理';
6934
6774
  const catalogGenerationOperation = snapshot.activeReview?.operationKind === 'catalogGeneration';
6935
6775
  const catalogSourcesRecovery = snapshot.activeReview?.operationKind === 'catalogSourcesRecovery';
6936
- title = catalogManagementOperation
6937
- ? `正在${snapshot.activeReview?.title.replace(/^确认/u, '') ?? '完成目录管理任务'}`
6938
- : taskOperation ? `正在${progressAction}插件` : portableOperation ? '正在安装通用 Skills' : issueOperation ? `正在${progressAction}插件`
6939
- : catalogGenerationOperation ? '正在验证并启用目录版本'
6940
- : catalogSourcesRecovery ? '正在恢复插件来源配置'
6941
- : sourceOperation ? '正在保存来源配置'
6942
- : configOperation ? configApply ? '正在保存并应用设置' : '正在保存设置'
6943
- : `正在${progressAction}插件`;
6944
- description = catalogManagementOperation ? '正在完成已确认的目录管理任务。'
6945
- : issueOperation ? '完成后会重新读取状态并检查问题。'
6946
- : catalogGenerationOperation ? '正在验证并应用已确认的目录版本操作。'
6947
- : catalogSourcesRecovery ? '正在备份损坏配置并恢复官方默认来源。'
6948
- : sourceOperation ? '只原子保存来源配置,不访问网络。'
6949
- : configOperation ? configApply ? '先保存所选层,再重新应用当前可见安装位置。' : '只保存所选设置层。'
6950
- : '请勿关闭当前终端。';
6776
+ title = taskOperation ? `正在${progressAction}插件` : portableOperation ? '正在安装通用 Skills' : issueOperation ? `正在${progressAction}插件`
6777
+ : catalogGenerationOperation ? '正在验证并启用目录版本'
6778
+ : catalogSourcesRecovery ? '正在恢复插件来源配置'
6779
+ : sourceOperation ? '正在保存来源配置'
6780
+ : configOperation ? configApply ? '正在保存并应用设置' : '正在保存设置'
6781
+ : `正在${progressAction}插件`;
6782
+ description = issueOperation ? '完成后会重新读取状态并检查问题。'
6783
+ : catalogGenerationOperation ? '正在验证并应用已确认的目录版本操作。'
6784
+ : catalogSourcesRecovery ? '正在备份损坏配置并恢复官方默认来源。'
6785
+ : sourceOperation ? '只原子保存来源配置,不访问网络。'
6786
+ : configOperation ? configApply ? '先保存所选层,再重新应用当前可见安装位置。' : '只保存所选设置层。'
6787
+ : '请勿关闭当前终端。';
6951
6788
  const batchProgress = snapshot.activeReview?.operationKind === 'pluginWriteBatch' || taskOperation;
6952
6789
  const progress = snapshot.progress;
6953
6790
  const elapsedSeconds = Math.max(0, Math.floor(((progress.elapsedMs
@@ -7050,7 +6887,7 @@ export function ConsoleAppV4(props) {
7050
6887
  return step === 2 ? '正在安装' : step === 3 ? '正在验证' : step === 1 ? '正在生成' : '正在检查';
7051
6888
  };
7052
6889
  const compactPortableProgress = policy.mode === 'compact' && showTechnical;
7053
- content = catalogManagementOperation ? _jsxs(StatusCard, { status: failedProgress ? 'error' : 'info', title: "\u76EE\u5F55\u7BA1\u7406", children: [_jsx(ProgressRow, { title: "\u786E\u8BA4\u8BA1\u5212", meta: "\u5B8C\u6210", state: "complete" }), _jsx(ProgressRow, { title: currentPhase || '准备执行', description: progress.current?.target, meta: `${elapsedSeconds}s`, state: failedProgress ? 'error' : currentPhase ? 'active' : 'pending', compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u5E76\u8BB0\u5F55\u7ED3\u679C", state: validationActive ? 'active' : 'pending' }), !showTechnical && latestMessage ? _jsx(StaticRow, { title: latestMessage, status: "muted", compact: true }) : null, showTechnical ? technicalMessages.map((message, index) => _jsx(StaticRow, { title: message, compact: true }, `${index}:${message}`)) : null, exitAfterBusy ? _jsx(Callout, { status: "warning", title: "\u64CD\u4F5C\u5B8C\u6210\u540E\u9000\u51FA" }) : null] }) : portableOperation ? _jsxs(StatusCard, { status: failedProgress ? 'error' : 'info', title: "Skills CLI", children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u63D2\u4EF6\u548C\u4F9D\u8D56", description: `${snapshot.activeReview?.subject.name ?? '当前插件'} · ${portableDraft?.dependencySummary?.directCount ?? 0} 个直接依赖`, meta: portableProgressMeta(0), state: portableProgressState(0), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u751F\u6210\u5DF2\u9009\u5019\u9009 Skills", description: `${portableProviderCount} 个来源或依赖插件提供 ${portableSelectedCount} 个 Skills`, meta: portableProgressMeta(1), state: portableProgressState(1), compact: compactPortableProgress }), _jsx(ProgressRow, { title: `安装已选择的 ${portableSelectedCount} 个 Skills`, description: `Agent:${portableDraft?.agentMode === 'explicit' ? portableDraft.requestedAgents.join('、') : 'Skills CLI 默认选择'}`, meta: portableProgressMeta(2), state: portableProgressState(2), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", description: "\u9010\u9879\u786E\u8BA4\u6240\u9009 Skill \u7684\u5B89\u88C5\u76EE\u6807", meta: portableProgressMeta(3), state: portableProgressState(3), compact: compactPortableProgress }), showTechnical ? _jsxs(TechnicalDetails, { children: [technicalMessages.map((message, index) => _jsx(StaticRow, { title: message, compact: true }, `${index}:${message}`)), hiddenTechnicalMessages > 0 ? _jsx(StaticRow, { title: `另有 ${hiddenTechnicalMessages} 条技术消息`, status: "muted", compact: true }) : null] }) : null] }) : _jsxs(StatusCard, { status: "info", children: [dependencyProgress ? _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u4F9D\u8D56\u5173\u7CFB", state: relationStep }), _jsx(ProgressRow, { title: "\u751F\u6210\u6267\u884C\u8BA1\u5212", state: planStep }), _jsx(ProgressRow, { title: `${progressAction}所选插件和所需插件`, description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: closureStep, compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u5B8C\u6574\u7ED3\u679C", state: verificationStep })] }) : _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: sourceOperation ? '检查来源操作输入' : configOperation ? '验证设置值' : '检查兼容性', state: !currentPhase ? 'pending' : preflightActive ? 'active' : 'complete' }), _jsx(ProgressRow, { title: progress.current?.phase || (sourceOperation ? '保存来源配置' : configOperation ? '保存设置层并重新应用' : '连接到所选目标平台'), description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: failedProgress ? 'error' : executionActive ? 'active' : validationActive ? 'complete' : 'pending', compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", state: failedProgress ? 'error' : validationActive ? 'active' : 'pending' })] }), dependencyProgress ? _jsxs(SectionCard, { title: "\u6267\u884C\u76EE\u6807", meta: `${snapshot.progressTargets.length} 个目标`, children: [progressTargetOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${progressTargetOffset} 个目标`, status: "muted", compact: true }) : null, visibleProgressTargets.map((entry) => {
6890
+ content = portableOperation ? _jsxs(StatusCard, { status: failedProgress ? 'error' : 'info', title: "Skills CLI", children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u63D2\u4EF6\u548C\u4F9D\u8D56", description: `${snapshot.activeReview?.subject.name ?? '当前插件'} · ${portableDraft?.dependencySummary?.directCount ?? 0} 个直接依赖`, meta: portableProgressMeta(0), state: portableProgressState(0), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u751F\u6210\u5DF2\u9009\u5019\u9009 Skills", description: `${portableProviderCount} 个来源或依赖插件提供 ${portableSelectedCount} 个 Skills`, meta: portableProgressMeta(1), state: portableProgressState(1), compact: compactPortableProgress }), _jsx(ProgressRow, { title: `安装已选择的 ${portableSelectedCount} 个 Skills`, description: `Agent:${portableDraft?.agentMode === 'explicit' ? portableDraft.requestedAgents.join('、') : 'Skills CLI 默认选择'}`, meta: portableProgressMeta(2), state: portableProgressState(2), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", description: "\u9010\u9879\u786E\u8BA4\u6240\u9009 Skill \u7684\u5B89\u88C5\u76EE\u6807", meta: portableProgressMeta(3), state: portableProgressState(3), compact: compactPortableProgress }), showTechnical ? _jsxs(TechnicalDetails, { children: [technicalMessages.map((message, index) => _jsx(StaticRow, { title: message, compact: true }, `${index}:${message}`)), hiddenTechnicalMessages > 0 ? _jsx(StaticRow, { title: `另有 ${hiddenTechnicalMessages} 条技术消息`, status: "muted", compact: true }) : null] }) : null] }) : _jsxs(StatusCard, { status: "info", children: [dependencyProgress ? _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u4F9D\u8D56\u5173\u7CFB", state: relationStep }), _jsx(ProgressRow, { title: "\u751F\u6210\u6267\u884C\u8BA1\u5212", state: planStep }), _jsx(ProgressRow, { title: `${progressAction}所选插件和所需插件`, description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: closureStep, compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u5B8C\u6574\u7ED3\u679C", state: verificationStep })] }) : _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: sourceOperation ? '检查来源操作输入' : configOperation ? '验证设置值' : '检查兼容性', state: !currentPhase ? 'pending' : preflightActive ? 'active' : 'complete' }), _jsx(ProgressRow, { title: progress.current?.phase || (sourceOperation ? '保存来源配置' : configOperation ? '保存设置层并重新应用' : '连接到所选目标平台'), description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: failedProgress ? 'error' : executionActive ? 'active' : validationActive ? 'complete' : 'pending', compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", state: failedProgress ? 'error' : validationActive ? 'active' : 'pending' })] }), dependencyProgress ? _jsxs(SectionCard, { title: "\u6267\u884C\u76EE\u6807", meta: `${snapshot.progressTargets.length} 个目标`, children: [progressTargetOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${progressTargetOffset} 个目标`, status: "muted", compact: true }) : null, visibleProgressTargets.map((entry) => {
7054
6891
  const state = progressLabel(entry);
7055
6892
  const relation = entry.relation === 'requested' ? '你选择的插件' : entry.relation === 'direct' ? '直接依赖' : '间接依赖';
7056
6893
  const title = props.controller.getPluginOverview(entry.pluginId)?.displayName
@@ -7070,9 +6907,6 @@ export function ConsoleAppV4(props) {
7070
6907
  : result.state === 'blocked' ? result.summary : undefined;
7071
6908
  const action = resultSummary?.action;
7072
6909
  const operationKind = 'operationKind' in result ? result.operationKind : undefined;
7073
- const catalogManagementOperation = operationKind === 'catalogManagement';
7074
- const catalogManagementResult = catalogManagementOperation
7075
- ? resultSummary?.catalogManagement : undefined;
7076
6910
  const taskOperation = operationKind === 'pluginWriteTask';
7077
6911
  const taskSummary = resultSummary?.task;
7078
6912
  const taskBlockedCount = taskSummary?.blockedTargets.length ?? 0;
@@ -7129,96 +6963,87 @@ export function ConsoleAppV4(props) {
7129
6963
  cleanup: '✓ 插件清理完成',
7130
6964
  sync: '✓ 插件同步完成',
7131
6965
  }[action ?? 'install'];
7132
- title = catalogManagementOperation
7133
- ? blocked ? '× Catalog 管理操作未完成'
7134
- : partial ? '! Catalog 管理操作只完成了一部分'
7135
- : catalogManagementResult?.action === 'publishPlan' ? '✓ 发布计划已准备'
7136
- : catalogManagementResult?.action === 'publishApply' ? '✓ Catalog 发布完成'
7137
- : catalogManagementResult?.action === 'storePrune' ? '✓ Store 清理完成'
7138
- : '✓ Catalog 管理操作完成'
7139
- : taskOperation
7140
- ? blocked ? `× 插件${pluginWriteTaskLabel(taskSummary?.goal ?? 'restore')}没有完成`
7141
- : partial ? `! 插件${pluginWriteTaskLabel(taskSummary?.goal ?? 'restore')}只完成了一部分`
7142
- : `✓ 插件${pluginWriteTaskLabel(taskSummary?.goal ?? 'restore')}完成`
7143
- : batchOperation
7144
- ? blocked ? '× 批量操作没有完成'
7145
- : partial ? '! 批量操作只完成了一部分' : `✓ 批量${batchActionLabel(action)}完成`
7146
- : portableOperation
7147
- ? blocked ? '× 通用 Skills 安装被阻止'
7148
- : partial ? '! 通用 Skills 结果未完全完成' : '✓ 通用 Skills 已安装'
7149
- : blocked && result.writeMayHaveCompleted
7150
- ? '× 写入结果未确认'
7151
- : issueOperation
7152
- ? blocked || partial ? '× 问题仍未解决' : '✓ 问题已处理'
7153
- : sourceOperation
7154
- ? blocked ? '× 来源操作未完成'
7155
- : operationKind === 'catalogSourcesRecovery' ? '✓ Catalog 来源配置已恢复'
7156
- : resultSummary?.catalogAction === 'update'
7157
- ? resultSummary.catalogGeneration?.activeChanged
7158
- && resultSummary.catalogGeneration.outcome === 'activated'
7159
- ? '✓ Catalog 已更新' : '✓ Catalog 无需更新'
7160
- : resultSummary?.catalogAction === 'repair' ? '✓ Catalog 已修复'
7161
- : resultSummary?.catalogAction === 'replaceDamaged' ? '✓ 损坏的 Catalog 已替换'
7162
- : resultSummary?.catalogAction === 'recoverState' ? '✓ Catalog 状态已恢复'
7163
- : operationKind === 'catalogGeneration' ? '✓ Catalog 已启用'
7164
- : '✓ 来源配置已保存'
7165
- : configOperation
7166
- ? blocked
7167
- ? '× 设置未确认保存'
7168
- : partial ? resultSummary?.configApplySkippedReason === 'invalidConfig'
7169
- ? '! 设置已保存,但未应用'
7170
- : '! 设置已保存,但部分应用失败'
7171
- : resultSummary?.configApplied ? '✓ 设置已保存并应用' : '✓ 设置已保存'
7172
- : partial ? '! 插件操作只完成了一部分'
7173
- : blocked ? result.code === 'operationFailed' ? '× 插件操作没有完成' : '× 插件操作未完成'
7174
- : completedTitle;
7175
- description = catalogManagementOperation
7176
- ? blocked ? result.message : resultSummary?.message ?? 'Catalog 状态已更新。'
7177
- : taskOperation
7178
- ? blocked ? '任务被安全阻止。已完成和未完成目标按实际结果保留。'
7179
- : partial ? `${taskSummary?.retryTargets?.length ?? 0} 个失败目标可重试 · ${taskBlockedCount} 个目标需要决定。`
7180
- : `${taskSummary?.rootResults.length ?? 0} 个所选插件已处理;下方显示使用位置。`
7181
- : batchOperation
6966
+ title = taskOperation
6967
+ ? blocked ? `× 插件${pluginWriteTaskLabel(taskSummary?.goal ?? 'restore')}没有完成`
6968
+ : partial ? `! 插件${pluginWriteTaskLabel(taskSummary?.goal ?? 'restore')}只完成了一部分`
6969
+ : `✓ 插件${pluginWriteTaskLabel(taskSummary?.goal ?? 'restore')}完成`
6970
+ : batchOperation
6971
+ ? blocked ? '× 批量操作没有完成'
6972
+ : partial ? '! 批量操作只完成了一部分' : `✓ 批量${batchActionLabel(action)}完成`
6973
+ : portableOperation
6974
+ ? blocked ? '× 通用 Skills 安装被阻止'
6975
+ : partial ? '! 通用 Skills 结果未完全完成' : '✓ 通用 Skills 已安装'
6976
+ : blocked && result.writeMayHaveCompleted
6977
+ ? '× 写入结果未确认'
6978
+ : issueOperation
6979
+ ? blocked || partial ? '× 问题仍未解决' : '✓ 问题已处理'
6980
+ : sourceOperation
6981
+ ? blocked ? '× 来源操作未完成'
6982
+ : operationKind === 'catalogSourcesRecovery' ? '✓ Catalog 来源配置已恢复'
6983
+ : resultSummary?.catalogAction === 'update'
6984
+ ? resultSummary.catalogGeneration?.activeChanged
6985
+ && resultSummary.catalogGeneration.outcome === 'activated'
6986
+ ? '✓ Catalog 已更新' : '✓ Catalog 无需更新'
6987
+ : resultSummary?.catalogAction === 'repair' ? '✓ Catalog 已修复'
6988
+ : resultSummary?.catalogAction === 'replaceDamaged' ? '✓ 损坏的 Catalog 已替换'
6989
+ : resultSummary?.catalogAction === 'recoverState' ? '✓ Catalog 状态已恢复'
6990
+ : operationKind === 'catalogGeneration' ? '✓ Catalog 已启用'
6991
+ : '✓ 来源配置已保存'
6992
+ : configOperation
6993
+ ? blocked
6994
+ ? '× 设置未确认保存'
6995
+ : partial ? resultSummary?.configApplySkippedReason === 'invalidConfig'
6996
+ ? '! 设置已保存,但未应用'
6997
+ : '! 设置已保存,但部分应用失败'
6998
+ : resultSummary?.configApplied ? '✓ 设置已保存并应用' : '✓ 设置已保存'
6999
+ : partial ? '! 插件操作只完成了一部分'
7000
+ : blocked ? result.code === 'operationFailed' ? '× 插件操作没有完成' : '× 插件操作未完成'
7001
+ : completedTitle;
7002
+ description = taskOperation
7003
+ ? blocked ? '任务被安全阻止。已完成和未完成目标按实际结果保留。'
7004
+ : partial ? `${taskSummary?.retryTargets?.length ?? 0} 个失败目标可重试 · ${taskBlockedCount} 个目标需要决定。`
7005
+ : `${taskSummary?.rootResults.length ?? 0} 个所选插件已处理;下方显示使用位置。`
7006
+ : batchOperation
7007
+ ? blocked
7008
+ ? '批量写入被阻止。已完成和未完成目标按实际结果保留。'
7009
+ : partial
7010
+ ? (resultSummary?.batch?.retryTargets?.length ?? 0) > 0
7011
+ ? `${resultSummary?.batch?.failedRequestedPluginIds.length ?? 0} 个所选插件失败,涉及 ${resultSummary?.batch?.retryTargets?.length ?? 0} 个位置。成功目标不会重放。`
7012
+ : '失败目标无法精确定位。请查看本次记录后重新操作。'
7013
+ : `${resultSummary?.batch?.requestedPluginIds.length ?? 0} 个所选插件已处理;下方显示使用位置和所需插件。`
7014
+ : portableOperation
7182
7015
  ? blocked
7183
- ? '批量写入被阻止。已完成和未完成目标按实际结果保留。'
7184
- : partial
7185
- ? (resultSummary?.batch?.retryTargets?.length ?? 0) > 0
7186
- ? `${resultSummary?.batch?.failedRequestedPluginIds.length ?? 0} 个所选插件失败,涉及 ${resultSummary?.batch?.retryTargets?.length ?? 0} 个位置。成功目标不会重放。`
7187
- : '失败目标无法精确定位。请查看本次记录后重新操作。'
7188
- : `${resultSummary?.batch?.requestedPluginIds.length ?? 0} 个所选插件已处理;下方显示使用位置和所需插件。`
7189
- : portableOperation
7190
- ? blocked
7191
- ? result.code === 'operationReviewExpired' || result.code === 'reviewTicketExpired'
7192
- ? 'Review 已过期,写入未开始。请返回修改并重新确认。'
7193
- : result.code === 'operationReviewStale'
7194
- ? '安装证据已变化,写入被阻止。请返回修改并重新确认。'
7195
- : result.writeMayHaveCompleted
7196
- ? '写入结果无法确认。请检查外部 Skills 状态后重试。'
7197
- : '安装在写入前被阻止。请返回修改后重试。'
7198
- : portableInstallFailed ? 'Skills CLI 安装失败,可能已有部分目标写入。可以修改 Agent 或使用原选择重试。' : partial ? '无法确认全部已选择 Skills。' : '所选 Skills 已通过安装验证。'
7199
- : blocked && result.writeMayHaveCompleted
7200
- ? result.message
7201
- : issueOperation
7016
+ ? result.code === 'operationReviewExpired' || result.code === 'reviewTicketExpired'
7017
+ ? '确认信息已过期,写入未开始。请返回修改并重新确认。'
7018
+ : result.code === 'operationReviewStale'
7019
+ ? '安装证据已变化,写入被阻止。请返回修改并重新确认。'
7020
+ : result.writeMayHaveCompleted
7021
+ ? '写入结果无法确认。请检查外部 Skills 状态后重试。'
7022
+ : '安装在写入前被阻止。请返回修改后重试。'
7023
+ : portableInstallFailed ? 'Skills CLI 安装失败,可能已有部分目标写入。可以修改 Agent 或使用原选择重试。' : partial ? '无法确认全部已选择 Skills。' : '所选 Skills 已通过安装验证。'
7024
+ : blocked && result.writeMayHaveCompleted
7025
+ ? result.message
7026
+ : issueOperation
7027
+ ? blocked
7028
+ ? result.code === 'issueVerificationFailed'
7029
+ ? '写入可能已完成,但当前无法确认。请重新检查状态。'
7030
+ : result.code === 'issueStillPresent'
7031
+ ? '写入已完成,但重新检查后原问题仍然存在。'
7032
+ : '操作被安全阻止。可返回问题详情后重试。'
7033
+ : '状态已重新加载;原问题已确认消失。'
7034
+ : sourceOperation
7202
7035
  ? blocked
7203
- ? result.code === 'issueVerificationFailed'
7204
- ? '写入可能已完成,但当前无法确认。请重新检查状态。'
7205
- : result.code === 'issueStillPresent'
7206
- ? '写入已完成,但重新检查后原问题仍然存在。'
7207
- : '操作被安全阻止。可返回问题详情后重试。'
7208
- : '状态已重新加载;原问题已确认消失。'
7209
- : sourceOperation
7210
- ? blocked
7211
- ? result.writeMayHaveCompleted
7212
- ? '来源配置可能已保存。请重新检查来源列表。'
7213
- : '来源操作未执行。草稿已保留,可返回修改。'
7214
- : partial ? resultSummary?.message ?? '来源配置已保存,但 Catalog 尚未启用。可立即重试。'
7215
- : resultSummary?.message ?? '来源配置已保存。'
7216
- : blocked ? result.message
7217
- : configOperation
7218
- ? partial
7219
- ? resultSummary?.message ?? '设置层已经保存;平台应用失败不会回滚设置。'
7220
- : '设置层已经更新。'
7221
- : '状态已刷新。';
7036
+ ? result.writeMayHaveCompleted
7037
+ ? '来源配置可能已保存。请重新检查来源列表。'
7038
+ : '来源操作未执行。草稿已保留,可返回修改。'
7039
+ : partial ? resultSummary?.message ?? '来源配置已保存,但 Catalog 尚未启用。可立即重试。'
7040
+ : resultSummary?.message ?? '来源配置已保存。'
7041
+ : blocked ? result.message
7042
+ : configOperation
7043
+ ? partial
7044
+ ? resultSummary?.message ?? '设置层已经保存;平台应用失败不会回滚设置。'
7045
+ : '设置层已经更新。'
7046
+ : '状态已刷新。';
7222
7047
  const pluginId = resultSummary?.pluginId
7223
7048
  ?? ('pluginId' in result ? result.pluginId : undefined);
7224
7049
  const configResultPluginId = pluginId ?? ('returnRoute' in result
@@ -7268,7 +7093,7 @@ export function ConsoleAppV4(props) {
7268
7093
  const retryAction = failedPluginId && failedTarget && failedTargetState
7269
7094
  ? selectLifecycleRetryAction({
7270
7095
  operationKind: operationKind === 'catalogSourcesRecovery' || operationKind === 'pluginWriteBatch'
7271
- || operationKind === 'pluginWriteTask' || operationKind === 'catalogManagement'
7096
+ || operationKind === 'pluginWriteTask'
7272
7097
  ? undefined : operationKind,
7273
7098
  originalAction: action,
7274
7099
  target: {
@@ -7289,221 +7114,185 @@ export function ConsoleAppV4(props) {
7289
7114
  && (candidate.platform ?? failedIssue.platform) === failedTarget?.platform
7290
7115
  && (candidate.scope ?? failedIssue.scope) === failedTarget?.scope)
7291
7116
  : undefined;
7292
- const preparedPublication = catalogManagementResult?.action === 'publishPlan'
7293
- && catalogManagementResult.planDigest && catalogManagementResult.publication
7294
- ? catalogManagementResult : undefined;
7295
- actions = catalogManagementOperation
7117
+ actions = taskOperation
7296
7118
  ? [
7297
- ...(preparedPublication ? [{
7298
- label: '应用此发布计划…',
7299
- description: '进入独立确认;取消确认不会写入远端',
7119
+ ...(nestedTaskReturn && taskReturnRoute ? [{
7120
+ label: '返回剩余恢复任务',
7121
+ description: '保留父任务已选择的位置;返回后重新读取当前状态',
7300
7122
  status: 'success',
7301
- run: () => beginReview({
7302
- kind: 'catalogManagement',
7303
- action: 'publishApply',
7304
- expectedPlanDigest: preparedPublication.planDigest,
7305
- ...(catalogPublishDraft.target
7306
- ? catalogPublishDraft.targetKind === 'remote'
7307
- ? { remote: catalogPublishDraft.target }
7308
- : { remoteUrl: catalogPublishDraft.target }
7309
- : {}),
7310
- branch: catalogPublishDraft.branch,
7311
- }, { name: 'catalogPublish', step: 'overview' }),
7123
+ run: () => leaveResult(taskReturnRoute),
7124
+ }] : []),
7125
+ ...((partial || blocked) && (taskSummary?.retryTargets?.length ?? 0) > 0 ? [{
7126
+ label: `继续处理剩余 ${taskSummary.retryTargets.length} 项…`,
7127
+ description: '重新检查失败的精确目标和必要依赖,并进入新的确认页',
7128
+ run: () => {
7129
+ props.controller.retryFailedPluginWriteTask();
7130
+ setFocus(0);
7131
+ setScrollOffset(0);
7132
+ },
7312
7133
  }] : []),
7313
- { label: catalogManagementResult?.action === 'storePrune' ? '返回本地存储'
7314
- : catalogManagementResult?.action === 'devActivate' || catalogManagementResult?.action === 'devDeactivate' ? '返回开发来源'
7315
- : catalogManagementResult?.action === 'publishPlan' || catalogManagementResult?.action === 'publishApply' ? '返回发布管理'
7316
- : '返回 Catalog 工作区',
7317
- run: () => leaveResult(catalogManagementResult?.action === 'storePrune'
7318
- ? { name: 'catalogStore' }
7319
- : catalogManagementResult?.action === 'devActivate' || catalogManagementResult?.action === 'devDeactivate'
7320
- ? { name: 'catalogDev' }
7321
- : catalogManagementResult?.action === 'publishPlan' || catalogManagementResult?.action === 'publishApply'
7322
- ? { name: 'catalogPublish', step: 'overview' }
7323
- : 'returnRoute' in result && result.returnRoute ? result.returnRoute
7324
- : { name: 'catalogManagement' }) },
7134
+ ...(taskBlockedCount > 0 && taskReturnRoute ? [{
7135
+ label: `返回任务处理 ${taskBlockedCount} 个需决定项`,
7136
+ description: '受阻目标没有加入失败重试;返回后可查看原因和可用的下一步',
7137
+ status: 'warning',
7138
+ run: () => leaveResult(taskReturnRoute),
7139
+ }] : []),
7140
+ ...(!nestedTaskReturn ? [{ label: '完成,返回我的插件', run: () => {
7141
+ if (taskBatchOrigin?.owner === 'batch-write'
7142
+ && taskBatchOrigin.flowId === batchDraft?.flowId) {
7143
+ setBatchDraft(undefined);
7144
+ setDirty(false);
7145
+ }
7146
+ leaveResult({ name: 'pluginList', mode: 'installed' });
7147
+ } }] : []),
7325
7148
  { label: '查看本次记录', run: () => result.operationRecordId
7326
7149
  && go({ name: 'operationDiagnostic', recordId: result.operationRecordId }) },
7327
7150
  ]
7328
- : taskOperation
7151
+ : batchOperation
7329
7152
  ? [
7330
- ...(nestedTaskReturn && taskReturnRoute ? [{
7331
- label: '返回剩余恢复任务',
7332
- description: '保留父任务的冻结目标;返回后重新读取当前证据',
7333
- status: 'success',
7334
- run: () => leaveResult(taskReturnRoute),
7335
- }] : []),
7336
- ...((partial || blocked) && (taskSummary?.retryTargets?.length ?? 0) > 0 ? [{
7337
- label: `继续处理剩余 ${taskSummary.retryTargets.length} 项…`,
7338
- description: '重新检查失败的精确目标和必要依赖,并进入新的确认页',
7153
+ ...((partial || blocked) && (resultSummary?.batch?.retryTargets?.length ?? 0) > 0 ? [{
7154
+ label: '仅重试失败目标…',
7155
+ description: '重新读取失败根目标及其依赖,并进入新的确认页',
7339
7156
  run: () => {
7340
- props.controller.retryFailedPluginWriteTask();
7157
+ props.controller.retryFailedPluginWriteBatch();
7341
7158
  setFocus(0);
7342
7159
  setScrollOffset(0);
7343
7160
  },
7344
7161
  }] : []),
7345
- ...(taskBlockedCount > 0 && taskReturnRoute ? [{
7346
- label: `返回任务处理 ${taskBlockedCount} 个需决定项`,
7347
- description: '受阻目标没有加入失败重试;返回后可查看原因和可用的下一步',
7348
- status: 'warning',
7349
- run: () => leaveResult(taskReturnRoute),
7350
- }] : []),
7351
- ...(!nestedTaskReturn ? [{ label: '完成,返回我的插件', run: () => {
7352
- if (taskBatchOrigin?.owner === 'batch-write'
7353
- && taskBatchOrigin.flowId === batchDraft?.flowId) {
7354
- setBatchDraft(undefined);
7355
- setDirty(false);
7356
- }
7357
- leaveResult({ name: 'pluginList', mode: 'installed' });
7358
- } }] : []),
7162
+ { label: '返回我的插件', run: () => leaveResult() },
7359
7163
  { label: '查看本次记录', run: () => result.operationRecordId
7360
7164
  && go({ name: 'operationDiagnostic', recordId: result.operationRecordId }) },
7361
7165
  ]
7362
- : batchOperation
7363
- ? [
7364
- ...((partial || blocked) && (resultSummary?.batch?.retryTargets?.length ?? 0) > 0 ? [{
7365
- label: '仅重试失败目标…',
7366
- description: '重新读取失败根目标及其依赖,并进入新的确认页',
7367
- run: () => {
7368
- props.controller.retryFailedPluginWriteBatch();
7369
- setFocus(0);
7370
- setScrollOffset(0);
7371
- },
7372
- }] : []),
7373
- { label: '返回我的插件', run: () => leaveResult() },
7374
- { label: '查看本次记录', run: () => result.operationRecordId
7375
- && go({ name: 'operationDiagnostic', recordId: result.operationRecordId }) },
7376
- ]
7377
- : portableOperation
7378
- ? blocked || partial ? [
7379
- { label: blocked || partial ? '返回修改' : portableOriginIsDetail ? '返回插件详情' : '返回插件预览', run: async () => {
7380
- if (!pluginId) {
7381
- leaveResult();
7382
- return;
7383
- }
7384
- if (!blocked && !partial) {
7385
- props.controller.discardPortableDraft();
7386
- leaveResult();
7387
- return;
7388
- }
7389
- if (!await refreshPortableDraft(pluginId))
7390
- return;
7391
- if (portableInstallFailed && portableReceipt?.agentMode === 'explicit') {
7392
- props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableAgentInput', pluginId }, true);
7393
- return;
7394
- }
7395
- props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableSkillSelect', pluginId }, true);
7396
- } },
7397
- { label: blocked || partial ? '重试' : '再安装其他 Skills…', run: async () => {
7398
- if (!pluginId)
7399
- return;
7400
- if (blocked || partial) {
7401
- props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableSkillSelect', pluginId }, true);
7402
- await beginPortableReview(pluginId, snapshot.portableDraft?.scope ?? 'project');
7403
- return;
7404
- }
7405
- props.controller.resetPortableFlowToPreview(pluginId);
7406
- await beginPortable(pluginId);
7407
- } },
7408
- { label: portableOriginIsDetail ? '返回插件详情' : '返回插件预览', run: () => { if (pluginId)
7409
- props.controller.resetPortableFlowToPreview(pluginId); } },
7410
- ] : [
7411
- { label: portableOriginIsDetail ? '返回插件详情' : '返回插件预览', run: () => {
7166
+ : portableOperation
7167
+ ? blocked || partial ? [
7168
+ { label: blocked || partial ? '返回修改' : portableOriginIsDetail ? '返回插件详情' : '返回插件预览', run: async () => {
7169
+ if (!pluginId) {
7170
+ leaveResult();
7171
+ return;
7172
+ }
7173
+ if (!blocked && !partial) {
7412
7174
  props.controller.discardPortableDraft();
7413
7175
  leaveResult();
7414
- } },
7415
- { label: '再安装其他 Skills…', run: async () => {
7416
- if (!pluginId)
7417
- return;
7418
- props.controller.resetPortableFlowToPreview(pluginId);
7419
- await beginPortable(pluginId);
7420
- } },
7421
- ]
7422
- : issueOperation && !dependencyRecovery
7423
- ? blocked || partial
7176
+ return;
7177
+ }
7178
+ if (!await refreshPortableDraft(pluginId))
7179
+ return;
7180
+ if (portableInstallFailed && portableReceipt?.agentMode === 'explicit') {
7181
+ props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableAgentInput', pluginId }, true);
7182
+ return;
7183
+ }
7184
+ props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableSkillSelect', pluginId }, true);
7185
+ } },
7186
+ { label: blocked || partial ? '重试' : '再安装其他 Skills…', run: async () => {
7187
+ if (!pluginId)
7188
+ return;
7189
+ if (blocked || partial) {
7190
+ props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableSkillSelect', pluginId }, true);
7191
+ await beginPortableReview(pluginId, snapshot.portableDraft?.scope ?? 'project');
7192
+ return;
7193
+ }
7194
+ props.controller.resetPortableFlowToPreview(pluginId);
7195
+ await beginPortable(pluginId);
7196
+ } },
7197
+ { label: portableOriginIsDetail ? '返回插件详情' : '返回插件预览', run: () => { if (pluginId)
7198
+ props.controller.resetPortableFlowToPreview(pluginId); } },
7199
+ ] : [
7200
+ { label: portableOriginIsDetail ? '返回插件详情' : '返回插件预览', run: () => {
7201
+ props.controller.discardPortableDraft();
7202
+ leaveResult();
7203
+ } },
7204
+ { label: '再安装其他 Skills…', run: async () => {
7205
+ if (!pluginId)
7206
+ return;
7207
+ props.controller.resetPortableFlowToPreview(pluginId);
7208
+ await beginPortable(pluginId);
7209
+ } },
7210
+ ]
7211
+ : issueOperation && !dependencyRecovery
7212
+ ? blocked || partial
7213
+ ? [
7214
+ { label: '返回问题详情', run: () => blocked
7215
+ ? leaveResult()
7216
+ : failedIssue
7217
+ ? leaveResult({ name: 'issueDetail', issueId: failedIssue.issueId })
7218
+ : pluginId && failedTarget
7219
+ ? leaveResult({ name: 'platform', pluginId, platform: failedTarget.platform })
7220
+ : leaveResult() },
7221
+ { label: '重新检查问题', run: () => leaveResult({ name: 'issueList' }) },
7222
+ ]
7223
+ : [
7224
+ { label: '查看问题列表', run: () => leaveResult({ name: 'issueList' }) },
7225
+ { label: '返回首页', run: () => requestSessionNavigation('home') },
7226
+ ]
7227
+ : sourceOperation
7228
+ ? [{
7229
+ label: !blocked && 'returnRoute' in result && result.returnRoute?.name === 'pluginWriteTask'
7230
+ ? '重新准备插件更新' : blocked ? '返回修改' : partial ? '现在启用 / 重试' : '查看来源',
7231
+ run: () => blocked ? props.controller.resumeResultDraft() : leaveResult(),
7232
+ }, { label: '返回首页', run: () => requestSessionNavigation('home') }]
7233
+ : configOperation && partial
7424
7234
  ? [
7425
- { label: '返回问题详情', run: () => blocked
7426
- ? leaveResult()
7427
- : failedIssue
7428
- ? leaveResult({ name: 'issueDetail', issueId: failedIssue.issueId })
7429
- : pluginId && failedTarget
7430
- ? leaveResult({ name: 'platform', pluginId, platform: failedTarget.platform })
7431
- : leaveResult() },
7432
- { label: '重新检查问题', run: () => leaveResult({ name: 'issueList' }) },
7235
+ ...(configRetryAvailable ? [{
7236
+ label: '重试应用',
7237
+ description: '先重新显示操作汇总,并重新读取当前状态',
7238
+ run: () => beginReview({
7239
+ kind: 'configSave',
7240
+ pluginId: configResultPluginId,
7241
+ scope: resultSummary.configScope,
7242
+ apply: true,
7243
+ retryApply: true,
7244
+ }),
7245
+ }] : []),
7246
+ { label: invalidConfigResult ? '返回设置' : '返回修改', description: '重新打开已保存的设置层', run: () => leaveResult() },
7247
+ { label: '返回设置删除字段或重置设置层', description: '显式删除顶层字段或整个设置层', run: () => leaveResult() },
7248
+ { label: '保留设置并退出', run: () => requestExit({ code: 1, reason: 'partial' }) },
7433
7249
  ]
7434
- : [
7435
- { label: '查看问题列表', run: () => leaveResult({ name: 'issueList' }) },
7436
- { label: '返回首页', run: () => requestSessionNavigation('home') },
7437
- ]
7438
- : sourceOperation
7439
- ? [{
7440
- label: !blocked && 'returnRoute' in result && result.returnRoute?.name === 'pluginWriteTask'
7441
- ? '重新准备插件更新' : blocked ? '返回修改' : partial ? '现在启用 / 重试' : '查看来源',
7442
- run: () => blocked ? props.controller.resumeResultDraft() : leaveResult(),
7443
- }, { label: '返回首页', run: () => requestSessionNavigation('home') }]
7444
- : configOperation && partial
7250
+ : configOperation && blocked
7445
7251
  ? [
7446
- ...(configRetryAvailable ? [{
7447
- label: '重试应用',
7448
- description: '先重新进入 Review,并重新采集当前证据',
7449
- run: () => beginReview({
7450
- kind: 'configSave',
7451
- pluginId: configResultPluginId,
7452
- scope: resultSummary.configScope,
7453
- apply: true,
7454
- retryApply: true,
7455
- }),
7456
- }] : []),
7457
- { label: invalidConfigResult ? '返回设置' : '返回修改', description: '重新打开已保存的设置层', run: () => leaveResult() },
7458
- { label: '返回设置删除字段或重置设置层', description: '显式删除顶层字段或整个设置层', run: () => leaveResult() },
7459
- { label: '保留设置并退出', run: () => requestExit({ code: 1, reason: 'partial' }) },
7252
+ { label: '返回设置', run: () => props.controller.resumeResultDraft() },
7253
+ { label: '返回首页', run: () => requestSessionNavigation('home') },
7460
7254
  ]
7461
- : configOperation && blocked
7462
- ? [
7463
- { label: '返回设置', run: () => props.controller.resumeResultDraft() },
7464
- { label: '返回首页', run: () => requestSessionNavigation('home') },
7465
- ]
7466
- : [{ label: partial || blockedDependencyFailure ? '查看失败项' : successfulConfigOperation && configOrigin
7467
- ? configOrigin.name === 'pluginPreview' ? '返回插件预览'
7468
- : configOrigin.name === 'pluginWriteTask' ? '返回恢复任务' : '返回插件详情'
7469
- : configOperation ? '查看插件'
7470
- : action === 'uninstall' || action === 'cleanup' ? '返回插件详情' : '查看插件', run: () => {
7471
- if (successfulConfigOperation && configOrigin) {
7472
- leaveResult();
7473
- return;
7255
+ : [{ label: partial || blockedDependencyFailure ? '查看失败项' : successfulConfigOperation && configOrigin
7256
+ ? configOrigin.name === 'pluginPreview' ? '返回插件预览'
7257
+ : configOrigin.name === 'pluginWriteTask' ? '返回恢复任务' : '返回插件详情'
7258
+ : configOperation ? '查看插件'
7259
+ : action === 'uninstall' || action === 'cleanup' ? '返回插件详情' : '查看插件', run: () => {
7260
+ if (successfulConfigOperation && configOrigin) {
7261
+ leaveResult();
7262
+ return;
7263
+ }
7264
+ if ((partial || blockedDependencyFailure) && failedPluginId && failedTarget) {
7265
+ if (failedIssue)
7266
+ leaveResult({ name: 'issueDetail', issueId: failedIssue.issueId });
7267
+ else if (failedPluginPlatforms?.includes(failedTarget.platform)) {
7268
+ leaveResult({ name: 'platform', pluginId: failedPluginId, platform: failedTarget.platform });
7474
7269
  }
7475
- if ((partial || blockedDependencyFailure) && failedPluginId && failedTarget) {
7476
- if (failedIssue)
7477
- leaveResult({ name: 'issueDetail', issueId: failedIssue.issueId });
7478
- else if (failedPluginPlatforms?.includes(failedTarget.platform)) {
7479
- leaveResult({ name: 'platform', pluginId: failedPluginId, platform: failedTarget.platform });
7480
- }
7481
- else if (snapshot.viewModel?.plugins.some((entry) => entry.pluginId === failedPluginId)) {
7482
- leaveResult({ name: 'pluginDetail', pluginId: failedPluginId });
7483
- }
7484
- else
7485
- leaveResult({ name: 'pluginList', mode: 'installed' });
7486
- }
7487
- else if (pluginId && snapshot.viewModel?.plugins.some((entry) => entry.pluginId === pluginId)) {
7488
- leaveResult({ name: 'pluginDetail', pluginId });
7270
+ else if (snapshot.viewModel?.plugins.some((entry) => entry.pluginId === failedPluginId)) {
7271
+ leaveResult({ name: 'pluginDetail', pluginId: failedPluginId });
7489
7272
  }
7490
7273
  else
7491
7274
  leaveResult({ name: 'pluginList', mode: 'installed' });
7492
- } }, ...((partial || blockedDependencyFailure) && failedPluginId && failedTarget && retryAction ? [{
7493
- label: '重试失败部分…',
7494
- run: () => {
7495
- const issueIntent = failedIssue && retryIssueAction
7496
- ? issueWriteIntent(failedIssue, retryIssueAction)
7497
- : undefined;
7498
- return beginReview(issueIntent ?? {
7499
- kind: 'pluginWrite',
7500
- action: retryAction,
7501
- pluginId: failedPluginId,
7502
- platform: failedTarget.platform,
7503
- scope: failedTarget.scope,
7504
- });
7505
- },
7506
- }] : []), { label: '返回首页', run: () => requestSessionNavigation('home') }];
7275
+ }
7276
+ else if (pluginId && snapshot.viewModel?.plugins.some((entry) => entry.pluginId === pluginId)) {
7277
+ leaveResult({ name: 'pluginDetail', pluginId });
7278
+ }
7279
+ else
7280
+ leaveResult({ name: 'pluginList', mode: 'installed' });
7281
+ } }, ...((partial || blockedDependencyFailure) && failedPluginId && failedTarget && retryAction ? [{
7282
+ label: '重试失败部分…',
7283
+ run: () => {
7284
+ const issueIntent = failedIssue && retryIssueAction
7285
+ ? issueWriteIntent(failedIssue, retryIssueAction)
7286
+ : undefined;
7287
+ return beginReview(issueIntent ?? {
7288
+ kind: 'pluginWrite',
7289
+ action: retryAction,
7290
+ pluginId: failedPluginId,
7291
+ platform: failedTarget.platform,
7292
+ scope: failedTarget.scope,
7293
+ });
7294
+ },
7295
+ }] : []), { label: '返回首页', run: () => requestSessionNavigation('home') }];
7507
7296
  const visibleMessages = resultSummary?.messages?.slice(policy.mode === 'compact' ? -2 : -4) ?? [];
7508
7297
  const visibleChanges = resultSummary?.changes?.slice(0, policy.mode === 'compact' ? 2 : 4) ?? [];
7509
7298
  const resultTargetName = (target) => target.pluginId
@@ -7627,7 +7416,7 @@ export function ConsoleAppV4(props) {
7627
7416
  || prioritizedPortableSkills.length > portableSkillLimit) {
7628
7417
  help = 'PgUp/PgDn 查看全部项目 · ↑↓ 移动 · Enter 选择 · Esc 返回';
7629
7418
  }
7630
- content = catalogManagementOperation ? _jsxs(Box, { flexDirection: "column", children: [_jsxs(ResultCard, { status: resultStatus, title: resultSummary?.message ?? '目录管理结果', children: [catalogManagementResult?.catalogVersion ? _jsx(StaticRow, { title: "\u76EE\u5F55\u7248\u672C", meta: catalogManagementResult.catalogVersion, compact: true }) : null, catalogManagementResult?.store ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u5B9E\u9645\u5220\u9664", meta: `${catalogManagementResult.store.deletedEntries} 项 · ${catalogManagementResult.store.deletedBytes} bytes`, status: "success", compact: true }), _jsx(StaticRow, { title: "\u5B9E\u9645\u4FDD\u7559", meta: `${catalogManagementResult.store.retainedEntries} 项`, compact: true })] }) : null, catalogManagementResult?.publication ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u53D1\u5E03\u72B6\u6001", meta: catalogManagementResult.publication.state, status: catalogManagementResult.publication.state === 'uncertain' ? 'warning' : 'success', compact: true }), _jsx(StaticRow, { title: "\u76EE\u6807", meta: `${catalogManagementResult.publication.remote} · ${catalogManagementResult.publication.branch}`, compact: true }), _jsx(StaticRow, { title: "\u8BA1\u5212\u6807\u8BC6", meta: catalogManagementResult.publication.planDigest.slice(0, 15), compact: true })] }) : catalogManagementResult?.planDigest ? _jsx(StaticRow, { title: "\u8BA1\u5212\u5DF2\u51C6\u5907", meta: catalogManagementResult.planDigest.slice(0, 15), status: "success", compact: true }) : null, visibleMessages.map((message, index) => _jsx(StaticRow, { title: productResultMessage(message), status: "muted", compact: true }, `${index}:${message}`))] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: resultActionViewport.offset, limit: resultActionViewport.limit })] }) : taskOperation || batchOperation ? _jsxs(Box, { flexDirection: "column", children: [_jsxs(ResultCard, { status: resultStatus, title: "\u6240\u9009\u63D2\u4EF6\u7ED3\u679C", children: [taskResultOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${taskResultOffset} 项`, status: "muted", compact: true }) : null, visibleTaskResultRows, rootResultRows.length > taskResultOffset + visibleTaskResultRows.length
7419
+ content = taskOperation || batchOperation ? _jsxs(Box, { flexDirection: "column", children: [_jsxs(ResultCard, { status: resultStatus, title: "\u6240\u9009\u63D2\u4EF6\u7ED3\u679C", children: [taskResultOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${taskResultOffset} 项`, status: "muted", compact: true }) : null, visibleTaskResultRows, rootResultRows.length > taskResultOffset + visibleTaskResultRows.length
7631
7420
  ? _jsx(StaticRow, { title: "\u2193 \u540E\u9762\u8FD8\u6709", meta: `${rootResultRows.length - taskResultOffset - visibleTaskResultRows.length} 项`, status: "muted", compact: true }) : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: resultActionViewport.offset, limit: resultActionViewport.limit })] }) : portableOperation ? _jsxs(Box, { flexDirection: "column", children: [portableTechnicalSummary ? _jsxs(_Fragment, { children: [portableSkillOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${portableSkillOffset} 个 Skills`, status: "muted", compact: true }) : null, portableRows, hiddenPortableSkills > 0 ? _jsx(StaticRow, { title: `另有 ${hiddenPortableSkills} 个 Skills`, status: "muted", compact: true }) : null, portableReceipt?.recovery ? _jsx(StaticRow, { title: "\u5B89\u5168\u6062\u590D", meta: portableReceipt.recovery, status: "warning", compact: true }) : null, _jsx(TechnicalDetails, { children: compactTechnicalRows })] }) : _jsx(_Fragment, { children: _jsxs(ResultCard, { status: resultStatus, title: blocked ? '安装未开始或结果未确认' : partial ? '部分 Skills 未确认' : '通用 Skills 安装结果', children: [portableSkillOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${portableSkillOffset} 个 Skills`, status: "muted", compact: true }) : null, portableRows, hiddenPortableSkills > 0 ? _jsx(StaticRow, { title: `另有 ${hiddenPortableSkills} 个 Skills`, status: "muted", compact: true }) : null, portableReceipt ? _jsx(StaticRow, { title: `Agent:${portableReceipt.agentMode === 'automatic' ? 'Skills CLI 默认选择' : portableReceipt.requestedAgents.join('、')}`, meta: `范围:${scopeLabel(portableReceipt.scope)}`, compact: true }) : null, portableReceipt?.recovery ? policy.mode === 'compact'
7632
7421
  ? _jsx(StaticRow, { title: "\u5B89\u5168\u6062\u590D", meta: portableReceipt.recovery, status: "warning", compact: true })
7633
7422
  : _jsx(Callout, { status: "warning", title: "\u5B89\u5168\u6062\u590D", description: portableReceipt.recovery }) : null, showTechnical && portableReceipt ? _jsxs(TechnicalDetails, { children: [portableReceipt.failureCode ? _jsx(StaticRow, { title: "failure code", meta: portableReceipt.failureCode, compact: true }) : null, _jsx(StaticRow, { title: "verification missing", meta: String(portableReceipt.missing.length), compact: true }), _jsx(StaticRow, { title: "Skills CLI version", meta: portableReceipt.skillsCliVersion, compact: true }), partial || blocked
@@ -7716,7 +7505,6 @@ export function ConsoleAppV4(props) {
7716
7505
  case 'sourceAdd':
7717
7506
  case 'sourceSave':
7718
7507
  case 'scriptTimeout':
7719
- case 'catalogWorkspace':
7720
7508
  case 'reviewPreparing':
7721
7509
  case 'review':
7722
7510
  case 'result':
@@ -7779,6 +7567,16 @@ export function ConsoleAppV4(props) {
7779
7567
  if (scrollOffset > lastActionIndex)
7780
7568
  setScrollOffset(focus);
7781
7569
  }, [batchSelectionActionSignature, focus, scrollOffset]);
7570
+ useEffect(() => {
7571
+ if (!pendingActionFocus.current)
7572
+ return;
7573
+ const nextFocus = actions.findIndex((action) => action.actionId === pendingActionFocus.current);
7574
+ if (nextFocus < 0)
7575
+ return;
7576
+ pendingActionFocus.current = undefined;
7577
+ setFocus(nextFocus);
7578
+ setScrollOffset(0);
7579
+ });
7782
7580
  useEffect(() => {
7783
7581
  if (!targetActionSignature || !actions[focus]?.disabled)
7784
7582
  return;
@@ -7819,6 +7617,19 @@ export function ConsoleAppV4(props) {
7819
7617
  showSafeUiFailure(error, 'tuiActionFailed', 'ui-action');
7820
7618
  }
7821
7619
  };
7620
+ function requestConfirmedExit(closeModal) {
7621
+ closeModal?.();
7622
+ const hasDrafts = dirty || props.controller.hasSessionDraft
7623
+ || (discardDraftConfirmation?.length ?? 0) > 0;
7624
+ setOverlayFocus(0);
7625
+ setDiscardForExit(hasDrafts);
7626
+ setOverlay(hasDrafts ? 'discard' : 'exit');
7627
+ }
7628
+ function restoreActionFocus(actionId) {
7629
+ pendingActionFocus.current = actionId;
7630
+ setFocus(0);
7631
+ setScrollOffset(0);
7632
+ }
7822
7633
  function requestSessionNavigation(navigation, discardDrafts = false) {
7823
7634
  if (!props.onSessionNavigation) {
7824
7635
  if (navigation !== 'home')
@@ -7865,10 +7676,6 @@ export function ConsoleAppV4(props) {
7865
7676
  setObjectError(undefined);
7866
7677
  setSourceDraft(undefined);
7867
7678
  setBatchDraft(undefined);
7868
- setCatalogInput('');
7869
- setCatalogWorkspaceDraft({ ownerName: '', ownerUrl: '', displayName: '', catalogVersion: '0.1.0' });
7870
- setCatalogPublishDraft({ targetKind: 'remote', target: '', branch: 'catalog' });
7871
- setCatalogDevSourceId('');
7872
7679
  }
7873
7680
  function continueEditingFromSessionNavigation() {
7874
7681
  if (props.pendingSessionNavigation)
@@ -7940,9 +7747,11 @@ export function ConsoleAppV4(props) {
7940
7747
  }
7941
7748
  return;
7942
7749
  }
7943
- if (tooSmall) {
7750
+ if (tooSmall && !overlay) {
7944
7751
  if (input.toLowerCase() === 'q' || (key.ctrl && input.toLowerCase() === 'c')) {
7945
- requestExit({ code: snapshot.phase === 'error' ? 1 : 0, reason: snapshot.phase === 'error' ? 'initialError' : 'user' });
7752
+ setOperationConfirmation(undefined);
7753
+ setSourceTransportOverlay(undefined);
7754
+ requestConfirmedExit();
7946
7755
  }
7947
7756
  return;
7948
7757
  }
@@ -7957,14 +7766,8 @@ export function ConsoleAppV4(props) {
7957
7766
  if (key.escape || input.toLowerCase() === 'b') {
7958
7767
  closeConfirmation();
7959
7768
  }
7960
- else if (key.ctrl && input.toLowerCase() === 'c') {
7961
- closeConfirmation();
7962
- requestExit({ code: 0, reason: 'user' });
7963
- }
7964
- else if (input.toLowerCase() === 'q') {
7965
- closeConfirmation();
7966
- setDiscardForExit(dirty);
7967
- setOverlay(dirty ? 'discard' : 'exit');
7769
+ else if (input.toLowerCase() === 'q' || (key.ctrl && input.toLowerCase() === 'c')) {
7770
+ requestConfirmedExit(closeConfirmation);
7968
7771
  }
7969
7772
  else if (props.onSessionNavigation && (input === 'h' || input === 'H')) {
7970
7773
  const navigation = input === 'H' ? 'reload' : 'home';
@@ -8005,9 +7808,19 @@ export function ConsoleAppV4(props) {
8005
7808
  return;
8006
7809
  }
8007
7810
  if (sourceTransportOverlay) {
8008
- if (key.escape || input.toLowerCase() === 'b') {
7811
+ const closeTransportOverlay = () => {
8009
7812
  setSourceTransportOverlay(undefined);
8010
7813
  setOverlayFocus(0);
7814
+ };
7815
+ if (key.escape || input.toLowerCase() === 'b') {
7816
+ closeTransportOverlay();
7817
+ }
7818
+ else if (input.toLowerCase() === 'q' || (key.ctrl && input.toLowerCase() === 'c')) {
7819
+ requestConfirmedExit(closeTransportOverlay);
7820
+ }
7821
+ else if (props.onSessionNavigation && (input === 'h' || input === 'H')) {
7822
+ closeTransportOverlay();
7823
+ requestSessionNavigation(input === 'H' ? 'reload' : 'home');
8011
7824
  }
8012
7825
  else if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) {
8013
7826
  setOverlayFocus((value) => moveIndex(2, value, key.upArrow || key.leftArrow ? -1 : 1));
@@ -8024,14 +7837,17 @@ export function ConsoleAppV4(props) {
8024
7837
  setDirty(true);
8025
7838
  props.controller.replace({ name: 'sourceEdit', sourceId: route.sourceId, owner: current.owner });
8026
7839
  }
8027
- setSourceTransportOverlay(undefined);
8028
- setOverlayFocus(0);
7840
+ closeTransportOverlay();
8029
7841
  }
8030
7842
  return;
8031
7843
  }
8032
7844
  if (overlay) {
8033
7845
  if (key.ctrl && input.toLowerCase() === 'c') {
8034
- requestExit({ code: snapshot.phase === 'error' ? 1 : 0, reason: snapshot.phase === 'error' ? 'initialError' : 'user' });
7846
+ if (overlay === 'sessionNavigation')
7847
+ continueEditingFromSessionNavigation();
7848
+ setDiscardForSessionNavigation(undefined);
7849
+ setDiscardDraftConfirmation(undefined);
7850
+ requestConfirmedExit(overlay === 'help' ? () => setOverlay(undefined) : undefined);
8035
7851
  return;
8036
7852
  }
8037
7853
  if (overlay === 'help' && input.toLowerCase() === 'o') {
@@ -8101,7 +7917,7 @@ export function ConsoleAppV4(props) {
8101
7917
  return;
8102
7918
  }
8103
7919
  if (key.ctrl && input.toLowerCase() === 'c') {
8104
- requestExit({ code: snapshot.phase === 'error' ? 1 : 0, reason: snapshot.phase === 'error' ? 'initialError' : 'user' });
7920
+ requestConfirmedExit();
8105
7921
  return;
8106
7922
  }
8107
7923
  if (route.name === 'operationReportPreview' && reportSaveMode) {
@@ -8138,8 +7954,17 @@ export function ConsoleAppV4(props) {
8138
7954
  setReportSaveError(undefined);
8139
7955
  return;
8140
7956
  }
7957
+ if ((key.pageUp || key.pageDown) && route.name === 'pluginDetail'
7958
+ && placementConclusionPagination) {
7959
+ const { total, pageRows } = placementConclusionPagination;
7960
+ setBatchTargetOffset((value) => Math.min(Math.max(0, total - pageRows), Math.max(0, value + (key.pageUp ? -pageRows : pageRows))));
7961
+ return;
7962
+ }
8141
7963
  if ((key.pageUp || key.pageDown)
8142
- && route.name === 'pluginDependencyNode' && route.view === 'references'
7964
+ && (route.name === 'pluginDependencyNode'
7965
+ && (route.view === 'references' || route.view === 'details')
7966
+ || route.name === 'configSave' && route.view === 'changes'
7967
+ || route.name === 'sourceSave' && route.view === 'changes')
8143
7968
  && referenceDetailPagination) {
8144
7969
  const { total, pageRows } = referenceDetailPagination;
8145
7970
  setBatchTargetOffset((value) => Math.min(Math.max(0, total - 1), Math.max(0, value + (key.pageUp ? -pageRows : pageRows))));
@@ -8207,15 +8032,6 @@ export function ConsoleAppV4(props) {
8207
8032
  setBatchTargetOffset((value) => Math.min(Math.max(0, total - pageRows), Math.max(0, value + (key.pageUp ? -pageRows : pageRows))));
8208
8033
  return;
8209
8034
  }
8210
- if ((key.pageUp || key.pageDown) && (route.name === 'catalogStore'
8211
- || route.name === 'catalogPublish' && route.step === 'overview')) {
8212
- const total = route.name === 'catalogStore'
8213
- ? catalogStore?.entries.length ?? 0
8214
- : catalogPublication?.records.length ?? 0;
8215
- const pageRows = responsiveBudget(3, 7);
8216
- setBatchTargetOffset((value) => Math.min(Math.max(0, total - pageRows), Math.max(0, value + (key.pageUp ? -pageRows : pageRows))));
8217
- return;
8218
- }
8219
8035
  if ((key.pageUp || key.pageDown) && route.name === 'pluginDependencies' && plugin) {
8220
8036
  const overview = dependencyOverview(plugin);
8221
8037
  const dependents = route.view === 'removeBlocked' && route.platform && route.scope
@@ -8386,180 +8202,6 @@ export function ConsoleAppV4(props) {
8386
8202
  setSourceInputError(undefined);
8387
8203
  return;
8388
8204
  }
8389
- if (route.name === 'catalogWorkspace' && (route.view === 'select'
8390
- || route.view === 'create' || route.view === 'version' && route.step === 'catalogVersion')) {
8391
- if (key.escape) {
8392
- if (route.view === 'create') {
8393
- const step = route.step ?? 'ownerName';
8394
- const next = { ...catalogWorkspaceDraft, [step]: catalogInput };
8395
- setCatalogWorkspaceDraft(next);
8396
- const previous = { ownerUrl: 'ownerName', displayName: 'ownerUrl', catalogVersion: 'displayName' }[step];
8397
- if (previous) {
8398
- setCatalogInput(next[previous]);
8399
- props.controller.replace({ ...route, step: previous });
8400
- }
8401
- else
8402
- back();
8403
- }
8404
- else
8405
- back();
8406
- return;
8407
- }
8408
- if (key.return) {
8409
- const value = catalogInput.trim();
8410
- setCatalogInputError(undefined);
8411
- if (route.view === 'select') {
8412
- setCatalogLoading(true);
8413
- void props.controller.selectCatalogWorkspace(value || undefined).then((workspace) => {
8414
- setCatalogWorkspace(workspace);
8415
- props.controller.replace({ name: 'catalogWorkspace', view: 'overview' });
8416
- setFocus(0);
8417
- setScrollOffset(0);
8418
- setCatalogInput('');
8419
- }).catch((error) => setCatalogInputError(sanitizeDiagnosticText(error instanceof Error ? error.message : String(error), [], [catalogInput]))).finally(() => setCatalogLoading(false));
8420
- return;
8421
- }
8422
- if (route.view === 'version') {
8423
- if (!/^\d+\.\d+\.\d+(?:-beta\.\d+)?$/u.test(value)) {
8424
- setCatalogInputError('版本必须是 x.y.z 或精确 x.y.z-beta.N。');
8425
- return;
8426
- }
8427
- beginReview({ kind: 'catalogManagement', action: 'workspaceVersion', version: value }, { name: 'catalogWorkspace', view: 'overview' });
8428
- return;
8429
- }
8430
- const step = route.step ?? 'ownerName';
8431
- if (!value) {
8432
- setCatalogInputError('此字段不能为空。');
8433
- return;
8434
- }
8435
- if (step === 'ownerUrl') {
8436
- try {
8437
- const url = new URL(value);
8438
- if (url.protocol !== 'https:' && url.protocol !== 'http:')
8439
- throw new Error();
8440
- }
8441
- catch {
8442
- setCatalogInputError('请输入有效的 HTTP 或 HTTPS owner URL。');
8443
- return;
8444
- }
8445
- }
8446
- if (step === 'catalogVersion' && !/^\d+\.\d+\.\d+(?:-beta\.\d+)?$/u.test(value)) {
8447
- setCatalogInputError('版本必须是 x.y.z 或精确 x.y.z-beta.N。');
8448
- return;
8449
- }
8450
- const next = { ...catalogWorkspaceDraft, [step]: value };
8451
- setCatalogWorkspaceDraft(next);
8452
- setCatalogInput('');
8453
- if (step === 'ownerName')
8454
- props.controller.replace({ ...route, step: 'ownerUrl' });
8455
- else if (step === 'ownerUrl')
8456
- props.controller.replace({ ...route, step: 'displayName' });
8457
- else if (step === 'displayName') {
8458
- setCatalogInput('0.1.0');
8459
- props.controller.replace({ ...route, step: 'catalogVersion' });
8460
- }
8461
- else
8462
- beginReview({ kind: 'catalogManagement', action: 'workspaceInit', ...next }, { name: 'catalogWorkspace', view: 'overview' });
8463
- return;
8464
- }
8465
- if (input === '\u0015' || (input.toLowerCase() === 'u' && key.ctrl))
8466
- setCatalogInput('');
8467
- else if (key.backspace || key.delete)
8468
- setCatalogInput(removeLastGrapheme);
8469
- else if (input && !key.ctrl && !key.meta && input >= ' ')
8470
- setCatalogInput((value) => value + input);
8471
- setCatalogInputError(undefined);
8472
- return;
8473
- }
8474
- if (route.name === 'catalogDev' && route.step && route.step !== 'overview') {
8475
- if (key.escape) {
8476
- back();
8477
- return;
8478
- }
8479
- if (key.return) {
8480
- const value = catalogInput.trim();
8481
- if (value && !CATALOG_SOURCE_ID_PATTERN.test(value)) {
8482
- setCatalogInputError('格式必须是小写字母、数字或连字符,最多 32 字符。');
8483
- return;
8484
- }
8485
- if (route.step === 'sourceId') {
8486
- setCatalogDevSourceId(value);
8487
- back();
8488
- }
8489
- else {
8490
- if (!value) {
8491
- setCatalogInputError('请输入替代主来源 ID。');
8492
- return;
8493
- }
8494
- beginReview({ kind: 'catalogManagement', action: 'devDeactivate', replacementPrimary: value }, { name: 'catalogDev' });
8495
- }
8496
- return;
8497
- }
8498
- if (input === '\u0015' || (input.toLowerCase() === 'u' && key.ctrl))
8499
- setCatalogInput('');
8500
- else if (key.backspace || key.delete)
8501
- setCatalogInput(removeLastGrapheme);
8502
- else if (input && !key.ctrl && !key.meta && input >= ' ')
8503
- setCatalogInput((value) => value + input);
8504
- setCatalogInputError(undefined);
8505
- return;
8506
- }
8507
- if (route.name === 'catalogPublish' && route.step !== 'overview') {
8508
- if (key.escape) {
8509
- if (route.step === 'branch') {
8510
- setCatalogPublishDraft((draft) => ({ ...draft, branch: catalogInput.trim() || 'catalog' }));
8511
- setCatalogInput(catalogPublishDraft.target);
8512
- props.controller.replace({ name: 'catalogPublish', step: 'target' });
8513
- }
8514
- else {
8515
- const value = catalogInput.trim();
8516
- const targetKind = value.includes('://') || /^[^@\s]+@[^:\s]+:/u.test(value) || value.startsWith('/')
8517
- ? 'remoteUrl' : 'remote';
8518
- setCatalogPublishDraft((draft) => ({ ...draft, targetKind, target: value }));
8519
- back();
8520
- }
8521
- return;
8522
- }
8523
- if (key.return) {
8524
- const value = catalogInput.trim();
8525
- if (route.step === 'target') {
8526
- if (/\s/u.test(value)) {
8527
- setCatalogInputError('remote 名称或 URL 不能包含空白。');
8528
- return;
8529
- }
8530
- const targetKind = value.includes('://') || /^[^@\s]+@[^:\s]+:/u.test(value) || value.startsWith('/')
8531
- ? 'remoteUrl' : 'remote';
8532
- setCatalogPublishDraft((draft) => ({ ...draft, targetKind, target: value }));
8533
- setCatalogInput(catalogPublishDraft.expectedPlanDigest ? catalogPublishDraft.branch : 'catalog');
8534
- props.controller.replace({ name: 'catalogPublish', step: 'branch' });
8535
- }
8536
- else {
8537
- const branch = value || 'catalog';
8538
- if (/\s|\.\.|[~^:?*\[\\]/u.test(branch) || branch.startsWith('-') || branch.endsWith('/')) {
8539
- setCatalogInputError('请输入安全的 Git branch 名称。');
8540
- return;
8541
- }
8542
- const draft = { ...catalogPublishDraft, branch };
8543
- setCatalogPublishDraft(draft);
8544
- const target = draft.target
8545
- ? draft.targetKind === 'remote' ? { remote: draft.target } : { remoteUrl: draft.target }
8546
- : {};
8547
- beginReview(draft.expectedPlanDigest
8548
- ? { kind: 'catalogManagement', action: 'publishApply', expectedPlanDigest: draft.expectedPlanDigest,
8549
- ...target, branch }
8550
- : { kind: 'catalogManagement', action: 'publishPlan', ...target, branch }, { name: 'catalogPublish', step: 'overview' });
8551
- }
8552
- return;
8553
- }
8554
- if (input === '\u0015' || (input.toLowerCase() === 'u' && key.ctrl))
8555
- setCatalogInput('');
8556
- else if (key.backspace || key.delete)
8557
- setCatalogInput(removeLastGrapheme);
8558
- else if (input && !key.ctrl && !key.meta && input >= ' ')
8559
- setCatalogInput((value) => value + input);
8560
- setCatalogInputError(undefined);
8561
- return;
8562
- }
8563
8205
  if (route.name === 'configFieldEditor'
8564
8206
  && (route.editor === 'string' || route.editor === 'number')
8565
8207
  && ((activeField?.choices?.length ?? 0) === 0 || route.mode === 'custom')) {
@@ -8800,13 +8442,16 @@ export function ConsoleAppV4(props) {
8800
8442
  setOverlay('help');
8801
8443
  }
8802
8444
  else if (globalAction === 'exit') {
8803
- setOverlayFocus(0);
8804
- setDiscardForExit(dirty);
8805
- setOverlay(dirty ? 'discard' : 'exit');
8445
+ requestConfirmedExit();
8806
8446
  }
8807
8447
  else if (input.toLowerCase() === 'd' && supportsTechnicalDetails) {
8808
8448
  toggleTechnical();
8809
8449
  }
8450
+ else if (globalAction === 'back'
8451
+ && (route.name === 'configSave' || route.name === 'sourceSave')
8452
+ && route.view === 'changes') {
8453
+ back();
8454
+ }
8810
8455
  else if (globalAction === 'back'
8811
8456
  && (route.name === 'configFieldEditor'
8812
8457
  || route.name === 'configObjectPropertyEditor'
@@ -8816,8 +8461,7 @@ export function ConsoleAppV4(props) {
8816
8461
  else if (globalAction === 'back' && route.name === 'batchPlacement') {
8817
8462
  if (batchDraft?.showPlacementTargets) {
8818
8463
  setBatchDraft((current) => current ? { ...current, showPlacementTargets: false } : current);
8819
- setFocus(5);
8820
- setScrollOffset(0);
8464
+ restoreActionFocus('batch-placement-details');
8821
8465
  }
8822
8466
  else
8823
8467
  back();
@@ -8891,23 +8535,7 @@ export function ConsoleAppV4(props) {
8891
8535
  } : current);
8892
8536
  }
8893
8537
  else if (route.name === 'batchSelection' && batchDraft?.stage === 'select' && input.toLowerCase() === 'c') {
8894
- if (batchDraft.selectedPluginIds.length > 0) {
8895
- const invalid = invalidBatchSelection(batchDraft);
8896
- if (invalid.length > 0) {
8897
- setActionError(`${invalid.length} 个已选插件已不可用。请先在“查看全部已选”中取消选择。`);
8898
- return;
8899
- }
8900
- if (batchDraft.mode === 'browse') {
8901
- setBatchDraft((current) => current ? { ...current, action: 'install' } : current);
8902
- props.controller.push({ name: 'batchPlacement' });
8903
- setFocus(0);
8904
- setScrollOffset(0);
8905
- }
8906
- else
8907
- moveBatchStage('task');
8908
- }
8909
- else
8910
- setActionError('请至少选择一个插件。');
8538
+ runAction(actions.find((action) => action.actionId === 'batch-selection-continue'));
8911
8539
  }
8912
8540
  else if (route.name === 'batchSelection' && batchDraft?.stage === 'select' && input === ' ') {
8913
8541
  const action = actions[normalizedEffectiveFocus];
@@ -9075,7 +8703,7 @@ export function ConsoleAppV4(props) {
9075
8703
  runAction(actions[normalizedEffectiveFocus]);
9076
8704
  }
9077
8705
  });
9078
- if (tooSmall) {
8706
+ if (tooSmall && !overlay) {
9079
8707
  return (_jsx(ScreenFrame, { title: "\u7EC8\u7AEF\u7A7A\u95F4\u4E0D\u8DB3", breadcrumb: "\u7EC8\u7AEF\u7A7A\u95F4\u4E0D\u8DB3", context: `${size.columns} × ${size.rows}`, help: "q \u9000\u51FA", size: size, children: _jsx(Callout, { status: "warning", title: "\u2194 \u8BF7\u5C06\u7EC8\u7AEF\u8C03\u6574\u5230\u81F3\u5C11 60 \u00D7 18", description: "\u8C03\u6574\u540E\u4F1A\u8FD4\u56DE\u539F\u9875\u9762\uFF0C\u4E0D\u4F1A\u4E22\u5931\u5F53\u524D\u9009\u62E9\u3002" }) }));
9080
8708
  }
9081
8709
  if (actionError)
@@ -9142,7 +8770,8 @@ export function ConsoleAppV4(props) {
9142
8770
  : overlay === 'discard' || overlay === 'sessionNavigation' ? '放弃未保存修改?'
9143
8771
  : '退出控制台?', children: [overlay === 'help'
9144
8772
  ? _jsx(_Fragment, { children: helpRows.map(([key, value]) => _jsx(StaticRow, { title: `${key} ${value}`, compact: true }, key)) })
9145
- : _jsx(StaticRow, { title: overlay === 'discard' ? '放弃后将返回上一页。'
8773
+ : _jsx(StaticRow, { title: overlay === 'discard'
8774
+ ? discardForExit ? '放弃后将退出控制台。' : '放弃后将返回上一页。'
9146
8775
  : overlay === 'sessionNavigation'
9147
8776
  ? `放弃后将${discardForSessionNavigation === 'reload' ? '重新读取本地状态' : '返回首页'}。`
9148
8777
  : '进行中的写操作会先完成。', status: "muted" }), _jsx(SemanticRows, { actions: overlayActions, focus: overlayFocus, kind: "action", compact: true })] }) })] }));