From 43148e3e1f51c017b9c9b4042acf2b0a83fc77a9 Mon Sep 17 00:00:00 2001 From: QLHazycoder <2825305047@qq.com> Date: Tue, 19 May 2026 19:59:59 +0000 Subject: [PATCH] refactor: route kiro contribution uploads through step 9 --- background.js | 1 + background/kiro/desktop-authorize-runner.js | 9 --- background/kiro/publisher-kiro-rs.js | 50 ++++++++++++++++ data/step-definitions.js | 10 +++- sidepanel/sidepanel.js | 22 +++++++ ...ound-kiro-publisher-kiro-rs-module.test.js | 59 +++++++++++++++++++ tests/kiro-contribution-artifact.test.js | 10 ++-- tests/step-definitions-module.test.js | 2 + 8 files changed, 149 insertions(+), 14 deletions(-) diff --git a/background.js b/background.js index c37acba..d88d919 100644 --- a/background.js +++ b/background.js @@ -13575,6 +13575,7 @@ const kiroPublisher = self.MultiPageBackgroundKiroPublisherKiroRs?.createKiroRsP completeNodeFromBackground, fetchImpl: typeof fetch === 'function' ? fetch.bind(globalThis) : null, getState, + maybeSubmitFlowContribution, setState, }); const step10Executor = self.MultiPageBackgroundStep10?.createStep10Executor({ diff --git a/background/kiro/desktop-authorize-runner.js b/background/kiro/desktop-authorize-runner.js index a900e53..fb95aa9 100644 --- a/background/kiro/desktop-authorize-runner.js +++ b/background/kiro/desktop-authorize-runner.js @@ -478,15 +478,6 @@ }, }); await log('步骤 8:桌面授权回调已捕获,Token 换取成功。', 'ok', nodeId); - await maybeSubmitFlowContribution({ - ...currentState, - ...payload, - }, { - nodeId, - trigger: 'kiro-step-8', - }).catch(async (error) => { - await log(`步骤 8:Kiro 公共贡献提交异常,已保留桌面授权结果:${getErrorMessage(error)}`, 'warn', nodeId); - }); await completeNodeFromBackground(nodeId, payload); return payload; } diff --git a/background/kiro/publisher-kiro-rs.js b/background/kiro/publisher-kiro-rs.js index a99d739..edee9e5 100644 --- a/background/kiro/publisher-kiro-rs.js +++ b/background/kiro/publisher-kiro-rs.js @@ -295,6 +295,7 @@ completeNodeFromBackground, fetchImpl = typeof fetch === 'function' ? fetch.bind(globalThis) : null, getState = async () => ({}), + maybeSubmitFlowContribution = async () => ({ ok: true, skipped: true, reason: 'not_configured' }), setState = async () => {}, } = deps; @@ -329,10 +330,59 @@ await setState(nextPatch); } + function shouldUseContributionUpload(state = {}) { + return Boolean(state?.accountContributionEnabled) + && cleanString(state?.activeFlowId || state?.flowId).toLowerCase() === 'kiro' + && cleanString(state?.contributionAdapterId).toLowerCase() === 'kiro-builder-id'; + } + async function executeKiroUploadCredential(state = {}) { const nodeId = String(state?.nodeId || 'kiro-upload-credential').trim(); const currentState = await getState(); try { + if (shouldUseContributionUpload(currentState)) { + await applyRuntimeState(currentState, { + session: { + currentStage: 'upload', + lastError: '', + lastWarning: '', + }, + upload: { + targetId: 'contribution', + status: 'uploading', + error: '', + }, + }); + + await log('步骤 9:正在上传 Builder ID 到贡献池...', 'info', nodeId); + const contributionResult = await maybeSubmitFlowContribution(currentState, { + nodeId, + trigger: 'kiro-step-9', + }); + if (!contributionResult?.ok || contributionResult?.skipped) { + throw new Error(contributionResult?.message || 'Kiro 贡献上传失败。'); + } + + const uploadedAt = Date.now(); + const payload = await applyRuntimeState(currentState, { + session: { + currentStage: 'upload', + lastError: '', + }, + upload: { + targetId: 'contribution', + status: 'uploaded', + error: '', + credentialId: contributionResult.contributionId || '', + lastMessage: contributionResult.message || '贡献上传成功', + lastUploadedAt: uploadedAt, + }, + }); + await log(`步骤 9:贡献上传完成,状态:${contributionResult.message || '贡献上传成功'}`, 'ok', nodeId); + await completeNodeFromBackground(nodeId, payload); + return; + } + const targetId = resolveKiroTargetId(currentState); const targetConfig = resolveKiroTargetConfig(currentState, targetId); const baseUrl = normalizeKiroRsBaseUrl(targetConfig.baseUrl); diff --git a/data/step-definitions.js b/data/step-definitions.js index 75c495c..27b0a0a 100644 --- a/data/step-definitions.js +++ b/data/step-definitions.js @@ -305,6 +305,7 @@ 'submit-signup-email': '注册并输入手机号', 'fetch-signup-code': '获取手机验证码', }); + const KIRO_CONTRIBUTION_STEP_TITLE = '贡献上传'; function isPlusModeEnabled(options = {}) { return Boolean(options?.plusModeEnabled || options?.plusMode); @@ -415,6 +416,10 @@ return step.title; } + function isKiroContributionModeEnabled(options = {}) { + return Boolean(options?.accountContributionEnabled || options?.state?.accountContributionEnabled); + } + const FLOW_DEFINITION_BUILDERS = Object.freeze({ openai: { getAllSteps() { @@ -462,7 +467,10 @@ getPlusPaymentStepTitle() { return ''; }, - resolveStepTitle(step) { + resolveStepTitle(step, options = {}) { + if (step?.key === 'kiro-upload-credential' && isKiroContributionModeEnabled(options)) { + return KIRO_CONTRIBUTION_STEP_TITLE; + } return step?.title || ''; }, }, diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js index 9a3fb13..b546a8d 100644 --- a/sidepanel/sidepanel.js +++ b/sidepanel/sidepanel.js @@ -868,6 +868,9 @@ function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) { const phoneSignupReloginAfterBindEmailEnabled = typeof options === 'string' ? currentPhoneSignupReloginAfterBindEmailEnabled : Boolean(options.phoneSignupReloginAfterBindEmailEnabled ?? currentPhoneSignupReloginAfterBindEmailEnabled); + const accountContributionEnabled = typeof options === 'string' + ? Boolean(typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false) + : Boolean(options.accountContributionEnabled ?? (typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false)); const activeFlowId = typeof options === 'string' ? ((typeof latestState !== 'undefined' ? latestState?.activeFlowId : '') || defaultFlowId) : (options.activeFlowId || (typeof latestState !== 'undefined' ? latestState?.activeFlowId : '') || defaultFlowId); @@ -878,6 +881,7 @@ function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) { plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(rawPlusAccountAccessStrategy), signupMethod: normalizeSignupMethod(rawSignupMethod), phoneSignupReloginAfterBindEmailEnabled, + accountContributionEnabled, }) || []) .sort((left, right) => { const leftOrder = Number.isFinite(left.order) ? left.order : left.id; @@ -903,6 +907,9 @@ function getWorkflowNodesForMode(plusModeEnabled = false, options = {}) { const phoneSignupReloginAfterBindEmailEnabled = typeof options === 'string' ? currentPhoneSignupReloginAfterBindEmailEnabled : Boolean(options.phoneSignupReloginAfterBindEmailEnabled ?? currentPhoneSignupReloginAfterBindEmailEnabled); + const accountContributionEnabled = typeof options === 'string' + ? Boolean(typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false) + : Boolean(options.accountContributionEnabled ?? (typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false)); const activeFlowId = typeof options === 'string' ? ((typeof latestState !== 'undefined' ? latestState?.activeFlowId : '') || defaultFlowId) : (options.activeFlowId || (typeof latestState !== 'undefined' ? latestState?.activeFlowId : '') || defaultFlowId); @@ -913,6 +920,7 @@ function getWorkflowNodesForMode(plusModeEnabled = false, options = {}) { plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(rawPlusAccountAccessStrategy), signupMethod: normalizeSignupMethod(rawSignupMethod), phoneSignupReloginAfterBindEmailEnabled, + accountContributionEnabled, }); if (Array.isArray(nodes) && nodes.length) { return nodes.slice().sort((left, right) => { @@ -980,6 +988,10 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) { const phoneSignupReloginAfterBindEmailEnabled = typeof options === 'string' ? currentPhoneSignupReloginAfterBindEmailEnabled : Boolean(options.phoneSignupReloginAfterBindEmailEnabled ?? currentPhoneSignupReloginAfterBindEmailEnabled); + const accountContributionEnabled = Boolean( + options.accountContributionEnabled + ?? (typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false) + ); currentPlusPaymentMethod = normalizePlusPaymentMethod(rawPaymentMethod); currentPlusAccountAccessStrategy = normalizePlusAccountAccessStrategy(rawPlusAccountAccessStrategy); currentSignupMethod = normalizeSignupMethod(rawSignupMethod); @@ -998,6 +1010,7 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) { plusAccountAccessStrategy: currentPlusAccountAccessStrategy, signupMethod: currentSignupMethod, phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled, + accountContributionEnabled, }); const nextWorkflowNodes = typeof getWorkflowNodesForMode === 'function' ? getWorkflowNodesForMode(currentPlusModeEnabled, { @@ -1006,6 +1019,7 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) { plusAccountAccessStrategy: currentPlusAccountAccessStrategy, signupMethod: currentSignupMethod, phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled, + accountContributionEnabled, }) : stepDefinitions.map((step) => ({ nodeId: String(step.key || step.id || '').trim(), @@ -10170,6 +10184,10 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr ? inputPhoneSignupReloginAfterBindEmail.checked : currentPhoneSignupReloginAfterBindEmailEnabled) ); + const nextAccountContributionEnabled = Boolean( + options.accountContributionEnabled + ?? (typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false) + ); const nextPaymentMethod = normalizePlusPaymentMethod(rawPaymentMethod); const nextActiveFlowId = String( options.activeFlowId @@ -10196,6 +10214,7 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr || nextPlusAccountAccessStrategy !== currentPlusAccountAccessStrategy || nextSignupMethod !== currentSignupMethod || nextPhoneSignupReloginAfterBindEmailEnabled !== currentPhoneSignupReloginAfterBindEmailEnabled + || nextAccountContributionEnabled !== Boolean(typeof latestState !== 'undefined' ? latestState?.accountContributionEnabled : false) || nextActiveFlowId !== currentFlowId || paymentTitleChanged; if (!shouldRender) { @@ -10208,6 +10227,7 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr plusAccountAccessStrategy: nextPlusAccountAccessStrategy, signupMethod: nextSignupMethod, phoneSignupReloginAfterBindEmailEnabled: nextPhoneSignupReloginAfterBindEmailEnabled, + accountContributionEnabled: nextAccountContributionEnabled, }); renderStepsList(); } @@ -10234,6 +10254,7 @@ function syncStepDefinitionsFromUiState(stateOverrides = {}) { plusAccountAccessStrategy: stepDefinitionState.plusAccountAccessStrategy, signupMethod: stepDefinitionState.signupMethod, phoneSignupReloginAfterBindEmailEnabled: Boolean(nextState?.phoneSignupReloginAfterBindEmailEnabled), + accountContributionEnabled: Boolean(nextState?.accountContributionEnabled), }); return stepDefinitionState; } @@ -10257,6 +10278,7 @@ function applySettingsState(state) { plusPaymentMethod: state?.plusPaymentMethod, signupMethod: stepDefinitionState.signupMethod, phoneSignupReloginAfterBindEmailEnabled: Boolean(state?.phoneSignupReloginAfterBindEmailEnabled), + accountContributionEnabled: Boolean(state?.accountContributionEnabled), }); } const fallbackIpProxyService = '711proxy'; diff --git a/tests/background-kiro-publisher-kiro-rs-module.test.js b/tests/background-kiro-publisher-kiro-rs-module.test.js index 45f393b..e51d222 100644 --- a/tests/background-kiro-publisher-kiro-rs-module.test.js +++ b/tests/background-kiro-publisher-kiro-rs-module.test.js @@ -171,6 +171,65 @@ test('kiro publisher reads latest kiro.rs key from background state instead of s assert.equal(completed[0].nodeId, 'kiro-upload-credential'); }); +test('kiro publisher routes step 9 through public contribution upload when contribution mode is enabled', async () => { + const api = loadPublisherApi(); + const requests = []; + const completed = []; + let liveState = { + activeFlowId: 'kiro', + flowId: 'kiro', + accountContributionEnabled: true, + contributionAdapterId: 'kiro-builder-id', + kiroTargetId: 'kiro-rs', + kiroRuntime: { + register: { + email: 'aws-user@example.com', + }, + desktopAuth: { + region: 'us-east-1', + clientId: 'client-001', + clientSecret: 'secret-001', + refreshToken: 'refresh-token-001', + }, + upload: { + targetId: 'kiro-rs', + }, + }, + }; + const publisher = api.createKiroRsPublisher({ + addLog: async () => {}, + completeNodeFromBackground: async (nodeId, payload) => { + completed.push({ nodeId, payload }); + }, + fetchImpl: async (url, options = {}) => { + requests.push({ url, options }); + throw new Error('kiro.rs upload should not be called in contribution mode'); + }, + getState: async () => ({ ...liveState }), + maybeSubmitFlowContribution: async (_state, options = {}) => ({ + ok: true, + skipped: false, + contributionId: 'kiro-contribution-009', + message: `贡献链路成功:${options.trigger || 'unknown'}`, + }), + setState: async (updates = {}) => { + liveState = { ...liveState, ...updates }; + }, + }); + + await publisher.executeKiroUploadCredential({ + nodeId: 'kiro-upload-credential', + }); + + assert.equal(requests.length, 0); + assert.equal(completed.length, 1); + assert.equal(completed[0].nodeId, 'kiro-upload-credential'); + assert.equal(completed[0].payload.kiroRuntime.upload.targetId, 'contribution'); + assert.equal(completed[0].payload.kiroRuntime.upload.status, 'uploaded'); + assert.equal(completed[0].payload.kiroRuntime.upload.credentialId, 'kiro-contribution-009'); + assert.equal(completed[0].payload.kiroRuntime.upload.lastMessage, '贡献链路成功:kiro-step-9'); +}); + test('kiro publisher trims api key and includes fallback Authorization header during connection check', async () => { const api = loadPublisherApi(); const requests = []; diff --git a/tests/kiro-contribution-artifact.test.js b/tests/kiro-contribution-artifact.test.js index 4325953..390a55e 100644 --- a/tests/kiro-contribution-artifact.test.js +++ b/tests/kiro-contribution-artifact.test.js @@ -210,8 +210,10 @@ test('Kiro contribution adapter redacts server errors that echo submitted secret assert.equal(combined.includes('client-secret-super-long'), false); }); -test('Kiro desktop authorization runner is wired to submit public contribution after step 8', () => { - const source = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8'); - assert.match(source, /maybeSubmitFlowContribution/); - assert.match(source, /trigger:\s*'kiro-step-8'/); +test('Kiro public contribution is triggered from step 9 instead of step 8', () => { + const desktopSource = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8'); + const publisherSource = fs.readFileSync('background/kiro/publisher-kiro-rs.js', 'utf8'); + assert.doesNotMatch(desktopSource, /trigger:\s*'kiro-step-8'/); + assert.match(publisherSource, /maybeSubmitFlowContribution/); + assert.match(publisherSource, /trigger:\s*'kiro-step-9'/); }); diff --git a/tests/step-definitions-module.test.js b/tests/step-definitions-module.test.js index a93131a..9dfb329 100644 --- a/tests/step-definitions-module.test.js +++ b/tests/step-definitions-module.test.js @@ -190,6 +190,8 @@ test('step definitions module exposes ordered normal and Plus step metadata', () assert.equal(kiroSteps[6].title, '启动桌面授权'); assert.equal(kiroSteps[7].title, '完成桌面授权'); assert.equal(kiroSteps[8].title, '上传凭据到 kiro.rs'); + const kiroContributionSteps = api.getSteps({ activeFlowId: 'kiro', accountContributionEnabled: true }); + assert.equal(kiroContributionSteps[8].title, '贡献上传'); assert.deepStrictEqual(api.getStepIds({ activeFlowId: 'kiro' }), [1, 2, 3, 4, 5, 6, 7, 8, 9]); assert.equal(api.getLastStepId({ activeFlowId: 'kiro' }), 9); assert.deepStrictEqual(