siluzan-tso-cli 1.1.35-beta.1 → 1.1.35-beta.2

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.
package/README.md CHANGED
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
51
51
  siluzan-tso init --force # 强制覆盖已存在文件
52
52
  ```
53
53
 
54
- > **注意**:当前为测试版(1.1.35-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.35-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -124884,12 +124884,11 @@ import path18 from "path";
124884
124884
  // src/commands/market-analysis/report-content.ts
124885
124885
  var SILUZAN_ECHARTS_CDN_URL = "https://staticpn.siluzan.com/assets/slz/homeCDN/echarts.js";
124886
124886
  var MARKET_REPORT_DIMENSIONS = [
124887
- // ── 封面与元信息 ──
124888
124887
  {
124889
124888
  id: "cover",
124890
124889
  chapter: "\u5C01\u9762",
124891
- dimension: "\u62A5\u544A\u6807\u9898\u542B\u5BA2\u6237\u4E0E\u76EE\u6807\u5E02\u573A",
124892
- hint: "\u987B\u542B\u300C\u6218\u7565\u5E02\u573A\u5206\u6790\u300D\u6216\u300CKA\u5BA2\u6237\u300D\u53CA\u76EE\u6807\u5E02\u573A\u5173\u952E\u8BCD"
124890
+ dimension: "\u62A5\u544A\u6807\u9898\u542B\u6218\u7565/\u884C\u4E1A/\u5E02\u573A\u5206\u6790\u6807\u8BC6",
124891
+ hint: "\u987B\u542B\u300C\u6218\u7565\u5E02\u573A\u5206\u6790\u300D\u300C\u884C\u4E1A\u5206\u6790\u62A5\u544A\u300D\u300C\u5E02\u573A\u5206\u6790\u62A5\u544A\u300D\u6216\u300C\u884C\u4E1A\u8C03\u67E5\u300D\u7B49"
124893
124892
  },
124894
124893
  {
124895
124894
  id: "cover-kpi",
@@ -124897,7 +124896,6 @@ var MARKET_REPORT_DIMENSIONS = [
124897
124896
  dimension: "\u6838\u5FC3\u7ED3\u8BBA\u6216 KPI \u6458\u8981",
124898
124897
  hint: "\u5C01\u9762\u987B\u6709\u53EF\u626B\u8BFB\u7684\u7ED3\u8BBA\u6BB5\u6216 metric \u5361\u7247\uFF0C\u975E\u4EC5\u6807\u9898"
124899
124898
  },
124900
- // ── 一、市场与趋势诊断 ──
124901
124899
  {
124902
124900
  id: "ch1",
124903
124901
  chapter: "\u4E00\u3001\u5E02\u573A\u4E0E\u8D8B\u52BF\u8BCA\u65AD",
@@ -124920,7 +124918,7 @@ var MARKET_REPORT_DIMENSIONS = [
124920
124918
  id: "ch1-target-geo",
124921
124919
  chapter: "\u4E00\u3001\u5E02\u573A\u4E0E\u8D8B\u52BF\u8BCA\u65AD",
124922
124920
  dimension: "\u76EE\u6807\u5E02\u573A\u56FD\u5BB6/\u533A\u57DF\u62C6\u89E3",
124923
- hint: "\u987B\u6309\u56FD\u5BB6\u6216\u533A\u57DF\u5BF9\u6BD4\u89C4\u6A21\u3001\u589E\u957F\u3001\u4F18\u5148\u7EA7\uFF08\u8868\u683C\u6216\u5206\u6BB5\uFF09"
124921
+ hint: "\u987B\u6309\u56FD\u5BB6\u6216\u533A\u57DF\u5BF9\u6BD4\u89C4\u6A21\u3001\u589E\u957F\u3001\u4F18\u5148\u7EA7\uFF08\u8868\u683C\u6216\u5206\u6BB5\uFF09\uFF1B\u4E0E collect \u76EE\u6807\u5E02\u573A\u4E00\u81F4\u66F4\u4F73"
124924
124922
  },
124925
124923
  {
124926
124924
  id: "ch1-pestel",
@@ -124934,7 +124932,6 @@ var MARKET_REPORT_DIMENSIONS = [
124934
124932
  dimension: "3\u20135 \u5E74\u8D8B\u52BF\u9884\u6D4B\u4E0E\u5047\u8BBE",
124935
124933
  hint: "\u987B\u542B\u300C\u9884\u6D4B\u300D\u6216\u300C3\u300D\u5E74/\u300C5\u300D\u5E74\u8D8B\u52BF\u8868\u8FF0"
124936
124934
  },
124937
- // ── 二、目标行业深度洞察 ──
124938
124935
  {
124939
124936
  id: "ch2",
124940
124937
  chapter: "\u4E8C\u3001\u76EE\u6807\u884C\u4E1A\u6DF1\u5EA6\u6D1E\u5BDF",
@@ -124951,7 +124948,7 @@ var MARKET_REPORT_DIMENSIONS = [
124951
124948
  id: "ch2-compliance",
124952
124949
  chapter: "\u4E8C\u3001\u76EE\u6807\u884C\u4E1A\u6DF1\u5EA6\u6D1E\u5BDF",
124953
124950
  dimension: "\u6CD5\u89C4\u73AF\u5883\u4E0E\u5408\u89C4\u8981\u6C42",
124954
- hint: "\u987B\u542B\u6CD5\u89C4/\u5408\u89C4\u8868\uFF0C\u542B\u5E94\u5BF9\u7B56\u7565\uFF1B\u5B9C\u542B\u5408\u89C4\u6EA2\u4EF7\u6216\u6210\u672C\u4F30\u7B97"
124951
+ hint: "\u987B\u542B\u6CD5\u89C4/\u5408\u89C4\u8868\uFF0C\u542B\u5E94\u5BF9\u7B56\u7565\uFF1B\u5B9C\u542B\u5408\u89C4\u6210\u672C\u6216\u6EA2\u4EF7\u4F30\u7B97"
124955
124952
  },
124956
124953
  {
124957
124954
  id: "ch2-bpmn",
@@ -124959,7 +124956,6 @@ var MARKET_REPORT_DIMENSIONS = [
124959
124956
  dimension: "\u5178\u578B\u573A\u666F\u4E0E BPMN \u6D41\u7A0B\u5BF9\u6BD4",
124960
124957
  hint: "\u987B\u542B\u300C\u539F\u6D41\u7A0B\u300D\u4E0E\u300C\u65B0\u6D41\u7A0B\u300D\u6216 BPMN \u6587\u672C + \u6548\u7387/\u6210\u672C\u91CF\u5316"
124961
124958
  },
124962
- // ── 三、目标受众与场景 ──
124963
124959
  {
124964
124960
  id: "ch3",
124965
124961
  chapter: "\u4E09\u3001\u76EE\u6807\u53D7\u4F17\u4E0E\u573A\u666F",
@@ -124978,7 +124974,6 @@ var MARKET_REPORT_DIMENSIONS = [
124978
124974
  dimension: "\u4EA7\u54C1\u5E94\u7528\u573A\u666F\u4E0E\u4EF7\u503C\u5206\u6790",
124979
124975
  hint: "\u987B\u542B\u5E94\u7528\u573A\u666F\u3001\u5DEE\u5F02\u5316\u3001\u7528\u6237\u4EF7\u503C\u4E0E\u4F01\u4E1A\u4EF7\u503C"
124980
124976
  },
124981
- // ── 四、竞争策略与定位 ──
124982
124977
  {
124983
124978
  id: "ch4",
124984
124979
  chapter: "\u56DB\u3001\u7ADE\u4E89\u7B56\u7565\u4E0E\u5B9A\u4F4D",
@@ -124989,13 +124984,13 @@ var MARKET_REPORT_DIMENSIONS = [
124989
124984
  id: "ch4-competitors",
124990
124985
  chapter: "\u56DB\u3001\u7ADE\u4E89\u7B56\u7565\u4E0E\u5B9A\u4F4D",
124991
124986
  dimension: "\u4E3B\u8981\u7ADE\u54C1\u8BC6\u522B",
124992
- hint: "\u987B\u70B9\u540D \u22653 \u4E2A\u7ADE\u54C1\u6216\u5BF9\u6807\u54C1\u724C"
124987
+ hint: "\u987B\u70B9\u540D \u22653 \u4E2A\u7ADE\u54C1\u6216\u5BF9\u6807\u4F01\u4E1A\uFF08\u4E0D\u9650\u5B9A\u884C\u4E1A\u54C1\u724C\uFF09"
124993
124988
  },
124994
124989
  {
124995
124990
  id: "ch4-compare-table",
124996
124991
  chapter: "\u56DB\u3001\u7ADE\u4E89\u7B56\u7565\u4E0E\u5B9A\u4F4D",
124997
- dimension: "\u529F\u80FD\u4E0E\u6027\u80FD\u5BF9\u6BD4\u8868\uFF08\u226510 \u9879 \xD7 \u22653 \u7ADE\u54C1\uFF09",
124998
- hint: "\u987B\u6709\u7ADE\u54C1\u5BF9\u6BD4\u8868\uFF0C\u884C\u6570\u5145\u8DB3\uFF08\u5EFA\u8BAE \u226510 \u884C\u7EF4\u5EA6\uFF09"
124992
+ dimension: "\u529F\u80FD\u4E0E\u6027\u80FD\u5BF9\u6BD4\u8868\uFF08\u226510 \u9879 \xD7 \u22653 \u4E3B\u4F53\uFF09",
124993
+ hint: "\u987B\u6709\u7ADE\u54C1\u5BF9\u6BD4\u8868\uFF1A\u22654 \u5217\uFF08\u7EF4\u5EA6+\u591A\u65B9\uFF09\u4E14 \u226511 \u884C"
124999
124994
  },
125000
124995
  {
125001
124996
  id: "ch4-gaps",
@@ -125009,7 +125004,6 @@ var MARKET_REPORT_DIMENSIONS = [
125009
125004
  dimension: "\u6838\u5FC3\u5B9A\u4F4D\u9648\u8FF0\u4E0E\u5DEE\u5F02\u5316\u7EF4\u5EA6",
125010
125005
  hint: "\u987B\u6709\u4E00\u53E5\u5B9A\u4F4D\u9648\u8FF0 + \u591A\u4E2A\u5DEE\u5F02\u5316\u7EF4\u5EA6"
125011
125006
  },
125012
- // ── 五、增长与品牌策略 ──
125013
125007
  {
125014
125008
  id: "ch5",
125015
125009
  chapter: "\u4E94\u3001\u589E\u957F\u4E0E\u54C1\u724C\u7B56\u7565",
@@ -125034,7 +125028,6 @@ var MARKET_REPORT_DIMENSIONS = [
125034
125028
  dimension: "\u8425\u9500\u4E0E\u9500\u552E\u6218\u672F",
125035
125029
  hint: "\u987B\u542B\u5185\u5BB9\u8425\u9500/\u6E20\u9053/KOL/\u9500\u552E\u6A21\u5F0F\u7B49\u6218\u672F\u63CF\u8FF0"
125036
125030
  },
125037
- // ── 六、实施、资源与风险 ──
125038
125031
  {
125039
125032
  id: "ch6",
125040
125033
  chapter: "\u516D\u3001\u5B9E\u65BD\u3001\u8D44\u6E90\u4E0E\u98CE\u9669",
@@ -125059,7 +125052,6 @@ var MARKET_REPORT_DIMENSIONS = [
125059
125052
  dimension: "\u98CE\u9669\u77E9\u9635\u4E0E\u5E94\u5BF9\u7B56\u7565",
125060
125053
  hint: "\u987B\u542B\u5E02\u573A/\u7ADE\u4E89/\u6280\u672F/\u8FD0\u8425\u7B49\u98CE\u9669 + \u6BCF\u7C7B\u5E94\u5BF9\u63AA\u65BD"
125061
125054
  },
125062
- // ── 附录 ──
125063
125055
  {
125064
125056
  id: "appendix",
125065
125057
  chapter: "\u9644\u5F55",
@@ -125084,7 +125076,6 @@ var MARKET_REPORT_DIMENSIONS = [
125084
125076
  dimension: "\u672F\u8BED\u8868\uFF08ROI/CAGR/GTM/BPMN \u7B49\uFF09",
125085
125077
  hint: "\u987B\u89E3\u91CA\u81F3\u5C11 3 \u4E2A\u7F29\u5199"
125086
125078
  },
125087
- // ── 呈现规范(原始 prompt HTML 要求)──
125088
125079
  {
125089
125080
  id: "viz-echarts",
125090
125081
  chapter: "\u5448\u73B0",
@@ -125098,6 +125089,44 @@ var MARKET_REPORT_DIMENSIONS = [
125098
125089
  hint: "\u987B\u542B Source: \u6216\u300C\u6765\u6E90\u300D\u811A\u6CE8"
125099
125090
  }
125100
125091
  ];
125092
+ function stripHtmlTags(html) {
125093
+ return html.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ");
125094
+ }
125095
+ function countTableColumns(tableHtml) {
125096
+ const firstRow = tableHtml.match(/<tr[\s\S]*?<\/tr>/i)?.[0] ?? "";
125097
+ const th = (firstRow.match(/<th/gi) ?? []).length;
125098
+ const td = (firstRow.match(/<td/gi) ?? []).length;
125099
+ return Math.max(th, td);
125100
+ }
125101
+ function isCompareTable(tableHtml, html, tableIndex) {
125102
+ const inTable = /对比|竞品|功能|性能|维度|指标|参数/.test(tableHtml);
125103
+ if (inTable) return true;
125104
+ const windowStart = Math.max(0, tableIndex - 600);
125105
+ const windowEnd = Math.min(html.length, tableIndex + tableHtml.length + 400);
125106
+ const nearby = html.slice(windowStart, windowEnd);
125107
+ return /对比|竞品|竞争|功能|性能|对标/.test(nearby);
125108
+ }
125109
+ function findFeatureCompareTableRows(html) {
125110
+ const tables = html.match(/<table[\s\S]*?<\/table>/gi) ?? [];
125111
+ let best = 0;
125112
+ let searchFrom = 0;
125113
+ for (const t of tables) {
125114
+ const tableIndex = html.indexOf(t, searchFrom);
125115
+ searchFrom = tableIndex + 1;
125116
+ if (countTableColumns(t) < 4) continue;
125117
+ if (!isCompareTable(t, html, tableIndex)) continue;
125118
+ const rows = (t.match(/<tr/gi) ?? []).length;
125119
+ if (rows > best) best = rows;
125120
+ }
125121
+ return best;
125122
+ }
125123
+ function countPainPoints(html) {
125124
+ const labeled = (html.match(/痛点\s*\d/gi) ?? []).length;
125125
+ if (labeled >= 4) return labeled;
125126
+ const section = html.match(/痛点[\s\S]{0,3000}/i)?.[0] ?? html;
125127
+ const listItems = (section.match(/<li[^>]*>/gi) ?? []).length;
125128
+ return Math.max(labeled, listItems >= 4 ? 4 : listItems);
125129
+ }
125101
125130
  function countEchartsInstances(html) {
125102
125131
  const inits = (html.match(/echarts\.init\(/g) ?? []).length;
125103
125132
  if (inits > 0) return inits;
@@ -125106,67 +125135,97 @@ function countEchartsInstances(html) {
125106
125135
  function hasEchartsCdn(html) {
125107
125136
  return /homeCDN\/echarts\.js|echarts\.min\.js|npm\/echarts@/i.test(html);
125108
125137
  }
125109
- function countPainPoints(html) {
125110
- const labeled = (html.match(/痛点\s*\d/g) ?? []).length;
125111
- if (labeled >= 4) return labeled;
125112
- const section = html.match(/痛点[\s\S]{0,3000}/)?.[0] ?? html;
125113
- const listItems = (section.match(/<li[^>]*>/g) ?? []).length;
125114
- return Math.max(labeled, listItems >= 4 ? 4 : listItems);
125115
- }
125116
- function competitorCompareTableRows(html) {
125117
- const tables = html.match(/<table[\s\S]*?<\/table>/g) ?? [];
125118
- let best = 0;
125119
- for (const t of tables) {
125120
- const hasSelf = /小米|我方|客户/.test(t);
125121
- const rivalHits = ["Apple", "Samsung", "Google", "\u82F9\u679C", "\u4E09\u661F", "\u8C37\u6B4C", "\u534E\u4E3A"].filter(
125122
- (b) => t.includes(b)
125123
- ).length;
125124
- if (!hasSelf || rivalHits < 2) continue;
125125
- const rows = (t.match(/<tr/g) ?? []).length;
125126
- if (rows > best) best = rows;
125127
- }
125128
- return best;
125129
- }
125130
- function mentionsCompetitors(html) {
125131
- const brands = ["Apple", "Samsung", "Google", "\u82F9\u679C", "\u4E09\u661F", "\u8C37\u6B4C", "\u534E\u4E3A", "Motorola"];
125132
- let n = 0;
125133
- for (const b of brands) {
125134
- if (html.includes(b)) n++;
125138
+ function countCompetitorMentions(html) {
125139
+ const competitorSection = html.match(/(?:主要)?竞品[\s\S]{0,5000}/i)?.[0] ?? html.match(/竞争对手[\s\S]{0,5000}/i)?.[0] ?? html.match(/对标(?:企业|品牌|公司)[\s\S]{0,5000}/i)?.[0] ?? "";
125140
+ if (competitorSection) {
125141
+ const listItems = (competitorSection.match(/<li[^>]*>[\s\S]*?<\/li>/gi) ?? []).filter(
125142
+ (li) => stripHtmlTags(li).trim().length >= 2
125143
+ );
125144
+ if (listItems.length >= 3) return listItems.length;
125145
+ const inlineList = competitorSection.match(/(?:竞品|竞争对手|对标)[::][\s\S]{0,800}/i)?.[0];
125146
+ if (inlineList) {
125147
+ const parts = stripHtmlTags(inlineList).split(/[、,,;;|]/).map((s) => s.replace(/^(竞品|竞争对手|对标)[::]/, "").trim()).filter((s) => s.length >= 2);
125148
+ if (parts.length >= 3) return parts.length;
125149
+ }
125150
+ const plain = stripHtmlTags(competitorSection);
125151
+ const entities = plain.match(
125152
+ /[\u4e00-\u9fa5A-Za-z0-9&][\u4e00-\u9fa5A-Za-z0-9&.\- ]{1,30}(?:公司|集团|Co\.|Corp|Inc|Ltd|品牌)?/g
125153
+ );
125154
+ if (entities && new Set(entities.map((e) => e.trim())).size >= 3) {
125155
+ return new Set(entities.map((e) => e.trim())).size;
125156
+ }
125135
125157
  }
125136
- return n >= 3;
125158
+ const tables = html.match(/<table[\s\S]*?<\/table>/gi) ?? [];
125159
+ let searchFrom = 0;
125160
+ for (const t of tables) {
125161
+ const tableIndex = html.indexOf(t, searchFrom);
125162
+ searchFrom = tableIndex + 1;
125163
+ const cols = countTableColumns(t);
125164
+ if (cols >= 4 && isCompareTable(t, html, tableIndex)) {
125165
+ return Math.max(3, cols - 1);
125166
+ }
125167
+ }
125168
+ const globalPlain = stripHtmlTags(html);
125169
+ const named = globalPlain.match(
125170
+ /(?:竞品|竞争对手)[::][^\n。;;]{10,400}/
125171
+ )?.[0] ?? "";
125172
+ if (named) {
125173
+ const parts = named.replace(/^[^::]+[::]/, "").split(/[、,,;;|]/).map((s) => s.trim()).filter((s) => s.length >= 2);
125174
+ if (parts.length >= 3) return parts.length;
125175
+ }
125176
+ return 0;
125177
+ }
125178
+ function splitMarketTokens(value) {
125179
+ return value.split(/[、,,/|]/).map((t) => t.trim()).filter((t) => t.length >= 2);
125180
+ }
125181
+ function hasTargetGeoBreakdown(html, ctx) {
125182
+ const hasMetrics = /规模|增长|优先级|潜力|份额|CAGR|市场容量/.test(html);
125183
+ const hasGeoFrame = /国家|区域|地区|市场/.test(html);
125184
+ if (!hasMetrics || !hasGeoFrame) return false;
125185
+ const targetMarket = ctx.targetMarket?.trim() ?? "";
125186
+ if (targetMarket) {
125187
+ if (/全球|国际|worldwide/i.test(targetMarket)) {
125188
+ return /全球|国际|各区域|分区域|分市场/.test(html);
125189
+ }
125190
+ const tokens = splitMarketTokens(targetMarket);
125191
+ const hit = tokens.filter((t) => html.includes(t)).length;
125192
+ if (hit >= 1) return true;
125193
+ }
125194
+ const regionHits = (html.match(
125195
+ /(?:亚太|欧洲|北美|拉美|中东|非洲|东南亚|全球|[\u4e00-\u9fa5]{2,8}(?:市场|地区|国家|区域))/g
125196
+ ) ?? []).length;
125197
+ return regionHits >= 2;
125198
+ }
125199
+ function hasReportTitle(html, ctx) {
125200
+ const hasTitle = /战略市场分析|KA客户|行业分析报告|市场分析报告|行业调查|市场调查/.test(html);
125201
+ if (!hasTitle) return false;
125202
+ return /目标市场|全球市场|行业|细分|market/i.test(html) || !!ctx.targetMarket?.trim() || !!ctx.industry?.trim() || !!ctx.customerName?.trim();
125137
125203
  }
125138
125204
  var CONTENT_RULES = [
125139
- {
125140
- id: "cover",
125141
- test: (h) => /战略市场分析|KA客户/.test(h) && (/目标市场|北美|全球|欧洲|亚太/.test(h) || /targetMarket/i.test(h))
125142
- },
125143
- { id: "cover-kpi", test: (h) => /核心结论|metric|kpi|结论/.test(h) },
125205
+ { id: "cover", test: (h, ctx) => hasReportTitle(h, ctx) },
125206
+ { id: "cover-kpi", test: (h) => /核心结论|metric|kpi|结论|摘要|executive summary/i.test(h) },
125144
125207
  { id: "ch1", test: (h) => /市场与趋势诊断/.test(h) },
125145
125208
  {
125146
125209
  id: "ch1-tam",
125147
125210
  test: (h) => (/TAM|SAM|SOM/.test(h) || /市场规模/.test(h)) && /CAGR|增长率|增长趋势/.test(h)
125148
125211
  },
125149
125212
  { id: "ch1-value-chain", test: (h) => /价值链|生态定位|产业链/.test(h) },
125150
- {
125151
- id: "ch1-target-geo",
125152
- test: (h) => (/美国|加拿大|墨西哥|中国|欧洲/.test(h) || /国家|区域/.test(h)) && /增长|规模|优先级|潜力/.test(h)
125153
- },
125154
- { id: "ch1-pestel", test: (h) => /PESTEL|政策|法规环境|技术趋势/.test(h) },
125213
+ { id: "ch1-target-geo", test: (h, ctx) => hasTargetGeoBreakdown(h, ctx) },
125214
+ { id: "ch1-pestel", test: (h) => /PESTEL|政策|法规环境|技术趋势|经济|社会|环境/.test(h) },
125155
125215
  { id: "ch1-forecast", test: (h) => /预测|3.?5年|未来\d/.test(h) },
125156
125216
  { id: "ch2", test: (h) => /行业深度洞察|目标行业/.test(h) },
125157
125217
  { id: "ch2-pain", test: (h, ctx) => ctx.painPointCount >= 4 },
125158
- { id: "ch2-compliance", test: (h) => /法规|合规|FCC|隐私/.test(h) && /<table/.test(h) },
125218
+ { id: "ch2-compliance", test: (h) => /法规|合规/.test(h) && /<table/.test(h) },
125159
125219
  {
125160
125220
  id: "ch2-bpmn",
125161
- test: (h) => /原流程|BPMN|介入后|新流程/.test(h) && /效率|成本|提升|下降/.test(h)
125221
+ test: (h) => /原流程|BPMN|介入后|新流程/.test(h) && /效率|成本|提升|下降|节约/.test(h)
125162
125222
  },
125163
125223
  { id: "ch3", test: (h) => /目标受众|受众与场景/.test(h) },
125164
125224
  { id: "ch3-audience", test: (h) => /用户|受众|画像|群体/.test(h) && /<table/.test(h) },
125165
125225
  { id: "ch3-scenario", test: (h) => /应用场景|场景|差异化|用户价值|企业价值/.test(h) },
125166
125226
  { id: "ch4", test: (h) => /竞争策略|竞争.{0,6}定位/.test(h) },
125167
- { id: "ch4-competitors", test: (h) => mentionsCompetitors(h) },
125168
- // 表头 1 + ≥10 项维度 11 个 <tr>
125169
- { id: "ch4-compare-table", test: (h) => competitorCompareTableRows(h) >= 11 },
125227
+ { id: "ch4-competitors", test: (h, ctx) => ctx.competitorCount >= 3 },
125228
+ { id: "ch4-compare-table", test: (h, ctx) => ctx.competitorTableRows >= 11 },
125170
125229
  {
125171
125230
  id: "ch4-gaps",
125172
125231
  test: (h) => [
@@ -125195,11 +125254,22 @@ var CONTENT_RULES = [
125195
125254
  { id: "viz-echarts", test: (h, ctx) => hasEchartsCdn(h) && ctx.chartCount >= 1 },
125196
125255
  { id: "viz-source", test: (h) => /Source:|来源:|来源:/.test(h) }
125197
125256
  ];
125198
- function validateMarketReportContent(html) {
125257
+ function validationContextFromReport(data) {
125258
+ const customerInfo = data.customerInfo && typeof data.customerInfo === "object" && !Array.isArray(data.customerInfo) ? data.customerInfo : {};
125259
+ return {
125260
+ targetMarket: String(data.targetMarket ?? customerInfo.targetMarket ?? "").trim() || void 0,
125261
+ industry: String(customerInfo.industry ?? "").trim() || void 0,
125262
+ customerName: String(customerInfo.customerName ?? "").trim() || void 0
125263
+ };
125264
+ }
125265
+ function validateMarketReportContent(html, reportContext) {
125199
125266
  const ctx = {
125200
- tableCount: (html.match(/<table/g) ?? []).length,
125267
+ ...reportContext,
125268
+ tableCount: (html.match(/<table/gi) ?? []).length,
125201
125269
  chartCount: countEchartsInstances(html),
125202
- painPointCount: countPainPoints(html)
125270
+ painPointCount: countPainPoints(html),
125271
+ competitorTableRows: findFeatureCompareTableRows(html),
125272
+ competitorCount: countCompetitorMentions(html)
125203
125273
  };
125204
125274
  const dimById = new Map(MARKET_REPORT_DIMENSIONS.map((d) => [d.id, d]));
125205
125275
  const missing = [];
@@ -125222,7 +125292,7 @@ function validateMarketReportContent(html) {
125222
125292
  tables: ctx.tableCount,
125223
125293
  charts: ctx.chartCount,
125224
125294
  painPoints: ctx.painPointCount,
125225
- competitorTableRows: competitorCompareTableRows(html)
125295
+ competitorTableRows: ctx.competitorTableRows
125226
125296
  }
125227
125297
  };
125228
125298
  }
@@ -125230,7 +125300,7 @@ function formatMarketReportContentErrors(result) {
125230
125300
  if (result.ok) return "";
125231
125301
  const lines = result.missing.map((m) => ` - [${m.chapter}] ${m.dimension}\uFF1A${m.hint}`);
125232
125302
  return [
125233
- `\u62A5\u544A\u7F3A\u5C11 ${result.missing.length} \u9879\u5FC5\u542B\u5185\u5BB9\uFF08\u5BF9\u9F50 TSO getMarketReport \u539F\u59CB\u4E1A\u52A1\u7EF4\u5EA6\uFF09\uFF1A`,
125303
+ `\u62A5\u544A\u7F3A\u5C11 ${result.missing.length} \u9879\u5FC5\u542B\u5185\u5BB9\uFF08\u901A\u7528\u884C\u4E1A\u8C03\u67E5\u7EF4\u5EA6\uFF09\uFF1A`,
125234
125304
  ...lines,
125235
125305
  "",
125236
125306
  "\u8BF7 Read assets/market-analysis-rules.md\u300C\u539F\u59CB\u4E1A\u52A1\u7EF4\u5EA6\u6E05\u5355\u300D\uFF0CWebSearch \u8865\u5168\u7F3A\u5931\u7AE0\u8282\u540E\u91CD\u5199 market-report.json\u3002"
@@ -125280,7 +125350,8 @@ async function runMarketAnalysisRender(opts) {
125280
125350
  console.error("\n\u274C \u62A5\u544A HTML \u5185\u5BB9\u4E3A\u7A7A\n");
125281
125351
  process.exit(1);
125282
125352
  }
125283
- const contentCheck = validateMarketReportContent(html);
125353
+ const reportData = asRecord4(dataRaw);
125354
+ const contentCheck = validateMarketReportContent(html, validationContextFromReport(reportData));
125284
125355
  if (!contentCheck.ok) {
125285
125356
  console.error(`
125286
125357
  \u274C ${formatMarketReportContentErrors(contentCheck)}
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.35-beta.1",
4
- "publishedAt": 1783063300004
3
+ "version": "1.1.35-beta.2",
4
+ "publishedAt": 1783069471119
5
5
  }
@@ -27,10 +27,10 @@
27
27
 
28
28
  ### 封面
29
29
 
30
- | 维度 | 必含内容 |
31
- | -------- | -------------------------------------------- |
32
- | 报告标识 | 标题含「战略市场分析」或「KA客户」+ 目标市场 |
33
- | 执行摘要 | 核心结论段或 KPI/metric 卡片(非仅标题) |
30
+ | 维度 | 必含内容 |
31
+ | -------- | ------------------------------------------------------------------------ |
32
+ | 报告标识 | 标题含「战略市场分析」「行业分析报告」「市场分析报告」或「行业调查」等 |
33
+ | 执行摘要 | 核心结论段或 KPI/metric 卡片(非仅标题) |
34
34
 
35
35
  ### 一、市场与趋势诊断
36
36
 
@@ -38,7 +38,7 @@
38
38
  | --- | ------------------ | ------------------------------------------------------------------- |
39
39
  | 1.1 | 全球市场规模与增长 | TAM/SAM/SOM 或「市场规模」+ CAGR/增长率;**须有 ECharts 图** |
40
40
  | 1.2 | 赛道与生态定位 | 价值链/产业链表:上游·中游·下游·服务层 |
41
- | 1.3 | 目标市场国家拆解 | 按国家/区域:规模、增长、优先级、潜力(宜含美/加/墨或用户指定市场) |
41
+ | 1.3 | 目标市场国家拆解 | 按国家/区域:规模、增长、优先级、潜力(与 collect `--target-market` 一致) |
42
42
  | 1.4 | 技术趋势 PESTEL | 政策/经济/社会/技术/环境/法规 ≥6 维表或等价结构 |
43
43
  | 1.5 | 中期预测 | 未来 3–5 年趋势 + **假设依据** |
44
44
 
@@ -61,8 +61,8 @@
61
61
 
62
62
  | # | 维度 | 必含内容 |
63
63
  | --- | ------------ | ------------------------------------------------------ |
64
- | 4.1 | 竞品识别 | 点名 **≥3** 个主要竞品/对标品牌 |
65
- | 4.2 | 功能性能对比 | 对比表 **≥10 行维度** × 我方 + 3 竞品 + 性能指标行 |
64
+ | 4.1 | 竞品识别 | 点名 **≥3** 个主要竞品/对标企业(**不限定**具体行业品牌) |
65
+ | 4.2 | 功能性能对比 | 对比表 **≥10 行维度** × 维度列 + **≥3** 个对比主体列 + 性能指标行 |
66
66
  | 4.3 | 竞争空白 | **功能、场景、用户群、地域** 四类空白(至少覆盖 3 类) |
67
67
  | 4.4 | 定位与差异化 | **一句定位陈述** + **3 个差异化维度** |
68
68
 
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
9
9
  # -- Package info (injected at build time) ------------------------------------
10
10
  $PKG_NAME = 'siluzan-tso-cli'
11
11
  # PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
12
- $PKG_VERSION = '1.1.35-beta.1'
12
+ $PKG_VERSION = '1.1.35-beta.2'
13
13
  $CLI_BIN = 'siluzan-tso'
14
14
  $SKILL_LABEL = 'Siluzan TSO'
15
15
  $INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
@@ -9,7 +9,7 @@ set -euo pipefail
9
9
  # -- Package info (injected at build time) ------------------------------------
10
10
  readonly PKG_NAME="siluzan-tso-cli"
11
11
  # PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
12
- readonly PKG_VERSION="1.1.35-beta.1"
12
+ readonly PKG_VERSION="1.1.35-beta.2"
13
13
  readonly CLI_BIN="siluzan-tso"
14
14
  readonly SKILL_LABEL="Siluzan TSO"
15
15
  readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.35-beta.1",
3
+ "version": "1.1.35-beta.2",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",