Localize Kiro flow copy
This commit is contained in:
+6
-2
@@ -1,4 +1,4 @@
|
||||
// background.js — Service Worker: orchestration, state, tab management, message routing
|
||||
// background.js — Service Worker: orchestration, state, tab management, message routing
|
||||
|
||||
importScripts(
|
||||
'shared/flow-registry.js',
|
||||
@@ -12397,6 +12397,10 @@ async function runAutoSequenceFromNodeGraph(startNodeId, context = {}) {
|
||||
};
|
||||
const initialFlowState = await getState();
|
||||
const activeFlowId = String(initialFlowState?.activeFlowId || initialFlowState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID;
|
||||
const activeFlowLabel = String(
|
||||
self.MultiPageFlowRegistry?.getFlowLabel?.(activeFlowId)
|
||||
|| activeFlowId
|
||||
).trim() || activeFlowId;
|
||||
|
||||
if (activeFlowId !== DEFAULT_ACTIVE_FLOW_ID) {
|
||||
await broadcastAutoRunStatus('running', {
|
||||
@@ -12409,7 +12413,7 @@ async function runAutoSequenceFromNodeGraph(startNodeId, context = {}) {
|
||||
if (continueCurrentAttempt) {
|
||||
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮:继续当前进度,从节点 ${currentStartNodeId} 开始(第 ${attemptRuns} 次尝试)===`, 'info');
|
||||
} else {
|
||||
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮:第 ${attemptRuns} 次尝试,开始执行 ${activeFlowId} flow ===`, 'info');
|
||||
await addLog(`=== 目标 ${targetRun}/${totalRuns} 轮:第 ${attemptRuns} 次尝试,开始执行 ${activeFlowLabel} 流程 ===`, 'info');
|
||||
}
|
||||
|
||||
let latestState = await getState();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
function normalizeKiroRsBaseUrl(value = '') {
|
||||
const normalized = cleanString(value).replace(/\/+$/, '');
|
||||
if (!normalized) {
|
||||
throw new Error('Missing kiro.rs admin URL.');
|
||||
throw new Error('缺少 kiro.rs 管理后台地址。');
|
||||
}
|
||||
return normalized.endsWith('/admin')
|
||||
? normalized.slice(0, -'/admin'.length)
|
||||
@@ -45,7 +45,20 @@
|
||||
}
|
||||
|
||||
function getErrorMessage(error) {
|
||||
return error instanceof Error ? error.message : String(error ?? 'Unknown error');
|
||||
return error instanceof Error ? error.message : String(error ?? '未知错误');
|
||||
}
|
||||
|
||||
function normalizeKiroUploadMessage(value = '') {
|
||||
const rawValue = cleanString(value);
|
||||
if (!rawValue) {
|
||||
return '上传成功';
|
||||
}
|
||||
|
||||
const normalizedValue = rawValue.toLowerCase();
|
||||
if (normalizedValue === 'uploaded' || normalizedValue === 'credential uploaded.') {
|
||||
return '上传成功';
|
||||
}
|
||||
return rawValue;
|
||||
}
|
||||
|
||||
function normalizePositiveInteger(value, fallback) {
|
||||
@@ -121,13 +134,13 @@
|
||||
});
|
||||
const registerBody = await readResponse(registerResponse);
|
||||
if (!registerResponse.ok) {
|
||||
throw new Error(`Builder ID client registration failed: ${cleanString(registerBody.text || registerResponse.statusText) || registerResponse.status}`);
|
||||
throw new Error(`Builder ID 客户端注册失败:${cleanString(registerBody.text || registerResponse.statusText) || registerResponse.status}`);
|
||||
}
|
||||
|
||||
const clientId = cleanString(registerBody.json?.clientId);
|
||||
const clientSecret = String(registerBody.json?.clientSecret || '');
|
||||
if (!clientId || !clientSecret) {
|
||||
throw new Error('Builder ID client registration response is missing client credentials.');
|
||||
throw new Error('Builder ID 客户端注册响应缺少凭据。');
|
||||
}
|
||||
|
||||
const authorizationResponse = await fetchImpl(`${oidcBaseUrl}/device_authorization`, {
|
||||
@@ -143,7 +156,7 @@
|
||||
});
|
||||
const authorizationBody = await readResponse(authorizationResponse);
|
||||
if (!authorizationResponse.ok) {
|
||||
throw new Error(`Builder ID device authorization failed: ${cleanString(authorizationBody.text || authorizationResponse.statusText) || authorizationResponse.status}`);
|
||||
throw new Error(`Builder ID 设备授权失败:${cleanString(authorizationBody.text || authorizationResponse.statusText) || authorizationResponse.status}`);
|
||||
}
|
||||
|
||||
const deviceCode = String(authorizationBody.json?.deviceCode || '');
|
||||
@@ -155,7 +168,7 @@
|
||||
const interval = normalizePositiveInteger(authorizationBody.json?.interval, 5);
|
||||
const expiresIn = normalizePositiveInteger(authorizationBody.json?.expiresIn, 600);
|
||||
if (!deviceCode || !userCode || !verificationUriComplete) {
|
||||
throw new Error('Builder ID device authorization response is missing required fields.');
|
||||
throw new Error('Builder ID 设备授权响应缺少必要字段。');
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -205,14 +218,14 @@
|
||||
return { completed: false, status: 'slow_down' };
|
||||
}
|
||||
if (errorCode === 'expired_token') {
|
||||
throw new Error('Kiro device login expired.');
|
||||
throw new Error('Kiro 设备登录已过期。');
|
||||
}
|
||||
if (errorCode === 'access_denied') {
|
||||
throw new Error('User denied the Builder ID device login request.');
|
||||
throw new Error('用户拒绝了 Builder ID 设备登录授权请求。');
|
||||
}
|
||||
throw new Error(`Builder ID authorization failed: ${errorCode || cleanString(body.text || response.statusText) || response.status}`);
|
||||
throw new Error(`Builder ID 授权失败:${errorCode || cleanString(body.text || response.statusText) || response.status}`);
|
||||
}
|
||||
throw new Error(`Builder ID token request failed: HTTP ${response.status}`);
|
||||
throw new Error(`Builder ID 令牌请求失败:HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
async function checkKiroRsConnection(baseUrl, apiKey, fetchImpl) {
|
||||
@@ -228,31 +241,31 @@
|
||||
if (response.ok) {
|
||||
return {
|
||||
ok: true,
|
||||
message: `kiro.rs connection ok (HTTP ${response.status})`,
|
||||
message: `kiro.rs 连接正常(HTTP ${response.status})`,
|
||||
};
|
||||
}
|
||||
if (response.status === 405) {
|
||||
return {
|
||||
ok: true,
|
||||
message: 'kiro.rs upload endpoint is reachable.',
|
||||
message: 'kiro.rs 上传接口可访问。',
|
||||
};
|
||||
}
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
return {
|
||||
ok: false,
|
||||
message: `kiro.rs API key rejected (HTTP ${response.status})`,
|
||||
message: `kiro.rs API Key 被拒绝(HTTP ${response.status})`,
|
||||
};
|
||||
}
|
||||
if (response.status === 404) {
|
||||
return {
|
||||
ok: false,
|
||||
message: 'kiro.rs admin endpoint not found.',
|
||||
message: '未找到 kiro.rs 管理接口。',
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
message: cleanString(body.json?.error?.message || body.json?.message || body.text || response.statusText)
|
||||
|| `kiro.rs connection failed (HTTP ${response.status})`,
|
||||
|| `kiro.rs 连接失败(HTTP ${response.status})`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -271,13 +284,13 @@
|
||||
if (!response.ok) {
|
||||
const message = cleanString(body.json?.error?.message || body.json?.message || body.text || response.statusText)
|
||||
|| `HTTP ${response.status}`;
|
||||
throw new Error(`kiro.rs credential upload failed: ${message}`);
|
||||
throw new Error(`kiro.rs 凭据上传失败:${message}`);
|
||||
}
|
||||
|
||||
return {
|
||||
credentialId: Number(body.json?.credentialId || body.json?.credential_id || 0) || null,
|
||||
email: cleanString(body.json?.email),
|
||||
message: cleanString(body.json?.message) || 'Credential uploaded.',
|
||||
message: normalizeKiroUploadMessage(body.json?.message),
|
||||
raw: body.json,
|
||||
};
|
||||
}
|
||||
@@ -360,7 +373,7 @@
|
||||
};
|
||||
|
||||
await setState(updates);
|
||||
await log(`Kiro device login started. Open ${loginUrl} and approve with code ${auth.userCode}.`, 'info', nodeId);
|
||||
await log(`Kiro 设备登录已启动。请打开 ${loginUrl},并输入授权码 ${auth.userCode} 完成确认。`, 'info', nodeId);
|
||||
await completeNodeFromBackground(nodeId, updates);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
@@ -382,10 +395,10 @@
|
||||
const region = normalizeRegion(latestState.kiroAuthRegion, DEFAULT_REGION);
|
||||
const expiresAt = Math.max(0, Number(latestState.kiroAuthExpiresAt) || 0);
|
||||
if (!clientId || !clientSecret || !deviceCode) {
|
||||
throw new Error('Kiro device login has not been started yet.');
|
||||
throw new Error('尚未启动 Kiro 设备登录,请先执行步骤 1。');
|
||||
}
|
||||
if (!expiresAt || expiresAt <= Date.now()) {
|
||||
throw new Error('Kiro device login expired. Restart step 1.');
|
||||
throw new Error('Kiro 设备登录已过期,请重新执行步骤 1。');
|
||||
}
|
||||
|
||||
await setState({
|
||||
@@ -393,7 +406,7 @@
|
||||
kiroAuthStatus: 'waiting_user',
|
||||
kiroUploadStatus: 'waiting_login',
|
||||
});
|
||||
await log('Waiting for Kiro device login approval...', 'info', nodeId);
|
||||
await log('正在等待 Kiro 设备登录授权确认...', 'info', nodeId);
|
||||
|
||||
let intervalSeconds = normalizePositiveInteger(latestState.kiroAuthIntervalSeconds, 5);
|
||||
while (Date.now() < expiresAt) {
|
||||
@@ -414,7 +427,7 @@
|
||||
kiroUploadStatus: 'ready_to_upload',
|
||||
};
|
||||
await setState(updates);
|
||||
await log('Kiro device login approved. Refresh token captured.', 'ok', nodeId);
|
||||
await log('Kiro 设备登录已确认,已获取 Refresh Token。', 'ok', nodeId);
|
||||
await completeNodeFromBackground(nodeId, updates);
|
||||
return;
|
||||
}
|
||||
@@ -425,12 +438,12 @@
|
||||
await sleepWithStop(intervalSeconds * 1000);
|
||||
}
|
||||
|
||||
throw new Error('Kiro device login expired. Restart step 1.');
|
||||
throw new Error('Kiro 设备登录已过期,请重新执行步骤 1。');
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
await persistFailure({
|
||||
kiroAuthError: message,
|
||||
kiroAuthStatus: /expired/i.test(message) ? 'expired' : 'error',
|
||||
kiroAuthStatus: /(expired|已过期)/i.test(message) ? 'expired' : 'error',
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
@@ -447,20 +460,20 @@
|
||||
const kiroRsUrl = String(latestState.kiroRsUrl || '');
|
||||
const kiroRsKey = String(latestState.kiroRsKey || '');
|
||||
if (!refreshToken || !clientId || !clientSecret) {
|
||||
throw new Error('Kiro refresh token is missing. Complete step 2 first.');
|
||||
throw new Error('缺少 Kiro Refresh Token,请先完成步骤 2。');
|
||||
}
|
||||
if (!cleanString(kiroRsUrl)) {
|
||||
throw new Error('Missing kiro.rs admin URL.');
|
||||
throw new Error('缺少 kiro.rs 管理后台地址。');
|
||||
}
|
||||
if (!cleanString(kiroRsKey)) {
|
||||
throw new Error('Missing kiro.rs API key.');
|
||||
throw new Error('缺少 kiro.rs API Key。');
|
||||
}
|
||||
|
||||
await setState({
|
||||
kiroUploadError: '',
|
||||
kiroUploadStatus: 'uploading',
|
||||
});
|
||||
await log('Uploading Builder ID credential to kiro.rs...', 'info', nodeId);
|
||||
await log('正在上传 Builder ID 凭据到 kiro.rs...', 'info', nodeId);
|
||||
|
||||
const connection = await checkKiroRsConnection(kiroRsUrl, kiroRsKey, fetchImpl);
|
||||
await setState({
|
||||
@@ -492,11 +505,11 @@
|
||||
kiroCredentialId: uploadResult.credentialId,
|
||||
kiroLastUploadAt: Date.now(),
|
||||
kiroUploadError: '',
|
||||
kiroUploadStatus: uploadResult.message || 'uploaded',
|
||||
kiroUploadStatus: normalizeKiroUploadMessage(uploadResult.message),
|
||||
};
|
||||
|
||||
await setState(updates);
|
||||
await log(`kiro.rs upload completed: ${updates.kiroUploadStatus}`, 'ok', nodeId);
|
||||
await log(`kiro.rs 上传完成:${updates.kiroUploadStatus}`, 'ok', nodeId);
|
||||
await completeNodeFromBackground(nodeId, updates);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
id: 1,
|
||||
order: 10,
|
||||
key: 'kiro-start-device-login',
|
||||
title: 'Start device login',
|
||||
title: '启动设备登录',
|
||||
sourceId: 'kiro-device-auth',
|
||||
driverId: 'background/kiro-device-auth',
|
||||
command: 'kiro-start-device-login',
|
||||
@@ -125,7 +125,7 @@
|
||||
id: 2,
|
||||
order: 20,
|
||||
key: 'kiro-await-device-login',
|
||||
title: 'Wait for device login',
|
||||
title: '等待设备登录确认',
|
||||
sourceId: 'kiro-device-auth',
|
||||
driverId: 'background/kiro-device-auth',
|
||||
command: 'kiro-await-device-login',
|
||||
@@ -134,7 +134,7 @@
|
||||
id: 3,
|
||||
order: 30,
|
||||
key: 'kiro-upload-credential',
|
||||
title: 'Upload credential to kiro.rs',
|
||||
title: '上传凭据到 kiro.rs',
|
||||
sourceId: 'kiro-rs-admin',
|
||||
driverId: 'background/kiro-device-auth',
|
||||
command: 'kiro-upload-credential',
|
||||
|
||||
+31
-1
@@ -2373,6 +2373,36 @@ function normalizeStepExecutionRangeEntry(value = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function getKiroUploadStatusLabel(value = '') {
|
||||
const rawValue = String(value || '').trim();
|
||||
if (!rawValue) {
|
||||
return '未开始';
|
||||
}
|
||||
|
||||
const normalizedValue = rawValue.toLowerCase();
|
||||
switch (normalizedValue) {
|
||||
case 'waiting_login':
|
||||
return '等待登录授权';
|
||||
case 'ready_to_upload':
|
||||
return '等待上传';
|
||||
case 'uploading':
|
||||
return '上传中';
|
||||
case 'uploaded':
|
||||
case 'credential uploaded.':
|
||||
return '上传成功';
|
||||
case 'error':
|
||||
return '上传失败';
|
||||
case 'waiting_user':
|
||||
return '等待用户确认';
|
||||
case 'authorized':
|
||||
return '已授权';
|
||||
case 'expired':
|
||||
return '已过期';
|
||||
default:
|
||||
return rawValue;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeStepExecutionRangeByFlow(value = {}) {
|
||||
const source = isPlainObjectValue(value) ? value : {};
|
||||
const next = {};
|
||||
@@ -9954,7 +9984,7 @@ function applySettingsState(state) {
|
||||
|| state?.kiroUploadStatus
|
||||
|| ''
|
||||
).trim();
|
||||
displayKiroUploadStatus.textContent = kiroUploadStatus || '未开始';
|
||||
displayKiroUploadStatus.textContent = getKiroUploadStatusLabel(kiroUploadStatus);
|
||||
}
|
||||
const normalizedIpProxyService = resolveIpProxyService(state?.ipProxyService);
|
||||
const normalizedIpProxyServiceProfiles = typeof normalizeIpProxyServiceProfiles === 'function'
|
||||
|
||||
@@ -312,15 +312,15 @@ test('kiro upload credential checks connection and uploads builder id credential
|
||||
});
|
||||
|
||||
const finalState = mergeUpdates(stateUpdates);
|
||||
assert.equal(finalState.kiroLastConnectionMessage, 'kiro.rs connection ok (HTTP 200)');
|
||||
assert.equal(finalState.kiroLastConnectionMessage, 'kiro.rs 连接正常(HTTP 200)');
|
||||
assert.equal(finalState.kiroAuthorizedEmail, 'aws-user@example.com');
|
||||
assert.equal(finalState.kiroCredentialId, 321);
|
||||
assert.equal(finalState.kiroUploadStatus, 'uploaded');
|
||||
assert.equal(finalState.kiroUploadStatus, '上传成功');
|
||||
assert.equal(typeof finalState.kiroLastUploadAt, 'number');
|
||||
assert.equal(finalState.kiroLastUploadAt > 0, true);
|
||||
|
||||
assert.equal(completeCalls.length, 1);
|
||||
assert.equal(completeCalls[0].nodeId, 'kiro-upload-credential');
|
||||
assert.equal(completeCalls[0].payload.kiroCredentialId, 321);
|
||||
assert.equal(completeCalls[0].payload.kiroUploadStatus, 'uploaded');
|
||||
assert.equal(completeCalls[0].payload.kiroUploadStatus, '上传成功');
|
||||
});
|
||||
|
||||
@@ -175,6 +175,9 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
|
||||
assert.equal(kiroSteps.every((step) => step.flowId === 'kiro'), true);
|
||||
assert.equal(kiroSteps[0].driverId, 'background/kiro-device-auth');
|
||||
assert.equal(kiroSteps[2].sourceId, 'kiro-rs-admin');
|
||||
assert.equal(kiroSteps[0].title, '启动设备登录');
|
||||
assert.equal(kiroSteps[1].title, '等待设备登录确认');
|
||||
assert.equal(kiroSteps[2].title, '上传凭据到 kiro.rs');
|
||||
assert.deepStrictEqual(api.getStepIds({ activeFlowId: 'kiro' }), [1, 2, 3]);
|
||||
assert.equal(api.getLastStepId({ activeFlowId: 'kiro' }), 3);
|
||||
assert.deepStrictEqual(
|
||||
|
||||
Reference in New Issue
Block a user