diff --git a/.agents/skills/ai-native-eval/scripts/eval/src/cli.ts b/.agents/skills/ai-native-eval/scripts/eval/src/cli.ts index 618cc47..933cc16 100644 --- a/.agents/skills/ai-native-eval/scripts/eval/src/cli.ts +++ b/.agents/skills/ai-native-eval/scripts/eval/src/cli.ts @@ -140,7 +140,7 @@ async function runInitRunCommand(repoRoot: string, rest: string[]): Promise - ai-native-eval render --out [--language zh-TW] [--ui-language zh-TW] [--review-type event] [--target pull_request] [--phase opened] [--trigger-mode one_shot] [--target-surface pr]... - ai-native-eval persist [--root .ai-native-eval/artifacts] [--language zh-TW] [--ui-language zh-TW] [--changed-file ]... [--review-type event] [--target pull_request] [--trigger-mode one_shot] + ai-native-eval render --out [--language zh-TW] [--ui-language zh-CN|zh-TW|es|de|ja] [--review-type event] [--target pull_request] [--phase opened] [--trigger-mode one_shot] [--target-surface pr]... + ai-native-eval persist [--root .ai-native-eval/artifacts] [--language zh-TW] [--ui-language zh-CN|zh-TW|es|de|ja] [--changed-file ]... [--review-type event] [--target pull_request] [--trigger-mode one_shot] ai-native-eval init-run [--out ] [--config ] [--project-config ] [--person-config ] [--review-type event] [--target pull_request] [--target-ref PR-123] [--phase opened] [--trigger user] [--trigger-mode external_event] [--trigger-source github] [--trigger-event pull_request.opened] [--threshold 0.85] [--max-iterations 3] [--target-surface pr]... ai-native-eval validate-folder [--skills-dir .agents/skills] ai-native-eval render-folder [--out ] [--json-out ] [--markdown-out ] [--skills-dir .agents/skills] diff --git a/.agents/skills/ai-native-eval/scripts/eval/src/config.ts b/.agents/skills/ai-native-eval/scripts/eval/src/config.ts index 17d1a79..9d2a061 100644 --- a/.agents/skills/ai-native-eval/scripts/eval/src/config.ts +++ b/.agents/skills/ai-native-eval/scripts/eval/src/config.ts @@ -9,6 +9,7 @@ import type { EvalConfig, EvalContextRoute, EvalConfigSource, + ReportUiLanguage, ResolvedDisabledPlugin, ResolvedEvaluatorConfig, ResolvedContextRoute, @@ -41,7 +42,7 @@ export interface InitRunInput { reportId?: string; generatedAt?: string; language?: string; - uiLanguage?: "en" | "zh-TW"; + uiLanguage?: ReportUiLanguage; scope?: string; evaluationContext?: EvaluationContext; repoCommit?: string; diff --git a/.agents/skills/ai-native-eval/scripts/eval/src/renderHtml.ts b/.agents/skills/ai-native-eval/scripts/eval/src/renderHtml.ts index aa98cde..8a4cda2 100644 --- a/.agents/skills/ai-native-eval/scripts/eval/src/renderHtml.ts +++ b/.agents/skills/ai-native-eval/scripts/eval/src/renderHtml.ts @@ -27,7 +27,86 @@ const translations = { recommendedActions: "Recommended Actions", improvementReferences: "Improvement References", copyAgentPrompt: "Copy agent prompt", - language: "Language" + language: "Language", + error: "error", + warning: "warning", + reviewType: "Review type", + target: "Target", + targetRef: "Target ref", + phase: "Phase", + trigger: "Trigger", + triggerMode: "Trigger mode", + triggerSource: "Trigger source", + triggerEvent: "Trigger event", + triggerThreshold: "Trigger threshold", + triggerMaxIterations: "Trigger max iterations", + triggerOwner: "Trigger owner", + triggerOwnerExternal: "External systems own scheduling, enforcement, and iteration loops.", + targetSurfaces: "Target surfaces", + outputIntents: "Output intents", + affectsOverallScore: "Affects overall score", + assumption: "Assumption", + builtIn: "Built-in", + additional: "Additional", + disabled: "Disabled", + contextRoutes: "Context routes", + evaluatorConfigs: "Evaluator configs", + warnings: "Warnings", + none: "None", + enabled: "enabled", + recommendation: "Recommendation", + reason: "Reason" + }, + "zh-CN": { + reportTitle: "AI Native Eval 报告", + generated: "生成于", + score: "分数", + policy: "Policy", + confidence: "置信度", + evaluationTree: "评估树", + evaluationContext: "评估上下文", + runConfiguration: "运行配置", + reproducibility: "可复现信息", + points: "点数", + node: "节点", + status: "状态", + action: "操作", + evidence: "证据", + whyNot10: "为什么不是 10/10", + policyRules: "Policy 规则", + cappedAt: "上限", + recommendedActions: "建议操作", + improvementReferences: "改进参考", + copyAgentPrompt: "复制 agent prompt", + language: "语言", + error: "错误", + warning: "警告", + reviewType: "评审类型", + target: "目标", + targetRef: "目标引用", + phase: "阶段", + trigger: "触发器", + triggerMode: "触发模式", + triggerSource: "触发来源", + triggerEvent: "触发事件", + triggerThreshold: "触发阈值", + triggerMaxIterations: "触发最大迭代次数", + triggerOwner: "触发责任方", + triggerOwnerExternal: "外部系统负责调度、执行约束和迭代循环。", + targetSurfaces: "目标界面", + outputIntents: "输出意图", + affectsOverallScore: "影响总分", + assumption: "假设", + builtIn: "内置", + additional: "额外", + disabled: "已禁用", + contextRoutes: "上下文路由", + evaluatorConfigs: "Evaluator 配置", + warnings: "警告", + none: "无", + enabled: "已启用", + recommendation: "建议", + reason: "原因" }, "zh-TW": { reportTitle: "AI Native 段位報告", @@ -50,7 +129,188 @@ const translations = { recommendedActions: "建議動作", improvementReferences: "改善參考", copyAgentPrompt: "複製 agent prompt", - language: "語言" + language: "語言", + error: "錯誤", + warning: "警告", + reviewType: "評審類型", + target: "目標", + targetRef: "目標引用", + phase: "階段", + trigger: "觸發器", + triggerMode: "觸發模式", + triggerSource: "觸發來源", + triggerEvent: "觸發事件", + triggerThreshold: "觸發門檻", + triggerMaxIterations: "觸發最大迭代次數", + triggerOwner: "觸發責任方", + triggerOwnerExternal: "外部系統負責排程、執行約束和迭代循環。", + targetSurfaces: "目標介面", + outputIntents: "輸出意圖", + affectsOverallScore: "影響總分", + assumption: "假設", + builtIn: "內建", + additional: "額外", + disabled: "已停用", + contextRoutes: "情境路由", + evaluatorConfigs: "Evaluator 設定", + warnings: "警告", + none: "無", + enabled: "已啟用", + recommendation: "建議", + reason: "原因" + }, + es: { + reportTitle: "Informe de AI Native Eval", + generated: "generado", + score: "Puntuación", + policy: "Policy", + confidence: "Confianza", + evaluationTree: "Árbol de evaluación", + evaluationContext: "Contexto de evaluación", + runConfiguration: "Configuración de ejecución", + reproducibility: "Reproducibilidad", + points: "Puntos", + node: "Nodo", + status: "Estado", + action: "Acción", + evidence: "Evidencia", + whyNot10: "Por qué no 10/10", + policyRules: "Reglas de policy", + cappedAt: "Limitado a", + recommendedActions: "Acciones recomendadas", + improvementReferences: "Referencias de mejora", + copyAgentPrompt: "Copiar prompt del agente", + language: "Idioma", + error: "error", + warning: "advertencia", + reviewType: "Tipo de revisión", + target: "Objetivo", + targetRef: "Referencia del objetivo", + phase: "Fase", + trigger: "Disparador", + triggerMode: "Modo de disparo", + triggerSource: "Fuente del disparo", + triggerEvent: "Evento del disparo", + triggerThreshold: "Umbral del disparo", + triggerMaxIterations: "Iteraciones máximas", + triggerOwner: "Responsable del disparo", + triggerOwnerExternal: "Los sistemas externos controlan programación, cumplimiento y ciclos de iteración.", + targetSurfaces: "Superficies objetivo", + outputIntents: "Intenciones de salida", + affectsOverallScore: "Afecta la puntuación total", + assumption: "Suposición", + builtIn: "Integrado", + additional: "Adicional", + disabled: "Deshabilitado", + contextRoutes: "Rutas de contexto", + evaluatorConfigs: "Configuraciones de evaluador", + warnings: "Advertencias", + none: "Ninguno", + enabled: "habilitado", + recommendation: "Recomendación", + reason: "Razón" + }, + de: { + reportTitle: "AI Native Eval Bericht", + generated: "erstellt", + score: "Score", + policy: "Policy", + confidence: "Konfidenz", + evaluationTree: "Evaluationsbaum", + evaluationContext: "Evaluationskontext", + runConfiguration: "Run-Konfiguration", + reproducibility: "Reproduzierbarkeit", + points: "Punkte", + node: "Knoten", + status: "Status", + action: "Aktion", + evidence: "Evidenz", + whyNot10: "Warum nicht 10/10", + policyRules: "Policy-Regeln", + cappedAt: "Begrenzt auf", + recommendedActions: "Empfohlene Aktionen", + improvementReferences: "Verbesserungsreferenzen", + copyAgentPrompt: "Agent-Prompt kopieren", + language: "Sprache", + error: "Fehler", + warning: "Warnung", + reviewType: "Review-Typ", + target: "Ziel", + targetRef: "Zielreferenz", + phase: "Phase", + trigger: "Trigger", + triggerMode: "Trigger-Modus", + triggerSource: "Trigger-Quelle", + triggerEvent: "Trigger-Ereignis", + triggerThreshold: "Trigger-Schwelle", + triggerMaxIterations: "Maximale Iterationen", + triggerOwner: "Trigger-Verantwortung", + triggerOwnerExternal: "Externe Systeme steuern Planung, Durchsetzung und Iterationsschleifen.", + targetSurfaces: "Zielflächen", + outputIntents: "Ausgabeabsichten", + affectsOverallScore: "Beeinflusst Gesamtscore", + assumption: "Annahme", + builtIn: "Eingebaut", + additional: "Zusätzlich", + disabled: "Deaktiviert", + contextRoutes: "Kontextrouten", + evaluatorConfigs: "Evaluator-Konfigurationen", + warnings: "Warnungen", + none: "Keine", + enabled: "aktiviert", + recommendation: "Empfehlung", + reason: "Grund" + }, + ja: { + reportTitle: "AI Native Eval レポート", + generated: "生成日時", + score: "スコア", + policy: "Policy", + confidence: "信頼度", + evaluationTree: "評価ツリー", + evaluationContext: "評価コンテキスト", + runConfiguration: "実行設定", + reproducibility: "再現性情報", + points: "点数", + node: "ノード", + status: "状態", + action: "操作", + evidence: "証拠", + whyNot10: "10/10 ではない理由", + policyRules: "Policy ルール", + cappedAt: "上限", + recommendedActions: "推奨アクション", + improvementReferences: "改善リファレンス", + copyAgentPrompt: "agent prompt をコピー", + language: "言語", + error: "エラー", + warning: "警告", + reviewType: "レビュー種別", + target: "対象", + targetRef: "対象参照", + phase: "フェーズ", + trigger: "トリガー", + triggerMode: "トリガーモード", + triggerSource: "トリガー元", + triggerEvent: "トリガーイベント", + triggerThreshold: "トリガーしきい値", + triggerMaxIterations: "最大イテレーション", + triggerOwner: "トリガー責任", + triggerOwnerExternal: "外部システムがスケジューリング、強制、イテレーションループを管理します。", + targetSurfaces: "対象サーフェス", + outputIntents: "出力意図", + affectsOverallScore: "総合スコアへの影響", + assumption: "仮定", + builtIn: "組み込み", + additional: "追加", + disabled: "無効", + contextRoutes: "コンテキストルート", + evaluatorConfigs: "Evaluator 設定", + warnings: "警告", + none: "なし", + enabled: "有効", + recommendation: "推奨", + reason: "理由" } } satisfies Record>; @@ -185,7 +445,11 @@ export function renderHtmlReport(report: EvaluationReport): string { @@ -318,14 +582,14 @@ function policyMetric(tr: TranslationDictionary, report: EvaluationReport): stri const policy = report.policy; const status = policy?.status ?? "pass"; const value = status === "blocked" ? "BLOCKED" : status.toUpperCase(); - const subvalue = policy - ? `${policy.errorCount} error · ${policy.warnCount} warning` - : "0 error · 0 warning"; + const errorCount = policy?.errorCount ?? 0; + const warnCount = policy?.warnCount ?? 0; + const subvalue = `${errorCount} ${escapeHtml( + tr.error + )} · ${warnCount} ${escapeHtml(tr.warning)}`; return `
${escapeHtml( tr.policy - )}
${escapeHtml(value)}
${escapeHtml( - subvalue - )}
`; + )}
${escapeHtml(value)}
${subvalue}
`; } function scoreMetricClass(score: number | null): "good" | "warn" | "bad" { @@ -348,48 +612,48 @@ function renderEvaluationContext( const context = report.evaluationContext; if (!context) return ""; const rows = [ - ["Review type", context.reviewType], - ["Target", context.target], - ["Target ref", context.targetRef], - ["Phase", context.phase], - ["Trigger", context.trigger], - ["Trigger mode", context.triggerMetadata?.mode], - ["Trigger source", context.triggerMetadata?.source], - ["Trigger event", context.triggerMetadata?.event], + ["reviewType", context.reviewType], + ["target", context.target], + ["targetRef", context.targetRef], + ["phase", context.phase], + ["trigger", context.trigger], + ["triggerMode", context.triggerMetadata?.mode], + ["triggerSource", context.triggerMetadata?.source], + ["triggerEvent", context.triggerMetadata?.event], [ - "Trigger threshold", + "triggerThreshold", context.triggerMetadata?.threshold === undefined ? undefined : String(context.triggerMetadata.threshold) ], [ - "Trigger max iterations", + "triggerMaxIterations", context.triggerMetadata?.maxIterations === undefined ? undefined : String(context.triggerMetadata.maxIterations) ], [ - "Trigger owner", + "triggerOwner", context.triggerMetadata - ? "External systems own scheduling, enforcement, and iteration loops." + ? tr.triggerOwnerExternal : undefined ], - ["Target surfaces", context.targetSurfaces?.join(", ")], - ["Output intents", context.outputIntents?.join(", ")], + ["targetSurfaces", context.targetSurfaces?.join(", ")], + ["outputIntents", context.outputIntents?.join(", ")], [ - "Affects overall score", + "affectsOverallScore", context.affectsOverallScore === undefined ? undefined : String(context.affectsOverallScore) ], - ["Assumption", context.assumption] - ].filter((row): row is [string, string] => Boolean(row[1])); + ["assumption", context.assumption] + ].filter((row): row is [TranslationKey, string] => Boolean(row[1])); return `

${escapeHtml( tr.evaluationContext )}

${rows .map( - ([label, value]) => - `` + ([key, value]) => + `` ) .join("")}
${escapeHtml(label)}${escapeHtml(value)}
${escapeHtml(tr[key])}${escapeHtml(value)}
`; } @@ -410,10 +674,10 @@ function renderRunConfiguration( return `

${escapeHtml( tr.runConfiguration )}

-

Built-in

    ${builtIn +

    ${escapeHtml(tr.builtIn)}

      ${builtIn .map((root) => `
    • ${escapeHtml(root.pluginId)}
    • `) .join("")}
    -

    Additional

      ${ +

      ${escapeHtml(tr.additional)}

        ${ additional.length > 0 ? additional .map( @@ -421,9 +685,9 @@ function renderRunConfiguration( `
      • ${escapeHtml(root.pluginId)}${root.reason ? ` ${escapeHtml(root.reason)}` : ""}
      • ` ) .join("") - : `
      • None
      • ` + : `
      • ${escapeHtml(tr.none)}
      • ` }
      -

      Disabled

        ${ +

        ${escapeHtml(tr.disabled)}

          ${ disabled.length > 0 ? disabled .map( @@ -431,9 +695,9 @@ function renderRunConfiguration( `
        • ${escapeHtml(item.pluginId)}
          ${escapeHtml(item.reason)} (${escapeHtml(item.source)})
        • ` ) .join("") - : `
        • None
        • ` + : `
        • ${escapeHtml(tr.none)}
        • ` }
        -

        Context routes

          ${ +

          ${escapeHtml(tr.contextRoutes)}

            ${ routes.length > 0 ? routes .map( @@ -441,14 +705,14 @@ function renderRunConfiguration( `
          • ${escapeHtml(route.id)}
            ${escapeHtml(route.description ?? route.source)}
          • ` ) .join("") - : `
          • None
          • ` + : `
          • ${escapeHtml(tr.none)}
          • ` }
          -

          Evaluator configs

            ${ +

            ${escapeHtml(tr.evaluatorConfigs)}

              ${ evaluatorConfigs.length > 0 ? evaluatorConfigs .map((config) => { const details = [ - config.enabled === false ? "disabled" : "enabled", + config.enabled === false ? tr.disabled : tr.enabled, config.additionalChildren?.length ? `+${config.additionalChildren.map((child) => child.pluginId).join(", ")}` : "", @@ -459,9 +723,9 @@ function renderRunConfiguration( return `
            • ${escapeHtml(config.pluginId)}
              ${escapeHtml(config.source)} · ${escapeHtml(details)}
            • `; }) .join("") - : `
            • None
            • ` + : `
            • ${escapeHtml(tr.none)}
            • ` }
            -

            Warnings

              ${ +

              ${escapeHtml(tr.warnings)}

                ${ warnings.length > 0 ? warnings .map( @@ -469,7 +733,7 @@ function renderRunConfiguration( `
              • ${escapeHtml(warning.code)}
                ${escapeHtml(warning.message)} (${escapeHtml(warning.source)})
              • ` ) .join("") - : `
              • None
              • ` + : `
              • ${escapeHtml(tr.none)}
              • ` }
`; } @@ -511,8 +775,8 @@ function renderNodeRows( ${escapeHtml(node.label)} # ${node.kind ? `${escapeHtml(node.kind)}` : ""} - ${node.origin === "additional" ? `additional` : ""} - ${node.disabledReason ? `disabled` : ""} + ${node.origin === "additional" ? `${escapeHtml(tr.additional)}` : ""} + ${node.disabledReason ? `${escapeHtml(tr.disabled)}` : ""} ${renderPolicyBadges(node)}
${escapeHtml(node.id)}${node.dimension ? ` · ${escapeHtml(node.dimension)}` : ""}
@@ -610,7 +874,7 @@ function renderDeductions( ? ` (${escapeHtml(tr.cappedAt)} ${group.budget})` : ""; const deductions = group.appliedDeductions - .map((deduction) => renderDeductionItem(deduction, repoUrl)) + .map((deduction) => renderDeductionItem(deduction, repoUrl, tr)) .join(""); return `
  • ${escapeHtml(group.label)} -${group.pointsLost}${cap}
      ${deductions}
  • `; }) @@ -623,24 +887,26 @@ type AppliedDeduction = NonNullable< function renderDeductionItem( deduction: AppliedDeduction, - repoUrl: string | undefined + repoUrl: string | undefined, + tr: TranslationDictionary ): string { - const evidence = renderDeductionEvidenceList(deduction.evidence, repoUrl); + const evidence = renderDeductionEvidenceList(deduction.evidence, repoUrl, tr); const recommendation = deduction.recommendation?.summary - ? `Recommendation

    ${escapeHtml(deduction.recommendation.summary)}

    ` + ? `${escapeHtml(tr.recommendation)}

    ${escapeHtml(deduction.recommendation.summary)}

    ` : ""; const reason = deduction.reason - ? `Reason

    ${escapeHtml(deduction.reason)}

    ` + ? `${escapeHtml(tr.reason)}

    ${escapeHtml(deduction.reason)}

    ` : ""; return `
  • ${escapeHtml(deduction.label)} -${deduction.pointsLost}
    ${reason}${evidence}${recommendation}
  • `; } function renderDeductionEvidenceList( evidence: EvaluationNodeResult["evidence"], - repoUrl: string | undefined + repoUrl: string | undefined, + tr: TranslationDictionary ): string { if (!evidence || evidence.length === 0) return ""; - return `Evidence
      ${evidence + return `${escapeHtml(tr.evidence)}
        ${evidence .map((item) => { const label = item.locator ? `${item.source} ${item.locator}` : item.source; const url = item.url ?? synthesizeRepoUrl(item.source, repoUrl); @@ -731,9 +997,16 @@ function confidenceTone(confidence: string): "good" | "warn" | "bad" | "neutral" function supportedUiLanguage(language: string | undefined): ReportUiLanguage { if (!language) return "en"; - if (language === "zh-TW" || language.toLowerCase().startsWith("zh")) { + const normalized = language.toLowerCase(); + if (normalized === "zh-cn" || normalized === "zh-hans") { + return "zh-CN"; + } + if (normalized === "zh-tw" || normalized === "zh-hant" || normalized === "zh") { return "zh-TW"; } + if (normalized === "es" || normalized.startsWith("es-")) return "es"; + if (normalized === "de" || normalized.startsWith("de-")) return "de"; + if (normalized === "ja" || normalized.startsWith("ja-")) return "ja"; return "en"; } diff --git a/.agents/skills/ai-native-eval/scripts/eval/src/types.ts b/.agents/skills/ai-native-eval/scripts/eval/src/types.ts index 62bced0..790ddc7 100644 --- a/.agents/skills/ai-native-eval/scripts/eval/src/types.ts +++ b/.agents/skills/ai-native-eval/scripts/eval/src/types.ts @@ -8,7 +8,7 @@ export type EvaluationStatus = export type Confidence = "low" | "medium" | "high"; -export type ReportUiLanguage = "en" | "zh-TW"; +export type ReportUiLanguage = "en" | "zh-CN" | "zh-TW" | "es" | "de" | "ja"; export type TriggerMode = | "one_shot" diff --git a/.agents/skills/ai-native-eval/scripts/eval/tests/aggregate.test.ts b/.agents/skills/ai-native-eval/scripts/eval/tests/aggregate.test.ts index 99b2408..607f4a2 100644 --- a/.agents/skills/ai-native-eval/scripts/eval/tests/aggregate.test.ts +++ b/.agents/skills/ai-native-eval/scripts/eval/tests/aggregate.test.ts @@ -105,9 +105,21 @@ test("renders drill-down HTML report with evidence and recommendations", async ( assert.match(html, /AI Native Eval Report/); assert.match(html, /AI Native 段位報告/); + assert.match(html, /AI Native Eval 报告/); + assert.match(html, /Informe de AI Native Eval/); + assert.match(html, /AI Native Eval Bericht/); + assert.match(html, /AI Native Eval レポート/); assert.match(html, /data-language-select/); assert.match(html, /