@lesliechan721/aw 0.1.0-beta.10 → 0.1.0-beta.11
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/authoring/assets/aw-config.d.mts +1 -50
- package/dist/authoring/assets/aw-config.mjs +58 -928
- package/dist/authoring/assets/aw-config.mjs.map +1 -1
- package/dist/authoring/scripts/init-plugin.mjs +28 -33
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/lib/plugin-version-check.d.mts +1 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +229 -8
- package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +165 -45
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
- package/dist/scripts/bundle-plugins.js +18 -4
- package/dist/scripts/bundle-plugins.js.map +1 -1
- package/dist/scripts/test-plugin-scripts.d.ts +2 -0
- package/dist/scripts/test-plugin-scripts.js +21 -5
- package/dist/scripts/test-plugin-scripts.js.map +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +1 -1
- package/dist/src/commands/aw-capabilities.js +1 -1
- package/dist/src/commands/aw-capabilities.js.map +1 -1
- package/dist/src/commands/catalog-dev-source.d.ts +6 -3
- package/dist/src/commands/catalog-dev-source.js +96 -35
- package/dist/src/commands/catalog-dev-source.js.map +1 -1
- package/dist/src/commands/catalog-publication-inspection.d.ts +1 -1
- package/dist/src/commands/catalog-publication-inspection.js +54 -8
- package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
- package/dist/src/commands/catalog-publication-journal.js +1 -1
- package/dist/src/commands/catalog-publication-journal.js.map +1 -1
- package/dist/src/commands/catalog-source.d.ts +19 -4
- package/dist/src/commands/catalog-source.js +121 -12
- package/dist/src/commands/catalog-source.js.map +1 -1
- package/dist/src/commands/catalog-store.d.ts +26 -7
- package/dist/src/commands/catalog-store.js +361 -42
- package/dist/src/commands/catalog-store.js.map +1 -1
- package/dist/src/commands/console.js +28 -17
- package/dist/src/commands/console.js.map +1 -1
- package/dist/src/commands/operation-plan.d.ts +2 -1
- package/dist/src/commands/operation-plan.js +24 -0
- package/dist/src/commands/operation-plan.js.map +1 -1
- package/dist/src/commands/operation-planner.d.ts +2 -2
- package/dist/src/commands/operation-planner.js +11 -19
- package/dist/src/commands/operation-planner.js.map +1 -1
- package/dist/src/commands/options.d.ts +2 -2
- package/dist/src/commands/options.js +18 -4
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/plugin-capabilities.js +2 -2
- package/dist/src/commands/plugin-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +7 -0
- package/dist/src/commands/rebuild-command.js +769 -279
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +24 -47
- package/dist/src/commands/rebuild-integration.js +1074 -1011
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/rebuild-operations.d.ts +50 -12
- package/dist/src/commands/rebuild-operations.js +207 -101
- package/dist/src/commands/rebuild-operations.js.map +1 -1
- package/dist/src/commands/status-v6.d.ts +21 -2
- package/dist/src/commands/status-v6.js +163 -31
- package/dist/src/commands/status-v6.js.map +1 -1
- package/dist/src/commands/sync-command.d.ts +17 -0
- package/dist/src/commands/sync-command.js +45 -37
- package/dist/src/commands/sync-command.js.map +1 -1
- package/dist/src/commands/write-commands.d.ts +5 -0
- package/dist/src/commands/write-commands.js +50 -3
- package/dist/src/commands/write-commands.js.map +1 -1
- package/dist/src/generators/local-plugin.js +14 -4
- package/dist/src/generators/local-plugin.js.map +1 -1
- package/dist/src/index.js +216 -85
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/command-receipt.js +1 -3
- package/dist/src/output/command-receipt.js.map +1 -1
- package/dist/src/output/rebuild-progress.js +1 -3
- package/dist/src/output/rebuild-progress.js.map +1 -1
- package/dist/src/portable/materializer.js +6 -6
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/tui/catalog-generation.js +41 -1
- package/dist/src/tui/catalog-generation.js.map +1 -1
- package/dist/src/tui/catalog-sources/session.d.ts +1 -0
- package/dist/src/tui/catalog-sources/session.js +16 -3
- package/dist/src/tui/catalog-sources/session.js.map +1 -1
- package/dist/src/tui/catalog-sources/types.d.ts +3 -2
- package/dist/src/tui/components.d.ts +4 -0
- package/dist/src/tui/components.js +36 -24
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/console-app-v4.d.ts +13 -4
- package/dist/src/tui/console-app-v4.js +2067 -839
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.js +585 -33
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +152 -6
- package/dist/src/tui/controller.js +1168 -156
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/diagnostic-projection.d.ts +22 -0
- package/dist/src/tui/diagnostic-projection.js +437 -0
- package/dist/src/tui/diagnostic-projection.js.map +1 -0
- package/dist/src/tui/diagnostics.d.ts +1 -1
- package/dist/src/tui/diagnostics.js +6 -1
- package/dist/src/tui/diagnostics.js.map +1 -1
- package/dist/src/tui/glossary.d.ts +23 -0
- package/dist/src/tui/glossary.js +42 -0
- package/dist/src/tui/glossary.js.map +1 -0
- package/dist/src/tui/index.d.ts +4 -1
- package/dist/src/tui/index.js +4 -1
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/keys.d.ts +44 -0
- package/dist/src/tui/keys.js +43 -15
- package/dist/src/tui/keys.js.map +1 -1
- package/dist/src/tui/lifecycle-action-view.d.ts +6 -0
- package/dist/src/tui/lifecycle-action-view.js +34 -0
- package/dist/src/tui/lifecycle-action-view.js.map +1 -0
- package/dist/src/tui/model.d.ts +12 -2
- package/dist/src/tui/model.js +128 -52
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-diagnostic-screens.d.ts +21 -0
- package/dist/src/tui/operation-diagnostic-screens.js +101 -0
- package/dist/src/tui/operation-diagnostic-screens.js.map +1 -0
- package/dist/src/tui/operation-history.d.ts +80 -0
- package/dist/src/tui/operation-history.js +130 -0
- package/dist/src/tui/operation-history.js.map +1 -0
- package/dist/src/tui/operation-review-planner.js +306 -86
- package/dist/src/tui/operation-review-planner.js.map +1 -1
- package/dist/src/tui/router.d.ts +82 -17
- package/dist/src/tui/router.js +186 -38
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/screen-registry.d.ts +546 -0
- package/dist/src/tui/screen-registry.js +179 -0
- package/dist/src/tui/screen-registry.js.map +1 -0
- package/dist/src/tui/session-console-app.d.ts +6 -0
- package/dist/src/tui/session-console-app.js +13 -0
- package/dist/src/tui/session-console-app.js.map +1 -0
- package/dist/src/tui/session-host.d.ts +44 -0
- package/dist/src/tui/session-host.js +197 -0
- package/dist/src/tui/session-host.js.map +1 -0
- package/dist/src/types.d.ts +64 -3
- package/dist/src/types.js +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/agent-version.js +1 -1
- package/dist/src/utils/agent-version.js.map +1 -1
- package/dist/src/utils/artifact-renderer.d.ts +2 -1
- package/dist/src/utils/artifact-renderer.js +52 -52
- package/dist/src/utils/artifact-renderer.js.map +1 -1
- package/dist/src/utils/bundle-layout.js +4 -4
- package/dist/src/utils/bundle-layout.js.map +1 -1
- package/dist/src/utils/catalog-capability-projection.d.ts +8 -0
- package/dist/src/utils/catalog-capability-projection.js +14 -0
- package/dist/src/utils/catalog-capability-projection.js.map +1 -0
- package/dist/src/utils/catalog-generation-resolver.d.ts +14 -2
- package/dist/src/utils/catalog-generation-resolver.js +49 -27
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
- package/dist/src/utils/catalog-generation-service.d.ts +8 -1
- package/dist/src/utils/catalog-generation-service.js +81 -47
- package/dist/src/utils/catalog-generation-service.js.map +1 -1
- package/dist/src/utils/catalog-generation-store.d.ts +1 -0
- package/dist/src/utils/catalog-generation-store.js +60 -5
- package/dist/src/utils/catalog-generation-store.js.map +1 -1
- package/dist/src/utils/catalog-operation-context.js +1 -0
- package/dist/src/utils/catalog-operation-context.js.map +1 -1
- package/dist/src/utils/catalog-public-error.js +4 -0
- package/dist/src/utils/catalog-public-error.js.map +1 -1
- package/dist/src/utils/catalog-source-impact.d.ts +3 -2
- package/dist/src/utils/catalog-source-impact.js +142 -20
- package/dist/src/utils/catalog-source-impact.js.map +1 -1
- package/dist/src/utils/catalog-source-references.js +95 -9
- package/dist/src/utils/catalog-source-references.js.map +1 -1
- package/dist/src/utils/catalog-sources.d.ts +1 -1
- package/dist/src/utils/catalog-sources.js +19 -3
- package/dist/src/utils/catalog-sources.js.map +1 -1
- package/dist/src/utils/codex-manager.js +8 -0
- package/dist/src/utils/codex-manager.js.map +1 -1
- package/dist/src/utils/codex-native-observation.d.ts +34 -1
- package/dist/src/utils/codex-native-observation.js +132 -0
- package/dist/src/utils/codex-native-observation.js.map +1 -1
- package/dist/src/utils/codex-reconciler.d.ts +0 -2
- package/dist/src/utils/codex-reconciler.js.map +1 -1
- package/dist/src/utils/codex-shared-native.d.ts +2 -26
- package/dist/src/utils/codex-shared-native.js +8 -82
- package/dist/src/utils/codex-shared-native.js.map +1 -1
- package/dist/src/utils/git-catalog-provider.d.ts +3 -0
- package/dist/src/utils/git-catalog-provider.js +40 -1
- package/dist/src/utils/git-catalog-provider.js.map +1 -1
- package/dist/src/utils/local-marketplace.d.ts +1 -0
- package/dist/src/utils/local-marketplace.js +69 -73
- package/dist/src/utils/local-marketplace.js.map +1 -1
- package/dist/src/utils/multi-source-catalog.js +1 -0
- package/dist/src/utils/multi-source-catalog.js.map +1 -1
- package/dist/src/utils/native-cli.d.ts +9 -4
- package/dist/src/utils/native-cli.js +280 -34
- package/dist/src/utils/native-cli.js.map +1 -1
- package/dist/src/utils/path-catalog-provider.js +2 -0
- package/dist/src/utils/path-catalog-provider.js.map +1 -1
- package/dist/src/utils/plugin-config-write.d.ts +15 -13
- package/dist/src/utils/plugin-config-write.js +418 -198
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/plugin-config.d.ts +48 -4
- package/dist/src/utils/plugin-config.js +289 -38
- package/dist/src/utils/plugin-config.js.map +1 -1
- package/dist/src/utils/plugin-scripts.d.ts +20 -12
- package/dist/src/utils/plugin-scripts.js +376 -109
- package/dist/src/utils/plugin-scripts.js.map +1 -1
- package/dist/src/utils/process-tree.d.ts +2 -2
- package/dist/src/utils/process-tree.js +1 -1
- package/dist/src/utils/process-tree.js.map +1 -1
- package/dist/src/utils/project-boundary.d.ts +11 -1
- package/dist/src/utils/project-boundary.js +17 -8
- package/dist/src/utils/project-boundary.js.map +1 -1
- package/dist/src/utils/safe-operation-diagnostic.d.ts +15 -0
- package/dist/src/utils/safe-operation-diagnostic.js +33 -0
- package/dist/src/utils/safe-operation-diagnostic.js.map +1 -0
- package/dist/src/utils/sensitive-content.d.ts +1 -0
- package/dist/src/utils/sensitive-content.js +15 -0
- package/dist/src/utils/sensitive-content.js.map +1 -0
- package/dist/src/utils/windows-claude-shim.d.ts +9 -0
- package/dist/src/utils/windows-claude-shim.js +141 -0
- package/dist/src/utils/windows-claude-shim.js.map +1 -0
- package/dist/vitest.config.js +91 -10
- package/dist/vitest.config.js.map +1 -1
- package/package.json +9 -9
- package/dist/authoring/templates/aw-config-runtime.d.mts +0 -2
- package/dist/authoring/templates/aw-config-runtime.mjs +0 -407
- package/dist/authoring/templates/aw-config-runtime.mjs.map +0 -1
|
@@ -2,13 +2,19 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { statusCommandV7, statusTargetIntent, } from '../commands/status-v6.js';
|
|
4
4
|
import { addCatalogSourceCommand, listCatalogSources, preflightCatalogSourceMutation, removeCatalogSourceCommand, setPrimaryCatalogSourceCommand, updateCatalogSourceCommand, } from '../commands/catalog-source.js';
|
|
5
|
-
import { cleanupWriteCommand, installWriteCommand, reinstallWriteCommand, syncWriteCommand, uninstallWriteCommand, } from '../commands/write-commands.js';
|
|
5
|
+
import { cleanupWriteCommand, failedWriteCommandResult, installWriteCommand, mergeWriteCommandResults, reinstallWriteCommand, syncWriteCommand, uninstallWriteCommand, } from '../commands/write-commands.js';
|
|
6
|
+
import { resolveSyncIntentSelection } from '../commands/sync-command.js';
|
|
7
|
+
import { parseScriptTimeoutMs, SCRIPT_TIMEOUT_DEFAULT_MS, } from '../commands/options.js';
|
|
6
8
|
import { readCliPackageInfo } from '../utils/local-marketplace.js';
|
|
9
|
+
import { createCodexNativeObservationSession, } from '../utils/codex-native-observation.js';
|
|
7
10
|
import { readCatalogSourcesConfigSnapshot, recoverInvalidCatalogSourcesConfig, } from '../utils/catalog-sources.js';
|
|
8
11
|
import { withResolvedCatalogPlugin, withResolvedMultiSourceCatalog, formatPluginId, parsePluginId, } from '../utils/multi-source-catalog.js';
|
|
9
|
-
import { coercePluginConfigUpdates, inspectPluginConfigResetTarget, readPluginConfigStore, resolveConfigRead, resolveEffectivePluginConfig, } from '../utils/plugin-config.js';
|
|
12
|
+
import { coercePluginConfigUpdates, inspectPluginConfigResetTarget, listNamespacedPluginConfigStoreIdentities, readPluginConfigStore, resolveConfigRead, resolveEffectivePluginConfig, resolvePluginConfigStorePath, } from '../utils/plugin-config.js';
|
|
13
|
+
import { assertProjectSharedConfigPathVisible } from '../utils/project-boundary.js';
|
|
14
|
+
import { readPluginIntentState } from '../utils/plugin-intent-state.js';
|
|
10
15
|
import { applyPluginConfigWrite, replayConfigRuntimeWrites, resetPluginConfigWithHelper, } from '../utils/plugin-config-write.js';
|
|
11
|
-
import {
|
|
16
|
+
import { createBatchIntentCompatiblePlanFingerprint } from '../commands/operation-plan.js';
|
|
17
|
+
import { offlineCleanupEvidenceFromInventory, offlineCleanupEvidenceMatches, } from '../commands/offline-cleanup-evidence.js';
|
|
12
18
|
import { inventoryCatalogSourceReferences } from '../utils/catalog-source-references.js';
|
|
13
19
|
import { operationEvidenceMatches, operationEvidenceFingerprint, TuiConfigInvalidStoreError, TuiController, TuiOperationBlockedError, } from './controller.js';
|
|
14
20
|
import { buildConfigGroups, buildConfigPage, projectPlatformPlacement, } from './model.js';
|
|
@@ -113,12 +119,14 @@ export function configAffectedStatusTargets(targets, pluginId, configScope) {
|
|
|
113
119
|
.localeCompare(`${right.platform}\0${right.scope}`, 'en'));
|
|
114
120
|
}
|
|
115
121
|
function configSharedNativeRenderTargets(plugin, changedKeys) {
|
|
116
|
-
const changed = new Set(changedKeys);
|
|
122
|
+
const changed = changedKeys ? new Set(changedKeys) : undefined;
|
|
117
123
|
return (plugin.manifest.artifacts?.targets ?? []).flatMap((target) => target.platform === 'codex'
|
|
118
124
|
&& target.target === 'codex.skill'
|
|
119
125
|
&& target.delivery.mode === 'codex-native'
|
|
120
126
|
&& target.skillKey
|
|
121
|
-
&&
|
|
127
|
+
&& (changed
|
|
128
|
+
? target.refreshKeys.some((key) => changed.has(key))
|
|
129
|
+
: target.refreshKeys.length > 0)
|
|
122
130
|
? [{ id: target.id, skillKey: target.skillKey, refreshKeys: [...target.refreshKeys] }]
|
|
123
131
|
: []);
|
|
124
132
|
}
|
|
@@ -130,6 +138,7 @@ function sourceEvidenceForPlugin(source, pluginName) {
|
|
|
130
138
|
return {
|
|
131
139
|
sourceId: source.sourceId,
|
|
132
140
|
sourceIdentity: source.sourceIdentity,
|
|
141
|
+
logicalIdentity: source.logicalIdentity,
|
|
133
142
|
requestedRef: source.requestedRef,
|
|
134
143
|
resolvedCommit: source.resolvedCommit,
|
|
135
144
|
manifestDigest: source.manifestDigest,
|
|
@@ -140,9 +149,27 @@ function sourceEvidenceForPlugin(source, pluginName) {
|
|
|
140
149
|
channel: source.manifest.channel,
|
|
141
150
|
};
|
|
142
151
|
}
|
|
152
|
+
async function inspectConfigShareability(options) {
|
|
153
|
+
if (options.scope !== 'project')
|
|
154
|
+
return undefined;
|
|
155
|
+
const targetPath = resolvePluginConfigStorePath({
|
|
156
|
+
sourceId: options.sourceId,
|
|
157
|
+
pluginName: options.pluginName,
|
|
158
|
+
scope: 'project',
|
|
159
|
+
cwd: options.cwd,
|
|
160
|
+
env: options.env,
|
|
161
|
+
});
|
|
162
|
+
const visibility = await assertProjectSharedConfigPathVisible({
|
|
163
|
+
cwd: options.cwd,
|
|
164
|
+
targetPath,
|
|
165
|
+
env: options.env,
|
|
166
|
+
});
|
|
167
|
+
return visibility.state === 'unverified' ? 'unverified' : 'verified';
|
|
168
|
+
}
|
|
143
169
|
function assertSourceEvidenceMatches(expected, actual) {
|
|
144
170
|
if (actual.sourceId !== expected.sourceId
|
|
145
171
|
|| actual.sourceIdentity !== expected.sourceIdentity
|
|
172
|
+
|| actual.logicalIdentity !== expected.logicalIdentity
|
|
146
173
|
|| actual.resolvedCommit !== expected.resolvedCommit
|
|
147
174
|
|| actual.manifestDigest !== expected.manifestDigest
|
|
148
175
|
|| actual.snapshotDigest !== expected.snapshotDigest
|
|
@@ -150,10 +177,12 @@ function assertSourceEvidenceMatches(expected, actual) {
|
|
|
150
177
|
throw operationReviewStale('确认后来源内容发生变化。');
|
|
151
178
|
}
|
|
152
179
|
}
|
|
153
|
-
function
|
|
154
|
-
|
|
180
|
+
function writeReviewIsStale(result) {
|
|
181
|
+
return result.targetResults.some((target) => target.errorCode === 'operationReviewStale'
|
|
155
182
|
|| target.errorCode === 'operationPlanStale');
|
|
156
|
-
|
|
183
|
+
}
|
|
184
|
+
function throwIfWriteReviewStale(result) {
|
|
185
|
+
if (writeReviewIsStale(result)) {
|
|
157
186
|
throw operationReviewStale('确认后实际写入计划发生变化。');
|
|
158
187
|
}
|
|
159
188
|
}
|
|
@@ -163,6 +192,122 @@ const SOURCE_PROGRESS_PHASES = {
|
|
|
163
192
|
function pluginIntent(intent) {
|
|
164
193
|
return 'pluginId' in intent;
|
|
165
194
|
}
|
|
195
|
+
function reviewedScriptTimeoutMs(intent) {
|
|
196
|
+
if ((intent.kind === 'pluginWrite' || intent.kind === 'pluginWriteBatch')
|
|
197
|
+
&& (intent.action === 'install' || intent.action === 'refreshAndSync'
|
|
198
|
+
|| intent.action === 'reinstall' || intent.action === 'sync')) {
|
|
199
|
+
return parseScriptTimeoutMs(intent.scriptTimeoutMs ?? SCRIPT_TIMEOUT_DEFAULT_MS);
|
|
200
|
+
}
|
|
201
|
+
if (intent.kind === 'configSave' && intent.apply) {
|
|
202
|
+
return parseScriptTimeoutMs(intent.scriptTimeoutMs ?? SCRIPT_TIMEOUT_DEFAULT_MS);
|
|
203
|
+
}
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
function selectedBatchGroups(intent) {
|
|
207
|
+
if (intent.selection.kind !== 'selected' && intent.selection.kind !== 'targets') {
|
|
208
|
+
throw new TuiOperationBlockedError('syncSelectionRequired', '当前项目全部同步必须从项目 intent roots 解析。');
|
|
209
|
+
}
|
|
210
|
+
const rawTargets = intent.selection.kind === 'targets'
|
|
211
|
+
? intent.selection.targets
|
|
212
|
+
: intent.selection.pluginIds.map((pluginId) => ({
|
|
213
|
+
pluginId, platform: intent.platform, scope: intent.scope,
|
|
214
|
+
}));
|
|
215
|
+
const normalizedTargets = rawTargets.map((target) => {
|
|
216
|
+
if ((target.platform !== 'codex' && target.platform !== 'claude' && target.platform !== 'both')
|
|
217
|
+
|| target.scope !== intent.scope
|
|
218
|
+
|| (intent.selection.kind === 'targets' && target.platform === 'both')) {
|
|
219
|
+
throw new TuiOperationBlockedError('batchTargetInvalid', '批量精确目标必须使用共同 scope 和单个平台。');
|
|
220
|
+
}
|
|
221
|
+
const pluginId = target.pluginId;
|
|
222
|
+
const parsed = parsePluginId(pluginId);
|
|
223
|
+
if (!parsed.sourceId) {
|
|
224
|
+
throw new TuiOperationBlockedError('invalidPluginId', '批量操作必须使用 canonical pluginId。');
|
|
225
|
+
}
|
|
226
|
+
const canonicalPluginId = formatPluginId({ sourceId: parsed.sourceId, pluginName: parsed.pluginName });
|
|
227
|
+
if (intent.selection.kind === 'targets' && canonicalPluginId !== pluginId) {
|
|
228
|
+
throw new TuiOperationBlockedError('invalidPluginId', '批量精确目标必须使用 canonical pluginId。');
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
pluginId: canonicalPluginId,
|
|
232
|
+
platform: target.platform,
|
|
233
|
+
scope: target.scope,
|
|
234
|
+
};
|
|
235
|
+
}).sort((left, right) => [left.pluginId, left.platform, left.scope].join('\0')
|
|
236
|
+
.localeCompare([right.pluginId, right.platform, right.scope].join('\0'), 'en'));
|
|
237
|
+
const uniqueTargets = [...new Map(normalizedTargets.map((target) => [
|
|
238
|
+
[target.pluginId, target.platform, target.scope].join('\0'), target,
|
|
239
|
+
])).values()];
|
|
240
|
+
const requestedPluginIds = [...new Set(uniqueTargets.map((target) => target.pluginId))];
|
|
241
|
+
if (requestedPluginIds.length === 0) {
|
|
242
|
+
throw new TuiOperationBlockedError('syncSelectionRequired', '批量操作至少需要一个插件。');
|
|
243
|
+
}
|
|
244
|
+
const groups = new Map();
|
|
245
|
+
for (const target of uniqueTargets) {
|
|
246
|
+
const pluginId = target.pluginId;
|
|
247
|
+
const sourceId = parsePluginId(pluginId).sourceId;
|
|
248
|
+
const groupKey = [sourceId, target.platform, target.scope].join('\0');
|
|
249
|
+
const group = groups.get(groupKey) ?? {
|
|
250
|
+
groupId: groupKey,
|
|
251
|
+
sourceId,
|
|
252
|
+
platform: target.platform,
|
|
253
|
+
scope: target.scope,
|
|
254
|
+
requestedPluginIds: [],
|
|
255
|
+
};
|
|
256
|
+
group.requestedPluginIds.push(pluginId);
|
|
257
|
+
groups.set(groupKey, group);
|
|
258
|
+
}
|
|
259
|
+
return { requestedPluginIds, groups: [...groups.values()] };
|
|
260
|
+
}
|
|
261
|
+
async function resolveBatchGroups(intent, env, cwd, frozenRequestedPluginIds) {
|
|
262
|
+
if (intent.selection.kind === 'selected' || intent.selection.kind === 'targets') {
|
|
263
|
+
return selectedBatchGroups(intent);
|
|
264
|
+
}
|
|
265
|
+
if (intent.action !== 'sync' || intent.scope !== 'project') {
|
|
266
|
+
throw new TuiOperationBlockedError('syncSelectionRequired', '当前项目全部操作只支持 project scope sync。');
|
|
267
|
+
}
|
|
268
|
+
const state = await readPluginIntentState({ scope: 'project', cwd, env });
|
|
269
|
+
const selection = resolveSyncIntentSelection({
|
|
270
|
+
roots: state.roots,
|
|
271
|
+
selectors: frozenRequestedPluginIds ?? [],
|
|
272
|
+
all: frozenRequestedPluginIds === undefined,
|
|
273
|
+
platform: intent.platform,
|
|
274
|
+
});
|
|
275
|
+
if (selection.requestedPluginIds.length === 0) {
|
|
276
|
+
throw new TuiOperationBlockedError('syncSelectionRequired', '当前项目没有可同步的 intent roots。');
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
requestedPluginIds: selection.requestedPluginIds,
|
|
280
|
+
groups: selection.groups.map((group) => ({
|
|
281
|
+
groupId: `${group.sourceId}\0${group.platform}\0${intent.scope}`,
|
|
282
|
+
sourceId: group.sourceId,
|
|
283
|
+
platform: group.platform,
|
|
284
|
+
scope: intent.scope,
|
|
285
|
+
requestedPluginIds: group.pluginIds,
|
|
286
|
+
})),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
async function runBatchWriteGroup(options) {
|
|
290
|
+
const commandOptions = {
|
|
291
|
+
cwd: options.cwd,
|
|
292
|
+
platform: options.group.platform,
|
|
293
|
+
scope: options.group.scope,
|
|
294
|
+
...(reviewedScriptTimeoutMs(options.intent) === undefined
|
|
295
|
+
? {}
|
|
296
|
+
: { scriptTimeoutMs: reviewedScriptTimeoutMs(options.intent) }),
|
|
297
|
+
};
|
|
298
|
+
switch (options.intent.action) {
|
|
299
|
+
case 'install':
|
|
300
|
+
return installWriteCommand(options.group.requestedPluginIds, commandOptions, options.runtime);
|
|
301
|
+
case 'sync':
|
|
302
|
+
return syncWriteCommand(options.group.requestedPluginIds, commandOptions, options.runtime);
|
|
303
|
+
case 'reinstall':
|
|
304
|
+
return reinstallWriteCommand(options.group.requestedPluginIds, commandOptions, options.runtime);
|
|
305
|
+
case 'uninstall':
|
|
306
|
+
return uninstallWriteCommand(options.group.requestedPluginIds, commandOptions, options.runtime);
|
|
307
|
+
case 'cleanup':
|
|
308
|
+
return cleanupWriteCommand(options.group.requestedPluginIds, commandOptions, options.runtime);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
166
311
|
async function loadDependencyOverviews(options) {
|
|
167
312
|
const graph = await withResolvedMultiSourceCatalog({
|
|
168
313
|
cliVersion: options.cliVersion,
|
|
@@ -437,6 +582,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
437
582
|
};
|
|
438
583
|
};
|
|
439
584
|
const catalogOperationByEvidence = new WeakMap();
|
|
585
|
+
const codexManagerByEvidence = new WeakMap();
|
|
440
586
|
let sessionCatalogOperationContext;
|
|
441
587
|
let sessionStatusResult;
|
|
442
588
|
const sessionContextForPlugin = (pluginId) => {
|
|
@@ -450,6 +596,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
450
596
|
const stores = await Promise.all(scopes.map((scope) => readPluginConfigStore({
|
|
451
597
|
sourceId: config.sourceId,
|
|
452
598
|
sourceIdentity: config.sourceIdentity,
|
|
599
|
+
logicalIdentity: config.logicalIdentity,
|
|
453
600
|
pluginName: config.pluginName,
|
|
454
601
|
scope,
|
|
455
602
|
cwd: context.cwd,
|
|
@@ -541,14 +688,38 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
541
688
|
signal.throwIfAborted();
|
|
542
689
|
const catalogGenerations = await loadCatalogGenerations();
|
|
543
690
|
signal.throwIfAborted();
|
|
691
|
+
const configStoreInventory = (await Promise.all(['user', 'project'].map(async (scope) => {
|
|
692
|
+
try {
|
|
693
|
+
return (await listNamespacedPluginConfigStoreIdentities({
|
|
694
|
+
cwd: context.cwd,
|
|
695
|
+
env: context.env,
|
|
696
|
+
scope,
|
|
697
|
+
})).map(({ pluginId, sourceId, pluginName }) => ({
|
|
698
|
+
pluginId, sourceId, pluginName, scope,
|
|
699
|
+
}));
|
|
700
|
+
}
|
|
701
|
+
catch {
|
|
702
|
+
await context.debugLogger.log({
|
|
703
|
+
type: 'tui:config-inventory-error',
|
|
704
|
+
level: 'debug',
|
|
705
|
+
target: 'debugLog',
|
|
706
|
+
message: 'TUI saved config inventory could not be read.',
|
|
707
|
+
data: { scope },
|
|
708
|
+
});
|
|
709
|
+
return [];
|
|
710
|
+
}
|
|
711
|
+
}))).flat();
|
|
712
|
+
signal.throwIfAborted();
|
|
544
713
|
const statusById = new Map(result.payload.catalog.sources.map((source) => [source.id, source]));
|
|
545
714
|
return {
|
|
546
715
|
cliChannel: packageInfo.version.includes('-') ? 'beta' : 'latest',
|
|
716
|
+
configuredSources: structuredClone(configured.sources),
|
|
547
717
|
payload: result.payload,
|
|
548
718
|
pluginSummaries: result.pluginSummaries,
|
|
549
719
|
targetRevisions: result.targetRevisions,
|
|
550
720
|
dependencyOverviews,
|
|
551
721
|
portablePluginIds,
|
|
722
|
+
configStoreInventory,
|
|
552
723
|
catalogGenerations,
|
|
553
724
|
sessionGenerationKeys: Object.fromEntries((catalogOperationContext?.generationSet.sources ?? [])
|
|
554
725
|
.map((source) => [source.sourceId, source.storeKey])),
|
|
@@ -580,7 +751,8 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
580
751
|
}
|
|
581
752
|
throw new TuiOperationBlockedError('operationReviewStale', '状态读取期间来源配置持续变化。请重试。');
|
|
582
753
|
};
|
|
583
|
-
const captureEvidence = async (intent, signal, preparation, operationInventory = createOperationInventoryReader(), freshCatalog = false, reusableCandidate) => {
|
|
754
|
+
const captureEvidence = async (intent, signal, preparation, operationInventory = createOperationInventoryReader(), freshCatalog = false, reusableCandidate, codexObservationSession, frozenBatchEvidence) => {
|
|
755
|
+
reviewedScriptTimeoutMs(intent);
|
|
584
756
|
if (intent.kind === 'configReset') {
|
|
585
757
|
const parsed = parsePluginId(intent.pluginId);
|
|
586
758
|
if (!parsed.sourceId || !parsed.pluginName) {
|
|
@@ -684,12 +856,16 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
684
856
|
&& (preview.identityChanged || sourceFingerprintChanged);
|
|
685
857
|
if (preview.identityChanged)
|
|
686
858
|
sourceIdentityChangeImpact = {
|
|
687
|
-
impactSchemaVersion:
|
|
859
|
+
impactSchemaVersion: 3,
|
|
688
860
|
sourceId: preview.sourceId,
|
|
861
|
+
primaryChange: preview.references.primaryChange,
|
|
689
862
|
inventoryComplete: preview.references.inventoryComplete,
|
|
690
863
|
references: preview.references.references,
|
|
691
864
|
affectedReferences: preview.references.references,
|
|
692
|
-
changes: {
|
|
865
|
+
changes: {
|
|
866
|
+
added: [], removed: [], changed: [], newlyIncompatible: [],
|
|
867
|
+
dependencyChanged: [], platformSupportChanged: [],
|
|
868
|
+
},
|
|
693
869
|
errors: preview.references.errors,
|
|
694
870
|
};
|
|
695
871
|
if (!explicitSourceChange) {
|
|
@@ -828,7 +1004,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
828
1004
|
if (intent.action !== 'replaceDamaged' && !explicitSourceChange && candidateRelation === 'rollbackDetected') {
|
|
829
1005
|
throw new TuiOperationBlockedError('catalogRollbackDetected', '候选 Catalog 版本低于当前 Active。普通更新已阻止。');
|
|
830
1006
|
}
|
|
831
|
-
const impact =
|
|
1007
|
+
const impact = exactRepair ? undefined
|
|
832
1008
|
: sourceIdentityChangeImpact ?? await inspectCatalogSourceImpact({
|
|
833
1009
|
sourceId: intent.sourceId,
|
|
834
1010
|
cwd: context.cwd,
|
|
@@ -837,6 +1013,29 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
837
1013
|
mode: 'generation',
|
|
838
1014
|
candidateManifest: probe.manifest,
|
|
839
1015
|
});
|
|
1016
|
+
const primaryPreview = intent.setPrimaryAfterActivation
|
|
1017
|
+
? await preflightCatalogSourceMutation({
|
|
1018
|
+
request: { action: 'setPrimary', sourceId: intent.sourceId },
|
|
1019
|
+
cwd: context.cwd,
|
|
1020
|
+
env: context.env,
|
|
1021
|
+
})
|
|
1022
|
+
: undefined;
|
|
1023
|
+
if (primaryPreview && primaryPreview.configDigest !== config.digest) {
|
|
1024
|
+
throw operationReviewStale('准备主来源切换期间来源配置发生变化。');
|
|
1025
|
+
}
|
|
1026
|
+
const primaryImpact = primaryPreview ? {
|
|
1027
|
+
impactSchemaVersion: 3,
|
|
1028
|
+
sourceId: primaryPreview.sourceId,
|
|
1029
|
+
primaryChange: primaryPreview.references.primaryChange,
|
|
1030
|
+
inventoryComplete: primaryPreview.references.inventoryComplete,
|
|
1031
|
+
references: primaryPreview.references.references,
|
|
1032
|
+
affectedReferences: primaryPreview.references.references,
|
|
1033
|
+
changes: {
|
|
1034
|
+
added: [], removed: [], changed: [], newlyIncompatible: [],
|
|
1035
|
+
dependencyChanged: [], platformSupportChanged: [],
|
|
1036
|
+
},
|
|
1037
|
+
errors: primaryPreview.references.errors,
|
|
1038
|
+
} : undefined;
|
|
840
1039
|
return {
|
|
841
1040
|
catalog: {
|
|
842
1041
|
configDigest: config.digest,
|
|
@@ -857,6 +1056,11 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
857
1056
|
impactDigest: calculateCatalogSourceImpactDigest(impact),
|
|
858
1057
|
impactMode: sourceIdentityChangeImpact ? 'identityChange' : 'generation',
|
|
859
1058
|
} : {}),
|
|
1059
|
+
...(primaryPreview && primaryImpact ? {
|
|
1060
|
+
primaryImpact,
|
|
1061
|
+
primaryImpactDigest: primaryPreview.impactDigest,
|
|
1062
|
+
primaryConfigDigest: primaryPreview.configDigest,
|
|
1063
|
+
} : {}),
|
|
860
1064
|
configDigest: config.digest,
|
|
861
1065
|
...(proposedConfigDigest ? { proposedConfigDigest } : {}),
|
|
862
1066
|
...(proposedSource ? { proposedSource } : {}),
|
|
@@ -896,12 +1100,16 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
896
1100
|
referenceCount: preview.references.references.length,
|
|
897
1101
|
inventoryComplete: preview.references.inventoryComplete,
|
|
898
1102
|
impact: {
|
|
899
|
-
impactSchemaVersion:
|
|
1103
|
+
impactSchemaVersion: 3,
|
|
900
1104
|
sourceId: preview.sourceId,
|
|
1105
|
+
primaryChange: preview.references.primaryChange,
|
|
901
1106
|
inventoryComplete: preview.references.inventoryComplete,
|
|
902
1107
|
references: preview.references.references,
|
|
903
1108
|
affectedReferences: preview.references.references,
|
|
904
|
-
changes: {
|
|
1109
|
+
changes: {
|
|
1110
|
+
added: [], removed: [], changed: [], newlyIncompatible: [],
|
|
1111
|
+
dependencyChanged: [], platformSupportChanged: [],
|
|
1112
|
+
},
|
|
905
1113
|
errors: preview.references.errors,
|
|
906
1114
|
},
|
|
907
1115
|
},
|
|
@@ -912,10 +1120,95 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
912
1120
|
}
|
|
913
1121
|
return evidence;
|
|
914
1122
|
}
|
|
915
|
-
if (!pluginIntent(intent)) {
|
|
1123
|
+
if (!pluginIntent(intent) && intent.kind !== 'pluginWriteBatch') {
|
|
916
1124
|
throw new TuiOperationBlockedError('operationNotImplemented', '这个写操作尚未接入新 Controller。');
|
|
917
1125
|
}
|
|
918
1126
|
signal?.throwIfAborted();
|
|
1127
|
+
if (intent.kind === 'pluginWriteBatch') {
|
|
1128
|
+
await preparation?.reporter.emit('status');
|
|
1129
|
+
const selection = await resolveBatchGroups(intent, context.env, context.cwd, frozenBatchEvidence?.requestedPluginIds);
|
|
1130
|
+
signal?.throwIfAborted();
|
|
1131
|
+
const configSnapshot = await readCatalogSourcesConfigSnapshot(context.env);
|
|
1132
|
+
const groups = [];
|
|
1133
|
+
const ownsObservationSession = !codexObservationSession
|
|
1134
|
+
&& selection.groups.some((group) => {
|
|
1135
|
+
const reviewed = frozenBatchEvidence?.groups.find((candidate) => candidate.groupId === group.groupId);
|
|
1136
|
+
return reviewed?.executable !== false
|
|
1137
|
+
&& (group.platform === 'codex' || group.platform === 'both');
|
|
1138
|
+
});
|
|
1139
|
+
const observationSession = codexObservationSession ?? (ownsObservationSession
|
|
1140
|
+
? await createCodexNativeObservationSession({
|
|
1141
|
+
exactCwd: context.cwd,
|
|
1142
|
+
env: context.env,
|
|
1143
|
+
runner: context.nativeCliRunner,
|
|
1144
|
+
})
|
|
1145
|
+
: undefined);
|
|
1146
|
+
try {
|
|
1147
|
+
await preparation?.reporter.emit('catalog');
|
|
1148
|
+
for (const group of selection.groups) {
|
|
1149
|
+
signal?.throwIfAborted();
|
|
1150
|
+
const reviewed = frozenBatchEvidence?.groups.find((candidate) => candidate.groupId === group.groupId);
|
|
1151
|
+
if (reviewed?.executable === false) {
|
|
1152
|
+
groups.push({ ...group, preview: reviewed.preview, executable: false });
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
let catalogOperation;
|
|
1156
|
+
try {
|
|
1157
|
+
catalogOperation = !freshCatalog && sessionCatalogOperationContext
|
|
1158
|
+
? selectCatalogOperationContext(sessionCatalogOperationContext, [group.sourceId])
|
|
1159
|
+
: await resolveCatalogOperationContext({
|
|
1160
|
+
sourceIds: [group.sourceId],
|
|
1161
|
+
env: context.env,
|
|
1162
|
+
...(!freshCatalog ? { validatedStoreEntries, validatingStoreEntries } : {}),
|
|
1163
|
+
...(signal ? { signal } : {}),
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
catch {
|
|
1167
|
+
catalogOperation = undefined;
|
|
1168
|
+
}
|
|
1169
|
+
const preview = await runBatchWriteGroup({
|
|
1170
|
+
intent,
|
|
1171
|
+
group,
|
|
1172
|
+
cwd: context.cwd,
|
|
1173
|
+
runtime: {
|
|
1174
|
+
...context,
|
|
1175
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1176
|
+
expectedCatalogConfigDigest: configSnapshot.digest,
|
|
1177
|
+
...(catalogOperation ? {
|
|
1178
|
+
catalogOperationContext: catalogOperation,
|
|
1179
|
+
expectedGenerationSetDigest: catalogOperation.generationSetDigest,
|
|
1180
|
+
} : {}),
|
|
1181
|
+
previewOperationPlan: true,
|
|
1182
|
+
...(observationSession ? { codexObservationSession: observationSession } : {}),
|
|
1183
|
+
...(preparation ? {
|
|
1184
|
+
onPreviewStage: (stage) => stage === 'catalog' ? undefined : preparation.reporter.emit(stage),
|
|
1185
|
+
} : {}),
|
|
1186
|
+
},
|
|
1187
|
+
});
|
|
1188
|
+
groups.push({ ...group, preview, executable: preview.operationPlan !== undefined });
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
finally {
|
|
1192
|
+
if (ownsObservationSession)
|
|
1193
|
+
await observationSession?.dispose();
|
|
1194
|
+
}
|
|
1195
|
+
await preparation?.reporter.emit('evidence');
|
|
1196
|
+
signal?.throwIfAborted();
|
|
1197
|
+
const merged = mergeWriteCommandResults(groups.map((group) => group.preview));
|
|
1198
|
+
const evidence = {
|
|
1199
|
+
catalog: {
|
|
1200
|
+
configDigest: configSnapshot.digest,
|
|
1201
|
+
compositeDigest: sessionStatusResult?.payload.catalog.compositeDigest
|
|
1202
|
+
?? digest(groups.map((group) => [group.groupId, group.preview.operationPlan?.planFingerprint])),
|
|
1203
|
+
},
|
|
1204
|
+
requestedPluginIds: selection.requestedPluginIds,
|
|
1205
|
+
groups,
|
|
1206
|
+
...(merged.dependencyPlan ? { dependencyPlan: merged.dependencyPlan } : {}),
|
|
1207
|
+
...(merged.codexReconcilePlans ? { codexReconcilePlans: merged.codexReconcilePlans } : {}),
|
|
1208
|
+
...(merged.operationPlan ? { operationPlan: merged.operationPlan } : {}),
|
|
1209
|
+
};
|
|
1210
|
+
return evidence;
|
|
1211
|
+
}
|
|
919
1212
|
const packageInfo = await readCliPackageInfo();
|
|
920
1213
|
const offlineCleanupReason = intent.kind === 'pluginWrite'
|
|
921
1214
|
&& intent.action === 'cleanup'
|
|
@@ -1015,10 +1308,12 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1015
1308
|
pluginName: plugin.manifest.name,
|
|
1016
1309
|
source: sourceEvidenceForPlugin(source, plugin.manifest.name),
|
|
1017
1310
|
sharedNativeRenderTargets: intent.kind === 'configSave'
|
|
1018
|
-
? configSharedNativeRenderTargets(plugin,
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1311
|
+
? configSharedNativeRenderTargets(plugin, intent.retryApply
|
|
1312
|
+
? undefined
|
|
1313
|
+
: [
|
|
1314
|
+
...Object.keys(intent.updates ?? {}),
|
|
1315
|
+
...(intent.removeKeys ?? []),
|
|
1316
|
+
])
|
|
1022
1317
|
: [],
|
|
1023
1318
|
};
|
|
1024
1319
|
},
|
|
@@ -1028,6 +1323,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1028
1323
|
...(selected.source?.sourceIdentity
|
|
1029
1324
|
? { sourceIdentity: selected.source.sourceIdentity }
|
|
1030
1325
|
: {}),
|
|
1326
|
+
...(selected.source?.logicalIdentity
|
|
1327
|
+
? { logicalIdentity: selected.source.logicalIdentity }
|
|
1328
|
+
: {}),
|
|
1031
1329
|
pluginName: selected.pluginName,
|
|
1032
1330
|
scope: intent.scope,
|
|
1033
1331
|
cwd: context.cwd,
|
|
@@ -1099,6 +1397,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1099
1397
|
let dependencyPlan;
|
|
1100
1398
|
let codexReconcilePlans;
|
|
1101
1399
|
let operationPlan;
|
|
1400
|
+
let forceCleanupEvidence;
|
|
1102
1401
|
await preparation?.reporter.emit('catalog');
|
|
1103
1402
|
const offlineCleanupTarget = offlineCleanupReason && intent.kind === 'pluginWrite'
|
|
1104
1403
|
? status.payload.targets.find((target) => target.pluginId === intent.pluginId
|
|
@@ -1169,15 +1468,18 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1169
1468
|
pluginName: plugin.manifest.name,
|
|
1170
1469
|
source: sourceEvidenceForPlugin(source, plugin.manifest.name),
|
|
1171
1470
|
sharedNativeRenderTargets: intent.kind === 'configSave'
|
|
1172
|
-
? configSharedNativeRenderTargets(plugin,
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1471
|
+
? configSharedNativeRenderTargets(plugin, intent.retryApply
|
|
1472
|
+
? undefined
|
|
1473
|
+
: [
|
|
1474
|
+
...Object.keys(intent.updates ?? {}),
|
|
1475
|
+
...(intent.removeKeys ?? []),
|
|
1476
|
+
])
|
|
1176
1477
|
: [],
|
|
1177
1478
|
};
|
|
1178
1479
|
},
|
|
1179
1480
|
});
|
|
1180
1481
|
let codexManager;
|
|
1482
|
+
let resolvedCodexManager;
|
|
1181
1483
|
const hasDeclaredDependencies = (status.pluginSummaries.find((summary) => summary.pluginId === intent.pluginId)?.dependencyTotalCount ?? 0) > 0;
|
|
1182
1484
|
if (intent.kind === 'pluginWrite') {
|
|
1183
1485
|
const command = {
|
|
@@ -1192,6 +1494,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1192
1494
|
cwd: context.cwd,
|
|
1193
1495
|
platform: intent.platform,
|
|
1194
1496
|
scope: intent.scope,
|
|
1497
|
+
...(reviewedScriptTimeoutMs(intent) === undefined
|
|
1498
|
+
? {}
|
|
1499
|
+
: { scriptTimeoutMs: reviewedScriptTimeoutMs(intent) }),
|
|
1195
1500
|
...(intent.action === 'install' && intent.dependencyScopeOverrides
|
|
1196
1501
|
? { dependencyScopeOverrides: intent.dependencyScopeOverrides }
|
|
1197
1502
|
: {}),
|
|
@@ -1205,6 +1510,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1205
1510
|
expectedGenerationSetDigest: catalogOperation.generationSetDigest,
|
|
1206
1511
|
} : {}),
|
|
1207
1512
|
previewOperationPlan: true,
|
|
1513
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
1208
1514
|
...(preparation ? {
|
|
1209
1515
|
onPreviewStage: (stage) => stage === 'catalog' ? undefined : preparation.reporter.emit(stage),
|
|
1210
1516
|
} : {}),
|
|
@@ -1212,6 +1518,17 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1212
1518
|
signal?.throwIfAborted();
|
|
1213
1519
|
codexReconcilePlans = preview?.codexReconcilePlans;
|
|
1214
1520
|
operationPlan = preview?.operationPlan;
|
|
1521
|
+
if (intent.action === 'cleanup' && intent.force === true) {
|
|
1522
|
+
const candidates = preview?.offlineCleanupPlans?.filter((candidate) => candidate.forceExclusive === true
|
|
1523
|
+
&& candidate.pluginId === intent.pluginId
|
|
1524
|
+
&& candidate.platform === intent.platform
|
|
1525
|
+
&& candidate.scope === intent.scope
|
|
1526
|
+
&& candidate.plan.actions.length > 0) ?? [];
|
|
1527
|
+
if (candidates.length !== 1) {
|
|
1528
|
+
throw new TuiOperationBlockedError('forceCleanupPathUnavailable', '没有唯一且可验证的精确清理目标。');
|
|
1529
|
+
}
|
|
1530
|
+
[forceCleanupEvidence] = candidates;
|
|
1531
|
+
}
|
|
1215
1532
|
if (hasDeclaredDependencies
|
|
1216
1533
|
&& (intent.action === 'install'
|
|
1217
1534
|
|| intent.action === 'refreshAndSync'
|
|
@@ -1234,6 +1551,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1234
1551
|
throw new TuiOperationBlockedError(managerPreview.code, `${managerPreview.code}: ${message}`);
|
|
1235
1552
|
}
|
|
1236
1553
|
if (managerPreview) {
|
|
1554
|
+
if (managerPreview.state === 'system' || managerPreview.state === 'cached') {
|
|
1555
|
+
resolvedCodexManager = managerPreview.manager;
|
|
1556
|
+
}
|
|
1237
1557
|
codexManager = {
|
|
1238
1558
|
state: managerPreview.state,
|
|
1239
1559
|
packageName: MANAGED_CODEX_PACKAGE_NAME,
|
|
@@ -1263,6 +1583,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1263
1583
|
},
|
|
1264
1584
|
source: selected.source,
|
|
1265
1585
|
...(offlineCleanup ? { offlineCleanup } : {}),
|
|
1586
|
+
...(forceCleanupEvidence ? { offlineCleanup: forceCleanupEvidence } : {}),
|
|
1266
1587
|
...(dependencyPlan ? { dependencyPlan } : {}),
|
|
1267
1588
|
...(codexReconcilePlans ? { codexReconcilePlans } : {}),
|
|
1268
1589
|
...(operationPlan ? { operationPlan } : {}),
|
|
@@ -1273,6 +1594,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1273
1594
|
const store = await readPluginConfigStore({
|
|
1274
1595
|
sourceId: selected.source.sourceId,
|
|
1275
1596
|
sourceIdentity: selected.source.sourceIdentity,
|
|
1597
|
+
...('logicalIdentity' in selected.source
|
|
1598
|
+
? { logicalIdentity: selected.source.logicalIdentity }
|
|
1599
|
+
: {}),
|
|
1276
1600
|
pluginName: selected.pluginName,
|
|
1277
1601
|
scope: intent.scope,
|
|
1278
1602
|
cwd: context.cwd,
|
|
@@ -1286,6 +1610,15 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1286
1610
|
: {}),
|
|
1287
1611
|
storeDigest: digest({ exists: store.exists, rawDigest: store.rawDigest }),
|
|
1288
1612
|
affectedTargets: evidenceTargets.map(({ platform, scope }) => ({ platform, scope })),
|
|
1613
|
+
...(intent.scope === 'project' ? {
|
|
1614
|
+
shareability: await inspectConfigShareability({
|
|
1615
|
+
sourceId: selected.source.sourceId,
|
|
1616
|
+
pluginName: selected.pluginName,
|
|
1617
|
+
scope: intent.scope,
|
|
1618
|
+
cwd: context.cwd,
|
|
1619
|
+
env: context.env,
|
|
1620
|
+
}),
|
|
1621
|
+
} : {}),
|
|
1289
1622
|
...('sharedNativeRenderTargets' in selected
|
|
1290
1623
|
&& selected.sharedNativeRenderTargets.length > 0
|
|
1291
1624
|
? { sharedNativeRenderTargets: selected.sharedNativeRenderTargets }
|
|
@@ -1294,6 +1627,8 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1294
1627
|
}
|
|
1295
1628
|
if (catalogOperation)
|
|
1296
1629
|
catalogOperationByEvidence.set(evidence, catalogOperation);
|
|
1630
|
+
if (resolvedCodexManager)
|
|
1631
|
+
codexManagerByEvidence.set(evidence, resolvedCodexManager);
|
|
1297
1632
|
return evidence;
|
|
1298
1633
|
};
|
|
1299
1634
|
const dependencies = {
|
|
@@ -1501,6 +1836,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1501
1836
|
const stores = await readConfigStoresForTui({
|
|
1502
1837
|
sourceId: plugin.sourceId,
|
|
1503
1838
|
sourceIdentity: plugin.sourceIdentity,
|
|
1839
|
+
logicalIdentity: plugin.catalogLogicalIdentity,
|
|
1504
1840
|
pluginName: plugin.manifest.name,
|
|
1505
1841
|
schema: plugin.manifest.config.fields,
|
|
1506
1842
|
scope: layer.scope,
|
|
@@ -1535,6 +1871,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1535
1871
|
const effectiveRaw = await resolveEffectivePluginConfig({
|
|
1536
1872
|
sourceId: plugin.sourceId,
|
|
1537
1873
|
sourceIdentity: plugin.sourceIdentity,
|
|
1874
|
+
logicalIdentity: plugin.catalogLogicalIdentity,
|
|
1538
1875
|
pluginName: plugin.manifest.name,
|
|
1539
1876
|
manifest: plugin.manifest,
|
|
1540
1877
|
targetScope: layer.scope === 'user' ? 'user' : 'project',
|
|
@@ -1569,9 +1906,10 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1569
1906
|
throw new TuiOperationBlockedError('invalidPluginId', '设置目标必须使用 canonical pluginId。');
|
|
1570
1907
|
}
|
|
1571
1908
|
let sourceIdentity;
|
|
1909
|
+
let logicalIdentity;
|
|
1572
1910
|
try {
|
|
1573
1911
|
const packageInfo = await readCliPackageInfo();
|
|
1574
|
-
|
|
1912
|
+
const source = await withResolvedCatalogPlugin({
|
|
1575
1913
|
selector: pluginId,
|
|
1576
1914
|
cliVersion: packageInfo.version,
|
|
1577
1915
|
env: context.env,
|
|
@@ -1579,11 +1917,17 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1579
1917
|
...(sessionContextForPlugin(pluginId)
|
|
1580
1918
|
? { operationContext: sessionContextForPlugin(pluginId) }
|
|
1581
1919
|
: {}),
|
|
1582
|
-
consume: async ({ source }) =>
|
|
1920
|
+
consume: async ({ source }) => ({
|
|
1921
|
+
sourceIdentity: source.sourceIdentity,
|
|
1922
|
+
logicalIdentity: source.logicalIdentity,
|
|
1923
|
+
}),
|
|
1583
1924
|
});
|
|
1925
|
+
sourceIdentity = source.sourceIdentity;
|
|
1926
|
+
logicalIdentity = source.logicalIdentity;
|
|
1584
1927
|
}
|
|
1585
1928
|
catch {
|
|
1586
1929
|
sourceIdentity = undefined;
|
|
1930
|
+
logicalIdentity = undefined;
|
|
1587
1931
|
}
|
|
1588
1932
|
signal.throwIfAborted();
|
|
1589
1933
|
const target = await inspectPluginConfigResetTarget({
|
|
@@ -1598,6 +1942,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1598
1942
|
const store = await readPluginConfigStore({
|
|
1599
1943
|
sourceId: parsed.sourceId,
|
|
1600
1944
|
...(sourceIdentity ? { sourceIdentity } : {}),
|
|
1945
|
+
...(logicalIdentity ? { logicalIdentity } : {}),
|
|
1601
1946
|
pluginName: parsed.pluginName,
|
|
1602
1947
|
scope: layer.scope,
|
|
1603
1948
|
cwd: context.cwd,
|
|
@@ -1645,13 +1990,21 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1645
1990
|
expectedConfigDigest: expected.configDigest,
|
|
1646
1991
|
};
|
|
1647
1992
|
if (intent.sourceMutation.action === 'add') {
|
|
1648
|
-
await addCatalogSourceCommand({
|
|
1993
|
+
await addCatalogSourceCommand({
|
|
1994
|
+
...common,
|
|
1995
|
+
source: intent.sourceMutation.source,
|
|
1996
|
+
expectedProposedConfigDigest: expected.proposedConfigDigest,
|
|
1997
|
+
expectedImpactDigest: expected.impactDigest,
|
|
1998
|
+
requireImpactConfirmation: true,
|
|
1999
|
+
confirmImpact: true,
|
|
2000
|
+
});
|
|
1649
2001
|
}
|
|
1650
2002
|
else {
|
|
1651
2003
|
await updateCatalogSourceCommand({
|
|
1652
2004
|
...common,
|
|
1653
2005
|
sourceId: intent.sourceId,
|
|
1654
2006
|
update: intent.sourceMutation.update,
|
|
2007
|
+
expectedProposedConfigDigest: expected.proposedConfigDigest,
|
|
1655
2008
|
expectedImpactDigest: expected.impactDigest,
|
|
1656
2009
|
requireIdentityChangeConfirmation: true,
|
|
1657
2010
|
confirmIdentityChange: true,
|
|
@@ -1751,6 +2104,10 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1751
2104
|
sourceId: intent.sourceId,
|
|
1752
2105
|
cwd: context.cwd,
|
|
1753
2106
|
env: context.env,
|
|
2107
|
+
expectedConfigDigest: expected.primaryConfigDigest,
|
|
2108
|
+
expectedImpactDigest: expected.primaryImpactDigest,
|
|
2109
|
+
requireImpactConfirmation: true,
|
|
2110
|
+
confirmImpact: true,
|
|
1754
2111
|
});
|
|
1755
2112
|
primaryChanged = true;
|
|
1756
2113
|
}
|
|
@@ -1761,7 +2118,10 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1761
2118
|
configSaved,
|
|
1762
2119
|
generation,
|
|
1763
2120
|
activeAvailable: true,
|
|
1764
|
-
errorCode: error
|
|
2121
|
+
errorCode: typeof error === 'object' && error !== null
|
|
2122
|
+
&& 'code' in error && typeof error.code === 'string'
|
|
2123
|
+
? error.code
|
|
2124
|
+
: error instanceof Error ? error.name : 'catalogSourcePrimaryFailed',
|
|
1765
2125
|
};
|
|
1766
2126
|
}
|
|
1767
2127
|
}
|
|
@@ -1827,11 +2187,18 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1827
2187
|
cwd: context.cwd,
|
|
1828
2188
|
env: context.env,
|
|
1829
2189
|
expectedConfigDigest: expectedEvidence.sourceWrite?.configDigest,
|
|
2190
|
+
expectedProposedConfigDigest: expectedEvidence.sourceWrite?.proposedConfigDigest,
|
|
1830
2191
|
expectedImpactDigest: expectedEvidence.sourceWrite?.impactDigest,
|
|
1831
2192
|
runtime,
|
|
1832
2193
|
};
|
|
1833
2194
|
if (intent.action === 'add' && intent.source) {
|
|
1834
|
-
return addCatalogSourceCommand({
|
|
2195
|
+
return addCatalogSourceCommand({
|
|
2196
|
+
...common,
|
|
2197
|
+
source: intent.source,
|
|
2198
|
+
cliVersion: packageInfo.version,
|
|
2199
|
+
requireImpactConfirmation: true,
|
|
2200
|
+
confirmImpact: true,
|
|
2201
|
+
});
|
|
1835
2202
|
}
|
|
1836
2203
|
if (intent.action === 'update' && intent.update) {
|
|
1837
2204
|
return updateCatalogSourceCommand({
|
|
@@ -1844,7 +2211,12 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1844
2211
|
});
|
|
1845
2212
|
}
|
|
1846
2213
|
if (intent.action === 'setPrimary') {
|
|
1847
|
-
return setPrimaryCatalogSourceCommand({
|
|
2214
|
+
return setPrimaryCatalogSourceCommand({
|
|
2215
|
+
...common,
|
|
2216
|
+
sourceId: intent.sourceId,
|
|
2217
|
+
requireImpactConfirmation: true,
|
|
2218
|
+
confirmImpact: true,
|
|
2219
|
+
});
|
|
1848
2220
|
}
|
|
1849
2221
|
if (intent.action === 'remove') {
|
|
1850
2222
|
return removeCatalogSourceCommand({
|
|
@@ -1856,12 +2228,164 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1856
2228
|
}
|
|
1857
2229
|
throw new TuiOperationBlockedError('invalidSourceMutation', '来源操作缺少候选输入。');
|
|
1858
2230
|
}
|
|
2231
|
+
const codexObservationSession = intent.kind === 'pluginWrite'
|
|
2232
|
+
|| intent.kind === 'pluginWriteBatch'
|
|
2233
|
+
? await createCodexNativeObservationSession({
|
|
2234
|
+
exactCwd: context.cwd,
|
|
2235
|
+
env: context.env,
|
|
2236
|
+
runner: context.nativeCliRunner,
|
|
2237
|
+
manager: codexManagerByEvidence.get(expectedEvidence),
|
|
2238
|
+
})
|
|
2239
|
+
: undefined;
|
|
1859
2240
|
return withAwHomeMutationLock({
|
|
1860
2241
|
env: context.env,
|
|
1861
2242
|
action: async (awHomeMutationToken) => {
|
|
1862
2243
|
await tuiControllerRuntimeTestHooks?.beforeMutationEvidenceCapture?.();
|
|
1863
2244
|
const operationInventory = createOperationInventoryReader();
|
|
1864
|
-
const currentEvidence = await captureEvidence(intent, undefined, undefined, operationInventory, true
|
|
2245
|
+
const currentEvidence = await captureEvidence(intent, undefined, undefined, operationInventory, true, undefined, codexObservationSession, intent.kind === 'pluginWriteBatch'
|
|
2246
|
+
? expectedEvidence
|
|
2247
|
+
: undefined);
|
|
2248
|
+
if (intent.kind === 'pluginWriteBatch') {
|
|
2249
|
+
const expectedBatch = expectedEvidence;
|
|
2250
|
+
const currentBatch = currentEvidence;
|
|
2251
|
+
const reviewedGroups = expectedBatch.groups.map((group) => ({
|
|
2252
|
+
groupId: group.groupId,
|
|
2253
|
+
sourceId: group.sourceId,
|
|
2254
|
+
platform: group.platform,
|
|
2255
|
+
scope: group.scope,
|
|
2256
|
+
requestedPluginIds: group.requestedPluginIds,
|
|
2257
|
+
executable: group.executable,
|
|
2258
|
+
planFingerprint: group.preview.operationPlan
|
|
2259
|
+
? createBatchIntentCompatiblePlanFingerprint(group.preview.operationPlan)
|
|
2260
|
+
: undefined,
|
|
2261
|
+
}));
|
|
2262
|
+
const currentGroups = currentBatch.groups.map((group) => ({
|
|
2263
|
+
groupId: group.groupId,
|
|
2264
|
+
sourceId: group.sourceId,
|
|
2265
|
+
platform: group.platform,
|
|
2266
|
+
scope: group.scope,
|
|
2267
|
+
requestedPluginIds: group.requestedPluginIds,
|
|
2268
|
+
executable: expectedBatch.groups.find((reviewed) => reviewed.groupId === group.groupId)
|
|
2269
|
+
?.executable === false ? false : group.executable,
|
|
2270
|
+
planFingerprint: expectedBatch.groups.find((reviewed) => reviewed.groupId === group.groupId)
|
|
2271
|
+
?.executable === false
|
|
2272
|
+
? undefined
|
|
2273
|
+
: group.preview.operationPlan
|
|
2274
|
+
? createBatchIntentCompatiblePlanFingerprint(group.preview.operationPlan)
|
|
2275
|
+
: undefined,
|
|
2276
|
+
}));
|
|
2277
|
+
if (expectedBatch.catalog.configDigest !== currentBatch.catalog.configDigest
|
|
2278
|
+
|| JSON.stringify(expectedBatch.requestedPluginIds)
|
|
2279
|
+
!== JSON.stringify(currentBatch.requestedPluginIds)
|
|
2280
|
+
|| JSON.stringify(reviewedGroups) !== JSON.stringify(currentGroups)) {
|
|
2281
|
+
throw operationReviewStale('确认后批量目标或写入计划发生变化。');
|
|
2282
|
+
}
|
|
2283
|
+
await tuiControllerRuntimeTestHooks?.afterMutationEvidenceCapture?.();
|
|
2284
|
+
const groupResults = [];
|
|
2285
|
+
const completedTargetKeys = new Set();
|
|
2286
|
+
let executedGroupCount = 0;
|
|
2287
|
+
const appendStoppedGroups = (startIndex, staleMessage) => {
|
|
2288
|
+
for (const [offset, stopped] of expectedBatch.groups.slice(startIndex).entries()) {
|
|
2289
|
+
groupResults.push({
|
|
2290
|
+
groupId: stopped.groupId,
|
|
2291
|
+
sourceId: stopped.sourceId,
|
|
2292
|
+
platform: stopped.platform,
|
|
2293
|
+
scope: stopped.scope,
|
|
2294
|
+
requestedPluginIds: stopped.requestedPluginIds,
|
|
2295
|
+
result: !stopped.executable ? stopped.preview : failedWriteCommandResult(intent.action, stopped.requestedPluginIds, { cwd: context.cwd, platform: stopped.platform, scope: stopped.scope }, offset === 0
|
|
2296
|
+
? new TuiOperationBlockedError('operationReviewStale', staleMessage)
|
|
2297
|
+
: new TuiOperationBlockedError('batchNotStarted', '前一个批量组的写入计划已变化,因此这个组没有开始。')),
|
|
2298
|
+
});
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
for (const [groupIndex, reviewed] of expectedBatch.groups.entries()) {
|
|
2302
|
+
const current = currentBatch.groups.find((group) => group.groupId === reviewed.groupId);
|
|
2303
|
+
if (!reviewed.executable) {
|
|
2304
|
+
groupResults.push({
|
|
2305
|
+
groupId: reviewed.groupId,
|
|
2306
|
+
sourceId: reviewed.sourceId,
|
|
2307
|
+
platform: reviewed.platform,
|
|
2308
|
+
scope: reviewed.scope,
|
|
2309
|
+
requestedPluginIds: reviewed.requestedPluginIds,
|
|
2310
|
+
result: reviewed.preview,
|
|
2311
|
+
});
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
const groupInventory = groupResults.length === 0
|
|
2315
|
+
? operationInventory
|
|
2316
|
+
: createOperationInventoryReader();
|
|
2317
|
+
let executionPreview = current.preview;
|
|
2318
|
+
if (completedTargetKeys.size > 0) {
|
|
2319
|
+
executionPreview = await runBatchWriteGroup({
|
|
2320
|
+
intent,
|
|
2321
|
+
group: current,
|
|
2322
|
+
cwd: context.cwd,
|
|
2323
|
+
runtime: {
|
|
2324
|
+
...context,
|
|
2325
|
+
awHomeMutationToken,
|
|
2326
|
+
inventoryCatalogSourceReferences: groupInventory,
|
|
2327
|
+
expectedCatalogConfigDigest: expectedBatch.catalog.configDigest,
|
|
2328
|
+
previewOperationPlan: true,
|
|
2329
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
2330
|
+
},
|
|
2331
|
+
});
|
|
2332
|
+
if (!reviewed.preview.operationPlan || !executionPreview.operationPlan
|
|
2333
|
+
|| createBatchIntentCompatiblePlanFingerprint(reviewed.preview.operationPlan, completedTargetKeys) !== createBatchIntentCompatiblePlanFingerprint(executionPreview.operationPlan, completedTargetKeys)) {
|
|
2334
|
+
appendStoppedGroups(groupIndex, '前序批量结果改变了这个组的实际写入计划。');
|
|
2335
|
+
break;
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
const requiresManagedCodex = reviewed.preview.codexManagerPreview?.state === 'requires-install';
|
|
2339
|
+
const result = await runBatchWriteGroup({
|
|
2340
|
+
intent,
|
|
2341
|
+
group: current,
|
|
2342
|
+
cwd: context.cwd,
|
|
2343
|
+
runtime: {
|
|
2344
|
+
...context,
|
|
2345
|
+
awHomeMutationToken,
|
|
2346
|
+
inventoryCatalogSourceReferences: groupInventory,
|
|
2347
|
+
expectedCatalogConfigDigest: expectedBatch.catalog.configDigest,
|
|
2348
|
+
...(executionPreview.operationPlan ? {
|
|
2349
|
+
expectedPlanFingerprint: executionPreview.operationPlan.planFingerprint,
|
|
2350
|
+
} : {}),
|
|
2351
|
+
...(requiresManagedCodex ? {
|
|
2352
|
+
managedCodexAuthorizer: async () => true,
|
|
2353
|
+
} : {}),
|
|
2354
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
2355
|
+
},
|
|
2356
|
+
});
|
|
2357
|
+
if (writeReviewIsStale(result)) {
|
|
2358
|
+
if (executedGroupCount === 0)
|
|
2359
|
+
throwIfWriteReviewStale(result);
|
|
2360
|
+
appendStoppedGroups(groupIndex, '这个组的实际写入计划发生变化。');
|
|
2361
|
+
break;
|
|
2362
|
+
}
|
|
2363
|
+
executedGroupCount += 1;
|
|
2364
|
+
for (const target of result.targetResults) {
|
|
2365
|
+
if (target.state === 'completed') {
|
|
2366
|
+
completedTargetKeys.add([
|
|
2367
|
+
target.target.pluginId,
|
|
2368
|
+
target.target.platform,
|
|
2369
|
+
target.target.scope,
|
|
2370
|
+
].join('\0'));
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
groupResults.push({
|
|
2374
|
+
groupId: reviewed.groupId,
|
|
2375
|
+
sourceId: reviewed.sourceId,
|
|
2376
|
+
platform: reviewed.platform,
|
|
2377
|
+
scope: reviewed.scope,
|
|
2378
|
+
requestedPluginIds: reviewed.requestedPluginIds,
|
|
2379
|
+
result,
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2382
|
+
const merged = mergeWriteCommandResults(groupResults.map((group) => group.result));
|
|
2383
|
+
return {
|
|
2384
|
+
...merged,
|
|
2385
|
+
requestedPluginIds: expectedBatch.requestedPluginIds,
|
|
2386
|
+
groupResults,
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
1865
2389
|
if (intent.kind !== 'pluginWrite'
|
|
1866
2390
|
&& !operationEvidenceMatches(expectedEvidence, currentEvidence)) {
|
|
1867
2391
|
throw new TuiOperationBlockedError('operationReviewStale', '确认后状态发生变化。');
|
|
@@ -1877,6 +2401,9 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1877
2401
|
cwd: context.cwd,
|
|
1878
2402
|
platform: intent.platform,
|
|
1879
2403
|
scope: intent.scope,
|
|
2404
|
+
...(reviewedScriptTimeoutMs(intent) === undefined
|
|
2405
|
+
? {}
|
|
2406
|
+
: { scriptTimeoutMs: reviewedScriptTimeoutMs(intent) }),
|
|
1880
2407
|
...(intent.action === 'install' && intent.dependencyScopeOverrides
|
|
1881
2408
|
? { dependencyScopeOverrides: intent.dependencyScopeOverrides }
|
|
1882
2409
|
: {}),
|
|
@@ -1895,11 +2422,19 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1895
2422
|
}[intent.action];
|
|
1896
2423
|
const currentSource = currentEvidence.source;
|
|
1897
2424
|
const offlineCleanup = currentEvidence.offlineCleanup;
|
|
2425
|
+
const reviewedOfflineCleanup = expectedEvidence.offlineCleanup;
|
|
2426
|
+
if ((offlineCleanup || reviewedOfflineCleanup)
|
|
2427
|
+
&& (!offlineCleanup
|
|
2428
|
+
|| !reviewedOfflineCleanup
|
|
2429
|
+
|| !offlineCleanupEvidenceMatches(reviewedOfflineCleanup, offlineCleanup))) {
|
|
2430
|
+
throw new TuiOperationBlockedError('operationReviewStale', '确认后离线清理证据发生变化。');
|
|
2431
|
+
}
|
|
1898
2432
|
if (!offlineCleanup && (!expectedEvidence.source || !currentSource)) {
|
|
1899
2433
|
throw new TuiOperationBlockedError('operationReviewStale', '确认信息缺少来源身份。');
|
|
1900
2434
|
}
|
|
1901
2435
|
const result = await command([intent.pluginId], options, {
|
|
1902
2436
|
...context,
|
|
2437
|
+
...(codexObservationSession ? { codexObservationSession } : {}),
|
|
1903
2438
|
awHomeMutationToken,
|
|
1904
2439
|
inventoryCatalogSourceReferences: operationInventory,
|
|
1905
2440
|
...(expectedEvidence.operationPlan
|
|
@@ -1913,14 +2448,18 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1913
2448
|
...(expectedEvidence.codexManager?.state === 'requires-install'
|
|
1914
2449
|
? { managedCodexAuthorizer: async () => true }
|
|
1915
2450
|
: {}),
|
|
1916
|
-
...(
|
|
1917
|
-
? { expectedOfflineCleanupEvidence:
|
|
2451
|
+
...(reviewedOfflineCleanup
|
|
2452
|
+
? { expectedOfflineCleanupEvidence: reviewedOfflineCleanup }
|
|
1918
2453
|
: { reviewPreflight: (actual) => assertSourceEvidenceMatches(currentSource, actual) }),
|
|
1919
2454
|
});
|
|
1920
2455
|
throwIfWriteReviewStale(result);
|
|
1921
2456
|
return result;
|
|
1922
2457
|
}
|
|
1923
2458
|
if (intent.kind === 'configSave' || intent.kind === 'configReset') {
|
|
2459
|
+
const operationRebuildResults = [];
|
|
2460
|
+
const operationDiagnosticSink = (results) => {
|
|
2461
|
+
operationRebuildResults.push(...structuredClone(results));
|
|
2462
|
+
};
|
|
1924
2463
|
const currentSource = currentEvidence.source;
|
|
1925
2464
|
if (intent.kind === 'configReset') {
|
|
1926
2465
|
const parsed = parsePluginId(intent.pluginId);
|
|
@@ -1937,6 +2476,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1937
2476
|
rebuildRuntime: { ...context, awHomeMutationToken },
|
|
1938
2477
|
awHomeMutationToken,
|
|
1939
2478
|
apply: false,
|
|
2479
|
+
sharedNativeApplyConfirmed: false,
|
|
1940
2480
|
});
|
|
1941
2481
|
}
|
|
1942
2482
|
if (!currentSource) {
|
|
@@ -1967,6 +2507,10 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1967
2507
|
rebuildRuntime: {
|
|
1968
2508
|
...context,
|
|
1969
2509
|
awHomeMutationToken,
|
|
2510
|
+
operationDiagnosticSink,
|
|
2511
|
+
...(reviewedScriptTimeoutMs(intent) === undefined
|
|
2512
|
+
? {}
|
|
2513
|
+
: { scriptTimeoutMs: reviewedScriptTimeoutMs(intent) }),
|
|
1970
2514
|
...(catalogOperation ? {
|
|
1971
2515
|
catalogOperationContext: catalogOperation,
|
|
1972
2516
|
expectedGenerationSetDigest: expectedEvidence.catalog.generationSetDigest,
|
|
@@ -1974,6 +2518,7 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1974
2518
|
},
|
|
1975
2519
|
awHomeMutationToken,
|
|
1976
2520
|
applyTargets,
|
|
2521
|
+
sharedNativeApplyConfirmed: true,
|
|
1977
2522
|
})
|
|
1978
2523
|
: await applyPluginConfigWrite({
|
|
1979
2524
|
plugin,
|
|
@@ -1985,6 +2530,10 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1985
2530
|
rebuildRuntime: {
|
|
1986
2531
|
...context,
|
|
1987
2532
|
awHomeMutationToken,
|
|
2533
|
+
operationDiagnosticSink,
|
|
2534
|
+
...(reviewedScriptTimeoutMs(intent) === undefined
|
|
2535
|
+
? {}
|
|
2536
|
+
: { scriptTimeoutMs: reviewedScriptTimeoutMs(intent) }),
|
|
1988
2537
|
...(catalogOperation ? {
|
|
1989
2538
|
catalogOperationContext: catalogOperation,
|
|
1990
2539
|
expectedGenerationSetDigest: expectedEvidence.catalog.generationSetDigest,
|
|
@@ -1993,13 +2542,16 @@ export function createTuiControllerDependencies(context, progressFeed, options =
|
|
|
1993
2542
|
awHomeMutationToken,
|
|
1994
2543
|
applyTargets,
|
|
1995
2544
|
request: { updates: intent.updates, removeKeys: intent.removeKeys },
|
|
2545
|
+
sharedNativeApplyConfirmed: true,
|
|
1996
2546
|
});
|
|
1997
|
-
return result;
|
|
2547
|
+
return { ...result, operationRebuildResults };
|
|
1998
2548
|
},
|
|
1999
2549
|
});
|
|
2000
2550
|
}
|
|
2001
2551
|
throw new TuiOperationBlockedError('operationNotImplemented', '这个写操作尚未接入新 Controller。');
|
|
2002
2552
|
},
|
|
2553
|
+
}).finally(async () => {
|
|
2554
|
+
await codexObservationSession?.dispose();
|
|
2003
2555
|
});
|
|
2004
2556
|
},
|
|
2005
2557
|
};
|