spectra-cli 4.1.1 → 4.2.0

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 (422) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/go-adapter.d.ts.map +1 -1
  3. package/dist/adapters/go-adapter.js +2 -0
  4. package/dist/adapters/go-adapter.js.map +1 -1
  5. package/dist/adapters/index.d.ts +1 -1
  6. package/dist/adapters/index.d.ts.map +1 -1
  7. package/dist/adapters/java-adapter.d.ts.map +1 -1
  8. package/dist/adapters/java-adapter.js +2 -0
  9. package/dist/adapters/java-adapter.js.map +1 -1
  10. package/dist/adapters/language-adapter.d.ts +47 -9
  11. package/dist/adapters/language-adapter.d.ts.map +1 -1
  12. package/dist/adapters/python-adapter.d.ts +34 -6
  13. package/dist/adapters/python-adapter.d.ts.map +1 -1
  14. package/dist/adapters/python-adapter.js +157 -59
  15. package/dist/adapters/python-adapter.js.map +1 -1
  16. package/dist/adapters/ts-js-adapter.d.ts +13 -5
  17. package/dist/adapters/ts-js-adapter.d.ts.map +1 -1
  18. package/dist/adapters/ts-js-adapter.js +55 -14
  19. package/dist/adapters/ts-js-adapter.js.map +1 -1
  20. package/dist/batch/batch-orchestrator.d.ts +30 -4
  21. package/dist/batch/batch-orchestrator.d.ts.map +1 -1
  22. package/dist/batch/batch-orchestrator.js +284 -7
  23. package/dist/batch/batch-orchestrator.js.map +1 -1
  24. package/dist/batch/delta-regenerator.d.ts +2 -2
  25. package/dist/batch/delta-regenerator.d.ts.map +1 -1
  26. package/dist/batch/delta-regenerator.js.map +1 -1
  27. package/dist/batch/module-grouper.d.ts +2 -2
  28. package/dist/batch/module-grouper.d.ts.map +1 -1
  29. package/dist/batch/module-grouper.js +1 -1
  30. package/dist/batch/module-grouper.js.map +1 -1
  31. package/dist/cli/commands/graph.js +1 -1
  32. package/dist/cli/commands/graph.js.map +1 -1
  33. package/dist/cli/commands/index.d.ts +8 -0
  34. package/dist/cli/commands/index.d.ts.map +1 -0
  35. package/dist/cli/commands/index.js +274 -0
  36. package/dist/cli/commands/index.js.map +1 -0
  37. package/dist/cli/commands/query.d.ts.map +1 -1
  38. package/dist/cli/commands/query.js +3 -1
  39. package/dist/cli/commands/query.js.map +1 -1
  40. package/dist/cli/index.js +9 -9
  41. package/dist/cli/index.js.map +1 -1
  42. package/dist/cli/utils/parse-args.d.ts +13 -1
  43. package/dist/cli/utils/parse-args.d.ts.map +1 -1
  44. package/dist/cli/utils/parse-args.js +79 -2
  45. package/dist/cli/utils/parse-args.js.map +1 -1
  46. package/dist/core/ast-analyzer.d.ts.map +1 -1
  47. package/dist/core/ast-analyzer.js +79 -5
  48. package/dist/core/ast-analyzer.js.map +1 -1
  49. package/dist/core/import-resolver.d.ts +90 -0
  50. package/dist/core/import-resolver.d.ts.map +1 -0
  51. package/dist/core/import-resolver.js +273 -0
  52. package/dist/core/import-resolver.js.map +1 -0
  53. package/dist/core/query-mappers/base-mapper.d.ts +13 -0
  54. package/dist/core/query-mappers/base-mapper.d.ts.map +1 -1
  55. package/dist/core/query-mappers/go-mapper.d.ts +68 -0
  56. package/dist/core/query-mappers/go-mapper.d.ts.map +1 -1
  57. package/dist/core/query-mappers/go-mapper.js +421 -0
  58. package/dist/core/query-mappers/go-mapper.js.map +1 -1
  59. package/dist/core/query-mappers/java-mapper.d.ts +196 -0
  60. package/dist/core/query-mappers/java-mapper.d.ts.map +1 -1
  61. package/dist/core/query-mappers/java-mapper.js +600 -0
  62. package/dist/core/query-mappers/java-mapper.js.map +1 -1
  63. package/dist/core/query-mappers/python-mapper.d.ts +55 -0
  64. package/dist/core/query-mappers/python-mapper.d.ts.map +1 -1
  65. package/dist/core/query-mappers/python-mapper.js +273 -0
  66. package/dist/core/query-mappers/python-mapper.js.map +1 -1
  67. package/dist/core/query-mappers/typescript-mapper.d.ts +102 -0
  68. package/dist/core/query-mappers/typescript-mapper.d.ts.map +1 -1
  69. package/dist/core/query-mappers/typescript-mapper.js +470 -0
  70. package/dist/core/query-mappers/typescript-mapper.js.map +1 -1
  71. package/dist/core/single-spec-orchestrator.d.ts.map +1 -1
  72. package/dist/core/single-spec-orchestrator.js +146 -9
  73. package/dist/core/single-spec-orchestrator.js.map +1 -1
  74. package/dist/core/tree-sitter-analyzer.d.ts +6 -0
  75. package/dist/core/tree-sitter-analyzer.d.ts.map +1 -1
  76. package/dist/core/tree-sitter-analyzer.js +33 -1
  77. package/dist/core/tree-sitter-analyzer.js.map +1 -1
  78. package/dist/core/tree-sitter-fallback.d.ts +7 -4
  79. package/dist/core/tree-sitter-fallback.d.ts.map +1 -1
  80. package/dist/core/tree-sitter-fallback.js +157 -12
  81. package/dist/core/tree-sitter-fallback.js.map +1 -1
  82. package/dist/extraction/extraction-types.d.ts +25 -25
  83. package/dist/generator/index-generator.d.ts +3 -3
  84. package/dist/generator/index-generator.d.ts.map +1 -1
  85. package/dist/generator/index-generator.js +1 -1
  86. package/dist/generator/index-generator.js.map +1 -1
  87. package/dist/graph/directory-graph.d.ts +14 -4
  88. package/dist/graph/directory-graph.d.ts.map +1 -1
  89. package/dist/graph/directory-graph.js +71 -128
  90. package/dist/graph/directory-graph.js.map +1 -1
  91. package/dist/graph/mermaid-renderer.d.ts +8 -5
  92. package/dist/graph/mermaid-renderer.d.ts.map +1 -1
  93. package/dist/graph/mermaid-renderer.js +3 -3
  94. package/dist/graph/mermaid-renderer.js.map +1 -1
  95. package/dist/graph/topological-sort.d.ts +13 -6
  96. package/dist/graph/topological-sort.d.ts.map +1 -1
  97. package/dist/graph/topological-sort.js +2 -2
  98. package/dist/graph/topological-sort.js.map +1 -1
  99. package/dist/knowledge-graph/call-resolver.d.ts +64 -0
  100. package/dist/knowledge-graph/call-resolver.d.ts.map +1 -0
  101. package/dist/knowledge-graph/call-resolver.js +323 -0
  102. package/dist/knowledge-graph/call-resolver.js.map +1 -0
  103. package/dist/knowledge-graph/import-resolver.d.ts +114 -0
  104. package/dist/knowledge-graph/import-resolver.d.ts.map +1 -0
  105. package/dist/knowledge-graph/import-resolver.js +537 -0
  106. package/dist/knowledge-graph/import-resolver.js.map +1 -0
  107. package/dist/knowledge-graph/incremental.d.ts +110 -0
  108. package/dist/knowledge-graph/incremental.d.ts.map +1 -0
  109. package/dist/knowledge-graph/incremental.js +410 -0
  110. package/dist/knowledge-graph/incremental.js.map +1 -0
  111. package/dist/knowledge-graph/index.d.ts +74 -0
  112. package/dist/knowledge-graph/index.d.ts.map +1 -0
  113. package/dist/knowledge-graph/index.js +156 -0
  114. package/dist/knowledge-graph/index.js.map +1 -0
  115. package/dist/knowledge-graph/module-derivation.d.ts +238 -0
  116. package/dist/knowledge-graph/module-derivation.d.ts.map +1 -0
  117. package/dist/knowledge-graph/module-derivation.js +418 -0
  118. package/dist/knowledge-graph/module-derivation.js.map +1 -0
  119. package/dist/knowledge-graph/persistence.d.ts +270 -0
  120. package/dist/knowledge-graph/persistence.d.ts.map +1 -0
  121. package/dist/knowledge-graph/persistence.js +226 -0
  122. package/dist/knowledge-graph/persistence.js.map +1 -0
  123. package/dist/knowledge-graph/query-helpers.d.ts +164 -0
  124. package/dist/knowledge-graph/query-helpers.d.ts.map +1 -0
  125. package/dist/knowledge-graph/query-helpers.js +394 -0
  126. package/dist/knowledge-graph/query-helpers.js.map +1 -0
  127. package/dist/knowledge-graph/unified-graph.d.ts +310 -0
  128. package/dist/knowledge-graph/unified-graph.d.ts.map +1 -0
  129. package/dist/knowledge-graph/unified-graph.js +182 -0
  130. package/dist/knowledge-graph/unified-graph.js.map +1 -0
  131. package/dist/mcp/agent-context-tools.d.ts +104 -0
  132. package/dist/mcp/agent-context-tools.d.ts.map +1 -0
  133. package/dist/mcp/agent-context-tools.js +854 -0
  134. package/dist/mcp/agent-context-tools.js.map +1 -0
  135. package/dist/mcp/graph-tools.d.ts +20 -0
  136. package/dist/mcp/graph-tools.d.ts.map +1 -1
  137. package/dist/mcp/graph-tools.js +71 -11
  138. package/dist/mcp/graph-tools.js.map +1 -1
  139. package/dist/mcp/lib/response-helpers.d.ts +67 -0
  140. package/dist/mcp/lib/response-helpers.d.ts.map +1 -0
  141. package/dist/mcp/lib/response-helpers.js +103 -0
  142. package/dist/mcp/lib/response-helpers.js.map +1 -0
  143. package/dist/mcp/server.d.ts +3 -1
  144. package/dist/mcp/server.d.ts.map +1 -1
  145. package/dist/mcp/server.js +9 -10
  146. package/dist/mcp/server.js.map +1 -1
  147. package/dist/models/call-site.d.ts +68 -0
  148. package/dist/models/call-site.d.ts.map +1 -0
  149. package/dist/models/call-site.js +60 -0
  150. package/dist/models/call-site.js.map +1 -0
  151. package/dist/models/code-skeleton.d.ts +78 -6
  152. package/dist/models/code-skeleton.d.ts.map +1 -1
  153. package/dist/models/code-skeleton.js +29 -0
  154. package/dist/models/code-skeleton.js.map +1 -1
  155. package/dist/models/drift-item.d.ts +4 -4
  156. package/dist/models/module-spec.d.ts +155 -94
  157. package/dist/models/module-spec.d.ts.map +1 -1
  158. package/dist/panoramic/adr-decision-pipeline.d.ts +53 -0
  159. package/dist/panoramic/adr-decision-pipeline.d.ts.map +1 -0
  160. package/dist/panoramic/adr-decision-pipeline.js +685 -0
  161. package/dist/panoramic/adr-decision-pipeline.js.map +1 -0
  162. package/dist/panoramic/api-surface-generator.d.ts +56 -0
  163. package/dist/panoramic/api-surface-generator.d.ts.map +1 -0
  164. package/dist/panoramic/api-surface-generator.js +1671 -0
  165. package/dist/panoramic/api-surface-generator.js.map +1 -0
  166. package/dist/panoramic/architecture-ir-builder.d.ts +19 -0
  167. package/dist/panoramic/architecture-ir-builder.d.ts.map +1 -0
  168. package/dist/panoramic/architecture-ir-builder.js +561 -0
  169. package/dist/panoramic/architecture-ir-builder.js.map +1 -0
  170. package/dist/panoramic/architecture-ir-exporters.d.ts +7 -0
  171. package/dist/panoramic/architecture-ir-exporters.d.ts.map +1 -0
  172. package/dist/panoramic/architecture-ir-exporters.js +183 -0
  173. package/dist/panoramic/architecture-ir-exporters.js.map +1 -0
  174. package/dist/panoramic/architecture-ir-generator.d.ts +36 -0
  175. package/dist/panoramic/architecture-ir-generator.d.ts.map +1 -0
  176. package/dist/panoramic/architecture-ir-generator.js +51 -0
  177. package/dist/panoramic/architecture-ir-generator.js.map +1 -0
  178. package/dist/panoramic/architecture-ir-mermaid-adapter.d.ts +6 -0
  179. package/dist/panoramic/architecture-ir-mermaid-adapter.d.ts.map +1 -0
  180. package/dist/panoramic/architecture-ir-mermaid-adapter.js +98 -0
  181. package/dist/panoramic/architecture-ir-mermaid-adapter.js.map +1 -0
  182. package/dist/panoramic/architecture-ir-model.d.ts +87 -0
  183. package/dist/panoramic/architecture-ir-model.d.ts.map +1 -0
  184. package/dist/panoramic/architecture-ir-model.js +20 -0
  185. package/dist/panoramic/architecture-ir-model.js.map +1 -0
  186. package/dist/panoramic/architecture-narrative.d.ts +68 -0
  187. package/dist/panoramic/architecture-narrative.d.ts.map +1 -0
  188. package/dist/panoramic/architecture-narrative.js +401 -0
  189. package/dist/panoramic/architecture-narrative.js.map +1 -0
  190. package/dist/panoramic/architecture-overview-generator.d.ts +31 -0
  191. package/dist/panoramic/architecture-overview-generator.d.ts.map +1 -0
  192. package/dist/panoramic/architecture-overview-generator.js +454 -0
  193. package/dist/panoramic/architecture-overview-generator.js.map +1 -0
  194. package/dist/panoramic/architecture-overview-model.d.ts +77 -0
  195. package/dist/panoramic/architecture-overview-model.d.ts.map +1 -0
  196. package/dist/panoramic/architecture-overview-model.js +31 -0
  197. package/dist/panoramic/architecture-overview-model.js.map +1 -0
  198. package/dist/panoramic/batch-project-docs.d.ts.map +1 -1
  199. package/dist/panoramic/batch-project-docs.js +4 -2
  200. package/dist/panoramic/batch-project-docs.js.map +1 -1
  201. package/dist/panoramic/builders/component-view-builder.d.ts +25 -1
  202. package/dist/panoramic/builders/component-view-builder.d.ts.map +1 -1
  203. package/dist/panoramic/builders/component-view-builder.js +83 -3
  204. package/dist/panoramic/builders/component-view-builder.js.map +1 -1
  205. package/dist/panoramic/builders/doc-graph-builder.d.ts +2 -2
  206. package/dist/panoramic/builders/doc-graph-builder.d.ts.map +1 -1
  207. package/dist/panoramic/builders/doc-graph-builder.js.map +1 -1
  208. package/dist/panoramic/component-view-builder.d.ts +17 -0
  209. package/dist/panoramic/component-view-builder.d.ts.map +1 -0
  210. package/dist/panoramic/component-view-builder.js +652 -0
  211. package/dist/panoramic/component-view-builder.js.map +1 -0
  212. package/dist/panoramic/component-view-model.d.ts +127 -0
  213. package/dist/panoramic/component-view-model.d.ts.map +1 -0
  214. package/dist/panoramic/component-view-model.js +65 -0
  215. package/dist/panoramic/component-view-model.js.map +1 -0
  216. package/dist/panoramic/config-reference-generator.d.ts +78 -0
  217. package/dist/panoramic/config-reference-generator.d.ts.map +1 -0
  218. package/dist/panoramic/config-reference-generator.js +199 -0
  219. package/dist/panoramic/config-reference-generator.js.map +1 -0
  220. package/dist/panoramic/coverage-auditor.d.ts +95 -0
  221. package/dist/panoramic/coverage-auditor.d.ts.map +1 -0
  222. package/dist/panoramic/coverage-auditor.js +290 -0
  223. package/dist/panoramic/coverage-auditor.js.map +1 -0
  224. package/dist/panoramic/cross-package-analyzer.d.ts +112 -0
  225. package/dist/panoramic/cross-package-analyzer.d.ts.map +1 -0
  226. package/dist/panoramic/cross-package-analyzer.js +258 -0
  227. package/dist/panoramic/cross-package-analyzer.js.map +1 -0
  228. package/dist/panoramic/data-model-generator.d.ts +528 -0
  229. package/dist/panoramic/data-model-generator.d.ts.map +1 -0
  230. package/dist/panoramic/data-model-generator.js +647 -0
  231. package/dist/panoramic/data-model-generator.js.map +1 -0
  232. package/dist/panoramic/doc-graph-builder.d.ts +80 -0
  233. package/dist/panoramic/doc-graph-builder.d.ts.map +1 -0
  234. package/dist/panoramic/doc-graph-builder.js +352 -0
  235. package/dist/panoramic/doc-graph-builder.js.map +1 -0
  236. package/dist/panoramic/docs-bundle-manifest-reader.d.ts +26 -0
  237. package/dist/panoramic/docs-bundle-manifest-reader.d.ts.map +1 -0
  238. package/dist/panoramic/docs-bundle-manifest-reader.js +106 -0
  239. package/dist/panoramic/docs-bundle-manifest-reader.js.map +1 -0
  240. package/dist/panoramic/docs-bundle-orchestrator.d.ts +14 -0
  241. package/dist/panoramic/docs-bundle-orchestrator.d.ts.map +1 -0
  242. package/dist/panoramic/docs-bundle-orchestrator.js +538 -0
  243. package/dist/panoramic/docs-bundle-orchestrator.js.map +1 -0
  244. package/dist/panoramic/docs-bundle-profiles.d.ts +4 -0
  245. package/dist/panoramic/docs-bundle-profiles.d.ts.map +1 -0
  246. package/dist/panoramic/docs-bundle-profiles.js +82 -0
  247. package/dist/panoramic/docs-bundle-profiles.js.map +1 -0
  248. package/dist/panoramic/docs-bundle-types.d.ts +94 -0
  249. package/dist/panoramic/docs-bundle-types.d.ts.map +1 -0
  250. package/dist/panoramic/docs-bundle-types.js +10 -0
  251. package/dist/panoramic/docs-bundle-types.js.map +1 -0
  252. package/dist/panoramic/docs-quality-evaluator.d.ts +31 -0
  253. package/dist/panoramic/docs-quality-evaluator.d.ts.map +1 -0
  254. package/dist/panoramic/docs-quality-evaluator.js +941 -0
  255. package/dist/panoramic/docs-quality-evaluator.js.map +1 -0
  256. package/dist/panoramic/docs-quality-model.d.ts +125 -0
  257. package/dist/panoramic/docs-quality-model.d.ts.map +1 -0
  258. package/dist/panoramic/docs-quality-model.js +166 -0
  259. package/dist/panoramic/docs-quality-model.js.map +1 -0
  260. package/dist/panoramic/dynamic-scenarios-builder.d.ts +18 -0
  261. package/dist/panoramic/dynamic-scenarios-builder.d.ts.map +1 -0
  262. package/dist/panoramic/dynamic-scenarios-builder.js +316 -0
  263. package/dist/panoramic/dynamic-scenarios-builder.js.map +1 -0
  264. package/dist/panoramic/event-surface-generator.d.ts +52 -0
  265. package/dist/panoramic/event-surface-generator.d.ts.map +1 -0
  266. package/dist/panoramic/event-surface-generator.js +507 -0
  267. package/dist/panoramic/event-surface-generator.js.map +1 -0
  268. package/dist/panoramic/generator-registry.d.ts +1 -1
  269. package/dist/panoramic/generator-registry.d.ts.map +1 -1
  270. package/dist/panoramic/generator-registry.js +5 -2
  271. package/dist/panoramic/generator-registry.js.map +1 -1
  272. package/dist/panoramic/generators/cross-package-analyzer.d.ts +5 -5
  273. package/dist/panoramic/generators/cross-package-analyzer.d.ts.map +1 -1
  274. package/dist/panoramic/generators/cross-package-analyzer.js +1 -1
  275. package/dist/panoramic/generators/cross-package-analyzer.js.map +1 -1
  276. package/dist/panoramic/generators/data-model-generator.d.ts +27 -27
  277. package/dist/panoramic/graph/confidence-mapper.d.ts +18 -0
  278. package/dist/panoramic/graph/confidence-mapper.d.ts.map +1 -1
  279. package/dist/panoramic/graph/confidence-mapper.js +26 -0
  280. package/dist/panoramic/graph/confidence-mapper.js.map +1 -1
  281. package/dist/panoramic/graph/graph-builder.d.ts.map +1 -1
  282. package/dist/panoramic/graph/graph-builder.js +78 -0
  283. package/dist/panoramic/graph/graph-builder.js.map +1 -1
  284. package/dist/panoramic/graph/graph-paths.d.ts +8 -0
  285. package/dist/panoramic/graph/graph-paths.d.ts.map +1 -1
  286. package/dist/panoramic/graph/graph-paths.js +10 -0
  287. package/dist/panoramic/graph/graph-paths.js.map +1 -1
  288. package/dist/panoramic/graph/graph-query.d.ts +33 -2
  289. package/dist/panoramic/graph/graph-query.d.ts.map +1 -1
  290. package/dist/panoramic/graph/graph-query.js +69 -19
  291. package/dist/panoramic/graph/graph-query.js.map +1 -1
  292. package/dist/panoramic/graph/graph-types.d.ts +32 -3
  293. package/dist/panoramic/graph/graph-types.d.ts.map +1 -1
  294. package/dist/panoramic/hyperedges/schema.d.ts +6 -6
  295. package/dist/panoramic/interface-surface-generator.d.ts +50 -0
  296. package/dist/panoramic/interface-surface-generator.d.ts.map +1 -0
  297. package/dist/panoramic/interface-surface-generator.js +388 -0
  298. package/dist/panoramic/interface-surface-generator.js.map +1 -0
  299. package/dist/panoramic/interfaces.d.ts +2 -2
  300. package/dist/panoramic/mock-readme-generator.d.ts +90 -0
  301. package/dist/panoramic/mock-readme-generator.d.ts.map +1 -0
  302. package/dist/panoramic/mock-readme-generator.js +111 -0
  303. package/dist/panoramic/mock-readme-generator.js.map +1 -0
  304. package/dist/panoramic/models/component-view-model.d.ts +1 -1
  305. package/dist/panoramic/models/component-view-model.d.ts.map +1 -1
  306. package/dist/panoramic/models/component-view-model.js.map +1 -1
  307. package/dist/panoramic/narrative-provenance-adapter.d.ts +8 -0
  308. package/dist/panoramic/narrative-provenance-adapter.d.ts.map +1 -0
  309. package/dist/panoramic/narrative-provenance-adapter.js +99 -0
  310. package/dist/panoramic/narrative-provenance-adapter.js.map +1 -0
  311. package/dist/panoramic/parser-registry.d.ts +1 -1
  312. package/dist/panoramic/parser-registry.js +1 -1
  313. package/dist/panoramic/parsers/types.d.ts +6 -6
  314. package/dist/panoramic/pattern-hints-generator.d.ts +28 -0
  315. package/dist/panoramic/pattern-hints-generator.d.ts.map +1 -0
  316. package/dist/panoramic/pattern-hints-generator.js +218 -0
  317. package/dist/panoramic/pattern-hints-generator.js.map +1 -0
  318. package/dist/panoramic/pattern-hints-model.d.ts +89 -0
  319. package/dist/panoramic/pattern-hints-model.d.ts.map +1 -0
  320. package/dist/panoramic/pattern-hints-model.js +61 -0
  321. package/dist/panoramic/pattern-hints-model.js.map +1 -0
  322. package/dist/panoramic/pattern-knowledge-base.d.ts +31 -0
  323. package/dist/panoramic/pattern-knowledge-base.d.ts.map +1 -0
  324. package/dist/panoramic/pattern-knowledge-base.js +407 -0
  325. package/dist/panoramic/pattern-knowledge-base.js.map +1 -0
  326. package/dist/panoramic/pipelines/coverage-auditor.d.ts.map +1 -1
  327. package/dist/panoramic/pipelines/coverage-auditor.js +4 -2
  328. package/dist/panoramic/pipelines/coverage-auditor.js.map +1 -1
  329. package/dist/panoramic/pipelines/docs-bundle-orchestrator.js +13 -6
  330. package/dist/panoramic/pipelines/docs-bundle-orchestrator.js.map +1 -1
  331. package/dist/panoramic/pipelines/product-ux-docs.d.ts +5 -0
  332. package/dist/panoramic/pipelines/product-ux-docs.d.ts.map +1 -1
  333. package/dist/panoramic/pipelines/product-ux-docs.js +34 -6
  334. package/dist/panoramic/pipelines/product-ux-docs.js.map +1 -1
  335. package/dist/panoramic/product-ux-docs.d.ts +104 -0
  336. package/dist/panoramic/product-ux-docs.d.ts.map +1 -0
  337. package/dist/panoramic/product-ux-docs.js +817 -0
  338. package/dist/panoramic/product-ux-docs.js.map +1 -0
  339. package/dist/panoramic/qa/__tests__/citation.test.d.ts +2 -0
  340. package/dist/panoramic/qa/__tests__/citation.test.d.ts.map +1 -0
  341. package/dist/panoramic/qa/__tests__/citation.test.js +193 -0
  342. package/dist/panoramic/qa/__tests__/citation.test.js.map +1 -0
  343. package/dist/panoramic/qa/__tests__/debt-context.test.d.ts +2 -0
  344. package/dist/panoramic/qa/__tests__/debt-context.test.d.ts.map +1 -0
  345. package/dist/panoramic/qa/__tests__/debt-context.test.js +154 -0
  346. package/dist/panoramic/qa/__tests__/debt-context.test.js.map +1 -0
  347. package/dist/panoramic/qa/__tests__/graph-retriever.test.d.ts +2 -0
  348. package/dist/panoramic/qa/__tests__/graph-retriever.test.d.ts.map +1 -0
  349. package/dist/panoramic/qa/__tests__/graph-retriever.test.js +148 -0
  350. package/dist/panoramic/qa/__tests__/graph-retriever.test.js.map +1 -0
  351. package/dist/panoramic/qa/__tests__/index.test.d.ts +2 -0
  352. package/dist/panoramic/qa/__tests__/index.test.d.ts.map +1 -0
  353. package/dist/panoramic/qa/__tests__/index.test.js +246 -0
  354. package/dist/panoramic/qa/__tests__/index.test.js.map +1 -0
  355. package/dist/panoramic/qa/__tests__/llm-caller.test.d.ts +2 -0
  356. package/dist/panoramic/qa/__tests__/llm-caller.test.d.ts.map +1 -0
  357. package/dist/panoramic/qa/__tests__/llm-caller.test.js +168 -0
  358. package/dist/panoramic/qa/__tests__/llm-caller.test.js.map +1 -0
  359. package/dist/panoramic/qa/__tests__/prompt-builder.test.d.ts +2 -0
  360. package/dist/panoramic/qa/__tests__/prompt-builder.test.d.ts.map +1 -0
  361. package/dist/panoramic/qa/__tests__/prompt-builder.test.js +150 -0
  362. package/dist/panoramic/qa/__tests__/prompt-builder.test.js.map +1 -0
  363. package/dist/panoramic/qa/__tests__/qa-integration.test.d.ts +2 -0
  364. package/dist/panoramic/qa/__tests__/qa-integration.test.d.ts.map +1 -0
  365. package/dist/panoramic/qa/__tests__/qa-integration.test.js +296 -0
  366. package/dist/panoramic/qa/__tests__/qa-integration.test.js.map +1 -0
  367. package/dist/panoramic/qa/__tests__/rag-reranker.test.d.ts +2 -0
  368. package/dist/panoramic/qa/__tests__/rag-reranker.test.d.ts.map +1 -0
  369. package/dist/panoramic/qa/__tests__/rag-reranker.test.js +136 -0
  370. package/dist/panoramic/qa/__tests__/rag-reranker.test.js.map +1 -0
  371. package/dist/panoramic/qa/index.d.ts.map +1 -1
  372. package/dist/panoramic/qa/index.js +10 -3
  373. package/dist/panoramic/qa/index.js.map +1 -1
  374. package/dist/panoramic/runtime-topology-generator.d.ts +77 -0
  375. package/dist/panoramic/runtime-topology-generator.d.ts.map +1 -0
  376. package/dist/panoramic/runtime-topology-generator.js +676 -0
  377. package/dist/panoramic/runtime-topology-generator.js.map +1 -0
  378. package/dist/panoramic/runtime-topology-model.d.ts +145 -0
  379. package/dist/panoramic/runtime-topology-model.d.ts.map +1 -0
  380. package/dist/panoramic/runtime-topology-model.js +300 -0
  381. package/dist/panoramic/runtime-topology-model.js.map +1 -0
  382. package/dist/panoramic/troubleshooting-generator.d.ts +51 -0
  383. package/dist/panoramic/troubleshooting-generator.d.ts.map +1 -0
  384. package/dist/panoramic/troubleshooting-generator.js +451 -0
  385. package/dist/panoramic/troubleshooting-generator.js.map +1 -0
  386. package/dist/panoramic/utils/text-segmenter.d.ts +15 -0
  387. package/dist/panoramic/utils/text-segmenter.d.ts.map +1 -1
  388. package/dist/panoramic/utils/text-segmenter.js +38 -0
  389. package/dist/panoramic/utils/text-segmenter.js.map +1 -1
  390. package/dist/panoramic/workspace-index-generator.d.ts +148 -0
  391. package/dist/panoramic/workspace-index-generator.d.ts.map +1 -0
  392. package/dist/panoramic/workspace-index-generator.js +497 -0
  393. package/dist/panoramic/workspace-index-generator.js.map +1 -0
  394. package/dist/runtime-bootstrap.d.ts +9 -0
  395. package/dist/runtime-bootstrap.d.ts.map +1 -0
  396. package/dist/runtime-bootstrap.js +33 -0
  397. package/dist/runtime-bootstrap.js.map +1 -0
  398. package/dist/utils/file-scanner.js +1 -1
  399. package/dist/utils/file-scanner.js.map +1 -1
  400. package/package.json +12 -2
  401. package/plugins/spec-driver/.claude-plugin/plugin.json +1 -1
  402. package/plugins/spec-driver/README.md +18 -1
  403. package/plugins/spec-driver/agents/implement.md +20 -1
  404. package/plugins/spec-driver/agents/plan.md +20 -1
  405. package/plugins/spec-driver/agents/quality-review.md +20 -1
  406. package/plugins/spec-driver/agents/spec-review.md +20 -1
  407. package/plugins/spec-driver/agents/verify.md +20 -1
  408. package/plugins/spec-driver/docs/customization.md +134 -0
  409. package/plugins/spec-driver/docs/spectra-mcp-integration.md +165 -0
  410. package/plugins/spec-driver/lib/preference-rules.mjs +96 -0
  411. package/plugins/spec-driver/scripts/postinstall.sh +1 -1
  412. package/plugins/spec-driver/scripts/sync-preference-rules.mjs +148 -0
  413. package/plugins/spec-driver/skills/spec-driver-feature/SKILL.md +10 -0
  414. package/plugins/spec-driver/skills/spec-driver-fix/SKILL.md +10 -0
  415. package/plugins/spec-driver/skills/spec-driver-implement/SKILL.md +10 -0
  416. package/plugins/spec-driver/skills/spec-driver-refactor/SKILL.md +10 -0
  417. package/plugins/spec-driver/skills/spec-driver-story/SKILL.md +10 -0
  418. package/plugins/spec-driver/templates/preference-rules.md +39 -0
  419. package/plugins/spectra/.claude-plugin/plugin.json +1 -1
  420. package/plugins/spectra/README.md +48 -1
  421. package/plugins/spectra/hooks/post-commit.sh +40 -0
  422. package/templates/product-overview.hbs +1 -1
@@ -0,0 +1,817 @@
1
+ /**
2
+ * Product / UX fact ingestion
3
+ *
4
+ * Feature 060: 将 current-spec、README/设计说明、GitHub issue/PR 与近期提交
5
+ * 汇总为产品概览、用户旅程与 feature brief 文档。
6
+ *
7
+ * 设计原则:
8
+ * 1. current-spec 是首选事实源;README / 设计文档 / GitHub issue/PR 为补充源
9
+ * 2. 允许无 GitHub token / 无 gh CLI 的离线降级
10
+ * 3. narrative 与 journey/brief synthesis 必须保留 evidence / confidence / inferred
11
+ */
12
+ import * as fs from 'node:fs';
13
+ import * as path from 'node:path';
14
+ import { spawnSync } from 'node:child_process';
15
+ import { loadTemplate } from './utils/template-loader.js';
16
+ export function generateProductUxDocs(options) {
17
+ const corpus = buildProductFactCorpus(options.projectRoot);
18
+ const overview = buildProductOverview(corpus);
19
+ const journeys = buildUserJourneys(corpus, overview);
20
+ const featureBriefIndex = buildFeatureBriefIndex(corpus, overview, journeys);
21
+ const writtenFiles = [];
22
+ writtenFiles.push(...writeOverview(options.outputDir, overview));
23
+ writtenFiles.push(...writeJourneys(options.outputDir, journeys));
24
+ writtenFiles.push(...writeFeatureBriefs(options.outputDir, featureBriefIndex));
25
+ return {
26
+ overview,
27
+ journeys,
28
+ featureBriefIndex,
29
+ warnings: uniqueSorted([
30
+ ...corpus.warnings,
31
+ ...overview.warnings,
32
+ ...journeys.warnings,
33
+ ...featureBriefIndex.warnings,
34
+ ]),
35
+ writtenFiles,
36
+ };
37
+ }
38
+ function writeOverview(outputDir, overview) {
39
+ const mdPath = path.join(outputDir, 'product-overview.md');
40
+ const jsonPath = path.join(outputDir, 'product-overview.json');
41
+ fs.mkdirSync(outputDir, { recursive: true });
42
+ fs.writeFileSync(mdPath, renderProductOverview(overview), 'utf-8');
43
+ fs.writeFileSync(jsonPath, JSON.stringify(overview, null, 2), 'utf-8');
44
+ return [mdPath, jsonPath];
45
+ }
46
+ function writeJourneys(outputDir, journeys) {
47
+ const mdPath = path.join(outputDir, 'user-journeys.md');
48
+ const jsonPath = path.join(outputDir, 'user-journeys.json');
49
+ fs.mkdirSync(outputDir, { recursive: true });
50
+ fs.writeFileSync(mdPath, renderUserJourneys(journeys), 'utf-8');
51
+ fs.writeFileSync(jsonPath, JSON.stringify(journeys, null, 2), 'utf-8');
52
+ return [mdPath, jsonPath];
53
+ }
54
+ function writeFeatureBriefs(outputDir, index) {
55
+ const briefsDir = path.join(outputDir, 'feature-briefs');
56
+ const writtenFiles = [];
57
+ fs.mkdirSync(briefsDir, { recursive: true });
58
+ const indexMd = path.join(briefsDir, 'index.md');
59
+ const indexJson = path.join(briefsDir, 'index.json');
60
+ fs.writeFileSync(indexMd, renderFeatureBriefIndex(index), 'utf-8');
61
+ fs.writeFileSync(indexJson, JSON.stringify(index, null, 2), 'utf-8');
62
+ writtenFiles.push(indexMd, indexJson);
63
+ for (const brief of index.briefs) {
64
+ const mdPath = path.join(briefsDir, `${brief.fileName}.md`);
65
+ const jsonPath = path.join(briefsDir, `${brief.fileName}.json`);
66
+ fs.writeFileSync(mdPath, renderFeatureBrief(brief), 'utf-8');
67
+ fs.writeFileSync(jsonPath, JSON.stringify(brief, null, 2), 'utf-8');
68
+ writtenFiles.push(mdPath, jsonPath);
69
+ }
70
+ return writtenFiles;
71
+ }
72
+ function renderProductOverview(output) {
73
+ return loadTemplate('product-overview.hbs', import.meta.url)(output);
74
+ }
75
+ function renderUserJourneys(output) {
76
+ return loadTemplate('user-journeys.hbs', import.meta.url)(output);
77
+ }
78
+ function renderFeatureBriefIndex(output) {
79
+ return loadTemplate('feature-brief-index.hbs', import.meta.url)(output);
80
+ }
81
+ function renderFeatureBrief(output) {
82
+ return loadTemplate('feature-brief.hbs', import.meta.url)(output);
83
+ }
84
+ function buildProductFactCorpus(projectRoot) {
85
+ const currentSpecs = collectCurrentSpecs(projectRoot);
86
+ const readmes = collectReadmes(projectRoot);
87
+ const designDocs = collectLocalDesignDocs(projectRoot);
88
+ const gitHubFacts = collectGitHubFacts(projectRoot);
89
+ const commits = collectRecentCommits(projectRoot, 10);
90
+ const warnings = uniqueSorted([
91
+ ...gitHubFacts.warnings,
92
+ ...(currentSpecs.length === 0
93
+ ? ['未找到 current-spec.md,将更多依赖 README / 设计文档 / issue/PR 进行产品事实推断。']
94
+ : []),
95
+ ...(readmes.length === 0
96
+ ? ['未找到项目级 README.md,产品定位摘要将缺少一份高价值补充源。']
97
+ : []),
98
+ ...(designDocs.length === 0
99
+ ? ['未找到本地设计说明/roadmap Markdown,UX 旅程与 feature brief 将更多依赖 current-spec / issue/PR。']
100
+ : []),
101
+ ]);
102
+ return {
103
+ projectName: resolveProjectName(projectRoot, currentSpecs, readmes),
104
+ currentSpecs,
105
+ readmes,
106
+ designDocs,
107
+ issues: gitHubFacts.issues,
108
+ pullRequests: gitHubFacts.pullRequests,
109
+ commits,
110
+ warnings,
111
+ };
112
+ }
113
+ function buildProductOverview(corpus) {
114
+ const summary = collectOverviewParagraphs(corpus).slice(0, 4);
115
+ const targetUsers = buildTargetUsers(corpus);
116
+ const coreScenarios = buildCoreScenarios(corpus, targetUsers);
117
+ const evidence = uniqueEvidence([
118
+ ...collectEvidenceFromSources(corpus.currentSpecs, 'high'),
119
+ ...collectEvidenceFromSources(corpus.readmes, 'medium'),
120
+ ...collectEvidenceFromSources(corpus.designDocs, 'medium'),
121
+ ...corpus.issues.slice(0, 3).map((issue) => toGitHubEvidence(issue, issue.title, 'medium')),
122
+ ...corpus.pullRequests.slice(0, 2).map((pr) => toGitHubEvidence(pr, pr.title, 'medium')),
123
+ ]);
124
+ const warnings = uniqueSorted([
125
+ ...corpus.warnings,
126
+ ...(summary.length === 0
127
+ ? ['未提取到稳定的产品概述段落,product-overview 将更多依赖推断和标题级摘要。']
128
+ : []),
129
+ ...(targetUsers.length === 0
130
+ ? ['未识别到显式用户画像表或用户段落,将使用 README / issue 文本推断目标用户。']
131
+ : []),
132
+ ...(coreScenarios.length === 0
133
+ ? ['未识别到显式核心场景列表,将使用 feature briefs 和 README 文本推断核心任务流。']
134
+ : []),
135
+ ]);
136
+ const inferred = corpus.currentSpecs.length === 0;
137
+ return {
138
+ title: `产品概览: ${corpus.projectName}`,
139
+ generatedAt: new Date().toISOString(),
140
+ projectName: corpus.projectName,
141
+ summary: summary.length > 0
142
+ ? summary
143
+ : ['仅基于代码与现有规格推断;尚未找到足够稳定的产品事实源。'],
144
+ targetUsers,
145
+ coreScenarios,
146
+ keyTaskFlows: coreScenarios.slice(0, 5).map((scenario) => scenario.title),
147
+ warnings,
148
+ confidence: currentSpecConfidence(corpus.currentSpecs.length > 0, evidence.length),
149
+ inferred,
150
+ evidence,
151
+ };
152
+ }
153
+ function buildUserJourneys(corpus, overview) {
154
+ const journeys = overview.coreScenarios.slice(0, 5).map((scenario, index) => {
155
+ const actor = scenario.actors[0] ?? overview.targetUsers[0]?.name ?? '使用者';
156
+ const detail = scenario.summary || scenario.title;
157
+ return {
158
+ id: `journey-${String(index + 1).padStart(2, '0')}`,
159
+ title: scenario.title,
160
+ actor,
161
+ goal: detail,
162
+ outcome: `完成 ${scenario.title} 对应的关键任务,并获得结构化文档或可执行下一步。`,
163
+ steps: [
164
+ {
165
+ title: '触发场景',
166
+ detail: `${actor} 识别当前任务需要:${scenario.title}`,
167
+ inferred: true,
168
+ },
169
+ {
170
+ title: '执行关键动作',
171
+ detail,
172
+ inferred: false,
173
+ },
174
+ {
175
+ title: '消费输出',
176
+ detail: '使用生成的文档、接口说明或评审材料完成后续沟通、实现或交接。',
177
+ inferred: true,
178
+ },
179
+ ],
180
+ evidence: scenario.evidence,
181
+ confidence: scenario.confidence,
182
+ inferred: true,
183
+ };
184
+ });
185
+ const warnings = uniqueSorted([
186
+ ...corpus.warnings,
187
+ ...(journeys.length === 0
188
+ ? ['未识别到可稳定组织成用户旅程的场景,user-journeys 将为空。']
189
+ : []),
190
+ ]);
191
+ return {
192
+ title: `用户旅程: ${corpus.projectName}`,
193
+ generatedAt: new Date().toISOString(),
194
+ projectName: corpus.projectName,
195
+ summary: journeys.length > 0
196
+ ? [`基于 ${journeys.length} 条核心场景组织用户旅程,优先引用 current-spec、README 与可用的 issue/PR 事实。`]
197
+ : ['仅基于代码与现有规格推断;尚未识别到稳定的用户旅程输入。'],
198
+ journeys,
199
+ warnings,
200
+ confidence: currentSpecConfidence(corpus.currentSpecs.length > 0, journeys.length),
201
+ };
202
+ }
203
+ function buildFeatureBriefIndex(corpus, overview, journeys) {
204
+ const briefs = [];
205
+ const defaultAudience = overview.targetUsers[0]?.name ?? '开发者';
206
+ for (const issue of corpus.issues.slice(0, 3)) {
207
+ const id = `ISSUE-${issue.number}`;
208
+ briefs.push({
209
+ id,
210
+ slug: slugify(issue.title),
211
+ fileName: briefFileName(id, issue.title),
212
+ title: issue.title,
213
+ summary: firstMeaningfulSentence(issue.body) ?? issue.title,
214
+ problem: firstMeaningfulSentence(issue.body) ?? `${issue.title} 对应的问题陈述未在 issue 正文中明确给出。`,
215
+ proposedSolution: `围绕 issue #${issue.number} 组织功能说明,并将其纳入产品 / UX 文档事实层。`,
216
+ audience: inferAudience(issue.title, overview.targetUsers) ?? defaultAudience,
217
+ status: issue.state === 'closed' ? 'shipped' : 'candidate',
218
+ evidence: [toGitHubEvidence(issue, issue.title, 'high')],
219
+ confidence: 'high',
220
+ inferred: false,
221
+ });
222
+ }
223
+ for (const pr of corpus.pullRequests.slice(0, 2)) {
224
+ const id = `PR-${pr.number}`;
225
+ briefs.push({
226
+ id,
227
+ slug: slugify(pr.title),
228
+ fileName: briefFileName(id, pr.title),
229
+ title: pr.title,
230
+ summary: firstMeaningfulSentence(pr.body) ?? pr.title,
231
+ problem: firstMeaningfulSentence(pr.body) ?? `${pr.title} 对应的变更动机未在 PR 正文中明确给出。`,
232
+ proposedSolution: `把 PR #${pr.number} 的实现意图沉淀为可读的 feature brief,并连接到产品概览与用户旅程。`,
233
+ audience: inferAudience(pr.title, overview.targetUsers) ?? defaultAudience,
234
+ status: pr.state === 'closed' ? 'shipped' : 'candidate',
235
+ evidence: [toGitHubEvidence(pr, pr.title, 'high')],
236
+ confidence: 'high',
237
+ inferred: false,
238
+ });
239
+ }
240
+ if (briefs.length === 0) {
241
+ for (const scenario of journeys.journeys.slice(0, 3)) {
242
+ const id = `BRIEF-${String(briefs.length + 1).padStart(2, '0')}`;
243
+ briefs.push({
244
+ id,
245
+ slug: slugify(scenario.title),
246
+ fileName: briefFileName(id, scenario.title),
247
+ title: scenario.title,
248
+ summary: scenario.goal,
249
+ problem: `${scenario.actor} 需要更直接地完成“${scenario.title}”相关任务,但现有事实源未提供独立 issue/PR 说明。`,
250
+ proposedSolution: `围绕 ${scenario.title} 组织一份产品 brief,把用户目标、路径和预期输出显式化。`,
251
+ audience: scenario.actor,
252
+ status: 'candidate',
253
+ evidence: scenario.evidence,
254
+ confidence: 'medium',
255
+ inferred: true,
256
+ });
257
+ }
258
+ }
259
+ const warnings = uniqueSorted([
260
+ ...corpus.warnings,
261
+ ...(corpus.issues.length === 0 && corpus.pullRequests.length === 0
262
+ ? ['未获取到 GitHub issue/PR 事实,feature briefs 已回退到 current-spec / journey 派生模式。']
263
+ : []),
264
+ ]);
265
+ return {
266
+ title: `Feature Briefs: ${corpus.projectName}`,
267
+ generatedAt: new Date().toISOString(),
268
+ projectName: corpus.projectName,
269
+ summary: [
270
+ `共组织 ${briefs.length} 份 feature brief,优先使用 issue/PR 事实,缺失时回退到 current-spec 与 journey synthesis。`,
271
+ ],
272
+ briefs: briefs.slice(0, 5),
273
+ warnings,
274
+ confidence: currentSpecConfidence(corpus.issues.length + corpus.pullRequests.length > 0, briefs.length),
275
+ };
276
+ }
277
+ function collectCurrentSpecs(projectRoot) {
278
+ const currentSpecs = [];
279
+ const productsDir = path.join(projectRoot, 'specs', 'products');
280
+ if (!fs.existsSync(productsDir)) {
281
+ return currentSpecs;
282
+ }
283
+ for (const entry of fs.readdirSync(productsDir, { withFileTypes: true })) {
284
+ if (!entry.isDirectory()) {
285
+ continue;
286
+ }
287
+ const filePath = path.join(productsDir, entry.name, 'current-spec.md');
288
+ if (!fs.existsSync(filePath)) {
289
+ continue;
290
+ }
291
+ const text = fs.readFileSync(filePath, 'utf-8');
292
+ currentSpecs.push({
293
+ sourceType: 'current-spec',
294
+ label: `${entry.name}/current-spec.md`,
295
+ path: normalizeProjectPath(filePath, projectRoot),
296
+ text,
297
+ productId: entry.name,
298
+ sections: parseMarkdownSections(text),
299
+ });
300
+ }
301
+ return currentSpecs.sort((left, right) => left.productId.localeCompare(right.productId));
302
+ }
303
+ function collectReadmes(projectRoot) {
304
+ const readmes = [];
305
+ for (const candidate of ['README.md', 'readme.md']) {
306
+ const filePath = path.join(projectRoot, candidate);
307
+ if (!fs.existsSync(filePath)) {
308
+ continue;
309
+ }
310
+ readmes.push({
311
+ sourceType: 'readme',
312
+ label: candidate,
313
+ path: normalizeProjectPath(filePath, projectRoot),
314
+ text: fs.readFileSync(filePath, 'utf-8'),
315
+ });
316
+ }
317
+ return readmes;
318
+ }
319
+ function collectLocalDesignDocs(projectRoot) {
320
+ const matches = [];
321
+ walkMarkdownDocs(projectRoot, projectRoot, matches);
322
+ return matches.sort((left, right) => left.path.localeCompare(right.path));
323
+ }
324
+ function walkMarkdownDocs(root, dir, results) {
325
+ if (!fs.existsSync(dir)) {
326
+ return;
327
+ }
328
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
329
+ const fullPath = path.join(dir, entry.name);
330
+ const relative = normalizeProjectPath(fullPath, root);
331
+ if (entry.isDirectory()) {
332
+ if (['node_modules', '.git', 'specs', 'dist', 'coverage', 'bundles'].includes(entry.name)
333
+ || entry.name.startsWith('.reverse-spec')) {
334
+ continue;
335
+ }
336
+ walkMarkdownDocs(root, fullPath, results);
337
+ continue;
338
+ }
339
+ if (!entry.isFile() || !entry.name.toLowerCase().endsWith('.md')) {
340
+ continue;
341
+ }
342
+ const lower = relative.toLowerCase();
343
+ const isRootReadme = lower === 'readme.md';
344
+ const isGeneratedOutput = /(^|\/)\.reverse-spec[^/]*\//i.test(lower)
345
+ || /(^|\/)docs\/adr\//i.test(lower)
346
+ || /(^|\/)feature-briefs\//i.test(lower);
347
+ const isDesignLike = /(design|product|roadmap|journey|ux|persona|brief)/i.test(entry.name)
348
+ || /(^|\/)(design|product|roadmap|journey|ux|persona|brief)s?\//i.test(lower);
349
+ if (!isDesignLike || isRootReadme || isGeneratedOutput) {
350
+ continue;
351
+ }
352
+ results.push({
353
+ sourceType: 'design-doc',
354
+ label: path.basename(fullPath),
355
+ path: relative,
356
+ text: fs.readFileSync(fullPath, 'utf-8'),
357
+ });
358
+ }
359
+ }
360
+ function collectGitHubFacts(projectRoot) {
361
+ const warnings = [];
362
+ const repo = resolveGitHubRepo(projectRoot);
363
+ if (!repo) {
364
+ return {
365
+ issues: [],
366
+ pullRequests: [],
367
+ warnings: ['未解析到 GitHub 远端仓库,跳过 issue/PR 事实接入。'],
368
+ };
369
+ }
370
+ const issues = runGhJson(projectRoot, [
371
+ 'issue',
372
+ 'list',
373
+ '--repo',
374
+ repo,
375
+ '--state',
376
+ 'all',
377
+ '--limit',
378
+ '12',
379
+ '--json',
380
+ 'number,title,body,state,labels,url',
381
+ ], 'issue', warnings);
382
+ const pullRequests = runGhJson(projectRoot, [
383
+ 'pr',
384
+ 'list',
385
+ '--repo',
386
+ repo,
387
+ '--state',
388
+ 'all',
389
+ '--limit',
390
+ '12',
391
+ '--json',
392
+ 'number,title,body,state,labels,url',
393
+ ], 'pull-request', warnings);
394
+ return {
395
+ issues,
396
+ pullRequests,
397
+ warnings,
398
+ };
399
+ }
400
+ function runGhJson(projectRoot, args, sourceType, warnings) {
401
+ const result = spawnSync('gh', args, {
402
+ cwd: projectRoot,
403
+ encoding: 'utf-8',
404
+ });
405
+ if (result.error) {
406
+ warnings.push(`gh CLI 不可用,跳过 GitHub ${sourceType === 'issue' ? 'issue' : 'PR'} 接入。`);
407
+ return [];
408
+ }
409
+ if (result.status !== 0) {
410
+ const stderr = `${result.stderr ?? ''}`.trim();
411
+ warnings.push(`GitHub ${sourceType === 'issue' ? 'issue' : 'PR'} 接入失败: ${stderr || `退出码 ${result.status}`}`);
412
+ return [];
413
+ }
414
+ try {
415
+ const parsed = JSON.parse(result.stdout || '[]');
416
+ return parsed.map((item) => ({
417
+ sourceType,
418
+ number: normalizeNumber(item.number),
419
+ title: `${item.title ?? ''}`.trim(),
420
+ body: `${item.body ?? ''}`.trim(),
421
+ state: `${item.state ?? 'unknown'}`.trim(),
422
+ labels: Array.isArray(item.labels)
423
+ ? item.labels
424
+ .map((label) => {
425
+ if (label && typeof label === 'object') {
426
+ return `${label.name ?? ''}`.trim();
427
+ }
428
+ return `${label ?? ''}`.trim();
429
+ })
430
+ .filter((label) => label.length > 0)
431
+ : [],
432
+ url: typeof item.url === 'string' ? item.url : undefined,
433
+ }));
434
+ }
435
+ catch (error) {
436
+ warnings.push(`GitHub ${sourceType === 'issue' ? 'issue' : 'PR'} 输出解析失败: ${String(error)}`);
437
+ return [];
438
+ }
439
+ }
440
+ function resolveGitHubRepo(projectRoot) {
441
+ const result = spawnSync('git', ['remote', 'get-url', 'origin'], {
442
+ cwd: projectRoot,
443
+ encoding: 'utf-8',
444
+ });
445
+ if (result.status !== 0) {
446
+ return undefined;
447
+ }
448
+ const remoteUrl = `${result.stdout ?? ''}`.trim();
449
+ const match = remoteUrl.match(/github\.com[:/](.+?)\/(.+?)(?:\.git)?$/i);
450
+ if (!match?.[1] || !match[2]) {
451
+ return undefined;
452
+ }
453
+ return `${match[1]}/${match[2]}`;
454
+ }
455
+ function collectRecentCommits(projectRoot, limit) {
456
+ const result = spawnSync('git', ['log', `-${limit}`, '--pretty=format:%H%n%s%n%b%n---END-COMMIT---'], {
457
+ cwd: projectRoot,
458
+ encoding: 'utf-8',
459
+ });
460
+ if (result.status !== 0 || !result.stdout) {
461
+ return [];
462
+ }
463
+ return result.stdout
464
+ .split('\n---END-COMMIT---\n')
465
+ .map((chunk) => chunk.trim())
466
+ .filter((chunk) => chunk.length > 0)
467
+ .map((chunk) => {
468
+ const [sha = '', subject = '', ...bodyLines] = chunk.split('\n');
469
+ return {
470
+ sha: sha.trim(),
471
+ subject: subject.trim(),
472
+ body: bodyLines.join('\n').trim(),
473
+ };
474
+ })
475
+ .filter((entry) => entry.sha.length > 0 && entry.subject.length > 0);
476
+ }
477
+ function collectOverviewParagraphs(corpus) {
478
+ const paragraphs = [];
479
+ for (const spec of corpus.currentSpecs) {
480
+ for (const key of ['产品概述', '概览']) {
481
+ const section = spec.sections.get(key);
482
+ if (!section) {
483
+ continue;
484
+ }
485
+ paragraphs.push(...extractParagraphs(section));
486
+ }
487
+ }
488
+ for (const source of [...corpus.readmes, ...corpus.designDocs]) {
489
+ paragraphs.push(...extractParagraphs(source.text).slice(0, 2));
490
+ }
491
+ return uniqueSorted(paragraphs.filter((paragraph) => paragraph.length >= 20)).slice(0, 6);
492
+ }
493
+ function buildTargetUsers(corpus) {
494
+ const segments = [];
495
+ for (const spec of corpus.currentSpecs) {
496
+ const userSection = spec.sections.get('用户画像与场景');
497
+ if (!userSection) {
498
+ continue;
499
+ }
500
+ const rows = parseFirstMarkdownTable(userSection);
501
+ for (const row of rows) {
502
+ const name = row['角色'] || row['用户'] || row['名称'] || row['persona'] || '';
503
+ const description = row['描述'] || row['说明'] || row['description'] || '';
504
+ const scenarios = splitScenarioText(row['主要使用场景'] || row['场景'] || row['scenario'] || '');
505
+ if (!name.trim()) {
506
+ continue;
507
+ }
508
+ segments.push({
509
+ name: name.trim(),
510
+ description: description.trim() || `${name.trim()} 是该产品的关键使用者。`,
511
+ primaryScenarios: scenarios,
512
+ evidence: [{
513
+ sourceType: 'current-spec',
514
+ label: spec.label,
515
+ path: spec.path,
516
+ excerpt: `${name} | ${description} | ${scenarios.join(' / ')}`,
517
+ confidence: 'high',
518
+ inferred: false,
519
+ }],
520
+ confidence: 'high',
521
+ });
522
+ }
523
+ }
524
+ if (segments.length > 0) {
525
+ return dedupeSegments(segments);
526
+ }
527
+ const readmeParagraph = corpus.readmes.flatMap((source) => extractParagraphs(source.text)).find(Boolean);
528
+ if (!readmeParagraph) {
529
+ return [];
530
+ }
531
+ return [{
532
+ name: '开发者',
533
+ description: firstSentence(readmeParagraph) ?? readmeParagraph,
534
+ primaryScenarios: ['阅读文档、生成规格、理解系统行为'],
535
+ evidence: [{
536
+ sourceType: 'readme',
537
+ label: corpus.readmes[0].label,
538
+ path: corpus.readmes[0].path,
539
+ excerpt: readmeParagraph,
540
+ confidence: 'medium',
541
+ inferred: true,
542
+ }],
543
+ confidence: 'medium',
544
+ }];
545
+ }
546
+ function buildCoreScenarios(corpus, targetUsers) {
547
+ const scenarios = [];
548
+ for (const spec of corpus.currentSpecs) {
549
+ const userSection = spec.sections.get('用户画像与场景');
550
+ if (!userSection) {
551
+ continue;
552
+ }
553
+ const items = extractListItems(userSection);
554
+ for (const item of items) {
555
+ const [titlePart, ...restParts] = item.split(/[::]/);
556
+ const title = titlePart?.trim() || item;
557
+ const summary = restParts.join(':').trim() || item;
558
+ const actors = inferActors(title + summary, targetUsers);
559
+ scenarios.push({
560
+ id: `scenario-${scenarios.length + 1}`,
561
+ title,
562
+ summary,
563
+ actors,
564
+ evidence: [{
565
+ sourceType: 'current-spec',
566
+ label: spec.label,
567
+ path: spec.path,
568
+ excerpt: item,
569
+ confidence: 'high',
570
+ inferred: false,
571
+ }],
572
+ confidence: 'high',
573
+ inferred: false,
574
+ });
575
+ }
576
+ }
577
+ if (scenarios.length === 0) {
578
+ for (const item of [...corpus.issues.slice(0, 2), ...corpus.pullRequests.slice(0, 2)]) {
579
+ scenarios.push({
580
+ id: `scenario-${scenarios.length + 1}`,
581
+ title: item.title,
582
+ summary: firstMeaningfulSentence(item.body) ?? item.title,
583
+ actors: [inferAudience(item.title, targetUsers) ?? targetUsers[0]?.name ?? '使用者'],
584
+ evidence: [toGitHubEvidence(item, item.title, 'medium')],
585
+ confidence: 'medium',
586
+ inferred: true,
587
+ });
588
+ }
589
+ }
590
+ return dedupeScenarios(scenarios).slice(0, 6);
591
+ }
592
+ function parseMarkdownSections(markdown) {
593
+ const sections = new Map();
594
+ const matches = [...markdown.matchAll(/^##\s+(.+)$/gm)];
595
+ for (let index = 0; index < matches.length; index += 1) {
596
+ const current = matches[index];
597
+ const next = matches[index + 1];
598
+ if (!current?.index) {
599
+ continue;
600
+ }
601
+ const rawHeading = current[1]?.trim() ?? '';
602
+ const start = current.index + current[0].length;
603
+ const end = next?.index ?? markdown.length;
604
+ const content = markdown.slice(start, end).trim();
605
+ const normalized = normalizeHeading(rawHeading);
606
+ if (normalized) {
607
+ sections.set(normalized, content);
608
+ }
609
+ }
610
+ return sections;
611
+ }
612
+ function normalizeHeading(heading) {
613
+ return heading
614
+ .replace(/^[0-9]+\.\s*/, '')
615
+ .replace(/^[一二三四五六七八九十]+\.\s*/, '')
616
+ .replace(/[::]\s*$/, '')
617
+ .trim();
618
+ }
619
+ function parseFirstMarkdownTable(content) {
620
+ const lines = content
621
+ .split('\n')
622
+ .map((line) => line.trim())
623
+ .filter((line) => line.startsWith('|'));
624
+ if (lines.length < 3) {
625
+ return [];
626
+ }
627
+ const header = splitMarkdownTableLine(lines[0]);
628
+ const divider = lines[1];
629
+ if (!divider.includes('---')) {
630
+ return [];
631
+ }
632
+ return lines.slice(2).map((line) => {
633
+ const values = splitMarkdownTableLine(line);
634
+ const row = {};
635
+ for (let index = 0; index < header.length; index += 1) {
636
+ row[header[index] ?? `col-${index}`] = values[index] ?? '';
637
+ }
638
+ return row;
639
+ });
640
+ }
641
+ function splitMarkdownTableLine(line) {
642
+ return line
643
+ .split('|')
644
+ .map((segment) => segment.trim())
645
+ .filter((segment) => segment.length > 0);
646
+ }
647
+ function extractListItems(content) {
648
+ return [...content.matchAll(/^(?:[-*]|\d+\.)\s+(.+)$/gm)]
649
+ .map((match) => match[1]?.trim() ?? '')
650
+ .filter((item) => item.length > 0);
651
+ }
652
+ function extractParagraphs(content) {
653
+ return content
654
+ .split(/\n\s*\n/g)
655
+ .map((paragraph) => paragraph.replace(/\n+/g, ' ').trim())
656
+ .filter((paragraph) => paragraph.length > 0
657
+ && !paragraph.startsWith('|')
658
+ && !paragraph.startsWith('##')
659
+ && !paragraph.startsWith('```'));
660
+ }
661
+ function splitScenarioText(value) {
662
+ return value
663
+ .split(/[、,,/]/)
664
+ .map((item) => item.trim())
665
+ .filter((item) => item.length > 0);
666
+ }
667
+ function inferActors(text, users) {
668
+ const matched = users
669
+ .filter((user) => text.includes(user.name) || user.primaryScenarios.some((scenario) => text.includes(scenario)))
670
+ .map((user) => user.name);
671
+ if (matched.length > 0) {
672
+ return uniqueSorted(matched);
673
+ }
674
+ return users[0] ? [users[0].name] : [];
675
+ }
676
+ function inferAudience(title, users) {
677
+ return inferActors(title, users)[0];
678
+ }
679
+ function dedupeSegments(segments) {
680
+ const byName = new Map();
681
+ for (const segment of segments) {
682
+ const existing = byName.get(segment.name);
683
+ if (!existing) {
684
+ byName.set(segment.name, segment);
685
+ continue;
686
+ }
687
+ existing.description = existing.description.length >= segment.description.length
688
+ ? existing.description
689
+ : segment.description;
690
+ existing.primaryScenarios = uniqueSorted([...existing.primaryScenarios, ...segment.primaryScenarios]);
691
+ existing.evidence = uniqueEvidence([...existing.evidence, ...segment.evidence]);
692
+ }
693
+ return [...byName.values()];
694
+ }
695
+ function dedupeScenarios(scenarios) {
696
+ const byTitle = new Map();
697
+ for (const scenario of scenarios) {
698
+ const key = scenario.title.toLowerCase();
699
+ const existing = byTitle.get(key);
700
+ if (!existing) {
701
+ byTitle.set(key, scenario);
702
+ continue;
703
+ }
704
+ existing.summary = existing.summary.length >= scenario.summary.length ? existing.summary : scenario.summary;
705
+ existing.actors = uniqueSorted([...existing.actors, ...scenario.actors]);
706
+ existing.evidence = uniqueEvidence([...existing.evidence, ...scenario.evidence]);
707
+ }
708
+ return [...byTitle.values()];
709
+ }
710
+ function collectEvidenceFromSources(sources, confidence) {
711
+ return sources.slice(0, 3).map((source) => ({
712
+ sourceType: source.sourceType,
713
+ label: source.label,
714
+ path: source.path,
715
+ excerpt: extractParagraphs(source.text)[0] ?? source.text.slice(0, 160).trim(),
716
+ confidence,
717
+ inferred: false,
718
+ }));
719
+ }
720
+ function toGitHubEvidence(item, excerpt, confidence) {
721
+ return {
722
+ sourceType: item.sourceType,
723
+ label: `${item.sourceType === 'issue' ? 'issue' : 'pr'} #${item.number}`,
724
+ path: item.url,
725
+ ref: item.url,
726
+ excerpt,
727
+ confidence,
728
+ inferred: false,
729
+ };
730
+ }
731
+ function currentSpecConfidence(hasCurrentSpec, signalCount) {
732
+ if (hasCurrentSpec && signalCount >= 2) {
733
+ return 'high';
734
+ }
735
+ if (signalCount > 0) {
736
+ return 'medium';
737
+ }
738
+ return 'low';
739
+ }
740
+ function resolveProjectName(projectRoot, currentSpecs, readmes) {
741
+ const currentSpecTitle = currentSpecs[0]?.text.match(/^#\s+(.+)$/m)?.[1]?.trim();
742
+ if (currentSpecTitle) {
743
+ return currentSpecTitle.replace(/^[^—-]+[—-]\s*/, '').replace(/^产品规范活文档[::]?\s*/, '').trim();
744
+ }
745
+ const packageJsonPath = path.join(projectRoot, 'package.json');
746
+ if (fs.existsSync(packageJsonPath)) {
747
+ try {
748
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
749
+ if (pkg.name?.trim()) {
750
+ return pkg.name.trim();
751
+ }
752
+ }
753
+ catch {
754
+ // ignore
755
+ }
756
+ }
757
+ const readmeTitle = readmes[0]?.text.match(/^#\s+(.+)$/m)?.[1]?.trim();
758
+ if (readmeTitle) {
759
+ return readmeTitle;
760
+ }
761
+ return path.basename(projectRoot);
762
+ }
763
+ function firstMeaningfulSentence(text) {
764
+ const normalized = text.replace(/\s+/g, ' ').trim();
765
+ if (!normalized) {
766
+ return undefined;
767
+ }
768
+ const sentence = normalized.split(/(?<=[。.!?])\s+/)[0]?.trim();
769
+ return sentence && sentence.length > 0 ? sentence : normalized;
770
+ }
771
+ function firstSentence(text) {
772
+ return firstMeaningfulSentence(text);
773
+ }
774
+ function slugify(value) {
775
+ const slug = value
776
+ .toLowerCase()
777
+ .replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-')
778
+ .replace(/^-+|-+$/g, '')
779
+ .replace(/-+/g, '-');
780
+ return slug || 'untitled';
781
+ }
782
+ function briefFileName(id, title) {
783
+ return `${id.toLowerCase()}-${slugify(title)}`;
784
+ }
785
+ function normalizeProjectPath(filePath, projectRoot) {
786
+ return path.relative(projectRoot, filePath).split(path.sep).join('/');
787
+ }
788
+ function normalizeNumber(value) {
789
+ if (typeof value === 'number' && Number.isFinite(value)) {
790
+ return value;
791
+ }
792
+ const parsed = Number.parseInt(`${value ?? ''}`, 10);
793
+ return Number.isFinite(parsed) ? parsed : 0;
794
+ }
795
+ function uniqueSorted(values) {
796
+ return [...new Set(values.filter((value) => value.trim().length > 0))].sort((left, right) => left.localeCompare(right, 'zh-Hans-CN'));
797
+ }
798
+ function uniqueEvidence(entries) {
799
+ const seen = new Set();
800
+ const deduped = [];
801
+ for (const entry of entries) {
802
+ const key = [
803
+ entry.sourceType,
804
+ entry.label,
805
+ entry.path ?? '',
806
+ entry.ref ?? '',
807
+ entry.excerpt,
808
+ ].join('|');
809
+ if (seen.has(key)) {
810
+ continue;
811
+ }
812
+ seen.add(key);
813
+ deduped.push(entry);
814
+ }
815
+ return deduped;
816
+ }
817
+ //# sourceMappingURL=product-ux-docs.js.map