@lesliechan721/aw 0.1.0-beta.16 → 0.1.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/commands/offline-cleanup-evidence.d.ts +8 -0
- package/dist/src/commands/offline-cleanup-evidence.js +18 -0
- package/dist/src/commands/offline-cleanup-evidence.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +4 -1
- package/dist/src/commands/rebuild-command.js +662 -177
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/status-v6.d.ts +2 -2
- package/dist/src/commands/status-v6.js +40 -11
- package/dist/src/commands/status-v6.js.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/command-receipt.js +11 -6
- package/dist/src/output/command-receipt.js.map +1 -1
- package/dist/src/tui/console-app-v4.js +9 -6
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.js +191 -151
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +1 -0
- package/dist/src/tui/controller.js +10 -7
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/model.d.ts +1 -1
- package/dist/src/tui/model.js +42 -8
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-review-planner.js +103 -26
- package/dist/src/tui/operation-review-planner.js.map +1 -1
- package/dist/src/utils/codex-manager.d.ts +5 -7
- package/dist/src/utils/codex-manager.js +24 -97
- package/dist/src/utils/codex-manager.js.map +1 -1
- package/package.json +3 -3
|
@@ -15,7 +15,6 @@ import { readPluginIntentState } from '../utils/plugin-intent-state.js';
|
|
|
15
15
|
import { applyPluginConfigWrite, replayConfigRuntimeWrites, resolveConfigPreApplyAuthorization, resetPluginConfigWithHelper, } from '../utils/plugin-config-write.js';
|
|
16
16
|
import { analyzePluginConfigMutationImpact } from '../utils/plugin-config-impact.js';
|
|
17
17
|
import { createBatchIntentCompatiblePlanFingerprint } from '../commands/operation-plan.js';
|
|
18
|
-
import { offlineCleanupEvidenceFromInventory, offlineCleanupEvidenceMatches, } from '../commands/offline-cleanup-evidence.js';
|
|
19
18
|
import { inventoryCatalogSourceReferences } from '../utils/catalog-source-references.js';
|
|
20
19
|
import { operationEvidenceMatches, operationEvidenceFingerprint, TuiConfigInvalidStoreError, TuiController, TuiOperationBlockedError, } from './controller.js';
|
|
21
20
|
import { buildConfigGroups, buildConfigPage, buildTuiViewModel, projectPlatformPlacement, } from './model.js';
|
|
@@ -265,10 +264,12 @@ function selectedBatchGroups(intent) {
|
|
|
265
264
|
for (const target of uniqueTargets) {
|
|
266
265
|
const pluginId = target.pluginId;
|
|
267
266
|
const sourceId = parsePluginId(pluginId).sourceId;
|
|
268
|
-
const groupKey =
|
|
267
|
+
const groupKey = intent.action === 'cleanup'
|
|
268
|
+
? ['cleanup', target.platform, target.scope].join('\0')
|
|
269
|
+
: [sourceId, target.platform, target.scope].join('\0');
|
|
269
270
|
const group = groups.get(groupKey) ?? {
|
|
270
271
|
groupId: groupKey,
|
|
271
|
-
sourceId,
|
|
272
|
+
sourceId: intent.action === 'cleanup' ? 'offline' : sourceId,
|
|
272
273
|
platform: target.platform,
|
|
273
274
|
scope: target.scope,
|
|
274
275
|
requestedPluginIds: [],
|
|
@@ -1554,6 +1555,41 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1554
1555
|
await preparation?.reporter.emit('status');
|
|
1555
1556
|
const selection = await resolveBatchGroups(intent, context.env, context.cwd, frozenBatchEvidence?.requestedPluginIds);
|
|
1556
1557
|
signal?.throwIfAborted();
|
|
1558
|
+
if (intent.action === 'cleanup') {
|
|
1559
|
+
const groups = [];
|
|
1560
|
+
for (const group of selection.groups) {
|
|
1561
|
+
signal?.throwIfAborted();
|
|
1562
|
+
const preview = await runBatchWriteGroup({
|
|
1563
|
+
intent,
|
|
1564
|
+
group,
|
|
1565
|
+
cwd: context.cwd,
|
|
1566
|
+
runtime: {
|
|
1567
|
+
...context,
|
|
1568
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1569
|
+
previewOperationPlan: true,
|
|
1570
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
1571
|
+
...(preparation ? {
|
|
1572
|
+
onPreviewStage: (stage) => stage === 'catalog' ? undefined : preparation.reporter.emit(stage),
|
|
1573
|
+
} : {}),
|
|
1574
|
+
},
|
|
1575
|
+
});
|
|
1576
|
+
groups.push({ ...group, preview, executable: preview.operationPlan !== undefined });
|
|
1577
|
+
}
|
|
1578
|
+
await preparation?.reporter.emit('evidence');
|
|
1579
|
+
signal?.throwIfAborted();
|
|
1580
|
+
const evidence = {
|
|
1581
|
+
catalog: {
|
|
1582
|
+
configDigest: 'cleanup-offline',
|
|
1583
|
+
compositeDigest: digest(groups.map((group) => [
|
|
1584
|
+
group.groupId,
|
|
1585
|
+
group.preview.operationPlan?.planFingerprint,
|
|
1586
|
+
])),
|
|
1587
|
+
},
|
|
1588
|
+
requestedPluginIds: selection.requestedPluginIds,
|
|
1589
|
+
groups,
|
|
1590
|
+
};
|
|
1591
|
+
return evidence;
|
|
1592
|
+
}
|
|
1557
1593
|
const configSnapshot = await readCatalogSourcesConfigSnapshot(context.env);
|
|
1558
1594
|
const groups = [];
|
|
1559
1595
|
const ownsObservationSession = !codexObservationSession
|
|
@@ -1669,17 +1705,44 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1669
1705
|
};
|
|
1670
1706
|
return evidence;
|
|
1671
1707
|
}
|
|
1708
|
+
if (intent.kind === 'pluginWrite' && intent.action === 'cleanup') {
|
|
1709
|
+
const preview = await cleanupWriteCommand([intent.pluginId], {
|
|
1710
|
+
cwd: context.cwd,
|
|
1711
|
+
platform: intent.platform,
|
|
1712
|
+
scope: intent.scope,
|
|
1713
|
+
force: intent.force === true,
|
|
1714
|
+
}, {
|
|
1715
|
+
...context,
|
|
1716
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1717
|
+
previewOperationPlan: true,
|
|
1718
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
1719
|
+
...(preparation ? {
|
|
1720
|
+
onPreviewStage: (stage) => stage === 'catalog' ? undefined : preparation.reporter.emit(stage),
|
|
1721
|
+
} : {}),
|
|
1722
|
+
});
|
|
1723
|
+
signal?.throwIfAborted();
|
|
1724
|
+
if (!preview.operationPlan) {
|
|
1725
|
+
throw new TuiOperationBlockedError('cleanupPlanUnavailable', '无法建立可信的清理计划。');
|
|
1726
|
+
}
|
|
1727
|
+
const offlineCleanupPlans = preview.offlineCleanupPlans ?? [];
|
|
1728
|
+
await preparation?.reporter.emit('evidence');
|
|
1729
|
+
return {
|
|
1730
|
+
catalog: {
|
|
1731
|
+
configDigest: 'cleanup-offline',
|
|
1732
|
+
compositeDigest: preview.operationPlan.planFingerprint,
|
|
1733
|
+
},
|
|
1734
|
+
operationPlan: preview.operationPlan,
|
|
1735
|
+
offlineCleanupPlans,
|
|
1736
|
+
...(offlineCleanupPlans.length === 1
|
|
1737
|
+
? { offlineCleanup: offlineCleanupPlans[0] }
|
|
1738
|
+
: {}),
|
|
1739
|
+
targetFingerprint: preview.operationPlan.planFingerprint,
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1672
1742
|
const packageInfo = await readCliPackageInfo();
|
|
1673
|
-
const offlineCleanupReason = intent.kind === 'pluginWrite'
|
|
1674
|
-
&& intent.action === 'cleanup'
|
|
1675
|
-
&& intent.originIssue?.actionId === 'cleanup'
|
|
1676
|
-
&& (intent.originIssue?.category === 'sourceMissing'
|
|
1677
|
-
|| intent.originIssue?.category === 'sourceUnavailable')
|
|
1678
|
-
? intent.originIssue.category === 'sourceMissing' ? 'sourceMissing' : 'bundleUnavailable'
|
|
1679
|
-
: undefined;
|
|
1680
1743
|
let catalogOperation;
|
|
1681
1744
|
let catalogOperationError;
|
|
1682
|
-
if (
|
|
1745
|
+
if (intent.kind !== 'portableInstall') {
|
|
1683
1746
|
try {
|
|
1684
1747
|
const sourceIds = [parsePluginId(intent.pluginId).sourceId];
|
|
1685
1748
|
catalogOperation = !freshCatalog && sessionCatalogOperationContext
|
|
@@ -1850,9 +1913,8 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1850
1913
|
return evidence;
|
|
1851
1914
|
}
|
|
1852
1915
|
await preparation?.reporter.emit('status');
|
|
1853
|
-
const statusCatalogOperation =
|
|
1854
|
-
? undefined
|
|
1855
|
-
: catalogOperation ?? (!freshCatalog ? sessionCatalogOperationContext : undefined);
|
|
1916
|
+
const statusCatalogOperation = catalogOperation
|
|
1917
|
+
?? (!freshCatalog ? sessionCatalogOperationContext : undefined);
|
|
1856
1918
|
const status = await statusCommandV7({
|
|
1857
1919
|
plugins: [...new Set([intent.pluginId,
|
|
1858
1920
|
...(intent.kind === 'pluginWrite' && intent.originIssue?.consumerPluginId
|
|
@@ -1877,7 +1939,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1877
1939
|
}
|
|
1878
1940
|
if (catalogOperationError)
|
|
1879
1941
|
throw catalogOperationError;
|
|
1880
|
-
if (!
|
|
1942
|
+
if (!catalogOperation) {
|
|
1881
1943
|
catalogOperation = await resolveCatalogOperationContext({
|
|
1882
1944
|
sourceIds: [parsePluginId(intent.pluginId).sourceId],
|
|
1883
1945
|
configSnapshot,
|
|
@@ -1889,122 +1951,80 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1889
1951
|
let dependencyPlan;
|
|
1890
1952
|
let codexReconcilePlans;
|
|
1891
1953
|
let operationPlan;
|
|
1892
|
-
let forceCleanupEvidence;
|
|
1893
1954
|
await preparation?.reporter.emit('catalog');
|
|
1894
|
-
const offlineCleanupTarget = offlineCleanupReason && intent.kind === 'pluginWrite'
|
|
1895
|
-
? status.payload.targets.find((target) => target.pluginId === intent.pluginId
|
|
1896
|
-
&& target.platform === intent.platform
|
|
1897
|
-
&& target.scope === intent.scope
|
|
1898
|
-
&& target.reasons.some((error) => error.code === offlineCleanupReason))
|
|
1899
|
-
: undefined;
|
|
1900
|
-
const catalogSource = offlineCleanupTarget
|
|
1901
|
-
? status.payload.catalog.sources.find((source) => source.id === offlineCleanupTarget.sourceId)
|
|
1902
|
-
: undefined;
|
|
1903
|
-
let offlineCleanup;
|
|
1904
|
-
if (offlineCleanupReason && offlineCleanupTarget) {
|
|
1905
|
-
await preparation?.reporter.emit('inventory');
|
|
1906
|
-
const inventory = await operationInventory({
|
|
1907
|
-
cwd: context.cwd,
|
|
1908
|
-
env: context.env,
|
|
1909
|
-
});
|
|
1910
|
-
signal?.throwIfAborted();
|
|
1911
|
-
offlineCleanup = offlineCleanupEvidenceFromInventory({
|
|
1912
|
-
reason: offlineCleanupReason,
|
|
1913
|
-
pluginId: offlineCleanupTarget.pluginId,
|
|
1914
|
-
pluginName: offlineCleanupTarget.pluginName,
|
|
1915
|
-
sourceId: offlineCleanupTarget.sourceId,
|
|
1916
|
-
sourceIdentity: offlineCleanupTarget.sourceIdentity,
|
|
1917
|
-
platform: offlineCleanupTarget.platform,
|
|
1918
|
-
scope: offlineCleanupTarget.scope,
|
|
1919
|
-
inventory,
|
|
1920
|
-
}) ?? undefined;
|
|
1921
|
-
if (!offlineCleanup) {
|
|
1922
|
-
throw operationReviewStale('离线清理现场证据已消失或无法验证。');
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
1955
|
const configVisibleTargets = intent.kind === 'configSave'
|
|
1926
1956
|
? configAffectedStatusTargets(status.payload.targets, intent.pluginId, intent.scope)
|
|
1927
1957
|
: [];
|
|
1928
|
-
const selected =
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1950
|
-
}
|
|
1951
|
-
await coercePluginConfigUpdates({
|
|
1952
|
-
schema: plugin.manifest.config.fields,
|
|
1953
|
-
updates: intent.updates ?? {},
|
|
1954
|
-
cwd: context.cwd,
|
|
1955
|
-
});
|
|
1956
|
-
for (const key of intent.removeKeys ?? []) {
|
|
1957
|
-
if (!plugin.manifest.config.fields[key]) {
|
|
1958
|
-
throw new TuiOperationBlockedError('unknownConfigKey', '设置字段已变化,请重新检查。');
|
|
1959
|
-
}
|
|
1958
|
+
const selected = await withResolvedCatalogPlugin({
|
|
1959
|
+
selector: intent.pluginId,
|
|
1960
|
+
cliVersion: packageInfo.version,
|
|
1961
|
+
configSnapshot,
|
|
1962
|
+
env: context.env,
|
|
1963
|
+
...(catalogOperation ? { operationContext: catalogOperation } : {}),
|
|
1964
|
+
...(signal ? { signal } : {}),
|
|
1965
|
+
consume: async ({ plugin, source }) => {
|
|
1966
|
+
if (preparation?.validateIntent && intent.kind === 'configSave') {
|
|
1967
|
+
await preparation.reporter.emit('config');
|
|
1968
|
+
if (!plugin.manifest.config) {
|
|
1969
|
+
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1970
|
+
}
|
|
1971
|
+
await coercePluginConfigUpdates({
|
|
1972
|
+
schema: plugin.manifest.config.fields,
|
|
1973
|
+
updates: intent.updates ?? {},
|
|
1974
|
+
cwd: context.cwd,
|
|
1975
|
+
});
|
|
1976
|
+
for (const key of intent.removeKeys ?? []) {
|
|
1977
|
+
if (!plugin.manifest.config.fields[key]) {
|
|
1978
|
+
throw new TuiOperationBlockedError('unknownConfigKey', '设置字段已变化,请重新检查。');
|
|
1960
1979
|
}
|
|
1961
1980
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1981
|
+
}
|
|
1982
|
+
const impact = intent.kind === 'configSave' && !intent.retryApply
|
|
1983
|
+
? await analyzePluginConfigMutationImpact({
|
|
1984
|
+
plugin,
|
|
1985
|
+
scope: intent.scope,
|
|
1986
|
+
cwd: context.cwd,
|
|
1987
|
+
env: context.env,
|
|
1988
|
+
visibleTargets: configImpactVisibleTargets(plugin.manifest.name, configVisibleTargets),
|
|
1989
|
+
mutation: {
|
|
1990
|
+
kind: 'patch',
|
|
1991
|
+
updates: intent.updates,
|
|
1992
|
+
removeKeys: intent.removeKeys,
|
|
1993
|
+
},
|
|
1994
|
+
})
|
|
1995
|
+
: undefined;
|
|
1996
|
+
return {
|
|
1997
|
+
pluginName: plugin.manifest.name,
|
|
1998
|
+
source: sourceEvidenceForPlugin(source, plugin.manifest.name),
|
|
1999
|
+
impact,
|
|
2000
|
+
preApplyAuthorization: intent.kind === 'configSave'
|
|
2001
|
+
&& configIntentRequestsApply(intent)
|
|
2002
|
+
? (await resolveConfigPreApplyAuthorization({
|
|
1964
2003
|
plugin,
|
|
1965
2004
|
scope: intent.scope,
|
|
1966
2005
|
cwd: context.cwd,
|
|
1967
2006
|
env: context.env,
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
2007
|
+
applyTargets: intent.retryApply
|
|
2008
|
+
? configImpactVisibleTargets(plugin.manifest.name, configVisibleTargets)
|
|
2009
|
+
: impact.affectedTargets,
|
|
2010
|
+
nativeCliRunner: context.nativeCliRunner,
|
|
2011
|
+
rebuildRuntime: {
|
|
2012
|
+
...(catalogOperation ? { catalogOperationContext: catalogOperation } : {}),
|
|
2013
|
+
...(catalogOperation?.generationSetDigest
|
|
2014
|
+
? { expectedGenerationSetDigest: catalogOperation.generationSetDigest }
|
|
2015
|
+
: {}),
|
|
2016
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1973
2017
|
},
|
|
1974
|
-
})
|
|
1975
|
-
:
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
scope: intent.scope,
|
|
1985
|
-
cwd: context.cwd,
|
|
1986
|
-
env: context.env,
|
|
1987
|
-
applyTargets: intent.retryApply
|
|
1988
|
-
? configImpactVisibleTargets(plugin.manifest.name, configVisibleTargets)
|
|
1989
|
-
: impact.affectedTargets,
|
|
1990
|
-
nativeCliRunner: context.nativeCliRunner,
|
|
1991
|
-
rebuildRuntime: {
|
|
1992
|
-
...(catalogOperation ? { catalogOperationContext: catalogOperation } : {}),
|
|
1993
|
-
...(catalogOperation?.generationSetDigest
|
|
1994
|
-
? { expectedGenerationSetDigest: catalogOperation.generationSetDigest }
|
|
1995
|
-
: {}),
|
|
1996
|
-
inventoryCatalogSourceReferences: operationInventory,
|
|
1997
|
-
},
|
|
1998
|
-
})).targets
|
|
1999
|
-
: [],
|
|
2000
|
-
sharedNativeRenderTargets: intent.kind === 'configSave'
|
|
2001
|
-
? intent.retryApply
|
|
2002
|
-
? configRetrySharedNativeRenderTargets(plugin)
|
|
2003
|
-
: impact.sharedNativeRenderTargets
|
|
2004
|
-
: [],
|
|
2005
|
-
};
|
|
2006
|
-
},
|
|
2007
|
-
});
|
|
2018
|
+
})).targets
|
|
2019
|
+
: [],
|
|
2020
|
+
sharedNativeRenderTargets: intent.kind === 'configSave'
|
|
2021
|
+
? intent.retryApply
|
|
2022
|
+
? configRetrySharedNativeRenderTargets(plugin)
|
|
2023
|
+
: impact.sharedNativeRenderTargets
|
|
2024
|
+
: [],
|
|
2025
|
+
};
|
|
2026
|
+
},
|
|
2027
|
+
});
|
|
2008
2028
|
if (intent.kind === 'pluginWrite' && intent.expectedUpdate) {
|
|
2009
2029
|
const revision = status.targetRevisions.find((entry) => entry.pluginId === intent.pluginId && entry.platform === intent.platform
|
|
2010
2030
|
&& entry.scope === intent.scope);
|
|
@@ -2060,17 +2080,6 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2060
2080
|
signal?.throwIfAborted();
|
|
2061
2081
|
codexReconcilePlans = preview?.codexReconcilePlans;
|
|
2062
2082
|
operationPlan = preview?.operationPlan;
|
|
2063
|
-
if (intent.action === 'cleanup' && intent.force === true) {
|
|
2064
|
-
const candidates = preview?.offlineCleanupPlans?.filter((candidate) => candidate.forceExclusive === true
|
|
2065
|
-
&& candidate.pluginId === intent.pluginId
|
|
2066
|
-
&& candidate.platform === intent.platform
|
|
2067
|
-
&& candidate.scope === intent.scope
|
|
2068
|
-
&& candidate.plan.actions.length > 0) ?? [];
|
|
2069
|
-
if (candidates.length !== 1) {
|
|
2070
|
-
throw new TuiOperationBlockedError('forceCleanupPathUnavailable', '没有唯一且可验证的精确清理目标。');
|
|
2071
|
-
}
|
|
2072
|
-
[forceCleanupEvidence] = candidates;
|
|
2073
|
-
}
|
|
2074
2083
|
if (hasDeclaredDependencies
|
|
2075
2084
|
&& (intent.action === 'install'
|
|
2076
2085
|
|| intent.action === 'refreshAndSync'
|
|
@@ -2124,8 +2133,6 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2124
2133
|
: {}),
|
|
2125
2134
|
},
|
|
2126
2135
|
source: selected.source,
|
|
2127
|
-
...(offlineCleanup ? { offlineCleanup } : {}),
|
|
2128
|
-
...(forceCleanupEvidence ? { offlineCleanup: forceCleanupEvidence } : {}),
|
|
2129
2136
|
...(dependencyPlan ? { dependencyPlan } : {}),
|
|
2130
2137
|
...(codexReconcilePlans ? { codexReconcilePlans } : {}),
|
|
2131
2138
|
...(operationPlan ? { operationPlan } : {}),
|
|
@@ -2857,7 +2864,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2857
2864
|
requestedPluginIds: group.requestedPluginIds,
|
|
2858
2865
|
executable: group.executable,
|
|
2859
2866
|
planFingerprint: group.preview.operationPlan
|
|
2860
|
-
?
|
|
2867
|
+
? intent.action === 'cleanup'
|
|
2868
|
+
? group.preview.operationPlan.planFingerprint
|
|
2869
|
+
: createBatchIntentCompatiblePlanFingerprint(group.preview.operationPlan)
|
|
2861
2870
|
: undefined,
|
|
2862
2871
|
}));
|
|
2863
2872
|
const currentGroups = currentBatch.groups.map((group) => ({
|
|
@@ -2872,7 +2881,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2872
2881
|
?.executable === false
|
|
2873
2882
|
? undefined
|
|
2874
2883
|
: group.preview.operationPlan
|
|
2875
|
-
?
|
|
2884
|
+
? intent.action === 'cleanup'
|
|
2885
|
+
? group.preview.operationPlan.planFingerprint
|
|
2886
|
+
: createBatchIntentCompatiblePlanFingerprint(group.preview.operationPlan)
|
|
2876
2887
|
: undefined,
|
|
2877
2888
|
}));
|
|
2878
2889
|
if (expectedBatch.catalog.configDigest !== currentBatch.catalog.configDigest
|
|
@@ -2884,6 +2895,12 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2884
2895
|
await tuiControllerRuntimeTestHooks?.afterMutationEvidenceCapture?.();
|
|
2885
2896
|
const groupResults = [];
|
|
2886
2897
|
const completedTargetKeys = new Set();
|
|
2898
|
+
const expectedIntentDigests = new Map();
|
|
2899
|
+
for (const group of expectedBatch.groups) {
|
|
2900
|
+
for (const intentDigest of group.preview.operationPlan?.evidence.intentDigests ?? []) {
|
|
2901
|
+
expectedIntentDigests.set(intentDigest.scope, intentDigest.digest);
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2887
2904
|
let executedGroupCount = 0;
|
|
2888
2905
|
const appendStoppedGroups = (startIndex, staleMessage) => {
|
|
2889
2906
|
for (const [offset, stopped] of expectedBatch.groups.slice(startIndex).entries()) {
|
|
@@ -2916,7 +2933,8 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2916
2933
|
? operationInventory
|
|
2917
2934
|
: createOperationInventoryReader();
|
|
2918
2935
|
let executionPreview = current.preview;
|
|
2919
|
-
if (completedTargetKeys.size > 0
|
|
2936
|
+
if (completedTargetKeys.size > 0
|
|
2937
|
+
|| (intent.action === 'cleanup' && executedGroupCount > 0)) {
|
|
2920
2938
|
executionPreview = await runBatchWriteGroup({
|
|
2921
2939
|
intent,
|
|
2922
2940
|
group: current,
|
|
@@ -2925,12 +2943,17 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2925
2943
|
...context,
|
|
2926
2944
|
awHomeMutationToken,
|
|
2927
2945
|
inventoryCatalogSourceReferences: groupInventory,
|
|
2928
|
-
|
|
2946
|
+
...(intent.action === 'cleanup' ? {} : {
|
|
2947
|
+
expectedCatalogConfigDigest: expectedBatch.catalog.configDigest,
|
|
2948
|
+
}),
|
|
2929
2949
|
previewOperationPlan: true,
|
|
2930
2950
|
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
2931
2951
|
},
|
|
2932
2952
|
});
|
|
2933
|
-
|
|
2953
|
+
const cleanupIntentDigestChanged = intent.action === 'cleanup'
|
|
2954
|
+
&& executionPreview.operationPlan?.evidence.intentDigests.find((entry) => entry.scope === current.scope)?.digest !== expectedIntentDigests.get(current.scope);
|
|
2955
|
+
if (cleanupIntentDigestChanged
|
|
2956
|
+
|| !reviewed.preview.operationPlan || !executionPreview.operationPlan
|
|
2934
2957
|
|| createBatchIntentCompatiblePlanFingerprint(reviewed.preview.operationPlan, completedTargetKeys) !== createBatchIntentCompatiblePlanFingerprint(executionPreview.operationPlan, completedTargetKeys)) {
|
|
2935
2958
|
appendStoppedGroups(groupIndex, '前序批量结果改变了这个组的实际写入计划。');
|
|
2936
2959
|
break;
|
|
@@ -2946,7 +2969,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2946
2969
|
awHomeMutationToken,
|
|
2947
2970
|
preApplyConfirmed: true,
|
|
2948
2971
|
inventoryCatalogSourceReferences: groupInventory,
|
|
2949
|
-
|
|
2972
|
+
...(intent.action === 'cleanup' ? {} : {
|
|
2973
|
+
expectedCatalogConfigDigest: expectedBatch.catalog.configDigest,
|
|
2974
|
+
}),
|
|
2950
2975
|
...(executionPreview.operationPlan ? {
|
|
2951
2976
|
expectedPlanFingerprint: executionPreview.operationPlan.planFingerprint,
|
|
2952
2977
|
} : {}),
|
|
@@ -2962,6 +2987,11 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
2962
2987
|
appendStoppedGroups(groupIndex, '这个组的实际写入计划发生变化。');
|
|
2963
2988
|
break;
|
|
2964
2989
|
}
|
|
2990
|
+
if (intent.action === 'cleanup') {
|
|
2991
|
+
for (const change of result.operationPlan?.intentChanges ?? []) {
|
|
2992
|
+
expectedIntentDigests.set(change.scope, change.afterDigest);
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2965
2995
|
executedGroupCount += 1;
|
|
2966
2996
|
for (const target of result.targetResults) {
|
|
2967
2997
|
if (target.state === 'completed') {
|
|
@@ -3150,16 +3180,28 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
3150
3180
|
cleanup: cleanupWriteCommand,
|
|
3151
3181
|
sync: syncWriteCommand,
|
|
3152
3182
|
}[intent.action];
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3183
|
+
if (intent.action === 'cleanup') {
|
|
3184
|
+
if (!expectedEvidence.operationPlan || !currentEvidence.operationPlan
|
|
3185
|
+
|| expectedEvidence.operationPlan.planFingerprint
|
|
3186
|
+
!== currentEvidence.operationPlan.planFingerprint) {
|
|
3187
|
+
throw operationReviewStale('确认后清理计划发生变化。');
|
|
3188
|
+
}
|
|
3189
|
+
const result = await command([intent.pluginId], options, {
|
|
3190
|
+
...context,
|
|
3191
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
3192
|
+
awHomeMutationToken,
|
|
3193
|
+
preApplyConfirmed: true,
|
|
3194
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
3195
|
+
expectedPlanFingerprint: expectedEvidence.operationPlan.planFingerprint,
|
|
3196
|
+
...(expectedEvidence.codexManager?.state === 'requires-install'
|
|
3197
|
+
? { managedCodexAuthorizer: async () => true }
|
|
3198
|
+
: {}),
|
|
3199
|
+
});
|
|
3200
|
+
throwIfWriteReviewStale(result);
|
|
3201
|
+
return result;
|
|
3161
3202
|
}
|
|
3162
|
-
|
|
3203
|
+
const currentSource = currentEvidence.source;
|
|
3204
|
+
if (!expectedEvidence.source || !currentSource) {
|
|
3163
3205
|
throw new TuiOperationBlockedError('operationReviewStale', '确认信息缺少来源身份。');
|
|
3164
3206
|
}
|
|
3165
3207
|
const result = await command([intent.pluginId], options, {
|
|
@@ -3179,9 +3221,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
3179
3221
|
...(expectedEvidence.codexManager?.state === 'requires-install'
|
|
3180
3222
|
? { managedCodexAuthorizer: async () => true }
|
|
3181
3223
|
: {}),
|
|
3182
|
-
|
|
3183
|
-
? { expectedOfflineCleanupEvidence: reviewedOfflineCleanup }
|
|
3184
|
-
: { reviewPreflight: (actual) => assertSourceEvidenceMatches(currentSource, actual) }),
|
|
3224
|
+
reviewPreflight: (actual) => assertSourceEvidenceMatches(currentSource, actual),
|
|
3185
3225
|
});
|
|
3186
3226
|
throwIfWriteReviewStale(result);
|
|
3187
3227
|
return result;
|