refactor: 重构 Kiro flow 配置与运行链路

This commit is contained in:
QLHazyCoder
2026-05-18 19:34:59 +08:00
parent ccd21206c1
commit d9795f8b3a
14 changed files with 1048 additions and 762 deletions
@@ -124,8 +124,8 @@ test('runtime-state patch accepts nested flow and node updates without legacy st
assert.equal(patch.activeFlowId, 'openai');
assert.equal(patch.activeRunId, 'run-001');
assert.equal(patch.currentNodeId, 'oauth-login');
assert.equal(patch.oauthUrl, 'https://new.example.com/start');
assert.equal(patch.plusCheckoutTabId, 99);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'oauthUrl'), false);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'plusCheckoutTabId'), false);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'currentStep'), false);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'stepStatuses'), false);
assert.deepStrictEqual(patch.nodeStatuses, {
@@ -135,6 +135,10 @@ test('runtime-state patch accepts nested flow and node updates without legacy st
});
assert.equal(patch.runtimeState.flowState.openai.auth.oauthUrl, 'https://new.example.com/start');
assert.equal(patch.runtimeState.flowState.openai.plus.plusCheckoutTabId, 99);
const view = helpers.buildStateView(patch);
assert.equal(view.oauthUrl, 'https://new.example.com/start');
assert.equal(view.plusCheckoutTabId, 99);
});
test('runtime-state patch prefers explicit activeFlowId over stale legacy flowId', () => {
@@ -57,6 +57,39 @@ ${flowRegistrySource}
${settingsSchemaSource}
const DEFAULT_ACTIVE_FLOW_ID = 'openai';
const DEFAULT_SUB2API_GROUP_NAMES = ['codex', 'openai-plus'];
const SETTINGS_SCHEMA_VIEW_KEYS = Object.freeze([
'activeFlowId',
'openaiIntegrationTargetId',
'kiroIntegrationTargetId',
'panelMode',
'kiroSourceId',
'vpsUrl',
'vpsPassword',
'localCpaStep9Mode',
'sub2apiUrl',
'sub2apiEmail',
'sub2apiPassword',
'sub2apiGroupName',
'sub2apiGroupNames',
'sub2apiAccountPriority',
'sub2apiDefaultProxyName',
'codex2apiUrl',
'codex2apiAdminKey',
'customPassword',
'signupMethod',
'phoneVerificationEnabled',
'phoneSignupReloginAfterBindEmailEnabled',
'plusModeEnabled',
'plusPaymentMethod',
'mailProvider',
'ipProxyEnabled',
'ipProxyService',
'ipProxyMode',
'kiroRsUrl',
'kiroRsKey',
'stepExecutionRangeByFlow',
]);
const SETTINGS_SCHEMA_VIEW_KEY_SET = new Set(SETTINGS_SCHEMA_VIEW_KEYS);
const PERSISTED_SETTING_DEFAULTS = {
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
panelMode: 'cpa',
@@ -77,6 +110,9 @@ const PERSISTED_SETTING_KEYS = Object.keys(PERSISTED_SETTING_DEFAULTS);
const PERSISTED_SETTINGS_SCHEMA_KEYS = ['settingsSchemaVersion', 'settingsState'];
const LEGACY_AUTO_STEP_DELAY_KEYS = [];
const LEGACY_VERIFICATION_RESEND_COUNT_KEYS = [];
function isPlainObjectValue(value) {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function normalizePanelMode(value = '') {
const normalized = String(value || '').trim().toLowerCase();
return normalized === 'sub2api' || normalized === 'codex2api' ? normalized : 'cpa';
@@ -131,6 +167,8 @@ function resolveSignupMethod(state = {}) {
function resolveLegacyAutoStepDelaySeconds() { return undefined; }
${extractFunction('normalizePersistentSettingValue')}
${extractFunction('getSettingsSchemaApi')}
${extractFunction('projectSettingsSchemaView')}
${extractFunction('buildPersistedSettingsStoragePayload')}
${extractFunction('buildPersistentSettingsPayload')}
${extractFunction('getPersistedSettings')}
${extractFunction('setPersistentSettings')}
@@ -141,6 +179,7 @@ return {
setPersistentSettings,
getRequestedKeys: typeof getRequestedKeys === 'function' ? getRequestedKeys : () => [],
getPersistedWrites: typeof getPersistedWrites === 'function' ? getPersistedWrites : () => [],
getRemovedKeys: typeof getRemovedKeys === 'function' ? getRemovedKeys : () => [],
};
`)();
}
@@ -159,26 +198,50 @@ test('buildPersistentSettingsPayload writes canonical settings schema into persi
assert.equal(payload.kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(payload.kiroRsKey, 'secret-key');
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
assert.equal(payload.settingsSchemaVersion, 3);
assert.equal(payload.settingsSchemaVersion, 4);
assert.equal(payload.settingsState.activeFlowId, 'kiro');
assert.equal(payload.settingsState.flows.kiro.source.selected, 'kiro-rs');
assert.equal(payload.settingsState.flows.kiro.integrationTargetId, 'kiro-rs');
assert.equal(
payload.settingsState.flows.kiro.integrationTargets['kiro-rs'].baseUrl,
'https://kiro.example.com/admin'
);
});
test('buildPersistentSettingsPayload accepts schema-only input when requireKnownKeys is enabled', () => {
const api = buildHarness();
const payload = api.buildPersistentSettingsPayload({
settingsSchemaVersion: 3,
settingsSchemaVersion: 4,
settingsState: {
activeFlowId: 'kiro',
services: {
account: { customPassword: '' },
email: { provider: '163' },
proxy: { enabled: false, provider: '711proxy', mode: 'account' },
},
flows: {
openai: {
source: { selected: 'cpa', entries: {} },
account: { customPassword: '' },
integrationTargetId: 'cpa',
integrationTargets: {
cpa: {
vpsUrl: '',
vpsPassword: '',
localCpaStep9Mode: 'submit',
},
sub2api: {
sub2apiUrl: '',
sub2apiEmail: '',
sub2apiPassword: '',
sub2apiGroupName: 'codex',
sub2apiGroupNames: ['codex', 'openai-plus'],
sub2apiAccountPriority: 1,
sub2apiDefaultProxyName: '',
},
codex2api: {
codex2apiUrl: '',
codex2apiAdminKey: '',
},
},
signup: {
signupMethod: 'email',
phoneVerificationEnabled: false,
@@ -193,17 +256,13 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
},
},
kiro: {
source: {
selected: 'kiro-rs',
entries: {
'kiro-rs': {
kiroRsUrl: 'https://kiro.example.com/admin',
kiroRsKey: 'schema-only-key',
},
integrationTargetId: 'kiro-rs',
integrationTargets: {
'kiro-rs': {
baseUrl: 'https://kiro.example.com/admin',
apiKey: 'schema-only-key',
},
},
options: {
},
autoRun: {
stepExecutionRange: { enabled: true, fromStep: 1, toStep: 7 },
},
@@ -217,7 +276,7 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
assert.equal(payload.kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(payload.kiroRsKey, 'schema-only-key');
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
assert.equal(payload.settingsSchemaVersion, 3);
assert.equal(payload.settingsSchemaVersion, 4);
});
test('getPersistedSettings reads schema keys alongside legacy flat settings keys', async () => {
@@ -242,7 +301,7 @@ function getRequestedKeys() {
assert.ok(api.getRequestedKeys().includes('settingsSchemaVersion'));
assert.ok(api.getRequestedKeys().includes('settingsState'));
assert.equal(state.settingsSchemaVersion, 3);
assert.equal(state.settingsSchemaVersion, 4);
assert.equal(state.settingsState.activeFlowId, 'openai');
});
@@ -253,20 +312,37 @@ const chrome = {
local: {
async get() {
return {
settingsSchemaVersion: 3,
settingsSchemaVersion: 4,
settingsState: {
activeFlowId: 'kiro',
services: {
account: { customPassword: '' },
email: { provider: 'hotmail' },
proxy: { enabled: true, provider: '711proxy', mode: 'account' },
},
flows: {
openai: {
source: {
selected: 'sub2api',
entries: {},
integrationTargetId: 'sub2api',
integrationTargets: {
cpa: {
vpsUrl: '',
vpsPassword: '',
localCpaStep9Mode: 'submit',
},
sub2api: {
sub2apiUrl: '',
sub2apiEmail: '',
sub2apiPassword: '',
sub2apiGroupName: 'codex',
sub2apiGroupNames: ['codex', 'openai-plus'],
sub2apiAccountPriority: 1,
sub2apiDefaultProxyName: '',
},
codex2api: {
codex2apiUrl: '',
codex2apiAdminKey: '',
},
},
account: { customPassword: '' },
signup: {
signupMethod: 'email',
phoneVerificationEnabled: false,
@@ -281,17 +357,13 @@ const chrome = {
},
},
kiro: {
source: {
selected: 'kiro-rs',
entries: {
'kiro-rs': {
kiroRsUrl: 'https://kiro.example.com/admin',
kiroRsKey: 'stored-key',
},
integrationTargetId: 'kiro-rs',
integrationTargets: {
'kiro-rs': {
baseUrl: 'https://kiro.example.com/admin',
apiKey: 'stored-key',
},
},
options: {
},
autoRun: {
stepExecutionRange: { enabled: true, fromStep: 1, toStep: 7 },
},
@@ -324,12 +396,16 @@ const chrome = {
test('setPersistentSettings materializes canonical schema keys for schema-only updates', async () => {
const api = buildHarness(`
const persistedWrites = [];
const removedKeys = [];
const chrome = {
storage: {
local: {
async get() {
return {};
},
async remove(keys) {
removedKeys.push(...(Array.isArray(keys) ? keys : [keys]));
},
async set(payload) {
persistedWrites.push(JSON.parse(JSON.stringify(payload)));
},
@@ -339,20 +415,43 @@ const chrome = {
function getPersistedWrites() {
return persistedWrites;
}
function getRemovedKeys() {
return removedKeys;
}
`);
const persisted = await api.setPersistentSettings({
settingsSchemaVersion: 3,
settingsSchemaVersion: 4,
settingsState: {
activeFlowId: 'kiro',
services: {
account: { customPassword: '' },
email: { provider: '163' },
proxy: { enabled: false, provider: '711proxy', mode: 'account' },
},
flows: {
openai: {
source: { selected: 'cpa', entries: {} },
account: { customPassword: '' },
integrationTargetId: 'cpa',
integrationTargets: {
cpa: {
vpsUrl: '',
vpsPassword: '',
localCpaStep9Mode: 'submit',
},
sub2api: {
sub2apiUrl: '',
sub2apiEmail: '',
sub2apiPassword: '',
sub2apiGroupName: 'codex',
sub2apiGroupNames: ['codex', 'openai-plus'],
sub2apiAccountPriority: 1,
sub2apiDefaultProxyName: '',
},
codex2api: {
codex2apiUrl: '',
codex2apiAdminKey: '',
},
},
signup: {
signupMethod: 'email',
phoneVerificationEnabled: false,
@@ -367,17 +466,13 @@ function getPersistedWrites() {
},
},
kiro: {
source: {
selected: 'kiro-rs',
entries: {
'kiro-rs': {
kiroRsUrl: 'https://kiro.example.com/admin',
kiroRsKey: 'nested-only-key',
},
integrationTargetId: 'kiro-rs',
integrationTargets: {
'kiro-rs': {
baseUrl: 'https://kiro.example.com/admin',
apiKey: 'nested-only-key',
},
},
options: {
},
autoRun: {
stepExecutionRange: { enabled: true, fromStep: 1, toStep: 7 },
},
@@ -392,11 +487,14 @@ function getPersistedWrites() {
assert.equal(persisted.kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(persisted.kiroRsKey, 'nested-only-key');
assert.equal(Object.prototype.hasOwnProperty.call(persisted, 'kiroRegion'), false);
assert.equal(persisted.settingsSchemaVersion, 3);
assert.equal(write.activeFlowId, 'kiro');
assert.equal(write.kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(write.kiroRsKey, 'nested-only-key');
assert.equal(persisted.settingsSchemaVersion, 4);
assert.equal(Object.prototype.hasOwnProperty.call(write, 'activeFlowId'), false);
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRsUrl'), false);
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRsKey'), false);
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRegion'), false);
assert.equal(write.settingsSchemaVersion, 3);
assert.equal(write.settingsSchemaVersion, 4);
assert.equal(write.settingsState.activeFlowId, 'kiro');
assert.equal(write.settingsState.flows.kiro.integrationTargetId, 'kiro-rs');
assert.ok(api.getRemovedKeys().includes('panelMode'));
assert.ok(api.getRemovedKeys().includes('kiroRsUrl'));
});
@@ -8,9 +8,8 @@ test('background node registry preserves node metadata even before an executor i
const registry = api.createNodeRegistry([
{
flowId: 'kiro',
legacyStepId: 1,
nodeId: 'kiro-start-device-login',
displayOrder: 10,
displayOrder: 1,
executeKey: 'kiro-start-device-login',
title: 'Start device login',
},
@@ -19,7 +18,7 @@ test('background node registry preserves node metadata even before an executor i
const node = registry.getNodeDefinition('kiro-start-device-login');
assert.equal(node.flowId, 'kiro');
assert.equal(node.legacyStepId, 1);
assert.equal(node.displayOrder, 1);
assert.equal(node.title, 'Start device login');
assert.throws(
() => registry.executeNode('kiro-start-device-login', {}),
@@ -34,9 +33,8 @@ test('background node registry executes registered nodes in display order', asyn
const registry = api.createNodeRegistry([
{
flowId: 'openai',
legacyStepId: 2,
displayOrder: 2,
nodeId: 'submit-signup-email',
displayOrder: 20,
executeKey: 'submit-signup-email',
title: 'Submit signup email',
execute: async (state) => {
@@ -45,9 +43,8 @@ test('background node registry executes registered nodes in display order', asyn
},
{
flowId: 'openai',
legacyStepId: 1,
displayOrder: 1,
nodeId: 'open-chatgpt',
displayOrder: 10,
executeKey: 'open-chatgpt',
title: 'Open ChatGPT',
},
+18 -15
View File
@@ -21,7 +21,7 @@ test('flow capability registry keeps OpenAI phone signup available only when run
const enabledState = registry.resolveSidepanelCapabilities({
state: {
activeFlowId: 'openai',
panelMode: 'cpa',
openaiIntegrationTargetId: 'cpa',
phoneVerificationEnabled: true,
plusModeEnabled: false,
contributionMode: false,
@@ -37,7 +37,7 @@ test('flow capability registry keeps OpenAI phone signup available only when run
const plusLockedState = registry.resolveSidepanelCapabilities({
state: {
activeFlowId: 'openai',
panelMode: 'sub2api',
openaiIntegrationTargetId: 'sub2api',
phoneVerificationEnabled: true,
plusModeEnabled: true,
contributionMode: false,
@@ -58,7 +58,7 @@ test('flow capability registry defaults unknown flows to minimal non-phone capab
const capabilityState = registry.resolveSidepanelCapabilities({
state: {
activeFlowId: 'site-a',
panelMode: 'codex2api',
openaiIntegrationTargetId: 'codex2api',
phoneVerificationEnabled: true,
plusModeEnabled: true,
contributionMode: true,
@@ -73,7 +73,7 @@ test('flow capability registry defaults unknown flows to minimal non-phone capab
assert.equal(capabilityState.canUsePhoneSignup, false);
assert.equal(capabilityState.effectiveSignupMethod, 'email');
assert.equal(capabilityState.panelMode, 'codex2api');
assert.deepEqual(capabilityState.supportedPanelModes, []);
assert.deepEqual(capabilityState.supportedIntegrationTargets, []);
});
test('flow capability registry exposes Kiro as an independent flow with its own visible groups', () => {
@@ -83,8 +83,8 @@ test('flow capability registry exposes Kiro as an independent flow with its own
const capabilityState = registry.resolveSidepanelCapabilities({
state: {
activeFlowId: 'kiro',
kiroSourceId: 'kiro-rs',
panelMode: 'sub2api',
kiroIntegrationTargetId: 'kiro-rs',
openaiIntegrationTargetId: 'sub2api',
signupMethod: 'phone',
plusModeEnabled: true,
phoneVerificationEnabled: true,
@@ -95,21 +95,21 @@ test('flow capability registry exposes Kiro as an independent flow with its own
assert.equal(capabilityState.canShowPhoneSettings, false);
assert.equal(capabilityState.canShowPlusSettings, false);
assert.equal(capabilityState.effectiveSignupMethod, 'email');
assert.equal(capabilityState.effectiveSourceId, 'kiro-rs');
assert.equal(capabilityState.effectiveIntegrationTargetId, 'kiro-rs');
assert.deepEqual(
capabilityState.visibleGroupIds,
['kiro-runtime-status', 'kiro-source-kiro-rs', 'service-account', 'service-email', 'service-proxy']
['kiro-runtime-status', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
);
});
test('flow capability registry exposes shared auto-run validation for phone locks and panel support', () => {
test('flow capability registry exposes shared auto-run validation for phone locks and target support', () => {
const api = loadApi();
const registry = api.createFlowCapabilityRegistry({
flowCapabilities: {
openai: api.FLOW_CAPABILITIES.openai,
'site-a': {
...api.DEFAULT_FLOW_CAPABILITIES,
supportsPlatformBinding: ['cpa'],
supportedIntegrationTargets: ['cpa'],
},
},
});
@@ -117,7 +117,7 @@ test('flow capability registry exposes shared auto-run validation for phone lock
const plusLockedResult = registry.validateAutoRunStart({
state: {
activeFlowId: 'openai',
panelMode: 'cpa',
openaiIntegrationTargetId: 'cpa',
signupMethod: 'phone',
phoneVerificationEnabled: true,
plusModeEnabled: true,
@@ -131,7 +131,7 @@ test('flow capability registry exposes shared auto-run validation for phone lock
const unsupportedPanelResult = registry.validateAutoRunStart({
state: {
activeFlowId: 'site-a',
panelMode: 'sub2api',
openaiIntegrationTargetId: 'sub2api',
signupMethod: 'email',
},
});
@@ -147,7 +147,7 @@ test('flow capability registry normalizes unsupported mode switches back to the
openai: api.FLOW_CAPABILITIES.openai,
'site-a': {
...api.DEFAULT_FLOW_CAPABILITIES,
supportsPlatformBinding: ['cpa'],
supportedIntegrationTargets: ['cpa'],
},
},
});
@@ -155,14 +155,14 @@ test('flow capability registry normalizes unsupported mode switches back to the
const validation = registry.validateModeSwitch({
state: {
activeFlowId: 'site-a',
panelMode: 'sub2api',
openaiIntegrationTargetId: 'sub2api',
signupMethod: 'phone',
phoneVerificationEnabled: true,
plusModeEnabled: true,
contributionMode: true,
},
changedKeys: [
'panelMode',
'openaiIntegrationTargetId',
'signupMethod',
'phoneVerificationEnabled',
'plusModeEnabled',
@@ -173,6 +173,9 @@ test('flow capability registry normalizes unsupported mode switches back to the
assert.equal(validation.ok, false);
assert.deepEqual(validation.normalizedUpdates, {
panelMode: 'cpa',
openaiIntegrationTargetId: 'cpa',
kiroIntegrationTargetId: 'cpa',
kiroSourceId: 'cpa',
signupMethod: 'email',
phoneVerificationEnabled: false,
plusModeEnabled: false,
+30 -34
View File
@@ -13,37 +13,31 @@ function loadApis() {
};`)(scope);
}
test('flow registry exposes openai and kiro with canonical source metadata', () => {
test('flow registry exposes canonical flow and integration target metadata', () => {
const { flowRegistry } = loadApis();
assert.deepEqual(flowRegistry.getRegisteredFlowIds(), ['openai', 'kiro']);
assert.equal(flowRegistry.getFlowLabel('codex'), 'Codex / OpenAI');
assert.equal(flowRegistry.normalizeFlowId('codex'), 'openai');
assert.equal(flowRegistry.normalizeSourceId('openai', 'sub2api'), 'sub2api');
assert.equal(flowRegistry.normalizeSourceId('kiro', 'anything-else'), 'kiro-rs');
assert.equal(flowRegistry.normalizeFlowId('kiro'), 'kiro');
assert.equal(flowRegistry.normalizeFlowId('unknown'), 'openai');
assert.equal(flowRegistry.getFlowLabel('openai'), 'Codex / OpenAI');
assert.equal(flowRegistry.normalizeIntegrationTargetId('openai', 'sub2api'), 'sub2api');
assert.equal(flowRegistry.normalizeIntegrationTargetId('kiro', 'anything-else'), 'kiro-rs');
assert.deepEqual(
flowRegistry.getVisibleGroupIds('openai', 'cpa'),
['openai-plus', 'openai-phone', 'openai-oauth', 'openai-step6', 'openai-source-cpa', 'service-account', 'service-email', 'service-proxy']
['openai-plus', 'openai-phone', 'openai-oauth', 'openai-step6', 'openai-target-cpa', 'service-account', 'service-email', 'service-proxy']
);
assert.deepEqual(
flowRegistry.getVisibleGroupIds('kiro', 'kiro-rs'),
['kiro-runtime-status', 'kiro-source-kiro-rs', 'service-account', 'service-email', 'service-proxy']
['kiro-runtime-status', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
);
assert.deepEqual(
flowRegistry.getSettingsGroupDefinition('openai-plus')?.rowIds || [],
['row-plus-mode']
);
assert.deepEqual(
flowRegistry.getSettingsGroupDefinition('openai-phone')?.rowIds || [],
[]
);
assert.deepEqual(
flowRegistry.getSettingsGroupDefinition('openai-step6')?.rowIds || [],
['row-step6-cookie-settings']
flowRegistry.getIntegrationTargetOptions('openai').map((entry) => entry.id),
['cpa', 'sub2api', 'codex2api']
);
assert.equal(flowRegistry.getPublicationTargetDefinition('kiro', 'kiro-rs')?.label, 'kiro.rs');
});
test('settings schema normalizes flat input into canonical flow and service namespaces', () => {
test('settings schema normalizes view input into canonical nested namespaces', () => {
const { settingsSchema } = loadApis();
const schema = settingsSchema.createSettingsSchema();
@@ -66,10 +60,10 @@ test('settings schema normalizes flat input into canonical flow and service name
assert.equal(normalized.services.email.provider, 'hotmail');
assert.equal(normalized.services.proxy.enabled, true);
assert.equal(normalized.services.account.customPassword, 'SharedSecret123!');
assert.equal(normalized.flows.openai.source.selected, 'sub2api');
assert.equal(normalized.flows.kiro.source.selected, 'kiro-rs');
assert.equal(normalized.flows.kiro.source.entries['kiro-rs'].kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(normalized.flows.kiro.source.entries['kiro-rs'].kiroRsKey, 'secret-key');
assert.equal(normalized.flows.openai.integrationTargetId, 'sub2api');
assert.equal(normalized.flows.kiro.integrationTargetId, 'kiro-rs');
assert.equal(normalized.flows.kiro.integrationTargets['kiro-rs'].baseUrl, 'https://kiro.example.com/admin');
assert.equal(normalized.flows.kiro.integrationTargets['kiro-rs'].apiKey, 'secret-key');
assert.deepEqual(normalized.flows.kiro.autoRun.stepExecutionRange, {
enabled: true,
fromStep: 1,
@@ -77,22 +71,24 @@ test('settings schema normalizes flat input into canonical flow and service name
});
});
test('settings schema can project canonical state back to legacy payload without losing flow selection', () => {
test('settings schema can project canonical state into a read view without legacy rebuild helpers', () => {
const { settingsSchema } = loadApis();
const schema = settingsSchema.createSettingsSchema();
const payload = schema.buildLegacySettingsPayload(schema.normalizeSettingsState({
const normalized = schema.normalizeSettingsState({
activeFlowId: 'kiro',
kiroSourceId: 'kiro-rs',
kiroIntegrationTargetId: 'kiro-rs',
kiroRsUrl: 'https://kiro.example.com/admin',
kiroRsKey: 'key-123',
}));
});
const view = schema.buildSettingsView(normalized);
assert.equal(payload.activeFlowId, 'kiro');
assert.equal(payload.panelMode, 'cpa');
assert.equal(payload.kiroSourceId, 'kiro-rs');
assert.equal(payload.kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(payload.kiroRsKey, 'key-123');
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
assert.equal(payload.settingsSchemaVersion, 3);
assert.equal(payload.settingsState.activeFlowId, 'kiro');
assert.equal(view.activeFlowId, 'kiro');
assert.equal(view.openaiIntegrationTargetId, 'cpa');
assert.equal(view.kiroIntegrationTargetId, 'kiro-rs');
assert.equal(view.panelMode, 'cpa');
assert.equal(view.kiroSourceId, 'kiro-rs');
assert.equal(view.kiroRsUrl, 'https://kiro.example.com/admin');
assert.equal(view.kiroRsKey, 'key-123');
assert.equal(view.settingsSchemaVersion, 4);
assert.equal(view.settingsState.activeFlowId, 'kiro');
});