@gracker/smartperfetto 1.0.18 → 1.0.20

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.
Files changed (163) hide show
  1. package/dist/agent/core/conclusionContract.d.ts +1 -0
  2. package/dist/agent/core/conclusionContract.d.ts.map +1 -1
  3. package/dist/agent/tools/frameAnalyzer.d.ts.map +1 -1
  4. package/dist/agent/tools/frameAnalyzer.js +1 -0
  5. package/dist/agent/tools/frameAnalyzer.js.map +1 -1
  6. package/dist/agentOpenAI/openAiRuntime.d.ts +24 -0
  7. package/dist/agentOpenAI/openAiRuntime.d.ts.map +1 -1
  8. package/dist/agentOpenAI/openAiRuntime.js +171 -195
  9. package/dist/agentOpenAI/openAiRuntime.js.map +1 -1
  10. package/dist/agentRuntime/index.d.ts +1 -0
  11. package/dist/agentRuntime/index.d.ts.map +1 -1
  12. package/dist/agentRuntime/index.js +16 -1
  13. package/dist/agentRuntime/index.js.map +1 -1
  14. package/dist/agentRuntime/runtimeCommon.d.ts +34 -0
  15. package/dist/agentRuntime/runtimeCommon.d.ts.map +1 -0
  16. package/dist/agentRuntime/runtimeCommon.js +231 -0
  17. package/dist/agentRuntime/runtimeCommon.js.map +1 -0
  18. package/dist/agentv3/claudeConfig.d.ts +6 -2
  19. package/dist/agentv3/claudeConfig.d.ts.map +1 -1
  20. package/dist/agentv3/claudeConfig.js +50 -48
  21. package/dist/agentv3/claudeConfig.js.map +1 -1
  22. package/dist/agentv3/claudeMcpServer.d.ts.map +1 -1
  23. package/dist/agentv3/claudeMcpServer.js +74 -66
  24. package/dist/agentv3/claudeMcpServer.js.map +1 -1
  25. package/dist/agentv3/claudeRuntime.d.ts +18 -2
  26. package/dist/agentv3/claudeRuntime.d.ts.map +1 -1
  27. package/dist/agentv3/claudeRuntime.js +201 -268
  28. package/dist/agentv3/claudeRuntime.js.map +1 -1
  29. package/dist/agentv3/claudeSseBridge.js +1 -1
  30. package/dist/agentv3/claudeSseBridge.js.map +1 -1
  31. package/dist/agentv3/claudeSystemPrompt.d.ts.map +1 -1
  32. package/dist/agentv3/claudeSystemPrompt.js +14 -1
  33. package/dist/agentv3/claudeSystemPrompt.js.map +1 -1
  34. package/dist/agentv3/claudeVerifier.d.ts +1 -1
  35. package/dist/agentv3/claudeVerifier.d.ts.map +1 -1
  36. package/dist/agentv3/claudeVerifier.js +42 -19
  37. package/dist/agentv3/claudeVerifier.js.map +1 -1
  38. package/dist/agentv3/strategyLoader.d.ts +28 -0
  39. package/dist/agentv3/strategyLoader.d.ts.map +1 -1
  40. package/dist/agentv3/strategyLoader.js +35 -0
  41. package/dist/agentv3/strategyLoader.js.map +1 -1
  42. package/dist/cli/commands/validate.d.ts.map +1 -1
  43. package/dist/cli/commands/validate.js +120 -10
  44. package/dist/cli/commands/validate.js.map +1 -1
  45. package/dist/cli-user/bin.js +83 -2
  46. package/dist/cli-user/bin.js.map +1 -1
  47. package/dist/cli-user/commands/analyze.d.ts +2 -0
  48. package/dist/cli-user/commands/analyze.d.ts.map +1 -1
  49. package/dist/cli-user/commands/analyze.js +1 -0
  50. package/dist/cli-user/commands/analyze.js.map +1 -1
  51. package/dist/cli-user/commands/capture.d.ts +37 -2
  52. package/dist/cli-user/commands/capture.d.ts.map +1 -1
  53. package/dist/cli-user/commands/capture.js +184 -95
  54. package/dist/cli-user/commands/capture.js.map +1 -1
  55. package/dist/cli-user/commands/codebase.js +4 -4
  56. package/dist/cli-user/commands/codebase.js.map +1 -1
  57. package/dist/cli-user/commands/compare.d.ts +2 -0
  58. package/dist/cli-user/commands/compare.d.ts.map +1 -1
  59. package/dist/cli-user/commands/compare.js +1 -0
  60. package/dist/cli-user/commands/compare.js.map +1 -1
  61. package/dist/cli-user/commands/doctor.js +4 -0
  62. package/dist/cli-user/commands/doctor.js.map +1 -1
  63. package/dist/cli-user/services/androidCapture.d.ts +59 -0
  64. package/dist/cli-user/services/androidCapture.d.ts.map +1 -0
  65. package/dist/cli-user/services/androidCapture.js +375 -0
  66. package/dist/cli-user/services/androidCapture.js.map +1 -0
  67. package/dist/cli-user/services/captureConfig.d.ts +38 -0
  68. package/dist/cli-user/services/captureConfig.d.ts.map +1 -0
  69. package/dist/cli-user/services/captureConfig.js +434 -0
  70. package/dist/cli-user/services/captureConfig.js.map +1 -0
  71. package/dist/cli-user/services/captureTools.d.ts +11 -0
  72. package/dist/cli-user/services/captureTools.d.ts.map +1 -0
  73. package/dist/cli-user/services/captureTools.js +247 -0
  74. package/dist/cli-user/services/captureTools.js.map +1 -0
  75. package/dist/cli-user/services/cliAnalyzeService.d.ts +2 -0
  76. package/dist/cli-user/services/cliAnalyzeService.d.ts.map +1 -1
  77. package/dist/cli-user/services/cliAnalyzeService.js +1 -0
  78. package/dist/cli-user/services/cliAnalyzeService.js.map +1 -1
  79. package/dist/cli-user/services/runtimeGuard.d.ts +10 -0
  80. package/dist/cli-user/services/runtimeGuard.d.ts.map +1 -1
  81. package/dist/cli-user/services/runtimeGuard.js +48 -0
  82. package/dist/cli-user/services/runtimeGuard.js.map +1 -1
  83. package/dist/cli-user/services/turnRunner.d.ts +3 -0
  84. package/dist/cli-user/services/turnRunner.d.ts.map +1 -1
  85. package/dist/cli-user/services/turnRunner.js +4 -0
  86. package/dist/cli-user/services/turnRunner.js.map +1 -1
  87. package/dist/cli-user/types.d.ts +57 -0
  88. package/dist/cli-user/types.d.ts.map +1 -1
  89. package/dist/perfetto-recording-tools-pin.env +24 -0
  90. package/dist/routes/ragAdminRoutes.js +7 -7
  91. package/dist/routes/ragAdminRoutes.js.map +1 -1
  92. package/dist/services/agentResultNormalizer.d.ts.map +1 -1
  93. package/dist/services/agentResultNormalizer.js +32 -4
  94. package/dist/services/agentResultNormalizer.js.map +1 -1
  95. package/dist/services/codebase/pathSecurityGate.d.ts +2 -2
  96. package/dist/services/codebase/pathSecurityGate.d.ts.map +1 -1
  97. package/dist/services/codebase/pathSecurityGate.js +33 -9
  98. package/dist/services/codebase/pathSecurityGate.js.map +1 -1
  99. package/dist/services/evidence/evidenceContractBuilder.d.ts.map +1 -1
  100. package/dist/services/evidence/evidenceContractBuilder.js +17 -3
  101. package/dist/services/evidence/evidenceContractBuilder.js.map +1 -1
  102. package/dist/services/finalReportContractGate.d.ts +13 -0
  103. package/dist/services/finalReportContractGate.d.ts.map +1 -0
  104. package/dist/services/finalReportContractGate.js +48 -0
  105. package/dist/services/finalReportContractGate.js.map +1 -0
  106. package/dist/services/finalResultQualityGate.d.ts +3 -1
  107. package/dist/services/finalResultQualityGate.d.ts.map +1 -1
  108. package/dist/services/finalResultQualityGate.js +18 -1
  109. package/dist/services/finalResultQualityGate.js.map +1 -1
  110. package/dist/services/htmlReportGenerator.d.ts +12 -0
  111. package/dist/services/htmlReportGenerator.d.ts.map +1 -1
  112. package/dist/services/htmlReportGenerator.js +286 -33
  113. package/dist/services/htmlReportGenerator.js.map +1 -1
  114. package/dist/services/perfettoSqlSkill.d.ts.map +1 -1
  115. package/dist/services/perfettoSqlSkill.js +1 -0
  116. package/dist/services/perfettoSqlSkill.js.map +1 -1
  117. package/dist/services/providerManager/connectionTester.d.ts.map +1 -1
  118. package/dist/services/providerManager/connectionTester.js +4 -68
  119. package/dist/services/providerManager/connectionTester.js.map +1 -1
  120. package/dist/services/providerManager/index.d.ts +1 -0
  121. package/dist/services/providerManager/index.d.ts.map +1 -1
  122. package/dist/services/providerManager/index.js +8 -1
  123. package/dist/services/providerManager/index.js.map +1 -1
  124. package/dist/services/providerManager/providerService.d.ts.map +1 -1
  125. package/dist/services/providerManager/providerService.js +37 -106
  126. package/dist/services/providerManager/providerService.js.map +1 -1
  127. package/dist/services/providerManager/providerSnapshot.d.ts.map +1 -1
  128. package/dist/services/providerManager/providerSnapshot.js +13 -12
  129. package/dist/services/providerManager/providerSnapshot.js.map +1 -1
  130. package/dist/services/providerManager/runtimeCapabilities.d.ts +9 -0
  131. package/dist/services/providerManager/runtimeCapabilities.d.ts.map +1 -0
  132. package/dist/services/providerManager/runtimeCapabilities.js +105 -0
  133. package/dist/services/providerManager/runtimeCapabilities.js.map +1 -0
  134. package/dist/services/rag/aospSourceIngester.d.ts +1 -1
  135. package/dist/services/rag/aospSourceIngester.d.ts.map +1 -1
  136. package/dist/services/rag/aospSourceIngester.js +6 -4
  137. package/dist/services/rag/aospSourceIngester.js.map +1 -1
  138. package/dist/services/rag/appSourceIngester.d.ts +1 -1
  139. package/dist/services/rag/appSourceIngester.d.ts.map +1 -1
  140. package/dist/services/rag/appSourceIngester.js +6 -4
  141. package/dist/services/rag/appSourceIngester.js.map +1 -1
  142. package/dist/services/rag/kernelSourceIngester.d.ts +1 -1
  143. package/dist/services/rag/kernelSourceIngester.d.ts.map +1 -1
  144. package/dist/services/rag/kernelSourceIngester.js +6 -4
  145. package/dist/services/rag/kernelSourceIngester.js.map +1 -1
  146. package/dist/services/ragStore.d.ts +2 -0
  147. package/dist/services/ragStore.d.ts.map +1 -1
  148. package/dist/services/ragStore.js +6 -1
  149. package/dist/services/ragStore.js.map +1 -1
  150. package/dist/services/skillEngine/skillExecutor.d.ts +1 -0
  151. package/dist/services/skillEngine/skillExecutor.d.ts.map +1 -1
  152. package/dist/services/skillEngine/skillExecutor.js +64 -12
  153. package/dist/services/skillEngine/skillExecutor.js.map +1 -1
  154. package/package.json +5 -5
  155. package/prebuilts/android-platform-tools/README.md +13 -0
  156. package/prebuilts/perfetto-recording-tools/README.md +17 -0
  157. package/skills/atomic/cpu_topology_detection.skill.yaml +105 -159
  158. package/skills/atomic/cpu_topology_view.skill.yaml +2 -0
  159. package/strategies/prompt-openai-final-report-continuation-en.template.md +5 -1
  160. package/strategies/prompt-openai-final-report-continuation-zh.template.md +5 -1
  161. package/strategies/prompt-output-format.template.md +1 -1
  162. package/strategies/scrolling.strategy.md +22 -0
  163. package/strategies/startup.strategy.md +27 -1
@@ -14,10 +14,9 @@ exports.getHTMLReportGenerator = getHTMLReportGenerator;
14
14
  * Generates detailed HTML reports for analysis results
15
15
  * Reports include:
16
16
  * - Full thinking process
17
- * - All SQL queries and results
17
+ * - Structured evidence tables and compact provenance
18
18
  * - Detailed tables with expanded lists
19
19
  * - Diagnostic information
20
- * - Executable SQL for reproduction
21
20
  */
22
21
  const markdown_it_1 = __importDefault(require("markdown-it"));
23
22
  const dataContract_1 = require("../types/dataContract");
@@ -3709,7 +3708,7 @@ class HTMLReportGenerator {
3709
3708
  const dataEnvelopes = this.prepareAgentDrivenEnvelopes(data.dataEnvelopes || []);
3710
3709
  const agentResponses = data.agentResponses || [];
3711
3710
  const traceStartNs = data.traceStartNs ? this.parseNs(data.traceStartNs) : null;
3712
- const normalizedConversationTimeline = this.normalizeConversationTimeline(conversationTimeline || [], dialogue || []);
3711
+ const normalizedConversationTimeline = this.normalizeConversationTimeline(conversationTimeline || [], dialogue || [], outputLanguage);
3713
3712
  const partialWarningHtml = result.partial
3714
3713
  ? `
3715
3714
  <div class="section partial-warning">
@@ -3825,12 +3824,34 @@ class HTMLReportGenerator {
3825
3824
  margin-bottom: 16px; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;
3826
3825
  }
3827
3826
  .envelope-header {
3828
- display: flex; justify-content: space-between; align-items: center;
3827
+ display: grid; gap: 4px; align-items: start;
3829
3828
  padding: 12px 16px; background: #f9fafb; border-bottom: 1px solid #e5e7eb;
3830
3829
  }
3831
3830
  .envelope-title { font-weight: 600; font-size: 14px; color: #374151; }
3832
3831
  .envelope-meta { font-size: 11px; color: #9ca3af; }
3833
3832
  .envelope-body { padding: 0; }
3833
+ .envelope-technical-details {
3834
+ margin-top: 8px; font-size: 11px; color: #6b7280;
3835
+ }
3836
+ .envelope-technical-details > summary {
3837
+ cursor: pointer; user-select: none; color: #4b5563; font-weight: 500;
3838
+ }
3839
+ .envelope-technical-grid {
3840
+ margin-top: 8px; display: grid; grid-template-columns: 128px minmax(0, 1fr);
3841
+ gap: 5px 10px; padding: 8px; background: #fff; border: 1px solid #e5e7eb; border-radius: 6px;
3842
+ }
3843
+ .envelope-technical-key { color: #6b7280; font-weight: 500; }
3844
+ .envelope-technical-value {
3845
+ color: #374151; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
3846
+ word-break: break-all;
3847
+ }
3848
+ .envelope-sql-detail {
3849
+ margin-top: 8px; background: #111827; color: #e5e7eb; border-radius: 6px; overflow: auto;
3850
+ max-height: 260px;
3851
+ }
3852
+ .envelope-sql-detail pre {
3853
+ margin: 0; padding: 10px; font-size: 11px; line-height: 1.5; white-space: pre-wrap;
3854
+ }
3834
3855
  .evidence-section { margin-top: 10px; padding: 10px; background: #f8f9fa; border-radius: 6px; }
3835
3856
  .evidence-item { font-size: 12px; color: #666; margin-bottom: 4px; }
3836
3857
  .evidence-support { color: #10b981; }
@@ -4781,43 +4802,30 @@ class HTMLReportGenerator {
4781
4802
  renderSingleEnvelope(envelope, index, traceStartNs, outputLanguage = outputLanguage_1.DEFAULT_OUTPUT_LANGUAGE) {
4782
4803
  if (!envelope || !envelope.data)
4783
4804
  return '';
4784
- const title = envelope.display?.title || (0, outputLanguage_1.localize)(outputLanguage, `数据表 ${index + 1}`, `Data Table ${index + 1}`);
4805
+ const title = this.getReportEnvelopeTitle(envelope, (0, outputLanguage_1.localize)(outputLanguage, `数据表 ${index + 1}`, `Data Table ${index + 1}`), outputLanguage);
4785
4806
  const source = envelope.meta?.source || '';
4786
- const skillId = envelope.meta?.skillId || '';
4787
- const stepId = envelope.meta?.stepId || '';
4788
- const evidenceRefId = envelope.meta?.evidenceRefId || '';
4789
4807
  const traceSide = envelope.meta?.traceSide || envelope?.traceSide || '';
4790
- const traceId = envelope.meta?.traceId || envelope?.traceId || '';
4791
4808
  const planPhaseId = envelope.meta?.planPhaseId || '';
4792
4809
  const planPhaseTitle = envelope.meta?.planPhaseTitle || '';
4793
- const planPhaseAttribution = envelope.meta?.planPhaseAttribution || '';
4794
- const planPhaseWarning = envelope.meta?.planPhaseWarning || '';
4795
- const sourceToolCallId = envelope.meta?.sourceToolCallId || '';
4796
- const producerReason = envelope.meta?.producerReason || envelope.meta?.toolNarration || '';
4810
+ const producerReason = this.getReportEnvelopePurpose(envelope, title, outputLanguage);
4811
+ const rowCount = this.getEnvelopeRowCount(envelope);
4812
+ const layer = envelope.display?.layer || '';
4797
4813
  const metaParts = [];
4798
4814
  if (traceSide) {
4799
4815
  metaParts.push(this.escapeHtml(traceSide === 'reference'
4800
4816
  ? (0, outputLanguage_1.localize)(outputLanguage, '参考 Trace', 'Reference trace')
4801
4817
  : (0, outputLanguage_1.localize)(outputLanguage, '当前 Trace', 'Current trace')));
4802
4818
  }
4803
- if (skillId)
4804
- metaParts.push(this.escapeHtml(skillId));
4805
- if (stepId)
4806
- metaParts.push(this.escapeHtml(stepId));
4807
- if (source && source !== skillId)
4808
- metaParts.push(this.escapeHtml(source));
4819
+ if (source)
4820
+ metaParts.push(`${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '来源', 'Source'))}: ${this.escapeHtml(this.formatEnvelopeSource(source))}`);
4821
+ if (layer)
4822
+ metaParts.push(this.escapeHtml(`DataEnvelope.${layer}`));
4809
4823
  if (planPhaseId || planPhaseTitle) {
4810
4824
  metaParts.push(`${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '阶段', 'Phase'))}: ${this.escapeHtml([planPhaseId, planPhaseTitle].filter(Boolean).join(' '))}`);
4811
4825
  }
4812
- if (planPhaseAttribution && planPhaseAttribution !== 'active') {
4813
- metaParts.push(`${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '阶段归因', 'Phase attribution'))}: ${this.escapeHtml(planPhaseAttribution)}`);
4826
+ if (rowCount !== undefined) {
4827
+ metaParts.push(this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, `${rowCount} 行`, `${rowCount} rows`)));
4814
4828
  }
4815
- if (sourceToolCallId)
4816
- metaParts.push(`${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '工具调用', 'Tool call'))}: ${this.escapeHtml(sourceToolCallId)}`);
4817
- if (traceId)
4818
- metaParts.push(`${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, 'Trace', 'Trace'))}: ${this.escapeHtml(traceId)}`);
4819
- if (evidenceRefId)
4820
- metaParts.push(`${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '证据', 'Evidence'))}: ${this.escapeHtml(evidenceRefId)}`);
4821
4829
  let bodyHtml;
4822
4830
  if (envelope.display?.format === 'summary') {
4823
4831
  bodyHtml = this.generateSummaryFromEnvelope(envelope, outputLanguage);
@@ -4828,13 +4836,14 @@ class HTMLReportGenerator {
4828
4836
  else {
4829
4837
  bodyHtml = this.generateTableFromEnvelope(envelope, traceStartNs, outputLanguage);
4830
4838
  }
4839
+ const technicalDetails = this.renderEnvelopeTechnicalDetails(envelope, outputLanguage);
4831
4840
  return `
4832
4841
  <div class="envelope-card">
4833
4842
  <div class="envelope-header">
4834
4843
  <div class="envelope-title">${this.escapeHtml(title)}</div>
4835
4844
  <div class="envelope-meta">${metaParts.join(' / ')}</div>
4836
- ${producerReason ? `<div class="envelope-meta">${this.escapeHtml(producerReason)}</div>` : ''}
4837
- ${planPhaseWarning ? `<div class="envelope-meta">${this.escapeHtml(planPhaseWarning)}</div>` : ''}
4845
+ ${producerReason ? `<div class="envelope-meta">${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '用途', 'Purpose'))}: ${this.escapeHtml(producerReason)}</div>` : ''}
4846
+ ${technicalDetails}
4838
4847
  </div>
4839
4848
  <div class="envelope-body">
4840
4849
  ${bodyHtml}
@@ -4842,6 +4851,240 @@ class HTMLReportGenerator {
4842
4851
  </div>
4843
4852
  `;
4844
4853
  }
4854
+ renderEnvelopeTechnicalDetails(envelope, outputLanguage) {
4855
+ const meta = envelope.meta || {};
4856
+ const rows = [
4857
+ [(0, outputLanguage_1.localize)(outputLanguage, '证据 ID', 'Evidence ID'), meta.evidenceRefId],
4858
+ [(0, outputLanguage_1.localize)(outputLanguage, '工具调用 ID', 'Tool call ID'), meta.sourceToolCallId],
4859
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Trace ID', 'Trace ID'), meta.traceId || envelope.traceId],
4860
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Query Hash', 'Query hash'), meta.queryHash],
4861
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Params Hash', 'Params hash'), meta.paramsHash],
4862
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Artifact ID', 'Artifact ID'), meta.artifactId],
4863
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Source Artifact', 'Source artifact'), meta.sourceArtifactId],
4864
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Identity', 'Identity'), meta.identityRefId],
4865
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Identity 状态', 'Identity status'), meta.identityStatus],
4866
+ [(0, outputLanguage_1.localize)(outputLanguage, '阶段归因', 'Phase attribution'), meta.planPhaseAttribution],
4867
+ [(0, outputLanguage_1.localize)(outputLanguage, '阶段目标', 'Phase goal'), meta.planPhaseGoal],
4868
+ [(0, outputLanguage_1.localize)(outputLanguage, '阶段告警', 'Phase warning'), meta.planPhaseWarning],
4869
+ [(0, outputLanguage_1.localize)(outputLanguage, '工具说明', 'Tool narration'), meta.toolNarration],
4870
+ [(0, outputLanguage_1.localize)(outputLanguage, '进程身份告警', 'Process identity warning'), meta.processIdentityWarning],
4871
+ [(0, outputLanguage_1.localize)(outputLanguage, 'Stdlib 模块', 'Stdlib modules'), envelope.stdlibInjectedModules],
4872
+ ];
4873
+ const renderedRows = rows
4874
+ .map(([label, value]) => this.renderEnvelopeTechnicalRow(label, value))
4875
+ .filter(Boolean)
4876
+ .join('');
4877
+ const sql = String(envelope.sql || '').trim();
4878
+ if (!renderedRows && !sql)
4879
+ return '';
4880
+ return `
4881
+ <details class="envelope-technical-details">
4882
+ <summary>${this.escapeHtml((0, outputLanguage_1.localize)(outputLanguage, '技术细节(默认收起)', 'Technical details (collapsed by default)'))}</summary>
4883
+ ${renderedRows ? `<div class="envelope-technical-grid">${renderedRows}</div>` : ''}
4884
+ ${sql ? `
4885
+ <div class="envelope-sql-detail">
4886
+ <pre>${this.escapeHtml(sql)}</pre>
4887
+ </div>
4888
+ ` : ''}
4889
+ </details>
4890
+ `;
4891
+ }
4892
+ renderEnvelopeTechnicalRow(label, value) {
4893
+ const text = this.formatTechnicalValue(value);
4894
+ if (!text)
4895
+ return '';
4896
+ return `
4897
+ <div class="envelope-technical-key">${this.escapeHtml(label)}</div>
4898
+ <div class="envelope-technical-value">${this.escapeHtml(text)}</div>
4899
+ `;
4900
+ }
4901
+ formatTechnicalValue(value) {
4902
+ if (value === null || value === undefined || value === '')
4903
+ return '';
4904
+ if (Array.isArray(value)) {
4905
+ if (value.length === 0)
4906
+ return '';
4907
+ return value.map(item => this.formatTechnicalValue(item)).filter(Boolean).join(', ');
4908
+ }
4909
+ if (typeof value === 'object') {
4910
+ try {
4911
+ return JSON.stringify(value);
4912
+ }
4913
+ catch {
4914
+ return String(value);
4915
+ }
4916
+ }
4917
+ return String(value);
4918
+ }
4919
+ getReportEnvelopeTitle(envelope, fallbackTitle, outputLanguage) {
4920
+ const title = String(envelope.display?.title || fallbackTitle || '').trim();
4921
+ if (!this.isGenericSqlTitle(title))
4922
+ return title || fallbackTitle;
4923
+ const columns = this.getEnvelopeColumns(envelope);
4924
+ const columnSet = new Set(columns.map(col => col.toLowerCase()));
4925
+ const has = (...names) => names.some(name => columnSet.has(name.toLowerCase()));
4926
+ if (has('state') && (has('state_dur_ms') || has('state_pct'))) {
4927
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · Slice 线程状态分布', 'SQL result · Slice thread-state distribution');
4928
+ }
4929
+ if (has('slice_name') && (has('self_ms') || has('self_dur_ms'))) {
4930
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · 主线程热点 Slice', 'SQL result · Main-thread hot slices');
4931
+ }
4932
+ if (has('slice_name') && (has('dur_ms') || has('total_ms') || has('total_dur_ms'))) {
4933
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · Slice 命中明细', 'SQL result · Slice matches');
4934
+ }
4935
+ if (has('reason_id') || (has('reason') && has('severity'))) {
4936
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · 诊断规则命中', 'SQL result · Diagnostic rule matches');
4937
+ }
4938
+ if (has('thread_name') || has('process_name') || has('upid') || has('utid')) {
4939
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · 线程/进程明细', 'SQL result · Thread/process details');
4940
+ }
4941
+ if (has('count') && (has('avg_ms') || has('total_ms') || has('total_dur_ms'))) {
4942
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · 耗时聚合统计', 'SQL result · Duration aggregation');
4943
+ }
4944
+ return (0, outputLanguage_1.localize)(outputLanguage, 'SQL 结果 · 数据验证', 'SQL result · Data verification');
4945
+ }
4946
+ getReportEnvelopePurpose(envelope, displayTitle, outputLanguage) {
4947
+ const producerReason = String(envelope.meta?.producerReason || '').trim();
4948
+ const toolNarration = String(envelope.meta?.toolNarration || '').trim();
4949
+ const inferred = this.inferReportEnvelopePurpose(envelope, displayTitle, outputLanguage);
4950
+ if (producerReason && !this.isLowSignalEnvelopeReason(producerReason))
4951
+ return producerReason;
4952
+ if (inferred)
4953
+ return inferred;
4954
+ if (toolNarration && !this.isLowSignalEnvelopeReason(toolNarration)) {
4955
+ return toolNarration.replace(/^执行\s*(?:当前|参考)?\s*Trace\s*SQL[::]\s*/i, '');
4956
+ }
4957
+ return producerReason || toolNarration;
4958
+ }
4959
+ inferReportEnvelopePurpose(envelope, displayTitle, outputLanguage) {
4960
+ const title = displayTitle.toLowerCase();
4961
+ const source = String(envelope.meta?.source || '').toLowerCase();
4962
+ const phase = String(envelope.meta?.planPhaseId || '').toLowerCase();
4963
+ const identity = `${title} ${source} ${phase}`;
4964
+ const columns = this.getEnvelopeColumns(envelope).map(col => col.toLowerCase());
4965
+ const has = (...names) => names.some(name => columns.includes(name.toLowerCase()));
4966
+ if (/洞见摘要|__synthesize_summary__|insight/.test(identity)) {
4967
+ return (0, outputLanguage_1.localize)(outputLanguage, '压缩本轮启动的关键指标、异常提示和候选方向,用来决定后续优先下钻哪些问题。', 'Condenses key startup metrics, warnings, and candidate directions so later phases know which issues to drill into first.');
4968
+ }
4969
+ if (/启动数据质量|startup_quality/.test(identity)) {
4970
+ return (0, outputLanguage_1.localize)(outputLanguage, '核对采样完整性、缺失项和质量警告,用来判断本轮结论是否可靠、是否需要降级为假设。', 'Checks sampling completeness, missing data, and quality warnings to decide whether conclusions are reliable or should remain hypotheses.');
4971
+ }
4972
+ if (/证据矩阵|evidence matrix/.test(identity)) {
4973
+ return (0, outputLanguage_1.localize)(outputLanguage, '汇总本阶段命中的规则、证据和归因标签,用来把根因树里的判断落到可核对的证据记录。', 'Summarizes matched rules, evidence, and attribution tags so the root-cause tree can be checked against concrete evidence.');
4974
+ }
4975
+ if (/主线程可操作热点|actionable.*slice|hot slice/.test(identity) || (has('slice_name') && has('self_ms'))) {
4976
+ return (0, outputLanguage_1.localize)(outputLanguage, '定位主线程里真正消耗 self time 的可优化 slice,用来判断启动耗时主要花在业务/模拟负载、框架包裹还是等待。', 'Identifies main-thread slices that own self time, showing whether startup cost comes from app/simulated work, framework wrappers, or waiting.');
4977
+ }
4978
+ if (/线程状态|thread-state|state distribution/.test(identity) || (has('state') && has('state_dur_ms'))) {
4979
+ return (0, outputLanguage_1.localize)(outputLanguage, '拆分热点 slice 的 Running/S/D/R 状态,用来区分 CPU 计算、主动等待、IO 等待和调度等待。', 'Breaks hot slices into Running/S/D/R states to distinguish CPU work, voluntary wait, IO wait, and scheduling wait.');
4980
+ }
4981
+ if (/主线程耗时操作|main_thread_slices/.test(identity)) {
4982
+ return (0, outputLanguage_1.localize)(outputLanguage, '按耗时聚合启动期间主线程操作,用来先圈出影响启动墙钟时间的最大候选阶段。', 'Aggregates main-thread operations during startup to identify the largest wall-time candidates before deeper analysis.');
4983
+ }
4984
+ if (/主线程文件\s*io|main_thread_file_io/.test(identity)) {
4985
+ return (0, outputLanguage_1.localize)(outputLanguage, '筛出启动期间主线程文件 IO,用来判断是否存在磁盘访问拖慢启动,或证明 IO 不是主因。', 'Highlights main-thread file IO during startup to decide whether disk access slowed launch or can be ruled out.');
4986
+ }
4987
+ if (/主线程同步\s*binder|main_thread_sync_binder/.test(identity)) {
4988
+ return (0, outputLanguage_1.localize)(outputLanguage, '只看主线程同步 Binder 调用,用来判断主线程是否被跨进程返回时间卡住。', 'Focuses on synchronous Binder calls on the main thread to see whether IPC response time blocks launch.');
4989
+ }
4990
+ if (/启动期间\s*binder|startup_binder/.test(identity)) {
4991
+ return (0, outputLanguage_1.localize)(outputLanguage, '汇总启动窗口内 Binder 调用耗时和次数,用来评估跨进程通信是否对启动耗时有实质贡献。', 'Summarizes Binder call cost and count during startup to evaluate whether IPC materially contributes to launch time.');
4992
+ }
4993
+ if (/binder\s*阻塞|binder_blocking/.test(identity)) {
4994
+ return (0, outputLanguage_1.localize)(outputLanguage, '检查主线程 Binder 等待和远端阻塞关系,用来判断慢启动是否由服务端响应或线程池排队触发。', 'Checks main-thread Binder waiting and remote blocking relationships to determine whether service response or thread-pool queueing caused delay.');
4995
+ }
4996
+ if (/启动期间主线程状态|main_thread_state_during_startup/.test(identity)) {
4997
+ return (0, outputLanguage_1.localize)(outputLanguage, '汇总启动窗口主线程 Running、Sleep、D、Runnable 占比,用来区分 CPU 忙、主动等待、IO 等待和调度等待。', 'Summarizes main-thread Running, Sleep, D, and Runnable time to separate CPU work, voluntary wait, IO wait, and scheduling wait.');
4998
+ }
4999
+ if (/启动期间类加载|class_loading/.test(identity)) {
5000
+ return (0, outputLanguage_1.localize)(outputLanguage, '检查启动窗口类加载记录,用来判断冷启动是否被类加载或反射初始化放大。', 'Checks class-loading records during startup to decide whether cold-start cost is amplified by class loading or reflection initialization.');
5001
+ }
5002
+ if (/启动期间\s*gc|gc_during_startup/.test(identity)) {
5003
+ return (0, outputLanguage_1.localize)(outputLanguage, '统计启动窗口 GC 类型、线程和耗时占比,用来判断内存回收是否干扰主线程启动路径。', 'Summarizes GC type, thread, and duration share during startup to decide whether memory reclamation interfered with launch.');
5004
+ }
5005
+ if (/启动期间调度延迟|sched_latency_during_startup/.test(identity)) {
5006
+ return (0, outputLanguage_1.localize)(outputLanguage, '量化 Runnable 等待和最大调度延迟,用来判断系统调度是否让主线程迟迟拿不到 CPU。', 'Quantifies Runnable waiting and maximum scheduling latency to see whether scheduler delay kept the main thread off CPU.');
5007
+ }
5008
+ if (/启动延迟归因|slow reason|诊断规则/.test(identity) || has('reason_id') || (has('reason') && has('severity'))) {
5009
+ return (0, outputLanguage_1.localize)(outputLanguage, '列出命中的启动慢规则和证据,用来判断哪些方向应进入根因树,哪些只是低优先级背景信号。', 'Lists matched startup-slow rules and evidence to decide which signals belong in the root-cause tree and which are background only.');
5010
+ }
5011
+ if (/启动\s*#?\d*\s*详情|startup_info/.test(identity)) {
5012
+ return (0, outputLanguage_1.localize)(outputLanguage, '校准单次启动 ID、起止时间、dur 和 TTID/TTFD,用来保证详情深钻沿用同一个启动窗口。', 'Calibrates the single startup id, bounds, duration, and TTID/TTFD so detail drill-down uses the same launch window.');
5013
+ }
5014
+ if (/初始化\s*cpu\s*拓扑|init_cpu_topology/.test(identity)) {
5015
+ return (0, outputLanguage_1.localize)(outputLanguage, '确认 CPU 核型和拓扑信息是否可用,用来判断后续大小核、频率和调度分析的可信度。', 'Confirms CPU topology availability so later core-placement, frequency, and scheduling analysis can be trusted.');
5016
+ }
5017
+ if (/大小核占比|cpu_core_analysis/.test(identity)) {
5018
+ return (0, outputLanguage_1.localize)(outputLanguage, '统计主线程 Running 时间落在大核/小核的比例,用来判断启动是否受小核执行或摆核策略影响。', 'Measures main-thread Running time on big versus little cores to determine whether core placement affected startup.');
5019
+ }
5020
+ if (/cpu\s*频率爬升|freq_rampup/.test(identity)) {
5021
+ return (0, outputLanguage_1.localize)(outputLanguage, '比较启动早期和稳定阶段的 CPU 频率,用来判断是否存在频率爬升过慢导致的启动拖延。', 'Compares early and steady CPU frequency to detect startup delay from slow frequency ramp-up.');
5022
+ }
5023
+ if (/cpu\s*频率|cpu_freq_analysis/.test(identity)) {
5024
+ return (0, outputLanguage_1.localize)(outputLanguage, '汇总启动期间 CPU 频率水平,用来判断系统算力供给是否偏低。', 'Summarizes CPU frequency during startup to decide whether compute supply was low.');
5025
+ }
5026
+ if (/四大象限|quadrant_analysis/.test(identity)) {
5027
+ return (0, outputLanguage_1.localize)(outputLanguage, '把主线程耗时拆成大核运行、小核运行、Runnable、IO 阻塞和 Sleep,用来定位根因所属象限。', 'Breaks main-thread time into big-core running, little-core running, Runnable, IO blocked, and Sleep to locate the root-cause quadrant.');
5028
+ }
5029
+ if (/主线程摆核时序|cpu_placement_timeline/.test(identity)) {
5030
+ return (0, outputLanguage_1.localize)(outputLanguage, '按时间桶展示主线程落在大核/小核的变化,用来定位慢阶段是否伴随小核执行或频繁迁移。', 'Shows main-thread big/little-core placement by time bucket to locate slow intervals with little-core execution or migrations.');
5031
+ }
5032
+ if (/binder\s*线程池|binder_pool/.test(identity)) {
5033
+ return (0, outputLanguage_1.localize)(outputLanguage, '检查 Binder 线程池容量、占用和评估结论,用来排除或确认远端线程池饱和。', 'Checks Binder thread-pool capacity, occupancy, and assessment to rule out or confirm remote pool saturation.');
5034
+ }
5035
+ if (/启动关键任务|critical_tasks/.test(identity)) {
5036
+ return (0, outputLanguage_1.localize)(outputLanguage, '列出启动窗口全线程关键任务的 CPU、睡眠和摆核情况,用来识别主线程外的竞争或依赖任务。', 'Lists CPU, sleep, and core placement for critical tasks across threads to identify off-main-thread competition or dependencies.');
5037
+ }
5038
+ if (/线程阻塞关系图|thread_blocking_graph/.test(identity)) {
5039
+ return (0, outputLanguage_1.localize)(outputLanguage, '构建线程间等待关系,用来验证是否存在锁、Binder 或线程依赖形成的阻塞链。', 'Builds inter-thread waiting relationships to verify lock, Binder, or thread-dependency blocking chains.');
5040
+ }
5041
+ if (/jit\s*影响|jit_analysis/.test(identity)) {
5042
+ return (0, outputLanguage_1.localize)(outputLanguage, '检查 JIT/编译活动是否落在启动关键路径,用来判断代码热身是否拖慢冷启动。', 'Checks whether JIT or compilation activity lands on the startup critical path.');
5043
+ }
5044
+ if (/问题诊断|startup_diagnosis/.test(identity)) {
5045
+ return (0, outputLanguage_1.localize)(outputLanguage, '承接技能内置诊断输出,用来确认是否已有明确问题标签、严重度或可执行建议。', 'Carries skill-level diagnosis output to confirm problem labels, severity, and actionable suggestions.');
5046
+ }
5047
+ if (/启动事件|startup/.test(identity) && (has('startup_type') || has('ttid_ms') || has('dur_ms'))) {
5048
+ return (0, outputLanguage_1.localize)(outputLanguage, '确认本次启动事件、启动类型、耗时边界和 TTID/TTFD 口径,是后续阶段归因的时间窗口基础。', 'Confirms the startup event, launch type, duration bounds, and TTID/TTFD scope used by later attribution steps.');
5049
+ }
5050
+ if (/sql 结果|sql result/.test(title)) {
5051
+ if (/webview|p2_10/.test(identity)) {
5052
+ return (0, outputLanguage_1.localize)(outputLanguage, '验证启动和 TTID 差值区间内是否存在 WebView/渲染相关 slice,用来排除 WebView 启动路径误判。', 'Checks whether WebView or rendering slices appear in the startup-to-TTID gap to avoid misclassifying the launch path.');
5053
+ }
5054
+ return (0, outputLanguage_1.localize)(outputLanguage, '验证综合结论里的具体数据点,帮助确认命中的 slice、耗时和 self time 是否支撑当前根因判断。', 'Verifies concrete data points in the conclusion, checking whether matched slices, durations, and self time support the root-cause call.');
5055
+ }
5056
+ return (0, outputLanguage_1.localize)(outputLanguage, '提供本阶段判断所需的结构化数据,用来核对关键指标、实体和时间范围。', 'Provides structured data for this phase so key metrics, entities, and time windows can be checked.');
5057
+ }
5058
+ isGenericSqlTitle(title) {
5059
+ return /^SQL\s+Query(?:\s*\([^)]+\))?$/i.test(String(title || '').trim());
5060
+ }
5061
+ isLowSignalEnvelopeReason(reason) {
5062
+ const text = String(reason || '').trim();
5063
+ if (!text)
5064
+ return true;
5065
+ return (/^调用 Skill .+收集本阶段结构化证据。?$/.test(text) ||
5066
+ /^执行(?:当前|参考)?\s*Trace\s*SQL,?验证(?:本阶段|对比)?(?:的)?(?:具体)?数据点。?$/.test(text) ||
5067
+ /^执行当前 Trace SQL,验证本阶段的具体数据点。?$/.test(text));
5068
+ }
5069
+ getEnvelopeColumns(envelope) {
5070
+ const dataColumns = Array.isArray(envelope.data?.columns) ? envelope.data.columns : [];
5071
+ const displayColumns = Array.isArray(envelope.display?.columns) ? envelope.display.columns.map(col => col.name) : [];
5072
+ return [...dataColumns, ...displayColumns]
5073
+ .map(col => String(col || '').trim())
5074
+ .filter(Boolean);
5075
+ }
5076
+ getEnvelopeRowCount(envelope) {
5077
+ const rows = envelope.data?.rows;
5078
+ if (Array.isArray(rows))
5079
+ return rows.length;
5080
+ const expandable = envelope.data?.expandableData;
5081
+ if (Array.isArray(expandable))
5082
+ return expandable.length;
5083
+ return undefined;
5084
+ }
5085
+ formatEnvelopeSource(source) {
5086
+ return String(source || '').replace(/^([^:#]+):/, '$1#');
5087
+ }
4845
5088
  /**
4846
5089
  * Render a finding with evidence, details, and recommendations
4847
5090
  */
@@ -5041,11 +5284,11 @@ class HTMLReportGenerator {
5041
5284
  </div>
5042
5285
  `;
5043
5286
  }
5044
- normalizeConversationTimeline(timeline, dialogue) {
5287
+ normalizeConversationTimeline(timeline, dialogue, outputLanguage = outputLanguage_1.DEFAULT_OUTPUT_LANGUAGE) {
5045
5288
  const normalized = [];
5046
5289
  if (Array.isArray(timeline) && timeline.length > 0) {
5047
5290
  for (const item of timeline) {
5048
- const text = String(item?.text || '').replace(/\s+/g, ' ').trim().slice(0, 240);
5291
+ const text = this.compactConversationTimelineText(String(item?.text || '').replace(/\s+/g, ' ').trim(), outputLanguage).slice(0, 240);
5049
5292
  const ordinal = Number(item?.ordinal);
5050
5293
  if (!text || !Number.isFinite(ordinal) || ordinal <= 0)
5051
5294
  continue;
@@ -5071,11 +5314,11 @@ class HTMLReportGenerator {
5071
5314
  for (let i = 0; i < dialogue.length; i++) {
5072
5315
  const item = dialogue[i];
5073
5316
  const content = item?.content || {};
5074
- const text = String(content.message ||
5317
+ const text = this.compactConversationTimelineText(String(content.message ||
5075
5318
  content.summary ||
5076
5319
  content.taskTitle ||
5077
5320
  content.phase ||
5078
- '').replace(/\s+/g, ' ').trim().slice(0, 240);
5321
+ '').replace(/\s+/g, ' ').trim(), outputLanguage).slice(0, 240);
5079
5322
  if (!text)
5080
5323
  continue;
5081
5324
  const phase = item.type === 'task' ? 'tool' : item.type === 'response' ? 'result' : 'thinking';
@@ -5098,6 +5341,16 @@ class HTMLReportGenerator {
5098
5341
  }
5099
5342
  return [...byOrdinal.values()].sort((a, b) => a.ordinal - b.ordinal);
5100
5343
  }
5344
+ compactConversationTimelineText(text, outputLanguage = outputLanguage_1.DEFAULT_OUTPUT_LANGUAGE) {
5345
+ let compact = String(text || '').trim();
5346
+ if (!compact)
5347
+ return compact;
5348
+ compact = compact.replace(/SQL Query\s*\((\d+)\s+rows?\)/gi, (_match, rows) => (0, outputLanguage_1.localize)(outputLanguage, `SQL 结果(${rows} 行)`, `SQL result (${rows} rows)`));
5349
+ compact = compact.replace(/执行\s*(?:当前|参考)?\s*Trace\s*SQL[::]\s*/gi, (0, outputLanguage_1.localize)(outputLanguage, '验证数据:', 'Verify data: '));
5350
+ compact = compact.replace(/,?已登记\s*\d+\s*个证据 ID[::]\s*执行当前 Trace SQL,验证本阶段的具体数据点。?/g, '');
5351
+ compact = compact.replace(/执行当前 Trace SQL,验证本阶段的具体数据点。?/g, '');
5352
+ return compact.replace(/\s+/g, ' ').replace(/,。/g, '。').trim();
5353
+ }
5101
5354
  getConversationPhaseLabel(phase, outputLanguage = outputLanguage_1.DEFAULT_OUTPUT_LANGUAGE) {
5102
5355
  switch (phase) {
5103
5356
  case 'thinking':