spectra-cli 4.1.1

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 (1147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +350 -0
  3. package/dist/adapters/go-adapter.d.ts +38 -0
  4. package/dist/adapters/go-adapter.d.ts.map +1 -0
  5. package/dist/adapters/go-adapter.js +58 -0
  6. package/dist/adapters/go-adapter.js.map +1 -0
  7. package/dist/adapters/index.d.ts +21 -0
  8. package/dist/adapters/index.d.ts.map +1 -0
  9. package/dist/adapters/index.js +36 -0
  10. package/dist/adapters/index.js.map +1 -0
  11. package/dist/adapters/java-adapter.d.ts +39 -0
  12. package/dist/adapters/java-adapter.d.ts.map +1 -0
  13. package/dist/adapters/java-adapter.js +65 -0
  14. package/dist/adapters/java-adapter.js.map +1 -0
  15. package/dist/adapters/language-adapter-registry.d.ts +56 -0
  16. package/dist/adapters/language-adapter-registry.d.ts.map +1 -0
  17. package/dist/adapters/language-adapter-registry.js +110 -0
  18. package/dist/adapters/language-adapter-registry.js.map +1 -0
  19. package/dist/adapters/language-adapter.d.ts +127 -0
  20. package/dist/adapters/language-adapter.d.ts.map +1 -0
  21. package/dist/adapters/language-adapter.js +2 -0
  22. package/dist/adapters/language-adapter.js.map +1 -0
  23. package/dist/adapters/python-adapter.d.ts +61 -0
  24. package/dist/adapters/python-adapter.d.ts.map +1 -0
  25. package/dist/adapters/python-adapter.js +260 -0
  26. package/dist/adapters/python-adapter.js.map +1 -0
  27. package/dist/adapters/tree-sitter-comment-extractor.d.ts +15 -0
  28. package/dist/adapters/tree-sitter-comment-extractor.d.ts.map +1 -0
  29. package/dist/adapters/tree-sitter-comment-extractor.js +105 -0
  30. package/dist/adapters/tree-sitter-comment-extractor.js.map +1 -0
  31. package/dist/adapters/ts-js-adapter.d.ts +38 -0
  32. package/dist/adapters/ts-js-adapter.d.ts.map +1 -0
  33. package/dist/adapters/ts-js-adapter.js +164 -0
  34. package/dist/adapters/ts-js-adapter.js.map +1 -0
  35. package/dist/auth/auth-detector.d.ts +41 -0
  36. package/dist/auth/auth-detector.d.ts.map +1 -0
  37. package/dist/auth/auth-detector.js +324 -0
  38. package/dist/auth/auth-detector.js.map +1 -0
  39. package/dist/auth/cli-proxy.d.ts +35 -0
  40. package/dist/auth/cli-proxy.d.ts.map +1 -0
  41. package/dist/auth/cli-proxy.js +225 -0
  42. package/dist/auth/cli-proxy.js.map +1 -0
  43. package/dist/auth/codex-proxy.d.ts +22 -0
  44. package/dist/auth/codex-proxy.d.ts.map +1 -0
  45. package/dist/auth/codex-proxy.js +199 -0
  46. package/dist/auth/codex-proxy.js.map +1 -0
  47. package/dist/batch/batch-orchestrator.d.ts +214 -0
  48. package/dist/batch/batch-orchestrator.d.ts.map +1 -0
  49. package/dist/batch/batch-orchestrator.js +1552 -0
  50. package/dist/batch/batch-orchestrator.js.map +1 -0
  51. package/dist/batch/batch-readme-generator.d.ts +32 -0
  52. package/dist/batch/batch-readme-generator.d.ts.map +1 -0
  53. package/dist/batch/batch-readme-generator.js +153 -0
  54. package/dist/batch/batch-readme-generator.js.map +1 -0
  55. package/dist/batch/budget-gate.d.ts +107 -0
  56. package/dist/batch/budget-gate.d.ts.map +1 -0
  57. package/dist/batch/budget-gate.js +279 -0
  58. package/dist/batch/budget-gate.js.map +1 -0
  59. package/dist/batch/checkpoint.d.ts +25 -0
  60. package/dist/batch/checkpoint.d.ts.map +1 -0
  61. package/dist/batch/checkpoint.js +68 -0
  62. package/dist/batch/checkpoint.js.map +1 -0
  63. package/dist/batch/cost-summary.d.ts +78 -0
  64. package/dist/batch/cost-summary.d.ts.map +1 -0
  65. package/dist/batch/cost-summary.js +191 -0
  66. package/dist/batch/cost-summary.js.map +1 -0
  67. package/dist/batch/delta-regenerator.d.ts +41 -0
  68. package/dist/batch/delta-regenerator.d.ts.map +1 -0
  69. package/dist/batch/delta-regenerator.js +267 -0
  70. package/dist/batch/delta-regenerator.js.map +1 -0
  71. package/dist/batch/directory-classifier.d.ts +79 -0
  72. package/dist/batch/directory-classifier.d.ts.map +1 -0
  73. package/dist/batch/directory-classifier.js +270 -0
  74. package/dist/batch/directory-classifier.js.map +1 -0
  75. package/dist/batch/language-grouper.d.ts +28 -0
  76. package/dist/batch/language-grouper.d.ts.map +1 -0
  77. package/dist/batch/language-grouper.js +67 -0
  78. package/dist/batch/language-grouper.js.map +1 -0
  79. package/dist/batch/model-override-decision.d.ts +27 -0
  80. package/dist/batch/model-override-decision.d.ts.map +1 -0
  81. package/dist/batch/model-override-decision.js +14 -0
  82. package/dist/batch/model-override-decision.js.map +1 -0
  83. package/dist/batch/module-grouper.d.ts +59 -0
  84. package/dist/batch/module-grouper.d.ts.map +1 -0
  85. package/dist/batch/module-grouper.js +286 -0
  86. package/dist/batch/module-grouper.js.map +1 -0
  87. package/dist/batch/progress-reporter.d.ts +68 -0
  88. package/dist/batch/progress-reporter.d.ts.map +1 -0
  89. package/dist/batch/progress-reporter.js +273 -0
  90. package/dist/batch/progress-reporter.js.map +1 -0
  91. package/dist/batch/readme-graph-section.d.ts +53 -0
  92. package/dist/batch/readme-graph-section.d.ts.map +1 -0
  93. package/dist/batch/readme-graph-section.js +183 -0
  94. package/dist/batch/readme-graph-section.js.map +1 -0
  95. package/dist/cli/commands/auth-status.d.ts +10 -0
  96. package/dist/cli/commands/auth-status.d.ts.map +1 -0
  97. package/dist/cli/commands/auth-status.js +50 -0
  98. package/dist/cli/commands/auth-status.js.map +1 -0
  99. package/dist/cli/commands/batch.d.ts +10 -0
  100. package/dist/cli/commands/batch.d.ts.map +1 -0
  101. package/dist/cli/commands/batch.js +133 -0
  102. package/dist/cli/commands/batch.js.map +1 -0
  103. package/dist/cli/commands/cache.d.ts +13 -0
  104. package/dist/cli/commands/cache.d.ts.map +1 -0
  105. package/dist/cli/commands/cache.js +65 -0
  106. package/dist/cli/commands/cache.js.map +1 -0
  107. package/dist/cli/commands/community.d.ts +10 -0
  108. package/dist/cli/commands/community.d.ts.map +1 -0
  109. package/dist/cli/commands/community.js +92 -0
  110. package/dist/cli/commands/community.js.map +1 -0
  111. package/dist/cli/commands/diff.d.ts +10 -0
  112. package/dist/cli/commands/diff.d.ts.map +1 -0
  113. package/dist/cli/commands/diff.js +49 -0
  114. package/dist/cli/commands/diff.js.map +1 -0
  115. package/dist/cli/commands/direction-audit.d.ts +12 -0
  116. package/dist/cli/commands/direction-audit.d.ts.map +1 -0
  117. package/dist/cli/commands/direction-audit.js +458 -0
  118. package/dist/cli/commands/direction-audit.js.map +1 -0
  119. package/dist/cli/commands/export.d.ts +22 -0
  120. package/dist/cli/commands/export.d.ts.map +1 -0
  121. package/dist/cli/commands/export.js +123 -0
  122. package/dist/cli/commands/export.js.map +1 -0
  123. package/dist/cli/commands/generate.d.ts +10 -0
  124. package/dist/cli/commands/generate.d.ts.map +1 -0
  125. package/dist/cli/commands/generate.js +50 -0
  126. package/dist/cli/commands/generate.js.map +1 -0
  127. package/dist/cli/commands/graph.d.ts +20 -0
  128. package/dist/cli/commands/graph.d.ts.map +1 -0
  129. package/dist/cli/commands/graph.js +189 -0
  130. package/dist/cli/commands/graph.js.map +1 -0
  131. package/dist/cli/commands/init.d.ts +10 -0
  132. package/dist/cli/commands/init.d.ts.map +1 -0
  133. package/dist/cli/commands/init.js +33 -0
  134. package/dist/cli/commands/init.js.map +1 -0
  135. package/dist/cli/commands/install.d.ts +11 -0
  136. package/dist/cli/commands/install.d.ts.map +1 -0
  137. package/dist/cli/commands/install.js +52 -0
  138. package/dist/cli/commands/install.js.map +1 -0
  139. package/dist/cli/commands/mcp-server.d.ts +23 -0
  140. package/dist/cli/commands/mcp-server.d.ts.map +1 -0
  141. package/dist/cli/commands/mcp-server.js +90 -0
  142. package/dist/cli/commands/mcp-server.js.map +1 -0
  143. package/dist/cli/commands/panoramic.d.ts +7 -0
  144. package/dist/cli/commands/panoramic.d.ts.map +1 -0
  145. package/dist/cli/commands/panoramic.js +43 -0
  146. package/dist/cli/commands/panoramic.js.map +1 -0
  147. package/dist/cli/commands/prepare.d.ts +13 -0
  148. package/dist/cli/commands/prepare.d.ts.map +1 -0
  149. package/dist/cli/commands/prepare.js +148 -0
  150. package/dist/cli/commands/prepare.js.map +1 -0
  151. package/dist/cli/commands/query.d.ts +13 -0
  152. package/dist/cli/commands/query.d.ts.map +1 -0
  153. package/dist/cli/commands/query.js +116 -0
  154. package/dist/cli/commands/query.js.map +1 -0
  155. package/dist/cli/commands/watch.d.ts +16 -0
  156. package/dist/cli/commands/watch.d.ts.map +1 -0
  157. package/dist/cli/commands/watch.js +188 -0
  158. package/dist/cli/commands/watch.js.map +1 -0
  159. package/dist/cli/index.d.ts +7 -0
  160. package/dist/cli/index.d.ts.map +1 -0
  161. package/dist/cli/index.js +193 -0
  162. package/dist/cli/index.js.map +1 -0
  163. package/dist/cli/utils/error-handler.d.ts +41 -0
  164. package/dist/cli/utils/error-handler.d.ts.map +1 -0
  165. package/dist/cli/utils/error-handler.js +90 -0
  166. package/dist/cli/utils/error-handler.js.map +1 -0
  167. package/dist/cli/utils/parse-args.d.ts +111 -0
  168. package/dist/cli/utils/parse-args.d.ts.map +1 -0
  169. package/dist/cli/utils/parse-args.js +756 -0
  170. package/dist/cli/utils/parse-args.js.map +1 -0
  171. package/dist/config/project-config.d.ts +49 -0
  172. package/dist/config/project-config.d.ts.map +1 -0
  173. package/dist/config/project-config.js +118 -0
  174. package/dist/config/project-config.js.map +1 -0
  175. package/dist/config/spec-driver-config.d.ts +32 -0
  176. package/dist/config/spec-driver-config.d.ts.map +1 -0
  177. package/dist/config/spec-driver-config.js +91 -0
  178. package/dist/config/spec-driver-config.js.map +1 -0
  179. package/dist/core/ast-analyzer.d.ts +49 -0
  180. package/dist/core/ast-analyzer.d.ts.map +1 -0
  181. package/dist/core/ast-analyzer.js +439 -0
  182. package/dist/core/ast-analyzer.js.map +1 -0
  183. package/dist/core/code-slice-extractor.d.ts +47 -0
  184. package/dist/core/code-slice-extractor.d.ts.map +1 -0
  185. package/dist/core/code-slice-extractor.js +227 -0
  186. package/dist/core/code-slice-extractor.js.map +1 -0
  187. package/dist/core/context-assembler.d.ts +80 -0
  188. package/dist/core/context-assembler.d.ts.map +1 -0
  189. package/dist/core/context-assembler.js +262 -0
  190. package/dist/core/context-assembler.js.map +1 -0
  191. package/dist/core/grammar-manager.d.ts +79 -0
  192. package/dist/core/grammar-manager.d.ts.map +1 -0
  193. package/dist/core/grammar-manager.js +188 -0
  194. package/dist/core/grammar-manager.js.map +1 -0
  195. package/dist/core/llm-client.d.ts +120 -0
  196. package/dist/core/llm-client.d.ts.map +1 -0
  197. package/dist/core/llm-client.js +608 -0
  198. package/dist/core/llm-client.js.map +1 -0
  199. package/dist/core/model-selection.d.ts +50 -0
  200. package/dist/core/model-selection.d.ts.map +1 -0
  201. package/dist/core/model-selection.js +410 -0
  202. package/dist/core/model-selection.js.map +1 -0
  203. package/dist/core/query-mappers/base-mapper.d.ts +22 -0
  204. package/dist/core/query-mappers/base-mapper.d.ts.map +1 -0
  205. package/dist/core/query-mappers/base-mapper.js +2 -0
  206. package/dist/core/query-mappers/base-mapper.js.map +1 -0
  207. package/dist/core/query-mappers/go-mapper.d.ts +46 -0
  208. package/dist/core/query-mappers/go-mapper.d.ts.map +1 -0
  209. package/dist/core/query-mappers/go-mapper.js +477 -0
  210. package/dist/core/query-mappers/go-mapper.js.map +1 -0
  211. package/dist/core/query-mappers/index.d.ts +6 -0
  212. package/dist/core/query-mappers/index.d.ts.map +1 -0
  213. package/dist/core/query-mappers/index.js +5 -0
  214. package/dist/core/query-mappers/index.js.map +1 -0
  215. package/dist/core/query-mappers/java-mapper.d.ts +40 -0
  216. package/dist/core/query-mappers/java-mapper.d.ts.map +1 -0
  217. package/dist/core/query-mappers/java-mapper.js +405 -0
  218. package/dist/core/query-mappers/java-mapper.js.map +1 -0
  219. package/dist/core/query-mappers/python-mapper.d.ts +65 -0
  220. package/dist/core/query-mappers/python-mapper.d.ts.map +1 -0
  221. package/dist/core/query-mappers/python-mapper.js +673 -0
  222. package/dist/core/query-mappers/python-mapper.js.map +1 -0
  223. package/dist/core/query-mappers/typescript-mapper.d.ts +54 -0
  224. package/dist/core/query-mappers/typescript-mapper.d.ts.map +1 -0
  225. package/dist/core/query-mappers/typescript-mapper.js +706 -0
  226. package/dist/core/query-mappers/typescript-mapper.js.map +1 -0
  227. package/dist/core/secret-redactor.d.ts +10 -0
  228. package/dist/core/secret-redactor.d.ts.map +1 -0
  229. package/dist/core/secret-redactor.js +208 -0
  230. package/dist/core/secret-redactor.js.map +1 -0
  231. package/dist/core/single-spec-orchestrator.d.ts +103 -0
  232. package/dist/core/single-spec-orchestrator.d.ts.map +1 -0
  233. package/dist/core/single-spec-orchestrator.js +911 -0
  234. package/dist/core/single-spec-orchestrator.js.map +1 -0
  235. package/dist/core/token-counter.d.ts +48 -0
  236. package/dist/core/token-counter.d.ts.map +1 -0
  237. package/dist/core/token-counter.js +136 -0
  238. package/dist/core/token-counter.js.map +1 -0
  239. package/dist/core/tree-sitter-analyzer.d.ts +62 -0
  240. package/dist/core/tree-sitter-analyzer.d.ts.map +1 -0
  241. package/dist/core/tree-sitter-analyzer.js +229 -0
  242. package/dist/core/tree-sitter-analyzer.js.map +1 -0
  243. package/dist/core/tree-sitter-fallback.d.ts +14 -0
  244. package/dist/core/tree-sitter-fallback.d.ts.map +1 -0
  245. package/dist/core/tree-sitter-fallback.js +423 -0
  246. package/dist/core/tree-sitter-fallback.js.map +1 -0
  247. package/dist/debt-scanner/aggregator/quality-report-patcher.d.ts +22 -0
  248. package/dist/debt-scanner/aggregator/quality-report-patcher.d.ts.map +1 -0
  249. package/dist/debt-scanner/aggregator/quality-report-patcher.js +107 -0
  250. package/dist/debt-scanner/aggregator/quality-report-patcher.js.map +1 -0
  251. package/dist/debt-scanner/aggregator/readme-indexer.d.ts +6 -0
  252. package/dist/debt-scanner/aggregator/readme-indexer.d.ts.map +1 -0
  253. package/dist/debt-scanner/aggregator/readme-indexer.js +52 -0
  254. package/dist/debt-scanner/aggregator/readme-indexer.js.map +1 -0
  255. package/dist/debt-scanner/aggregator/report-builder.d.ts +25 -0
  256. package/dist/debt-scanner/aggregator/report-builder.d.ts.map +1 -0
  257. package/dist/debt-scanner/aggregator/report-builder.js +162 -0
  258. package/dist/debt-scanner/aggregator/report-builder.js.map +1 -0
  259. package/dist/debt-scanner/comments/debt-classifier.d.ts +28 -0
  260. package/dist/debt-scanner/comments/debt-classifier.d.ts.map +1 -0
  261. package/dist/debt-scanner/comments/debt-classifier.js +50 -0
  262. package/dist/debt-scanner/comments/debt-classifier.js.map +1 -0
  263. package/dist/debt-scanner/comments/index.d.ts +32 -0
  264. package/dist/debt-scanner/comments/index.d.ts.map +1 -0
  265. package/dist/debt-scanner/comments/index.js +103 -0
  266. package/dist/debt-scanner/comments/index.js.map +1 -0
  267. package/dist/debt-scanner/comments/symbol-resolver.d.ts +18 -0
  268. package/dist/debt-scanner/comments/symbol-resolver.d.ts.map +1 -0
  269. package/dist/debt-scanner/comments/symbol-resolver.js +18 -0
  270. package/dist/debt-scanner/comments/symbol-resolver.js.map +1 -0
  271. package/dist/debt-scanner/design-docs/doc-discoverer.d.ts +6 -0
  272. package/dist/debt-scanner/design-docs/doc-discoverer.d.ts.map +1 -0
  273. package/dist/debt-scanner/design-docs/doc-discoverer.js +62 -0
  274. package/dist/debt-scanner/design-docs/doc-discoverer.js.map +1 -0
  275. package/dist/debt-scanner/design-docs/index.d.ts +28 -0
  276. package/dist/debt-scanner/design-docs/index.d.ts.map +1 -0
  277. package/dist/debt-scanner/design-docs/index.js +60 -0
  278. package/dist/debt-scanner/design-docs/index.js.map +1 -0
  279. package/dist/debt-scanner/design-docs/llm-topic-inferrer.d.ts +68 -0
  280. package/dist/debt-scanner/design-docs/llm-topic-inferrer.d.ts.map +1 -0
  281. package/dist/debt-scanner/design-docs/llm-topic-inferrer.js +151 -0
  282. package/dist/debt-scanner/design-docs/llm-topic-inferrer.js.map +1 -0
  283. package/dist/debt-scanner/design-docs/markdown-sections.d.ts +24 -0
  284. package/dist/debt-scanner/design-docs/markdown-sections.d.ts.map +1 -0
  285. package/dist/debt-scanner/design-docs/markdown-sections.js +92 -0
  286. package/dist/debt-scanner/design-docs/markdown-sections.js.map +1 -0
  287. package/dist/debt-scanner/design-docs/rule-detector.d.ts +18 -0
  288. package/dist/debt-scanner/design-docs/rule-detector.d.ts.map +1 -0
  289. package/dist/debt-scanner/design-docs/rule-detector.js +46 -0
  290. package/dist/debt-scanner/design-docs/rule-detector.js.map +1 -0
  291. package/dist/debt-scanner/index.d.ts +43 -0
  292. package/dist/debt-scanner/index.d.ts.map +1 -0
  293. package/dist/debt-scanner/index.js +177 -0
  294. package/dist/debt-scanner/index.js.map +1 -0
  295. package/dist/debt-scanner/llm-clients.d.ts +33 -0
  296. package/dist/debt-scanner/llm-clients.d.ts.map +1 -0
  297. package/dist/debt-scanner/llm-clients.js +78 -0
  298. package/dist/debt-scanner/llm-clients.js.map +1 -0
  299. package/dist/debt-scanner/types.d.ts +97 -0
  300. package/dist/debt-scanner/types.d.ts.map +1 -0
  301. package/dist/debt-scanner/types.js +7 -0
  302. package/dist/debt-scanner/types.js.map +1 -0
  303. package/dist/diff/drift-orchestrator.d.ts +25 -0
  304. package/dist/diff/drift-orchestrator.d.ts.map +1 -0
  305. package/dist/diff/drift-orchestrator.js +248 -0
  306. package/dist/diff/drift-orchestrator.js.map +1 -0
  307. package/dist/diff/noise-filter.d.ts +27 -0
  308. package/dist/diff/noise-filter.d.ts.map +1 -0
  309. package/dist/diff/noise-filter.js +129 -0
  310. package/dist/diff/noise-filter.js.map +1 -0
  311. package/dist/diff/semantic-diff.d.ts +12 -0
  312. package/dist/diff/semantic-diff.d.ts.map +1 -0
  313. package/dist/diff/semantic-diff.js +94 -0
  314. package/dist/diff/semantic-diff.js.map +1 -0
  315. package/dist/diff/structural-diff.d.ts +16 -0
  316. package/dist/diff/structural-diff.d.ts.map +1 -0
  317. package/dist/diff/structural-diff.js +171 -0
  318. package/dist/diff/structural-diff.js.map +1 -0
  319. package/dist/extraction/artifact-classifier.d.ts +19 -0
  320. package/dist/extraction/artifact-classifier.d.ts.map +1 -0
  321. package/dist/extraction/artifact-classifier.js +104 -0
  322. package/dist/extraction/artifact-classifier.js.map +1 -0
  323. package/dist/extraction/extraction-cache.d.ts +32 -0
  324. package/dist/extraction/extraction-cache.d.ts.map +1 -0
  325. package/dist/extraction/extraction-cache.js +117 -0
  326. package/dist/extraction/extraction-cache.js.map +1 -0
  327. package/dist/extraction/extraction-pipeline.d.ts +44 -0
  328. package/dist/extraction/extraction-pipeline.d.ts.map +1 -0
  329. package/dist/extraction/extraction-pipeline.js +286 -0
  330. package/dist/extraction/extraction-pipeline.js.map +1 -0
  331. package/dist/extraction/extraction-types.d.ts +180 -0
  332. package/dist/extraction/extraction-types.d.ts.map +1 -0
  333. package/dist/extraction/extraction-types.js +63 -0
  334. package/dist/extraction/extraction-types.js.map +1 -0
  335. package/dist/extraction/image-extractor.d.ts +21 -0
  336. package/dist/extraction/image-extractor.d.ts.map +1 -0
  337. package/dist/extraction/image-extractor.js +211 -0
  338. package/dist/extraction/image-extractor.js.map +1 -0
  339. package/dist/extraction/index.d.ts +8 -0
  340. package/dist/extraction/index.d.ts.map +1 -0
  341. package/dist/extraction/index.js +6 -0
  342. package/dist/extraction/index.js.map +1 -0
  343. package/dist/extraction/markdown-extractor.d.ts +11 -0
  344. package/dist/extraction/markdown-extractor.d.ts.map +1 -0
  345. package/dist/extraction/markdown-extractor.js +212 -0
  346. package/dist/extraction/markdown-extractor.js.map +1 -0
  347. package/dist/extraction/openapi-extractor.d.ts +10 -0
  348. package/dist/extraction/openapi-extractor.d.ts.map +1 -0
  349. package/dist/extraction/openapi-extractor.js +449 -0
  350. package/dist/extraction/openapi-extractor.js.map +1 -0
  351. package/dist/generator/frontmatter.d.ts +58 -0
  352. package/dist/generator/frontmatter.d.ts.map +1 -0
  353. package/dist/generator/frontmatter.js +100 -0
  354. package/dist/generator/frontmatter.js.map +1 -0
  355. package/dist/generator/index-generator.d.ts +27 -0
  356. package/dist/generator/index-generator.d.ts.map +1 -0
  357. package/dist/generator/index-generator.js +129 -0
  358. package/dist/generator/index-generator.js.map +1 -0
  359. package/dist/generator/mermaid-class-diagram.d.ts +14 -0
  360. package/dist/generator/mermaid-class-diagram.d.ts.map +1 -0
  361. package/dist/generator/mermaid-class-diagram.js +115 -0
  362. package/dist/generator/mermaid-class-diagram.js.map +1 -0
  363. package/dist/generator/mermaid-dependency-graph.d.ts +15 -0
  364. package/dist/generator/mermaid-dependency-graph.d.ts.map +1 -0
  365. package/dist/generator/mermaid-dependency-graph.js +84 -0
  366. package/dist/generator/mermaid-dependency-graph.js.map +1 -0
  367. package/dist/generator/spec-renderer.d.ts +24 -0
  368. package/dist/generator/spec-renderer.d.ts.map +1 -0
  369. package/dist/generator/spec-renderer.js +110 -0
  370. package/dist/generator/spec-renderer.js.map +1 -0
  371. package/dist/graph/dependency-graph.d.ts +24 -0
  372. package/dist/graph/dependency-graph.d.ts.map +1 -0
  373. package/dist/graph/dependency-graph.js +206 -0
  374. package/dist/graph/dependency-graph.js.map +1 -0
  375. package/dist/graph/directory-graph.d.ts +16 -0
  376. package/dist/graph/directory-graph.d.ts.map +1 -0
  377. package/dist/graph/directory-graph.js +281 -0
  378. package/dist/graph/directory-graph.js.map +1 -0
  379. package/dist/graph/mermaid-renderer.d.ts +22 -0
  380. package/dist/graph/mermaid-renderer.d.ts.map +1 -0
  381. package/dist/graph/mermaid-renderer.js +133 -0
  382. package/dist/graph/mermaid-renderer.js.map +1 -0
  383. package/dist/graph/topological-sort.d.ts +31 -0
  384. package/dist/graph/topological-sort.d.ts.map +1 -0
  385. package/dist/graph/topological-sort.js +167 -0
  386. package/dist/graph/topological-sort.js.map +1 -0
  387. package/dist/hooks/git-hook-installer.d.ts +37 -0
  388. package/dist/hooks/git-hook-installer.d.ts.map +1 -0
  389. package/dist/hooks/git-hook-installer.js +136 -0
  390. package/dist/hooks/git-hook-installer.js.map +1 -0
  391. package/dist/hooks/hook-installer.d.ts +39 -0
  392. package/dist/hooks/hook-installer.d.ts.map +1 -0
  393. package/dist/hooks/hook-installer.js +164 -0
  394. package/dist/hooks/hook-installer.js.map +1 -0
  395. package/dist/installer/skill-installer.d.ts +63 -0
  396. package/dist/installer/skill-installer.d.ts.map +1 -0
  397. package/dist/installer/skill-installer.js +203 -0
  398. package/dist/installer/skill-installer.js.map +1 -0
  399. package/dist/installer/skill-templates.d.ts +19 -0
  400. package/dist/installer/skill-templates.d.ts.map +1 -0
  401. package/dist/installer/skill-templates.js +42 -0
  402. package/dist/installer/skill-templates.js.map +1 -0
  403. package/dist/mcp/graph-tools.d.ts +17 -0
  404. package/dist/mcp/graph-tools.d.ts.map +1 -0
  405. package/dist/mcp/graph-tools.js +269 -0
  406. package/dist/mcp/graph-tools.js.map +1 -0
  407. package/dist/mcp/index.d.ts +10 -0
  408. package/dist/mcp/index.d.ts.map +1 -0
  409. package/dist/mcp/index.js +18 -0
  410. package/dist/mcp/index.js.map +1 -0
  411. package/dist/mcp/server.d.ts +10 -0
  412. package/dist/mcp/server.d.ts.map +1 -0
  413. package/dist/mcp/server.js +235 -0
  414. package/dist/mcp/server.js.map +1 -0
  415. package/dist/models/code-skeleton.d.ts +394 -0
  416. package/dist/models/code-skeleton.d.ts.map +1 -0
  417. package/dist/models/code-skeleton.js +119 -0
  418. package/dist/models/code-skeleton.js.map +1 -0
  419. package/dist/models/dependency-graph.d.ts +172 -0
  420. package/dist/models/dependency-graph.d.ts.map +1 -0
  421. package/dist/models/dependency-graph.js +44 -0
  422. package/dist/models/dependency-graph.js.map +1 -0
  423. package/dist/models/drift-item.d.ts +104 -0
  424. package/dist/models/drift-item.d.ts.map +1 -0
  425. package/dist/models/drift-item.js +38 -0
  426. package/dist/models/drift-item.js.map +1 -0
  427. package/dist/models/module-spec.d.ts +1905 -0
  428. package/dist/models/module-spec.d.ts.map +1 -0
  429. package/dist/models/module-spec.js +272 -0
  430. package/dist/models/module-spec.js.map +1 -0
  431. package/dist/panoramic/abstract-registry.d.ts +87 -0
  432. package/dist/panoramic/abstract-registry.d.ts.map +1 -0
  433. package/dist/panoramic/abstract-registry.js +88 -0
  434. package/dist/panoramic/abstract-registry.js.map +1 -0
  435. package/dist/panoramic/anchoring/chunker.d.ts +34 -0
  436. package/dist/panoramic/anchoring/chunker.d.ts.map +1 -0
  437. package/dist/panoramic/anchoring/chunker.js +274 -0
  438. package/dist/panoramic/anchoring/chunker.js.map +1 -0
  439. package/dist/panoramic/anchoring/edge-builder.d.ts +53 -0
  440. package/dist/panoramic/anchoring/edge-builder.d.ts.map +1 -0
  441. package/dist/panoramic/anchoring/edge-builder.js +183 -0
  442. package/dist/panoramic/anchoring/edge-builder.js.map +1 -0
  443. package/dist/panoramic/anchoring/embedding-provider.d.ts +51 -0
  444. package/dist/panoramic/anchoring/embedding-provider.d.ts.map +1 -0
  445. package/dist/panoramic/anchoring/embedding-provider.js +7 -0
  446. package/dist/panoramic/anchoring/embedding-provider.js.map +1 -0
  447. package/dist/panoramic/anchoring/index.d.ts +73 -0
  448. package/dist/panoramic/anchoring/index.d.ts.map +1 -0
  449. package/dist/panoramic/anchoring/index.js +91 -0
  450. package/dist/panoramic/anchoring/index.js.map +1 -0
  451. package/dist/panoramic/anchoring/providers/factory.d.ts +35 -0
  452. package/dist/panoramic/anchoring/providers/factory.d.ts.map +1 -0
  453. package/dist/panoramic/anchoring/providers/factory.js +33 -0
  454. package/dist/panoramic/anchoring/providers/factory.js.map +1 -0
  455. package/dist/panoramic/anchoring/providers/local-provider.d.ts +48 -0
  456. package/dist/panoramic/anchoring/providers/local-provider.d.ts.map +1 -0
  457. package/dist/panoramic/anchoring/providers/local-provider.js +145 -0
  458. package/dist/panoramic/anchoring/providers/local-provider.js.map +1 -0
  459. package/dist/panoramic/anchoring/providers/openai-provider.d.ts +45 -0
  460. package/dist/panoramic/anchoring/providers/openai-provider.d.ts.map +1 -0
  461. package/dist/panoramic/anchoring/providers/openai-provider.js +78 -0
  462. package/dist/panoramic/anchoring/providers/openai-provider.js.map +1 -0
  463. package/dist/panoramic/anchoring/similarity.d.ts +37 -0
  464. package/dist/panoramic/anchoring/similarity.d.ts.map +1 -0
  465. package/dist/panoramic/anchoring/similarity.js +75 -0
  466. package/dist/panoramic/anchoring/similarity.js.map +1 -0
  467. package/dist/panoramic/api-surface/endpoint-utils.d.ts +15 -0
  468. package/dist/panoramic/api-surface/endpoint-utils.d.ts.map +1 -0
  469. package/dist/panoramic/api-surface/endpoint-utils.js +145 -0
  470. package/dist/panoramic/api-surface/endpoint-utils.js.map +1 -0
  471. package/dist/panoramic/api-surface/express-extractor.d.ts +3 -0
  472. package/dist/panoramic/api-surface/express-extractor.d.ts.map +1 -0
  473. package/dist/panoramic/api-surface/express-extractor.js +288 -0
  474. package/dist/panoramic/api-surface/express-extractor.js.map +1 -0
  475. package/dist/panoramic/api-surface/fastapi-extractor.d.ts +6 -0
  476. package/dist/panoramic/api-surface/fastapi-extractor.d.ts.map +1 -0
  477. package/dist/panoramic/api-surface/fastapi-extractor.js +287 -0
  478. package/dist/panoramic/api-surface/fastapi-extractor.js.map +1 -0
  479. package/dist/panoramic/api-surface/framework-introspection.d.ts +3 -0
  480. package/dist/panoramic/api-surface/framework-introspection.d.ts.map +1 -0
  481. package/dist/panoramic/api-surface/framework-introspection.js +189 -0
  482. package/dist/panoramic/api-surface/framework-introspection.js.map +1 -0
  483. package/dist/panoramic/api-surface/index.d.ts +13 -0
  484. package/dist/panoramic/api-surface/index.d.ts.map +1 -0
  485. package/dist/panoramic/api-surface/index.js +238 -0
  486. package/dist/panoramic/api-surface/index.js.map +1 -0
  487. package/dist/panoramic/api-surface/openapi-extractor.d.ts +3 -0
  488. package/dist/panoramic/api-surface/openapi-extractor.d.ts.map +1 -0
  489. package/dist/panoramic/api-surface/openapi-extractor.js +247 -0
  490. package/dist/panoramic/api-surface/openapi-extractor.js.map +1 -0
  491. package/dist/panoramic/api-surface/types.d.ts +140 -0
  492. package/dist/panoramic/api-surface/types.d.ts.map +1 -0
  493. package/dist/panoramic/api-surface/types.js +7 -0
  494. package/dist/panoramic/api-surface/types.js.map +1 -0
  495. package/dist/panoramic/api-surface/utils.d.ts +29 -0
  496. package/dist/panoramic/api-surface/utils.d.ts.map +1 -0
  497. package/dist/panoramic/api-surface/utils.js +340 -0
  498. package/dist/panoramic/api-surface/utils.js.map +1 -0
  499. package/dist/panoramic/batch-project-docs.d.ts +101 -0
  500. package/dist/panoramic/batch-project-docs.d.ts.map +1 -0
  501. package/dist/panoramic/batch-project-docs.js +616 -0
  502. package/dist/panoramic/batch-project-docs.js.map +1 -0
  503. package/dist/panoramic/builders/architecture-ir-builder.d.ts +19 -0
  504. package/dist/panoramic/builders/architecture-ir-builder.d.ts.map +1 -0
  505. package/dist/panoramic/builders/architecture-ir-builder.js +561 -0
  506. package/dist/panoramic/builders/architecture-ir-builder.js.map +1 -0
  507. package/dist/panoramic/builders/architecture-ir-mermaid-adapter.d.ts +6 -0
  508. package/dist/panoramic/builders/architecture-ir-mermaid-adapter.d.ts.map +1 -0
  509. package/dist/panoramic/builders/architecture-ir-mermaid-adapter.js +98 -0
  510. package/dist/panoramic/builders/architecture-ir-mermaid-adapter.js.map +1 -0
  511. package/dist/panoramic/builders/component-view-builder.d.ts +38 -0
  512. package/dist/panoramic/builders/component-view-builder.d.ts.map +1 -0
  513. package/dist/panoramic/builders/component-view-builder.js +694 -0
  514. package/dist/panoramic/builders/component-view-builder.js.map +1 -0
  515. package/dist/panoramic/builders/doc-graph-builder.d.ts +179 -0
  516. package/dist/panoramic/builders/doc-graph-builder.d.ts.map +1 -0
  517. package/dist/panoramic/builders/doc-graph-builder.js +546 -0
  518. package/dist/panoramic/builders/doc-graph-builder.js.map +1 -0
  519. package/dist/panoramic/builders/dynamic-scenarios-builder.d.ts +38 -0
  520. package/dist/panoramic/builders/dynamic-scenarios-builder.d.ts.map +1 -0
  521. package/dist/panoramic/builders/dynamic-scenarios-builder.js +361 -0
  522. package/dist/panoramic/builders/dynamic-scenarios-builder.js.map +1 -0
  523. package/dist/panoramic/cache/cache-key-builder.d.ts +25 -0
  524. package/dist/panoramic/cache/cache-key-builder.d.ts.map +1 -0
  525. package/dist/panoramic/cache/cache-key-builder.js +119 -0
  526. package/dist/panoramic/cache/cache-key-builder.js.map +1 -0
  527. package/dist/panoramic/cache/cache-manager.d.ts +58 -0
  528. package/dist/panoramic/cache/cache-manager.d.ts.map +1 -0
  529. package/dist/panoramic/cache/cache-manager.js +170 -0
  530. package/dist/panoramic/cache/cache-manager.js.map +1 -0
  531. package/dist/panoramic/cache/content-hasher.d.ts +47 -0
  532. package/dist/panoramic/cache/content-hasher.d.ts.map +1 -0
  533. package/dist/panoramic/cache/content-hasher.js +89 -0
  534. package/dist/panoramic/cache/content-hasher.js.map +1 -0
  535. package/dist/panoramic/cache/index.d.ts +10 -0
  536. package/dist/panoramic/cache/index.d.ts.map +1 -0
  537. package/dist/panoramic/cache/index.js +13 -0
  538. package/dist/panoramic/cache/index.js.map +1 -0
  539. package/dist/panoramic/cache/manifest-manager.d.ts +83 -0
  540. package/dist/panoramic/cache/manifest-manager.d.ts.map +1 -0
  541. package/dist/panoramic/cache/manifest-manager.js +119 -0
  542. package/dist/panoramic/cache/manifest-manager.js.map +1 -0
  543. package/dist/panoramic/cache/schemas.d.ts +199 -0
  544. package/dist/panoramic/cache/schemas.d.ts.map +1 -0
  545. package/dist/panoramic/cache/schemas.js +53 -0
  546. package/dist/panoramic/cache/schemas.js.map +1 -0
  547. package/dist/panoramic/cluster-orchestrator.d.ts +278 -0
  548. package/dist/panoramic/cluster-orchestrator.d.ts.map +1 -0
  549. package/dist/panoramic/cluster-orchestrator.js +531 -0
  550. package/dist/panoramic/cluster-orchestrator.js.map +1 -0
  551. package/dist/panoramic/community/community-detector.d.ts +41 -0
  552. package/dist/panoramic/community/community-detector.d.ts.map +1 -0
  553. package/dist/panoramic/community/community-detector.js +190 -0
  554. package/dist/panoramic/community/community-detector.js.map +1 -0
  555. package/dist/panoramic/community/god-node-analyzer.d.ts +28 -0
  556. package/dist/panoramic/community/god-node-analyzer.d.ts.map +1 -0
  557. package/dist/panoramic/community/god-node-analyzer.js +91 -0
  558. package/dist/panoramic/community/god-node-analyzer.js.map +1 -0
  559. package/dist/panoramic/community/graph-report-generator.d.ts +31 -0
  560. package/dist/panoramic/community/graph-report-generator.d.ts.map +1 -0
  561. package/dist/panoramic/community/graph-report-generator.js +98 -0
  562. package/dist/panoramic/community/graph-report-generator.js.map +1 -0
  563. package/dist/panoramic/community/index.d.ts +31 -0
  564. package/dist/panoramic/community/index.d.ts.map +1 -0
  565. package/dist/panoramic/community/index.js +63 -0
  566. package/dist/panoramic/community/index.js.map +1 -0
  567. package/dist/panoramic/community/surprising-edges.d.ts +42 -0
  568. package/dist/panoramic/community/surprising-edges.d.ts.map +1 -0
  569. package/dist/panoramic/community/surprising-edges.js +154 -0
  570. package/dist/panoramic/community/surprising-edges.js.map +1 -0
  571. package/dist/panoramic/cross-reference-index.d.ts +4 -0
  572. package/dist/panoramic/cross-reference-index.d.ts.map +1 -0
  573. package/dist/panoramic/cross-reference-index.js +201 -0
  574. package/dist/panoramic/cross-reference-index.js.map +1 -0
  575. package/dist/panoramic/exporters/architecture-ir-exporters.d.ts +7 -0
  576. package/dist/panoramic/exporters/architecture-ir-exporters.d.ts.map +1 -0
  577. package/dist/panoramic/exporters/architecture-ir-exporters.js +183 -0
  578. package/dist/panoramic/exporters/architecture-ir-exporters.js.map +1 -0
  579. package/dist/panoramic/exporters/export-types.d.ts +33 -0
  580. package/dist/panoramic/exporters/export-types.d.ts.map +1 -0
  581. package/dist/panoramic/exporters/export-types.js +7 -0
  582. package/dist/panoramic/exporters/export-types.js.map +1 -0
  583. package/dist/panoramic/exporters/html-exporter.d.ts +83 -0
  584. package/dist/panoramic/exporters/html-exporter.d.ts.map +1 -0
  585. package/dist/panoramic/exporters/html-exporter.js +224 -0
  586. package/dist/panoramic/exporters/html-exporter.js.map +1 -0
  587. package/dist/panoramic/exporters/html-template.d.ts +32 -0
  588. package/dist/panoramic/exporters/html-template.d.ts.map +1 -0
  589. package/dist/panoramic/exporters/html-template.js +737 -0
  590. package/dist/panoramic/exporters/html-template.js.map +1 -0
  591. package/dist/panoramic/exporters/obsidian-exporter.d.ts +67 -0
  592. package/dist/panoramic/exporters/obsidian-exporter.d.ts.map +1 -0
  593. package/dist/panoramic/exporters/obsidian-exporter.js +333 -0
  594. package/dist/panoramic/exporters/obsidian-exporter.js.map +1 -0
  595. package/dist/panoramic/generator-registry.d.ts +86 -0
  596. package/dist/panoramic/generator-registry.d.ts.map +1 -0
  597. package/dist/panoramic/generator-registry.js +194 -0
  598. package/dist/panoramic/generator-registry.js.map +1 -0
  599. package/dist/panoramic/generators/architecture-ir-generator.d.ts +36 -0
  600. package/dist/panoramic/generators/architecture-ir-generator.d.ts.map +1 -0
  601. package/dist/panoramic/generators/architecture-ir-generator.js +51 -0
  602. package/dist/panoramic/generators/architecture-ir-generator.js.map +1 -0
  603. package/dist/panoramic/generators/architecture-overview-generator.d.ts +31 -0
  604. package/dist/panoramic/generators/architecture-overview-generator.d.ts.map +1 -0
  605. package/dist/panoramic/generators/architecture-overview-generator.js +454 -0
  606. package/dist/panoramic/generators/architecture-overview-generator.js.map +1 -0
  607. package/dist/panoramic/generators/config-reference-generator.d.ts +78 -0
  608. package/dist/panoramic/generators/config-reference-generator.d.ts.map +1 -0
  609. package/dist/panoramic/generators/config-reference-generator.js +201 -0
  610. package/dist/panoramic/generators/config-reference-generator.js.map +1 -0
  611. package/dist/panoramic/generators/cross-package-analyzer.d.ts +112 -0
  612. package/dist/panoramic/generators/cross-package-analyzer.d.ts.map +1 -0
  613. package/dist/panoramic/generators/cross-package-analyzer.js +258 -0
  614. package/dist/panoramic/generators/cross-package-analyzer.js.map +1 -0
  615. package/dist/panoramic/generators/data-model-generator.d.ts +528 -0
  616. package/dist/panoramic/generators/data-model-generator.d.ts.map +1 -0
  617. package/dist/panoramic/generators/data-model-generator.js +674 -0
  618. package/dist/panoramic/generators/data-model-generator.js.map +1 -0
  619. package/dist/panoramic/generators/event-surface-generator.d.ts +52 -0
  620. package/dist/panoramic/generators/event-surface-generator.d.ts.map +1 -0
  621. package/dist/panoramic/generators/event-surface-generator.js +634 -0
  622. package/dist/panoramic/generators/event-surface-generator.js.map +1 -0
  623. package/dist/panoramic/generators/interface-surface-generator.d.ts +50 -0
  624. package/dist/panoramic/generators/interface-surface-generator.d.ts.map +1 -0
  625. package/dist/panoramic/generators/interface-surface-generator.js +393 -0
  626. package/dist/panoramic/generators/interface-surface-generator.js.map +1 -0
  627. package/dist/panoramic/generators/mock-readme-generator.d.ts +90 -0
  628. package/dist/panoramic/generators/mock-readme-generator.d.ts.map +1 -0
  629. package/dist/panoramic/generators/mock-readme-generator.js +113 -0
  630. package/dist/panoramic/generators/mock-readme-generator.js.map +1 -0
  631. package/dist/panoramic/generators/pattern-hints-generator.d.ts +28 -0
  632. package/dist/panoramic/generators/pattern-hints-generator.d.ts.map +1 -0
  633. package/dist/panoramic/generators/pattern-hints-generator.js +170 -0
  634. package/dist/panoramic/generators/pattern-hints-generator.js.map +1 -0
  635. package/dist/panoramic/generators/runtime-topology-generator.d.ts +77 -0
  636. package/dist/panoramic/generators/runtime-topology-generator.d.ts.map +1 -0
  637. package/dist/panoramic/generators/runtime-topology-generator.js +679 -0
  638. package/dist/panoramic/generators/runtime-topology-generator.js.map +1 -0
  639. package/dist/panoramic/generators/troubleshooting-generator.d.ts +51 -0
  640. package/dist/panoramic/generators/troubleshooting-generator.d.ts.map +1 -0
  641. package/dist/panoramic/generators/troubleshooting-generator.js +464 -0
  642. package/dist/panoramic/generators/troubleshooting-generator.js.map +1 -0
  643. package/dist/panoramic/generators/workspace-index-generator.d.ts +148 -0
  644. package/dist/panoramic/generators/workspace-index-generator.d.ts.map +1 -0
  645. package/dist/panoramic/generators/workspace-index-generator.js +500 -0
  646. package/dist/panoramic/generators/workspace-index-generator.js.map +1 -0
  647. package/dist/panoramic/graph/confidence-mapper.d.ts +39 -0
  648. package/dist/panoramic/graph/confidence-mapper.d.ts.map +1 -0
  649. package/dist/panoramic/graph/confidence-mapper.js +55 -0
  650. package/dist/panoramic/graph/confidence-mapper.js.map +1 -0
  651. package/dist/panoramic/graph/graph-builder.d.ts +33 -0
  652. package/dist/panoramic/graph/graph-builder.d.ts.map +1 -0
  653. package/dist/panoramic/graph/graph-builder.js +382 -0
  654. package/dist/panoramic/graph/graph-builder.js.map +1 -0
  655. package/dist/panoramic/graph/graph-paths.d.ts +13 -0
  656. package/dist/panoramic/graph/graph-paths.d.ts.map +1 -0
  657. package/dist/panoramic/graph/graph-paths.js +16 -0
  658. package/dist/panoramic/graph/graph-paths.js.map +1 -0
  659. package/dist/panoramic/graph/graph-query.d.ts +226 -0
  660. package/dist/panoramic/graph/graph-query.d.ts.map +1 -0
  661. package/dist/panoramic/graph/graph-query.js +571 -0
  662. package/dist/panoramic/graph/graph-query.js.map +1 -0
  663. package/dist/panoramic/graph/graph-types.d.ts +156 -0
  664. package/dist/panoramic/graph/graph-types.d.ts.map +1 -0
  665. package/dist/panoramic/graph/graph-types.js +10 -0
  666. package/dist/panoramic/graph/graph-types.js.map +1 -0
  667. package/dist/panoramic/graph/index.d.ts +6 -0
  668. package/dist/panoramic/graph/index.d.ts.map +1 -0
  669. package/dist/panoramic/graph/index.js +8 -0
  670. package/dist/panoramic/graph/index.js.map +1 -0
  671. package/dist/panoramic/hyperedges/constants.d.ts +16 -0
  672. package/dist/panoramic/hyperedges/constants.d.ts.map +1 -0
  673. package/dist/panoramic/hyperedges/constants.js +13 -0
  674. package/dist/panoramic/hyperedges/constants.js.map +1 -0
  675. package/dist/panoramic/hyperedges/extractor.d.ts +80 -0
  676. package/dist/panoramic/hyperedges/extractor.d.ts.map +1 -0
  677. package/dist/panoramic/hyperedges/extractor.js +133 -0
  678. package/dist/panoramic/hyperedges/extractor.js.map +1 -0
  679. package/dist/panoramic/hyperedges/index.d.ts +12 -0
  680. package/dist/panoramic/hyperedges/index.d.ts.map +1 -0
  681. package/dist/panoramic/hyperedges/index.js +19 -0
  682. package/dist/panoramic/hyperedges/index.js.map +1 -0
  683. package/dist/panoramic/hyperedges/prompt.d.ts +30 -0
  684. package/dist/panoramic/hyperedges/prompt.d.ts.map +1 -0
  685. package/dist/panoramic/hyperedges/prompt.js +88 -0
  686. package/dist/panoramic/hyperedges/prompt.js.map +1 -0
  687. package/dist/panoramic/hyperedges/schema.d.ts +91 -0
  688. package/dist/panoramic/hyperedges/schema.d.ts.map +1 -0
  689. package/dist/panoramic/hyperedges/schema.js +52 -0
  690. package/dist/panoramic/hyperedges/schema.js.map +1 -0
  691. package/dist/panoramic/index.d.ts +17 -0
  692. package/dist/panoramic/index.d.ts.map +1 -0
  693. package/dist/panoramic/index.js +22 -0
  694. package/dist/panoramic/index.js.map +1 -0
  695. package/dist/panoramic/interfaces.d.ts +243 -0
  696. package/dist/panoramic/interfaces.d.ts.map +1 -0
  697. package/dist/panoramic/interfaces.js +130 -0
  698. package/dist/panoramic/interfaces.js.map +1 -0
  699. package/dist/panoramic/internal.d.ts +67 -0
  700. package/dist/panoramic/internal.d.ts.map +1 -0
  701. package/dist/panoramic/internal.js +93 -0
  702. package/dist/panoramic/internal.js.map +1 -0
  703. package/dist/panoramic/models/architecture-ir-model.d.ts +92 -0
  704. package/dist/panoramic/models/architecture-ir-model.d.ts.map +1 -0
  705. package/dist/panoramic/models/architecture-ir-model.js +14 -0
  706. package/dist/panoramic/models/architecture-ir-model.js.map +1 -0
  707. package/dist/panoramic/models/architecture-overview-model.d.ts +77 -0
  708. package/dist/panoramic/models/architecture-overview-model.d.ts.map +1 -0
  709. package/dist/panoramic/models/architecture-overview-model.js +31 -0
  710. package/dist/panoramic/models/architecture-overview-model.js.map +1 -0
  711. package/dist/panoramic/models/component-view-model.d.ts +127 -0
  712. package/dist/panoramic/models/component-view-model.d.ts.map +1 -0
  713. package/dist/panoramic/models/component-view-model.js +65 -0
  714. package/dist/panoramic/models/component-view-model.js.map +1 -0
  715. package/dist/panoramic/models/docs-bundle-profiles.d.ts +4 -0
  716. package/dist/panoramic/models/docs-bundle-profiles.d.ts.map +1 -0
  717. package/dist/panoramic/models/docs-bundle-profiles.js +82 -0
  718. package/dist/panoramic/models/docs-bundle-profiles.js.map +1 -0
  719. package/dist/panoramic/models/docs-bundle-types.d.ts +94 -0
  720. package/dist/panoramic/models/docs-bundle-types.d.ts.map +1 -0
  721. package/dist/panoramic/models/docs-bundle-types.js +10 -0
  722. package/dist/panoramic/models/docs-bundle-types.js.map +1 -0
  723. package/dist/panoramic/models/docs-quality-model.d.ts +125 -0
  724. package/dist/panoramic/models/docs-quality-model.d.ts.map +1 -0
  725. package/dist/panoramic/models/docs-quality-model.js +166 -0
  726. package/dist/panoramic/models/docs-quality-model.js.map +1 -0
  727. package/dist/panoramic/models/pattern-hints-model.d.ts +89 -0
  728. package/dist/panoramic/models/pattern-hints-model.d.ts.map +1 -0
  729. package/dist/panoramic/models/pattern-hints-model.js +61 -0
  730. package/dist/panoramic/models/pattern-hints-model.js.map +1 -0
  731. package/dist/panoramic/models/pattern-knowledge-base.d.ts +31 -0
  732. package/dist/panoramic/models/pattern-knowledge-base.d.ts.map +1 -0
  733. package/dist/panoramic/models/pattern-knowledge-base.js +407 -0
  734. package/dist/panoramic/models/pattern-knowledge-base.js.map +1 -0
  735. package/dist/panoramic/models/runtime-topology-model.d.ts +145 -0
  736. package/dist/panoramic/models/runtime-topology-model.d.ts.map +1 -0
  737. package/dist/panoramic/models/runtime-topology-model.js +300 -0
  738. package/dist/panoramic/models/runtime-topology-model.js.map +1 -0
  739. package/dist/panoramic/output-filenames.d.ts +26 -0
  740. package/dist/panoramic/output-filenames.d.ts.map +1 -0
  741. package/dist/panoramic/output-filenames.js +48 -0
  742. package/dist/panoramic/output-filenames.js.map +1 -0
  743. package/dist/panoramic/parser-registry.d.ts +89 -0
  744. package/dist/panoramic/parser-registry.d.ts.map +1 -0
  745. package/dist/panoramic/parser-registry.js +169 -0
  746. package/dist/panoramic/parser-registry.js.map +1 -0
  747. package/dist/panoramic/parsers/abstract-artifact-parser.d.ts +48 -0
  748. package/dist/panoramic/parsers/abstract-artifact-parser.d.ts.map +1 -0
  749. package/dist/panoramic/parsers/abstract-artifact-parser.js +52 -0
  750. package/dist/panoramic/parsers/abstract-artifact-parser.js.map +1 -0
  751. package/dist/panoramic/parsers/abstract-config-parser.d.ts +35 -0
  752. package/dist/panoramic/parsers/abstract-config-parser.d.ts.map +1 -0
  753. package/dist/panoramic/parsers/abstract-config-parser.js +34 -0
  754. package/dist/panoramic/parsers/abstract-config-parser.js.map +1 -0
  755. package/dist/panoramic/parsers/behavior-yaml-parser.d.ts +34 -0
  756. package/dist/panoramic/parsers/behavior-yaml-parser.d.ts.map +1 -0
  757. package/dist/panoramic/parsers/behavior-yaml-parser.js +195 -0
  758. package/dist/panoramic/parsers/behavior-yaml-parser.js.map +1 -0
  759. package/dist/panoramic/parsers/comment-tracker.d.ts +37 -0
  760. package/dist/panoramic/parsers/comment-tracker.d.ts.map +1 -0
  761. package/dist/panoramic/parsers/comment-tracker.js +50 -0
  762. package/dist/panoramic/parsers/comment-tracker.js.map +1 -0
  763. package/dist/panoramic/parsers/dockerfile-parser.d.ts +42 -0
  764. package/dist/panoramic/parsers/dockerfile-parser.d.ts.map +1 -0
  765. package/dist/panoramic/parsers/dockerfile-parser.js +128 -0
  766. package/dist/panoramic/parsers/dockerfile-parser.js.map +1 -0
  767. package/dist/panoramic/parsers/env-config-parser.d.ts +37 -0
  768. package/dist/panoramic/parsers/env-config-parser.d.ts.map +1 -0
  769. package/dist/panoramic/parsers/env-config-parser.js +73 -0
  770. package/dist/panoramic/parsers/env-config-parser.js.map +1 -0
  771. package/dist/panoramic/parsers/index.d.ts +25 -0
  772. package/dist/panoramic/parsers/index.d.ts.map +1 -0
  773. package/dist/panoramic/parsers/index.js +25 -0
  774. package/dist/panoramic/parsers/index.js.map +1 -0
  775. package/dist/panoramic/parsers/skill-md-parser.d.ts +42 -0
  776. package/dist/panoramic/parsers/skill-md-parser.d.ts.map +1 -0
  777. package/dist/panoramic/parsers/skill-md-parser.js +105 -0
  778. package/dist/panoramic/parsers/skill-md-parser.js.map +1 -0
  779. package/dist/panoramic/parsers/toml-config-parser.d.ts +39 -0
  780. package/dist/panoramic/parsers/toml-config-parser.d.ts.map +1 -0
  781. package/dist/panoramic/parsers/toml-config-parser.js +98 -0
  782. package/dist/panoramic/parsers/toml-config-parser.js.map +1 -0
  783. package/dist/panoramic/parsers/types.d.ts +314 -0
  784. package/dist/panoramic/parsers/types.d.ts.map +1 -0
  785. package/dist/panoramic/parsers/types.js +136 -0
  786. package/dist/panoramic/parsers/types.js.map +1 -0
  787. package/dist/panoramic/parsers/yaml-config-parser.d.ts +58 -0
  788. package/dist/panoramic/parsers/yaml-config-parser.d.ts.map +1 -0
  789. package/dist/panoramic/parsers/yaml-config-parser.js +356 -0
  790. package/dist/panoramic/parsers/yaml-config-parser.js.map +1 -0
  791. package/dist/panoramic/pipelines/adr-decision-pipeline.d.ts +74 -0
  792. package/dist/panoramic/pipelines/adr-decision-pipeline.d.ts.map +1 -0
  793. package/dist/panoramic/pipelines/adr-decision-pipeline.js +421 -0
  794. package/dist/panoramic/pipelines/adr-decision-pipeline.js.map +1 -0
  795. package/dist/panoramic/pipelines/adr-evidence-verifier.d.ts +30 -0
  796. package/dist/panoramic/pipelines/adr-evidence-verifier.d.ts.map +1 -0
  797. package/dist/panoramic/pipelines/adr-evidence-verifier.js +141 -0
  798. package/dist/panoramic/pipelines/adr-evidence-verifier.js.map +1 -0
  799. package/dist/panoramic/pipelines/adr-mapreduce.d.ts +316 -0
  800. package/dist/panoramic/pipelines/adr-mapreduce.d.ts.map +1 -0
  801. package/dist/panoramic/pipelines/adr-mapreduce.js +331 -0
  802. package/dist/panoramic/pipelines/adr-mapreduce.js.map +1 -0
  803. package/dist/panoramic/pipelines/adr-migration.d.ts +26 -0
  804. package/dist/panoramic/pipelines/adr-migration.d.ts.map +1 -0
  805. package/dist/panoramic/pipelines/adr-migration.js +203 -0
  806. package/dist/panoramic/pipelines/adr-migration.js.map +1 -0
  807. package/dist/panoramic/pipelines/architecture-narrative-mapreduce.d.ts +121 -0
  808. package/dist/panoramic/pipelines/architecture-narrative-mapreduce.d.ts.map +1 -0
  809. package/dist/panoramic/pipelines/architecture-narrative-mapreduce.js +412 -0
  810. package/dist/panoramic/pipelines/architecture-narrative-mapreduce.js.map +1 -0
  811. package/dist/panoramic/pipelines/architecture-narrative.d.ts +123 -0
  812. package/dist/panoramic/pipelines/architecture-narrative.d.ts.map +1 -0
  813. package/dist/panoramic/pipelines/architecture-narrative.js +419 -0
  814. package/dist/panoramic/pipelines/architecture-narrative.js.map +1 -0
  815. package/dist/panoramic/pipelines/coverage-auditor.d.ts +95 -0
  816. package/dist/panoramic/pipelines/coverage-auditor.d.ts.map +1 -0
  817. package/dist/panoramic/pipelines/coverage-auditor.js +290 -0
  818. package/dist/panoramic/pipelines/coverage-auditor.js.map +1 -0
  819. package/dist/panoramic/pipelines/debt-intelligence-pipeline.d.ts +32 -0
  820. package/dist/panoramic/pipelines/debt-intelligence-pipeline.d.ts.map +1 -0
  821. package/dist/panoramic/pipelines/debt-intelligence-pipeline.js +108 -0
  822. package/dist/panoramic/pipelines/debt-intelligence-pipeline.js.map +1 -0
  823. package/dist/panoramic/pipelines/docs-bundle-manifest-reader.d.ts +26 -0
  824. package/dist/panoramic/pipelines/docs-bundle-manifest-reader.d.ts.map +1 -0
  825. package/dist/panoramic/pipelines/docs-bundle-manifest-reader.js +108 -0
  826. package/dist/panoramic/pipelines/docs-bundle-manifest-reader.js.map +1 -0
  827. package/dist/panoramic/pipelines/docs-bundle-orchestrator.d.ts +16 -0
  828. package/dist/panoramic/pipelines/docs-bundle-orchestrator.d.ts.map +1 -0
  829. package/dist/panoramic/pipelines/docs-bundle-orchestrator.js +588 -0
  830. package/dist/panoramic/pipelines/docs-bundle-orchestrator.js.map +1 -0
  831. package/dist/panoramic/pipelines/docs-quality-evaluator.d.ts +55 -0
  832. package/dist/panoramic/pipelines/docs-quality-evaluator.d.ts.map +1 -0
  833. package/dist/panoramic/pipelines/docs-quality-evaluator.js +1045 -0
  834. package/dist/panoramic/pipelines/docs-quality-evaluator.js.map +1 -0
  835. package/dist/panoramic/pipelines/narrative-provenance-adapter.d.ts +8 -0
  836. package/dist/panoramic/pipelines/narrative-provenance-adapter.d.ts.map +1 -0
  837. package/dist/panoramic/pipelines/narrative-provenance-adapter.js +99 -0
  838. package/dist/panoramic/pipelines/narrative-provenance-adapter.js.map +1 -0
  839. package/dist/panoramic/pipelines/product-ux-docs.d.ts +123 -0
  840. package/dist/panoramic/pipelines/product-ux-docs.d.ts.map +1 -0
  841. package/dist/panoramic/pipelines/product-ux-docs.js +959 -0
  842. package/dist/panoramic/pipelines/product-ux-docs.js.map +1 -0
  843. package/dist/panoramic/project-context.d.ts +17 -0
  844. package/dist/panoramic/project-context.d.ts.map +1 -0
  845. package/dist/panoramic/project-context.js +289 -0
  846. package/dist/panoramic/project-context.js.map +1 -0
  847. package/dist/panoramic/qa/citation.d.ts +21 -0
  848. package/dist/panoramic/qa/citation.d.ts.map +1 -0
  849. package/dist/panoramic/qa/citation.js +184 -0
  850. package/dist/panoramic/qa/citation.js.map +1 -0
  851. package/dist/panoramic/qa/debt-context.d.ts +33 -0
  852. package/dist/panoramic/qa/debt-context.d.ts.map +1 -0
  853. package/dist/panoramic/qa/debt-context.js +82 -0
  854. package/dist/panoramic/qa/debt-context.js.map +1 -0
  855. package/dist/panoramic/qa/graph-retriever.d.ts +29 -0
  856. package/dist/panoramic/qa/graph-retriever.d.ts.map +1 -0
  857. package/dist/panoramic/qa/graph-retriever.js +65 -0
  858. package/dist/panoramic/qa/graph-retriever.js.map +1 -0
  859. package/dist/panoramic/qa/index.d.ts +23 -0
  860. package/dist/panoramic/qa/index.d.ts.map +1 -0
  861. package/dist/panoramic/qa/index.js +201 -0
  862. package/dist/panoramic/qa/index.js.map +1 -0
  863. package/dist/panoramic/qa/llm-caller.d.ts +35 -0
  864. package/dist/panoramic/qa/llm-caller.d.ts.map +1 -0
  865. package/dist/panoramic/qa/llm-caller.js +138 -0
  866. package/dist/panoramic/qa/llm-caller.js.map +1 -0
  867. package/dist/panoramic/qa/prompt-builder.d.ts +36 -0
  868. package/dist/panoramic/qa/prompt-builder.d.ts.map +1 -0
  869. package/dist/panoramic/qa/prompt-builder.js +143 -0
  870. package/dist/panoramic/qa/prompt-builder.js.map +1 -0
  871. package/dist/panoramic/qa/rag-reranker.d.ts +43 -0
  872. package/dist/panoramic/qa/rag-reranker.d.ts.map +1 -0
  873. package/dist/panoramic/qa/rag-reranker.js +129 -0
  874. package/dist/panoramic/qa/rag-reranker.js.map +1 -0
  875. package/dist/panoramic/qa/types.d.ts +126 -0
  876. package/dist/panoramic/qa/types.d.ts.map +1 -0
  877. package/dist/panoramic/qa/types.js +6 -0
  878. package/dist/panoramic/qa/types.js.map +1 -0
  879. package/dist/panoramic/query.d.ts +29 -0
  880. package/dist/panoramic/query.d.ts.map +1 -0
  881. package/dist/panoramic/query.js +80 -0
  882. package/dist/panoramic/query.js.map +1 -0
  883. package/dist/panoramic/stored-module-specs.d.ts +26 -0
  884. package/dist/panoramic/stored-module-specs.d.ts.map +1 -0
  885. package/dist/panoramic/stored-module-specs.js +155 -0
  886. package/dist/panoramic/stored-module-specs.js.map +1 -0
  887. package/dist/panoramic/utils/html-sanitizer.d.ts +33 -0
  888. package/dist/panoramic/utils/html-sanitizer.d.ts.map +1 -0
  889. package/dist/panoramic/utils/html-sanitizer.js +170 -0
  890. package/dist/panoramic/utils/html-sanitizer.js.map +1 -0
  891. package/dist/panoramic/utils/llm-enricher.d.ts +74 -0
  892. package/dist/panoramic/utils/llm-enricher.d.ts.map +1 -0
  893. package/dist/panoramic/utils/llm-enricher.js +315 -0
  894. package/dist/panoramic/utils/llm-enricher.js.map +1 -0
  895. package/dist/panoramic/utils/llm-facade.d.ts +66 -0
  896. package/dist/panoramic/utils/llm-facade.d.ts.map +1 -0
  897. package/dist/panoramic/utils/llm-facade.js +136 -0
  898. package/dist/panoramic/utils/llm-facade.js.map +1 -0
  899. package/dist/panoramic/utils/logger.d.ts +43 -0
  900. package/dist/panoramic/utils/logger.d.ts.map +1 -0
  901. package/dist/panoramic/utils/logger.js +76 -0
  902. package/dist/panoramic/utils/logger.js.map +1 -0
  903. package/dist/panoramic/utils/mermaid-helpers.d.ts +19 -0
  904. package/dist/panoramic/utils/mermaid-helpers.d.ts.map +1 -0
  905. package/dist/panoramic/utils/mermaid-helpers.js +21 -0
  906. package/dist/panoramic/utils/mermaid-helpers.js.map +1 -0
  907. package/dist/panoramic/utils/multi-format-writer.d.ts +43 -0
  908. package/dist/panoramic/utils/multi-format-writer.d.ts.map +1 -0
  909. package/dist/panoramic/utils/multi-format-writer.js +73 -0
  910. package/dist/panoramic/utils/multi-format-writer.js.map +1 -0
  911. package/dist/panoramic/utils/template-loader.d.ts +15 -0
  912. package/dist/panoramic/utils/template-loader.d.ts.map +1 -0
  913. package/dist/panoramic/utils/template-loader.js +65 -0
  914. package/dist/panoramic/utils/template-loader.js.map +1 -0
  915. package/dist/panoramic/utils/text-segmenter.d.ts +50 -0
  916. package/dist/panoramic/utils/text-segmenter.d.ts.map +1 -0
  917. package/dist/panoramic/utils/text-segmenter.js +151 -0
  918. package/dist/panoramic/utils/text-segmenter.js.map +1 -0
  919. package/dist/scripts/postinstall.d.ts +7 -0
  920. package/dist/scripts/postinstall.d.ts.map +1 -0
  921. package/dist/scripts/postinstall.js +70 -0
  922. package/dist/scripts/postinstall.js.map +1 -0
  923. package/dist/scripts/preuninstall.d.ts +7 -0
  924. package/dist/scripts/preuninstall.d.ts.map +1 -0
  925. package/dist/scripts/preuninstall.js +62 -0
  926. package/dist/scripts/preuninstall.js.map +1 -0
  927. package/dist/spec-store/index.d.ts +9 -0
  928. package/dist/spec-store/index.d.ts.map +1 -0
  929. package/dist/spec-store/index.js +9 -0
  930. package/dist/spec-store/index.js.map +1 -0
  931. package/dist/spec-store/spec-identity.d.ts +28 -0
  932. package/dist/spec-store/spec-identity.d.ts.map +1 -0
  933. package/dist/spec-store/spec-identity.js +24 -0
  934. package/dist/spec-store/spec-identity.js.map +1 -0
  935. package/dist/spec-store/spec-store.d.ts +62 -0
  936. package/dist/spec-store/spec-store.d.ts.map +1 -0
  937. package/dist/spec-store/spec-store.js +201 -0
  938. package/dist/spec-store/spec-store.js.map +1 -0
  939. package/dist/utils/atomic-write.d.ts +10 -0
  940. package/dist/utils/atomic-write.d.ts.map +1 -0
  941. package/dist/utils/atomic-write.js +27 -0
  942. package/dist/utils/atomic-write.js.map +1 -0
  943. package/dist/utils/chunk-splitter.d.ts +32 -0
  944. package/dist/utils/chunk-splitter.d.ts.map +1 -0
  945. package/dist/utils/chunk-splitter.js +116 -0
  946. package/dist/utils/chunk-splitter.js.map +1 -0
  947. package/dist/utils/file-scanner.d.ts +38 -0
  948. package/dist/utils/file-scanner.d.ts.map +1 -0
  949. package/dist/utils/file-scanner.js +323 -0
  950. package/dist/utils/file-scanner.js.map +1 -0
  951. package/dist/utils/git-blame.d.ts +32 -0
  952. package/dist/utils/git-blame.d.ts.map +1 -0
  953. package/dist/utils/git-blame.js +151 -0
  954. package/dist/utils/git-blame.js.map +1 -0
  955. package/dist/utils/specify-template-sync.d.ts +16 -0
  956. package/dist/utils/specify-template-sync.d.ts.map +1 -0
  957. package/dist/utils/specify-template-sync.js +66 -0
  958. package/dist/utils/specify-template-sync.js.map +1 -0
  959. package/dist/watcher/file-watcher.d.ts +77 -0
  960. package/dist/watcher/file-watcher.d.ts.map +1 -0
  961. package/dist/watcher/file-watcher.js +233 -0
  962. package/dist/watcher/file-watcher.js.map +1 -0
  963. package/dist/watcher/index.d.ts +6 -0
  964. package/dist/watcher/index.d.ts.map +1 -0
  965. package/dist/watcher/index.js +5 -0
  966. package/dist/watcher/index.js.map +1 -0
  967. package/grammars/manifest.json +28 -0
  968. package/grammars/tree-sitter-go.wasm +0 -0
  969. package/grammars/tree-sitter-java.wasm +0 -0
  970. package/grammars/tree-sitter-javascript.wasm +0 -0
  971. package/grammars/tree-sitter-python.wasm +0 -0
  972. package/grammars/tree-sitter-typescript.wasm +0 -0
  973. package/package.json +84 -0
  974. package/plugins/spec-driver/.claude-plugin/plugin.json +16 -0
  975. package/plugins/spec-driver/README.md +401 -0
  976. package/plugins/spec-driver/agents/analyze.artifact.yaml +10 -0
  977. package/plugins/spec-driver/agents/analyze.md +144 -0
  978. package/plugins/spec-driver/agents/checklist.artifact.yaml +8 -0
  979. package/plugins/spec-driver/agents/checklist.md +84 -0
  980. package/plugins/spec-driver/agents/clarify.artifact.yaml +6 -0
  981. package/plugins/spec-driver/agents/clarify.md +104 -0
  982. package/plugins/spec-driver/agents/constitution.artifact.yaml +9 -0
  983. package/plugins/spec-driver/agents/constitution.md +100 -0
  984. package/plugins/spec-driver/agents/implement.artifact.yaml +8 -0
  985. package/plugins/spec-driver/agents/implement.md +159 -0
  986. package/plugins/spec-driver/agents/plan.artifact.yaml +12 -0
  987. package/plugins/spec-driver/agents/plan.md +116 -0
  988. package/plugins/spec-driver/agents/product-research.artifact.yaml +11 -0
  989. package/plugins/spec-driver/agents/product-research.md +94 -0
  990. package/plugins/spec-driver/agents/quality-review.artifact.yaml +11 -0
  991. package/plugins/spec-driver/agents/quality-review.md +165 -0
  992. package/plugins/spec-driver/agents/refactor-plan.md +132 -0
  993. package/plugins/spec-driver/agents/spec-review.artifact.yaml +12 -0
  994. package/plugins/spec-driver/agents/spec-review.md +111 -0
  995. package/plugins/spec-driver/agents/specify.artifact.yaml +9 -0
  996. package/plugins/spec-driver/agents/specify.md +109 -0
  997. package/plugins/spec-driver/agents/sync.artifact.yaml +19 -0
  998. package/plugins/spec-driver/agents/sync.md +91 -0
  999. package/plugins/spec-driver/agents/tasks.artifact.yaml +10 -0
  1000. package/plugins/spec-driver/agents/tasks.md +88 -0
  1001. package/plugins/spec-driver/agents/tech-research.artifact.yaml +12 -0
  1002. package/plugins/spec-driver/agents/tech-research.md +102 -0
  1003. package/plugins/spec-driver/agents/verify.artifact.yaml +11 -0
  1004. package/plugins/spec-driver/agents/verify.md +204 -0
  1005. package/plugins/spec-driver/config/orchestration.yaml +779 -0
  1006. package/plugins/spec-driver/contracts/orchestration-overrides-contract.yaml +124 -0
  1007. package/plugins/spec-driver/contracts/orchestration-schema.mjs +301 -0
  1008. package/plugins/spec-driver/contracts/scan-project-output.md +70 -0
  1009. package/plugins/spec-driver/contracts/wrapper-source-of-truth.yaml +44 -0
  1010. package/plugins/spec-driver/hooks/hooks.json +70 -0
  1011. package/plugins/spec-driver/hooks/post-tool-use-format.sh +28 -0
  1012. package/plugins/spec-driver/hooks/pre-tool-use-guard.sh +42 -0
  1013. package/plugins/spec-driver/hooks/stop-task-check.sh +22 -0
  1014. package/plugins/spec-driver/hooks/worktree-lifecycle.sh +33 -0
  1015. package/plugins/spec-driver/lib/orchestration-output-serializer.mjs +219 -0
  1016. package/plugins/spec-driver/lib/orchestration-resolver.mjs +485 -0
  1017. package/plugins/spec-driver/lib/orchestrator-fallback.mjs +98 -0
  1018. package/plugins/spec-driver/lib/orchestrator.mjs +280 -0
  1019. package/plugins/spec-driver/scorecards/default-governance.yaml +63 -0
  1020. package/plugins/spec-driver/scripts/codex-skills.sh +225 -0
  1021. package/plugins/spec-driver/scripts/experimental/README.md +9 -0
  1022. package/plugins/spec-driver/scripts/generate-adoption-insights.mjs +523 -0
  1023. package/plugins/spec-driver/scripts/generate-product-entity-catalog.mjs +472 -0
  1024. package/plugins/spec-driver/scripts/generate-product-quality-reports.mjs +18 -0
  1025. package/plugins/spec-driver/scripts/generate-product-scorecards.mjs +25 -0
  1026. package/plugins/spec-driver/scripts/generate-project-context-suggestions.mjs +622 -0
  1027. package/plugins/spec-driver/scripts/generate-workflow-registry.mjs +16 -0
  1028. package/plugins/spec-driver/scripts/init-project.sh +328 -0
  1029. package/plugins/spec-driver/scripts/lib/config-schema.mjs +433 -0
  1030. package/plugins/spec-driver/scripts/lib/init-project-output.sh +146 -0
  1031. package/plugins/spec-driver/scripts/lib/product-artifact-patchers.mjs +29 -0
  1032. package/plugins/spec-driver/scripts/lib/product-artifact-paths.mjs +129 -0
  1033. package/plugins/spec-driver/scripts/lib/product-governance-helpers.mjs +48 -0
  1034. package/plugins/spec-driver/scripts/lib/product-quality-core.mjs +531 -0
  1035. package/plugins/spec-driver/scripts/lib/product-scorecard-core.mjs +810 -0
  1036. package/plugins/spec-driver/scripts/lib/project-context-paths.mjs +21 -0
  1037. package/plugins/spec-driver/scripts/lib/project-profile-resolver.mjs +704 -0
  1038. package/plugins/spec-driver/scripts/lib/project-profile-schema.mjs +78 -0
  1039. package/plugins/spec-driver/scripts/lib/script-cli-args.mjs +25 -0
  1040. package/plugins/spec-driver/scripts/lib/script-diagnostics.mjs +29 -0
  1041. package/plugins/spec-driver/scripts/lib/script-report-io.mjs +37 -0
  1042. package/plugins/spec-driver/scripts/lib/simple-yaml.mjs +257 -0
  1043. package/plugins/spec-driver/scripts/lib/sync-conflict-resolver.mjs +128 -0
  1044. package/plugins/spec-driver/scripts/lib/sync-merge-strategy.mjs +388 -0
  1045. package/plugins/spec-driver/scripts/lib/sync-product-mapping.mjs +228 -0
  1046. package/plugins/spec-driver/scripts/lib/sync-timeline-builder.mjs +114 -0
  1047. package/plugins/spec-driver/scripts/lib/sync-validator.mjs +174 -0
  1048. package/plugins/spec-driver/scripts/lib/workflow-registry-core.mjs +281 -0
  1049. package/plugins/spec-driver/scripts/orchestrator-cli.mjs +490 -0
  1050. package/plugins/spec-driver/scripts/orchestrator-cli.sh +36 -0
  1051. package/plugins/spec-driver/scripts/postinstall.sh +101 -0
  1052. package/plugins/spec-driver/scripts/record-workflow-run.mjs +332 -0
  1053. package/plugins/spec-driver/scripts/resolve-project-context.mjs +56 -0
  1054. package/plugins/spec-driver/scripts/scan-project.sh +668 -0
  1055. package/plugins/spec-driver/scripts/sync-merge-engine.mjs +663 -0
  1056. package/plugins/spec-driver/scripts/validate-config.mjs +223 -0
  1057. package/plugins/spec-driver/scripts/validate-orchestration-overrides.mjs +190 -0
  1058. package/plugins/spec-driver/scripts/validate-wrapper-sources.mjs +302 -0
  1059. package/plugins/spec-driver/skills/spec-driver-constitution/SKILL.md +77 -0
  1060. package/plugins/spec-driver/skills/spec-driver-doc/SKILL.md +732 -0
  1061. package/plugins/spec-driver/skills/spec-driver-feature/SKILL.md +336 -0
  1062. package/plugins/spec-driver/skills/spec-driver-fix/SKILL.md +457 -0
  1063. package/plugins/spec-driver/skills/spec-driver-implement/SKILL.md +653 -0
  1064. package/plugins/spec-driver/skills/spec-driver-refactor/SKILL.md +250 -0
  1065. package/plugins/spec-driver/skills/spec-driver-resume/SKILL.md +325 -0
  1066. package/plugins/spec-driver/skills/spec-driver-story/SKILL.md +566 -0
  1067. package/plugins/spec-driver/skills/spec-driver-sync/SKILL.md +300 -0
  1068. package/plugins/spec-driver/templates/code-of-conduct-v2.1.md +85 -0
  1069. package/plugins/spec-driver/templates/licenses/Apache-2.0.txt +201 -0
  1070. package/plugins/spec-driver/templates/licenses/BSD-2-Clause.txt +24 -0
  1071. package/plugins/spec-driver/templates/licenses/BSD-3-Clause.txt +28 -0
  1072. package/plugins/spec-driver/templates/licenses/GPL-3.0.txt +232 -0
  1073. package/plugins/spec-driver/templates/licenses/ISC.txt +15 -0
  1074. package/plugins/spec-driver/templates/licenses/MIT.txt +21 -0
  1075. package/plugins/spec-driver/templates/licenses/MPL-2.0.txt +373 -0
  1076. package/plugins/spec-driver/templates/licenses/Unlicense.txt +24 -0
  1077. package/plugins/spec-driver/templates/orchestration-overrides.example.yaml +81 -0
  1078. package/plugins/spec-driver/templates/product-research-template.md +95 -0
  1079. package/plugins/spec-driver/templates/product-spec-template.md +250 -0
  1080. package/plugins/spec-driver/templates/research-synthesis-template.md +102 -0
  1081. package/plugins/spec-driver/templates/spec-driver.config-template.yaml +244 -0
  1082. package/plugins/spec-driver/templates/specify-base/agent-file-template.md +28 -0
  1083. package/plugins/spec-driver/templates/specify-base/checklist-template.md +40 -0
  1084. package/plugins/spec-driver/templates/specify-base/constitution-template.md +50 -0
  1085. package/plugins/spec-driver/templates/specify-base/plan-template.md +134 -0
  1086. package/plugins/spec-driver/templates/specify-base/product-research-template.md +95 -0
  1087. package/plugins/spec-driver/templates/specify-base/project-context-template.yaml +40 -0
  1088. package/plugins/spec-driver/templates/specify-base/research-synthesis-template.md +102 -0
  1089. package/plugins/spec-driver/templates/specify-base/spec-template.md +115 -0
  1090. package/plugins/spec-driver/templates/specify-base/tasks-template.md +266 -0
  1091. package/plugins/spec-driver/templates/specify-base/tech-research-template.md +111 -0
  1092. package/plugins/spec-driver/templates/specify-base/verification-report-template.md +63 -0
  1093. package/plugins/spec-driver/templates/tech-research-template.md +111 -0
  1094. package/plugins/spec-driver/templates/verification-report-template.md +63 -0
  1095. package/plugins/spec-driver/workflows/golden-paths.yaml +39 -0
  1096. package/plugins/spec-driver/workflows/spec-driver-doc.yaml +24 -0
  1097. package/plugins/spec-driver/workflows/spec-driver-feature.yaml +29 -0
  1098. package/plugins/spec-driver/workflows/spec-driver-fix.yaml +21 -0
  1099. package/plugins/spec-driver/workflows/spec-driver-implement.yaml +23 -0
  1100. package/plugins/spec-driver/workflows/spec-driver-resume.yaml +20 -0
  1101. package/plugins/spec-driver/workflows/spec-driver-story.yaml +24 -0
  1102. package/plugins/spec-driver/workflows/spec-driver-sync.yaml +34 -0
  1103. package/plugins/spectra/.claude-plugin/plugin.json +20 -0
  1104. package/plugins/spectra/.mcp.json +8 -0
  1105. package/plugins/spectra/README.md +128 -0
  1106. package/plugins/spectra/contracts/skill-source-of-truth.yaml +34 -0
  1107. package/plugins/spectra/hooks/hooks.json +15 -0
  1108. package/plugins/spectra/scripts/postinstall.sh +12 -0
  1109. package/plugins/spectra/scripts/sync-skill-mirrors.mjs +148 -0
  1110. package/plugins/spectra/scripts/validate-skill-sources.mjs +280 -0
  1111. package/plugins/spectra/skills/spectra/SKILL.md +214 -0
  1112. package/plugins/spectra/skills/spectra-batch/SKILL.md +232 -0
  1113. package/plugins/spectra/skills/spectra-diff/SKILL.md +99 -0
  1114. package/queries/go.scm +54 -0
  1115. package/queries/java.scm +50 -0
  1116. package/queries/javascript.scm +30 -0
  1117. package/queries/python.scm +35 -0
  1118. package/queries/typescript.scm +50 -0
  1119. package/scripts/lifecycle-runner.cjs +33 -0
  1120. package/templates/adr-draft.hbs +51 -0
  1121. package/templates/adr-index.hbs +25 -0
  1122. package/templates/api-surface.hbs +40 -0
  1123. package/templates/architecture-ir.hbs +49 -0
  1124. package/templates/architecture-narrative.hbs +116 -0
  1125. package/templates/architecture-overview.hbs +103 -0
  1126. package/templates/component-view.hbs +87 -0
  1127. package/templates/config-reference.hbs +22 -0
  1128. package/templates/coverage-report.hbs +84 -0
  1129. package/templates/cross-package-analysis.hbs +43 -0
  1130. package/templates/data-model.hbs +72 -0
  1131. package/templates/delta-report.hbs +53 -0
  1132. package/templates/docs-bundle-index.hbs +41 -0
  1133. package/templates/drift-report.hbs +53 -0
  1134. package/templates/dynamic-scenarios.hbs +46 -0
  1135. package/templates/event-surface.hbs +90 -0
  1136. package/templates/feature-brief-index.hbs +27 -0
  1137. package/templates/feature-brief.hbs +28 -0
  1138. package/templates/index-spec.hbs +57 -0
  1139. package/templates/interface-surface.hbs +87 -0
  1140. package/templates/module-spec.hbs +117 -0
  1141. package/templates/pattern-hints.hbs +85 -0
  1142. package/templates/product-overview.hbs +65 -0
  1143. package/templates/quality-report.hbs +130 -0
  1144. package/templates/runtime-topology.hbs +128 -0
  1145. package/templates/troubleshooting.hbs +86 -0
  1146. package/templates/user-journeys.hbs +44 -0
  1147. package/templates/workspace-index.hbs +26 -0
@@ -0,0 +1,1552 @@
1
+ /**
2
+ * 批量编排器
3
+ * 按模块级拓扑顺序编排全项目 Spec 生成(FR-012/FR-014/FR-015/FR-016/FR-017)
4
+ * 支持多语言混合项目:按语言分组、分组依赖图构建、图合并拓扑排序(Feature 031)
5
+ * 参见 contracts/batch-module.md
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import pLimit from 'p-limit';
10
+ import { findReadmePath } from '../extraction/index.js';
11
+ import { buildGraph } from '../graph/dependency-graph.js';
12
+ import { generateSpec } from '../core/single-spec-orchestrator.js';
13
+ import { generateIndex } from '../generator/index-generator.js';
14
+ import { renderIndex, initRenderer } from '../generator/spec-renderer.js';
15
+ import { loadCheckpoint, saveCheckpoint, clearCheckpoint, DEFAULT_CHECKPOINT_PATH, } from './checkpoint.js';
16
+ import { DeltaRegenerator } from './delta-regenerator.js';
17
+ import { createReporter, writeSummaryLog } from './progress-reporter.js';
18
+ import { aggregateCostSummary, } from './cost-summary.js';
19
+ import { estimateModuleCost, buildDryRunReport, renderDryRunReport, runBudgetGate, } from './budget-gate.js';
20
+ import { decideModelOverride } from './model-override-decision.js';
21
+ import { createLogger } from '../panoramic/utils/logger.js';
22
+ import { groupFilesToModules } from './module-grouper.js';
23
+ import { groupFilesByLanguage } from './language-grouper.js';
24
+ import { scanFiles } from '../utils/file-scanner.js';
25
+ import { LanguageAdapterRegistry } from '../adapters/language-adapter-registry.js';
26
+ import { buildDocGraph, runAnchorIntegration, runHyperedgeIntegration, scanStoredModuleSpecs, } from '../panoramic/builders/doc-graph-builder.js';
27
+ import { chunkMarkdownFiles } from '../panoramic/anchoring/chunker.js';
28
+ import { createEmbeddingProvider } from '../panoramic/anchoring/providers/factory.js';
29
+ import { DOC_NODE_KINDS } from '../panoramic/hyperedges/constants.js';
30
+ import { buildCrossReferenceIndex } from '../panoramic/cross-reference-index.js';
31
+ import { renderSpec } from '../generator/spec-renderer.js';
32
+ import { CoverageAuditor } from '../panoramic/pipelines/coverage-auditor.js';
33
+ import { buildProjectContext } from '../panoramic/project-context.js';
34
+ import { generateBatchProjectDocs, generateDocsQualityReport, } from '../panoramic/batch-project-docs.js';
35
+ import { resolveReverseSpecModel, getCanonicalSonnetModelId } from '../core/model-selection.js';
36
+ import { detectAuth } from '../auth/auth-detector.js';
37
+ import { orchestrateDocsBundle } from '../panoramic/pipelines/docs-bundle-orchestrator.js';
38
+ import { generateDebtIntelligence, } from '../panoramic/pipelines/debt-intelligence-pipeline.js';
39
+ import { BATCH_OUTPUT_SUBDIRS } from '../panoramic/output-filenames.js';
40
+ import { buildKnowledgeGraph, writeKnowledgeGraph } from '../panoramic/graph/index.js';
41
+ import { buildHtmlTemplate } from '../panoramic/exporters/html-template.js';
42
+ import { SpecStore } from '../spec-store/index.js';
43
+ import { createRequire } from 'node:module';
44
+ // 从 package.json 读取版本号(避免硬编码)
45
+ const _require = createRequire(import.meta.url);
46
+ const SPECTRA_VERSION = _require('../../package.json').version;
47
+ /**
48
+ * Bug 142:单模块重试累计 input token 预算上限。
49
+ * 超过该值时提前终止重试,避免相同 prompt 反复失败导致的 token 浪费。
50
+ * 默认 40_000(p-queue 实测:单模块合理上限 ~10k,4× 仍属充足容忍)。
51
+ * 可通过环境变量 SPECTRA_RETRY_TOKEN_BUDGET 覆盖。
52
+ */
53
+ const RETRY_TOKEN_BUDGET = Number(process.env['SPECTRA_RETRY_TOKEN_BUDGET'] ?? 40_000);
54
+ /**
55
+ * Bug 142:LLM 调用失败抛异常时(最常见失败模式),无法从 result.costMetadata 取到实际 token,
56
+ * 此时按估算值累积。基于 bench.ts 实测:单次失败的 input prompt 约 15k tokens。
57
+ * 这是关键修复点:若仅在成功路径累积 token,最常见的"LLM 调用本身失败"场景下
58
+ * cumulativeInputTokens 永远是 0,预算检查彻底失效。
59
+ */
60
+ const ESTIMATED_FAILED_CALL_INPUT = 15_000;
61
+ const logger = createLogger('batch-orchestrator');
62
+ // ============================================================
63
+ // 内部辅助函数
64
+ // ============================================================
65
+ /**
66
+ * 合并多个语言的 DependencyGraph 用于全局拓扑排序
67
+ * 仅合并 modules 和 edges,SCC/Mermaid 按语言独立保留(TD-002 选项 C)
68
+ */
69
+ export function mergeGraphsForTopologicalSort(graphs, projectRoot) {
70
+ const allModules = [];
71
+ const allEdges = [];
72
+ for (const graph of graphs) {
73
+ allModules.push(...graph.modules);
74
+ allEdges.push(...graph.edges);
75
+ }
76
+ // 合并 Mermaid 源码(各语言用注释分隔)
77
+ const mermaidParts = graphs
78
+ .filter((g) => g.mermaidSource.trim().length > 0)
79
+ .map((g) => g.mermaidSource);
80
+ const mermaidSource = mermaidParts.join('\n');
81
+ return {
82
+ projectRoot,
83
+ modules: allModules,
84
+ edges: allEdges,
85
+ topologicalOrder: allModules.map((m) => m.source),
86
+ sccs: graphs.flatMap((g) => g.sccs),
87
+ totalModules: allModules.length,
88
+ totalEdges: allEdges.length,
89
+ analyzedAt: new Date().toISOString(),
90
+ mermaidSource,
91
+ };
92
+ }
93
+ /**
94
+ * 检测跨语言引用
95
+ * 扫描模块 imports 是否引用了其他语言组的路径
96
+ */
97
+ export function detectCrossLanguageRefs(moduleFiles, languageGroups, graph) {
98
+ const refs = [];
99
+ // 构建文件到语言组的映射
100
+ const fileToLang = new Map();
101
+ for (const group of languageGroups) {
102
+ for (const file of group.files) {
103
+ fileToLang.set(file, group.adapterId);
104
+ }
105
+ }
106
+ // 查找当前模块文件的语言
107
+ const moduleFileSet = new Set(moduleFiles);
108
+ const moduleLangs = new Set();
109
+ for (const file of moduleFiles) {
110
+ const lang = fileToLang.get(file);
111
+ if (lang)
112
+ moduleLangs.add(lang);
113
+ }
114
+ // 查找依赖边中指向其他语言的引用
115
+ for (const edge of graph.edges) {
116
+ if (!moduleFileSet.has(edge.from))
117
+ continue;
118
+ const targetLang = fileToLang.get(edge.to);
119
+ if (targetLang && !moduleLangs.has(targetLang)) {
120
+ refs.push(`${targetLang}:${edge.to}`);
121
+ }
122
+ }
123
+ return [...new Set(refs)];
124
+ }
125
+ /**
126
+ * Feature 146 FR-002 — 并发数边界规范化
127
+ *
128
+ * 规则:
129
+ * - 非整数(含小数、非数字、Infinity、NaN)→ Math.floor 向下取整
130
+ * - 取整后 <= 0 → 修正为 1(顺序处理)并通过 onWarn 上报
131
+ *
132
+ * 提取为独立纯函数便于单元测试(不需要启动完整 pipeline)。
133
+ *
134
+ * @param raw 原始 concurrency 值(已合并 CLI / config / 默认值之后传入)
135
+ * @param onWarn 修正发生时的告警回调(用于注入 logger.warn 或测试中的 spy)
136
+ */
137
+ export function normalizeConcurrency(raw, onWarn) {
138
+ let normalized = Math.floor(raw);
139
+ if (!Number.isFinite(normalized) || normalized <= 0) {
140
+ onWarn?.(`concurrency=${raw} 无效,修正为 1(顺序处理)`);
141
+ normalized = 1;
142
+ }
143
+ return normalized;
144
+ }
145
+ /**
146
+ * 生成跨语言调用提示文本(CQ-001)
147
+ */
148
+ export function generateCrossLanguageHint(languageNames) {
149
+ return `\n\n> 注意:本项目包含多种编程语言(${languageNames.join('、')}),` +
150
+ '模块间可能存在 AST 不可见的隐式跨语言调用' +
151
+ '(如 REST API、gRPC、FFI、subprocess 等),' +
152
+ '建议人工审查跨语言交互边界。';
153
+ }
154
+ // ============================================================
155
+ // 核心 API
156
+ // ============================================================
157
+ /**
158
+ * 按模块级拓扑顺序编排全项目 Spec 生成
159
+ *
160
+ * @param projectRoot - 项目根目录
161
+ * @param options - 批量选项
162
+ * @returns 批量结果
163
+ */
164
+ export async function runBatch(projectRoot, options = {}) {
165
+ // F5:mode 校验,无效值在启动阶段立即报错
166
+ const validModes = ['full', 'reading', 'code-only'];
167
+ if (options.mode !== undefined && !validModes.includes(options.mode)) {
168
+ throw new Error(`无效的 mode 值: "${options.mode}"。有效值:full | reading | code-only`);
169
+ }
170
+ const effectiveMode = options.mode ?? 'full';
171
+ // F5:FR-006 — 日志输出当前 mode
172
+ logger.info(`[info] batch mode: ${effectiveMode}`);
173
+ const { force = false, incremental = false, maxRetries = 3, outputDir = 'specs', } = options;
174
+ const startTime = Date.now();
175
+ const resolvedRoot = path.resolve(projectRoot);
176
+ const resolvedOutputDir = path.isAbsolute(outputDir)
177
+ ? outputDir
178
+ : path.join(resolvedRoot, outputDir);
179
+ const checkpointPath = options.checkpointPath
180
+ ? (path.isAbsolute(options.checkpointPath)
181
+ ? options.checkpointPath
182
+ : path.join(resolvedRoot, options.checkpointPath))
183
+ : path.join(resolvedOutputDir, path.basename(DEFAULT_CHECKPOINT_PATH));
184
+ const toProjectPath = (absPath) => {
185
+ const rel = path.relative(resolvedRoot, absPath);
186
+ return rel.startsWith('..') ? absPath : rel;
187
+ };
188
+ const normalizeProjectPath = (inputPath) => inputPath.split(path.sep).join('/');
189
+ // 步骤 1:扫描文件获取 languageStats
190
+ const scanResult = scanFiles(resolvedRoot, { projectRoot: resolvedRoot });
191
+ const languageStats = scanResult.languageStats;
192
+ const detectedLanguages = languageStats
193
+ ? Array.from(languageStats.keys())
194
+ : [];
195
+ // 步骤 1.5:语言分组 + 过滤告警
196
+ const langGroupResult = groupFilesByLanguage(scanResult.files, options.languages);
197
+ const languageGroupsList = langGroupResult.groups;
198
+ let processedLanguages = langGroupResult.groups.map((g) => g.adapterId);
199
+ for (const warning of langGroupResult.warnings) {
200
+ console.warn(`\u26A0 ${warning}`);
201
+ }
202
+ if (processedLanguages.length === 0 && !options.languages?.length) {
203
+ processedLanguages = detectedLanguages;
204
+ }
205
+ const isMultiLang = processedLanguages.length >= 2;
206
+ const isSingleNonTsJs = processedLanguages.length === 1 && processedLanguages[0] !== 'ts-js';
207
+ // 步骤 1.6:根据语言组合选择主依赖图
208
+ let mergedGraph;
209
+ if (isMultiLang) {
210
+ const perLangGraphs = [];
211
+ for (const langGroup of languageGroupsList) {
212
+ perLangGraphs.push(await buildGraphForLanguageGroup(langGroup, resolvedRoot));
213
+ }
214
+ // 步骤 1.7:合并拓扑排序
215
+ mergedGraph = perLangGraphs.length > 0
216
+ ? mergeGraphsForTopologicalSort(perLangGraphs, resolvedRoot)
217
+ : await buildGraph(resolvedRoot);
218
+ }
219
+ else if (isSingleNonTsJs && languageGroupsList[0]) {
220
+ mergedGraph = await buildGraphForLanguageGroup(languageGroupsList[0], resolvedRoot);
221
+ }
222
+ else {
223
+ // 纯 TS/JS 或未识别受支持语言:保持 dependency-cruiser 现有路径
224
+ mergedGraph = await buildGraph(resolvedRoot);
225
+ }
226
+ // 步骤 2:文件→模块聚合 + 模块级拓扑排序
227
+ const groupingOptions = {
228
+ ...options.grouping,
229
+ languageAware: isMultiLang,
230
+ classifyDirectories: options.grouping?.classifyDirectories ?? true, // 默认启用目录语义分类(排除 examples/vendor/dist 等)
231
+ projectRoot: resolvedRoot,
232
+ };
233
+ const groupResult = groupFilesToModules(mergedGraph, groupingOptions);
234
+ const processingOrder = groupResult.moduleOrder;
235
+ const moduleGroups = new Map(groupResult.groups.map((g) => [g.name, g]));
236
+ const rootModuleName = options.grouping?.rootModuleName ?? 'root';
237
+ const existingStoredSpecs = scanStoredModuleSpecs(resolvedOutputDir, resolvedRoot);
238
+ const storedSpecByTarget = new Map(existingStoredSpecs.map((spec) => [spec.sourceTarget, spec]));
239
+ let deltaReport;
240
+ if (incremental) {
241
+ if (force) {
242
+ deltaReport = {
243
+ title: 'Delta Regeneration Report',
244
+ generatedAt: new Date().toISOString(),
245
+ projectRoot: resolvedRoot,
246
+ mode: 'full',
247
+ totalTargets: groupResult.groups.reduce((sum, group) => {
248
+ const isRootGroup = group.name === rootModuleName || group.name.startsWith(`${rootModuleName}--`);
249
+ return sum + (isRootGroup ? group.files.length : 1);
250
+ }, 0),
251
+ regenerateTargets: [],
252
+ directChanges: [],
253
+ propagatedChanges: [],
254
+ unchangedTargets: [],
255
+ fallbackReason: 'force-enabled',
256
+ };
257
+ }
258
+ else {
259
+ const deltaRegenerator = new DeltaRegenerator();
260
+ deltaReport = await deltaRegenerator.plan({
261
+ projectRoot: resolvedRoot,
262
+ dependencyGraph: mergedGraph,
263
+ moduleGroups: groupResult.groups,
264
+ storedSpecs: existingStoredSpecs,
265
+ // Bug 142:传入 effectiveMode 启用 mode-aware cache,
266
+ // 旧 spec(无 generatedByMode)或 mode 不匹配时强制 cache miss。
267
+ effectiveMode,
268
+ });
269
+ }
270
+ }
271
+ const regenerateTargets = new Set(deltaReport?.regenerateTargets ?? []);
272
+ const forceFullRegeneration = force || (incremental && deltaReport?.mode === 'full');
273
+ const shouldUseIncrementalPlan = incremental && !force && deltaReport?.mode === 'incremental';
274
+ console.log(`发现 ${mergedGraph.modules.length} 个文件,聚合为 ${processingOrder.length} 个模块`);
275
+ if (isMultiLang) {
276
+ console.log(`检测到 ${processedLanguages.length} 种语言: ${processedLanguages.join(', ')}`);
277
+ }
278
+ // Feature 127:dry-run 模式 — AST + 模块聚合已完成,直接产出预估报告后返回
279
+ if (options.dryRun) {
280
+ const estimates = [];
281
+ for (const moduleName of processingOrder) {
282
+ const group = moduleGroups.get(moduleName);
283
+ if (!group)
284
+ continue;
285
+ estimates.push(estimateModuleCost(moduleName, group.files, resolvedRoot));
286
+ }
287
+ const report = buildDryRunReport(estimates);
288
+ fs.mkdirSync(path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.META), { recursive: true });
289
+ const dryRunPath = path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.META, 'dry-run-estimate.md');
290
+ fs.writeFileSync(dryRunPath, renderDryRunReport(report), 'utf-8');
291
+ console.log(`[dry-run] 预估报告: ${toProjectPath(dryRunPath)}`);
292
+ console.log(`[dry-run] 预估总 tokens: ${(report.totalEstimatedInput + report.totalEstimatedOutput).toLocaleString()} ` +
293
+ `(input ${report.totalEstimatedInput.toLocaleString()} + output ${report.totalEstimatedOutput.toLocaleString()})`);
294
+ return {
295
+ totalModules: processingOrder.length,
296
+ successful: [],
297
+ failed: [],
298
+ skipped: processingOrder.slice(),
299
+ degraded: [],
300
+ duration: Date.now() - startTime,
301
+ indexGenerated: false,
302
+ summaryLogPath: '',
303
+ detectedLanguages: isMultiLang ? processedLanguages : undefined,
304
+ languageStats,
305
+ dryRunReportPath: toProjectPath(dryRunPath),
306
+ };
307
+ }
308
+ // Feature 127:预算守护 gate — AST + 模块聚合完成后预估,超预算时驱动 gate 循环
309
+ // Codex review 修复(Finding 1):降级 policy 后必须 re-estimate 并进入二次 gate,
310
+ // 否则 cheaper-model / skip-enrichment 形同虚设;最多循环一轮后强制 cancel。
311
+ let budgetDecisionResult;
312
+ let budgetSkipEnrichmentAll = false;
313
+ let budgetCheaperModelAll = false;
314
+ if (typeof options.budget === 'number' && options.budget > 0) {
315
+ const estimates = [];
316
+ for (const moduleName of processingOrder) {
317
+ const group = moduleGroups.get(moduleName);
318
+ if (!group)
319
+ continue;
320
+ estimates.push(estimateModuleCost(moduleName, group.files, resolvedRoot));
321
+ }
322
+ const baseTotal = estimates.reduce((s, e) => s + e.estimatedInput + e.estimatedOutput, 0);
323
+ const gateResult = await runBudgetGate({
324
+ baseEstimate: baseTotal,
325
+ budget: options.budget,
326
+ preset: options.onOverBudget,
327
+ isTTY: !!process.stdout.isTTY,
328
+ });
329
+ budgetSkipEnrichmentAll = gateResult.skipEnrichmentApplied;
330
+ budgetCheaperModelAll = gateResult.cheaperModelApplied;
331
+ for (const a of gateResult.attempts) {
332
+ console.log(`[budget] ${a.message}`);
333
+ }
334
+ // final message 取最后一条 attempt
335
+ const last = gateResult.attempts[gateResult.attempts.length - 1];
336
+ budgetDecisionResult = {
337
+ policy: gateResult.finalPolicy,
338
+ message: last.message,
339
+ interactive: false,
340
+ attempts: gateResult.attempts,
341
+ skipEnrichmentApplied: gateResult.skipEnrichmentApplied,
342
+ cheaperModelApplied: gateResult.cheaperModelApplied,
343
+ };
344
+ if (gateResult.finalPolicy === 'cancel') {
345
+ // 取消:不调用任何 LLM,立即返回
346
+ return {
347
+ totalModules: processingOrder.length,
348
+ successful: [],
349
+ failed: [],
350
+ skipped: processingOrder.slice(),
351
+ degraded: [],
352
+ duration: Date.now() - startTime,
353
+ indexGenerated: false,
354
+ summaryLogPath: '',
355
+ detectedLanguages: isMultiLang ? processedLanguages : undefined,
356
+ languageStats,
357
+ budgetDecision: budgetDecisionResult,
358
+ };
359
+ }
360
+ // continue 分支:budgetSkipEnrichmentAll / budgetCheaperModelAll 用于下方 genOptions 注入
361
+ }
362
+ // 步骤 3:检查是否存在检查点
363
+ let state = loadCheckpoint(checkpointPath);
364
+ const isResume = state !== null;
365
+ if (!state) {
366
+ state = {
367
+ batchId: `batch-${Date.now()}`,
368
+ projectRoot: resolvedRoot,
369
+ startedAt: new Date().toISOString(),
370
+ lastUpdatedAt: new Date().toISOString(),
371
+ totalModules: processingOrder.length,
372
+ processingOrder,
373
+ completedModules: [],
374
+ failedModules: [],
375
+ forceRegenerate: force,
376
+ // 多语言扩展字段
377
+ languageGroups: isMultiLang
378
+ ? Object.fromEntries(languageGroupsList.map((g) => [g.adapterId, g.files]))
379
+ : undefined,
380
+ filterLanguages: options.languages,
381
+ };
382
+ }
383
+ if (isResume) {
384
+ console.log(`恢复断点: 已完成 ${state.completedModules.length}/${state.totalModules} 模块`);
385
+ }
386
+ // 步骤 4:按模块级拓扑顺序处理
387
+ // Feature 146 FR-010/FR-011:通过 getActiveCount getter 注入 limit.activeCount,
388
+ // 使 TTY 进度条可展示「进行中」三维状态,而无需修改 ProgressReporter 接口。
389
+ // 这里使用闭包延迟读取:reporter 在 limit 之前创建,runtime 调用时 limit 已就位。
390
+ let limitRef;
391
+ const reporter = createReporter(processingOrder.length, options.progressMode, { getActiveCount: () => limitRef?.activeCount ?? 0 });
392
+ const successful = [];
393
+ const failed = [];
394
+ const skipped = [];
395
+ const degraded = [];
396
+ const collectedModuleSpecs = [];
397
+ // Feature 127:累积每模块成本,用于 batch 汇总 + 质量报告
398
+ const costRecords = [];
399
+ // 预计算跨语言提示文本(多语言项目)
400
+ const crossLangHint = isMultiLang
401
+ ? generateCrossLanguageHint(processedLanguages)
402
+ : '';
403
+ const completedPaths = new Set(state.completedModules.map((m) => m.path));
404
+ // Feature 146 — concurrency 读取与规范化(FR-002、FR-003)
405
+ // 默认值 3:Sonnet 调用 15-30s,concurrency=3 显著提升吞吐量且 429 风险可控。
406
+ // 优先级链:调用方(CLI)已合并 CLI flag > config,传入 options.concurrency;
407
+ // 此处仅做最后一道防线的规范化(防御非法传入),具体规则见 normalizeConcurrency 注释。
408
+ const concurrency = normalizeConcurrency(options.concurrency ?? 3, (msg) => logger.warn(msg));
409
+ const modulesDir = path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.MODULES);
410
+ // BUG-A 预计算:统计每个 dirPath 下有多少个单文件模块,冲突路径才使用文件路径
411
+ const dirPathGroupCount = new Map();
412
+ for (const group of groupResult.groups) {
413
+ if (group.files.length === 1) {
414
+ dirPathGroupCount.set(group.dirPath, (dirPathGroupCount.get(group.dirPath) ?? 0) + 1);
415
+ }
416
+ }
417
+ const conflictingDirPaths = new Set([...dirPathGroupCount.entries()]
418
+ .filter(([, count]) => count > 1)
419
+ .map(([dirPath]) => dirPath));
420
+ // state 在此处保证非 null(第 341 行的 if 分支已确保初始化)
421
+ const checkedState = state;
422
+ // H3 修复:通过集中模型配置解析 Sonnet 模型 ID,避免硬编码版本字符串。
423
+ // Fix 134:直接从 LOGICAL_*_MODEL_MAP 取 'sonnet',不走 yaml fallback
424
+ // 链——之前用 `agentId: 'specify-sonnet'` 在 yaml agents 不存在时回落到
425
+ // preset,当用户配置 quality-first 时 sonnetModelId 实际是 opus,破坏了
426
+ // 小模块/budget 降级/reading 模式 强制 sonnet 的设计意图(graphify E2E 暴露)。
427
+ // 按当前认证 runtime 决定 sonnet ID(claude → claude-sonnet-4-6;codex → gpt-5.4),
428
+ // 与 callLLM 内 detectAuth 的运行时保持一致;探测失败时默认 claude。
429
+ const detectedRuntime = (() => {
430
+ try {
431
+ const auth = detectAuth();
432
+ return auth.preferred?.provider === 'codex' ? 'codex' : 'claude';
433
+ }
434
+ catch {
435
+ return 'claude';
436
+ }
437
+ })();
438
+ const sonnetModelId = getCanonicalSonnetModelId(detectedRuntime);
439
+ /** 单个模块的处理逻辑(提取为函数以支持并行调度) */
440
+ async function processOneModule(moduleName) {
441
+ const group = moduleGroups.get(moduleName);
442
+ if (!group)
443
+ return;
444
+ if (completedPaths.has(moduleName))
445
+ return;
446
+ const isRoot = moduleName === rootModuleName || moduleName.startsWith(`${rootModuleName}--`);
447
+ const specPath = path.join(modulesDir, `${moduleName}.spec.md`);
448
+ // H4 修复:文件级降级场景下 moduleSourceTarget 须与 targetPath 保持一致(文件路径)
449
+ // 否则 --incremental 的 regenerateTargets 查询和 storedSpecByTarget 查询全部错位
450
+ const hasDirPathConflict = !isRoot && group.files.length === 1 && conflictingDirPaths.has(group.dirPath);
451
+ const moduleSourceTarget = hasDirPathConflict
452
+ ? normalizeProjectPath(group.files[0])
453
+ : normalizeProjectPath(group.dirPath);
454
+ const rootTargetsToGenerate = isRoot
455
+ ? group.files
456
+ .map((filePath) => normalizeProjectPath(filePath))
457
+ .filter((sourceTarget) => {
458
+ if (forceFullRegeneration)
459
+ return true;
460
+ if (shouldUseIncrementalPlan)
461
+ return regenerateTargets.has(sourceTarget);
462
+ const storedSpec = storedSpecByTarget.get(sourceTarget);
463
+ return !storedSpec || !fs.existsSync(path.join(resolvedRoot, storedSpec.outputPath));
464
+ })
465
+ : [];
466
+ if (isRoot) {
467
+ if (rootTargetsToGenerate.length === 0) {
468
+ skipped.push(moduleName);
469
+ reporter.complete(moduleName, 'skipped');
470
+ return;
471
+ }
472
+ }
473
+ else {
474
+ const shouldGenerate = forceFullRegeneration
475
+ || (shouldUseIncrementalPlan
476
+ ? regenerateTargets.has(moduleSourceTarget)
477
+ : !fs.existsSync(specPath));
478
+ if (!shouldGenerate) {
479
+ skipped.push(moduleName);
480
+ reporter.complete(moduleName, 'skipped');
481
+ return;
482
+ }
483
+ }
484
+ reporter.start(moduleName);
485
+ let retryCount = 0;
486
+ let moduleSuccess = false;
487
+ // Bug 142:单模块累计 input token 跟踪。
488
+ // 在「成功路径 + 失败路径」两侧都必须累积,否则最常见的 LLM 调用失败场景下,
489
+ // cumulativeInputTokens 永远为 0,预算检查彻底失效(参见 ESTIMATED_FAILED_CALL_INPUT 注释)。
490
+ let cumulativeInputTokens = 0;
491
+ let moduleTokenBudgetExceeded = false;
492
+ // 各阶段耗时(毫秒)— 用于模块完成后打印可观测性摘要行
493
+ const stageDurations = {};
494
+ const moduleStartTime = Date.now();
495
+ while (retryCount < maxRetries && !moduleSuccess) {
496
+ try {
497
+ // 小模块优化:文件数 ≤ 2 且总行数 < 200 时降级为 Sonnet + 跳过 enrichment
498
+ const totalLoc = group.files.reduce((sum, f) => {
499
+ try {
500
+ return sum + fs.readFileSync(path.join(resolvedRoot, f), 'utf-8').split('\n').length;
501
+ }
502
+ catch {
503
+ return sum;
504
+ }
505
+ }, 0);
506
+ const isSmallModule = group.files.length <= 2 && totalLoc < 200;
507
+ // Feature 127:预算降级策略(Codex review 修复):
508
+ // 降级在 gate 循环中就已采纳,此处只读取 budgetSkipEnrichmentAll /
509
+ // budgetCheaperModelAll 注入到每个模块的 genOptions,确保所有模块一致降级。
510
+ const genOptions = {
511
+ outputDir: modulesDir,
512
+ projectRoot: resolvedRoot,
513
+ deep: true,
514
+ // Feature 133 P0-2:reading/code-only 模式都跳过 enrichment(SC-001 < 120s
515
+ // 目标);同时尊重 small-module 优化和 budget gate 降级——任一为真都跳过
516
+ skipEnrichment: isSmallModule || budgetSkipEnrichmentAll || effectiveMode !== 'full',
517
+ // Fix 134 P0-3:reading/code-only 模式同样强制 sonnet override,
518
+ // 与默认 model 解耦(即使用户配置 quality-first/opus,reading 仍走
519
+ // sonnet,确保 SC-001 < 120s 始终满足);提取为 decideModelOverride 便于单测
520
+ modelOverride: decideModelOverride({
521
+ isSmallModule,
522
+ budgetCheaperModelAll,
523
+ effectiveMode,
524
+ sonnetModelId,
525
+ }),
526
+ // Bug 142:将 batch effectiveMode 写入 spec frontmatter 的 generatedByMode 字段,
527
+ // 供下次 batch 运行的 mode-aware cache 判定使用。
528
+ generatedByMode: effectiveMode,
529
+ onStageProgress: (progress) => {
530
+ reporter.stage(moduleName, progress);
531
+ if (progress.duration !== undefined) {
532
+ if (progress.stage === 'llm') {
533
+ // 首次 llm 完成记为 LLM#1,后续不覆盖(enrich 已独立为 'enrich' stage)
534
+ if (!('llm' in stageDurations)) {
535
+ stageDurations['llm'] = progress.duration;
536
+ }
537
+ }
538
+ else {
539
+ stageDurations[progress.stage] = progress.duration;
540
+ }
541
+ }
542
+ if (progress.stage === 'context' && progress.duration !== undefined) {
543
+ const currentCompleted = checkedState.completedModules.length + failed.length + skipped.length;
544
+ options.onProgress?.(currentCompleted + 0.5, processingOrder.length);
545
+ }
546
+ },
547
+ };
548
+ if (isRoot) {
549
+ const generatedRootSpecs = [];
550
+ for (const file of group.files) {
551
+ const sourceTarget = normalizeProjectPath(file);
552
+ if (!rootTargetsToGenerate.includes(sourceTarget))
553
+ continue;
554
+ const fullPath = path.join(resolvedRoot, file);
555
+ const storedSpec = storedSpecByTarget.get(sourceTarget);
556
+ // genOptions.skipEnrichment 已在 L648 处理 reading/code-only 模式分派
557
+ const result = await generateSpec(fullPath, {
558
+ ...genOptions,
559
+ existingVersion: storedSpec?.version,
560
+ });
561
+ // Bug 142:root 分支也必须累积 token——否则 root 模块的 budget 永远是 0,
562
+ // short-circuit 在 root 路径无效(前次实施漏掉这里导致 review 发现 CRITICAL)。
563
+ if (result.costMetadata?.tokenUsage.input) {
564
+ cumulativeInputTokens += result.costMetadata.tokenUsage.input;
565
+ }
566
+ collectedModuleSpecs.push(result.moduleSpec);
567
+ generatedRootSpecs.push(toProjectPath(path.resolve(result.specPath)));
568
+ // Feature 127:root 子模块也采集成本(mock 未返回时跳过)
569
+ if (result.costMetadata) {
570
+ let fileLoc = 0;
571
+ try {
572
+ fileLoc = fs.readFileSync(fullPath, 'utf-8').split('\n').length;
573
+ }
574
+ catch { /* ignore */ }
575
+ costRecords.push({
576
+ moduleName: `${moduleName}/${path.basename(file)}`,
577
+ loc: fileLoc,
578
+ cost: result.costMetadata,
579
+ });
580
+ }
581
+ }
582
+ if (generatedRootSpecs.length === 0) {
583
+ skipped.push(moduleName);
584
+ reporter.complete(moduleName, 'skipped');
585
+ moduleSuccess = true;
586
+ continue;
587
+ }
588
+ successful.push(moduleName);
589
+ reporter.complete(moduleName, 'success');
590
+ checkedState.completedModules.push({
591
+ path: moduleName,
592
+ specPath: generatedRootSpecs[0],
593
+ completedAt: new Date().toISOString(),
594
+ });
595
+ }
596
+ else {
597
+ // BUG-A 修复:同一 dirPath 下有多个单文件模块时(如 graphify/ 下有 a.py/b.py),
598
+ // 使用文件路径避免多个模块覆盖同一个 {dirName}.spec.md;
599
+ // 否则仍使用目录路径(每个目录只有一个文件时,目录名才是有意义的模块标识)
600
+ // 注意:hasDirPathConflict 已在上方计算(H4 修复)
601
+ const targetPath = hasDirPathConflict
602
+ ? path.join(resolvedRoot, group.files[0])
603
+ : path.join(resolvedRoot, group.dirPath);
604
+ // genOptions.skipEnrichment 已在 L648 处理 reading/code-only 模式分派
605
+ const result = await generateSpec(targetPath, {
606
+ ...genOptions,
607
+ existingVersion: storedSpecByTarget.get(moduleSourceTarget)?.version,
608
+ });
609
+ // Bug 142:非 root 分支累积 input token,供 catch 块统一做预算检查。
610
+ if (result.costMetadata?.tokenUsage.input) {
611
+ cumulativeInputTokens += result.costMetadata.tokenUsage.input;
612
+ }
613
+ if (isMultiLang && group.language) {
614
+ result.moduleSpec.frontmatter.language = group.language;
615
+ const crossRefs = detectCrossLanguageRefs(group.files, languageGroupsList, mergedGraph);
616
+ if (crossRefs.length > 0) {
617
+ result.moduleSpec.frontmatter.crossLanguageRefs = crossRefs;
618
+ }
619
+ if (crossLangHint) {
620
+ result.moduleSpec.sections.constraints += crossLangHint;
621
+ }
622
+ }
623
+ collectedModuleSpecs.push(result.moduleSpec);
624
+ if (result.confidence === 'low' && result.warnings.some((w) => w.includes('降级'))) {
625
+ degraded.push(moduleName);
626
+ reporter.complete(moduleName, 'degraded');
627
+ }
628
+ else {
629
+ successful.push(moduleName);
630
+ reporter.complete(moduleName, 'success');
631
+ }
632
+ checkedState.completedModules.push({
633
+ path: moduleName,
634
+ specPath: toProjectPath(path.resolve(result.specPath)),
635
+ completedAt: new Date().toISOString(),
636
+ tokenUsage: result.tokenUsage,
637
+ // Feature 127:结构化成本元数据(mock 未返回时省略)
638
+ ...(result.costMetadata ? { costMetadata: result.costMetadata } : {}),
639
+ });
640
+ // Feature 127:采集用于 batch 汇总(基于 module group 行数)
641
+ if (result.costMetadata) {
642
+ costRecords.push({
643
+ moduleName,
644
+ loc: group.files.reduce((sum, f) => {
645
+ try {
646
+ return sum + fs.readFileSync(path.join(resolvedRoot, f), 'utf-8').split('\n').length;
647
+ }
648
+ catch {
649
+ return sum;
650
+ }
651
+ }, 0),
652
+ cost: result.costMetadata,
653
+ });
654
+ }
655
+ }
656
+ // 耗时可观测性:打印各阶段耗时摘要
657
+ const fmt = (ms) => ms !== undefined ? `${(ms / 1000).toFixed(1)}s` : '-';
658
+ const totalMs = Date.now() - moduleStartTime;
659
+ process.stderr.write(`[${moduleName}] AST: ${fmt(stageDurations['ast'])} | context: ${fmt(stageDurations['context'])} | LLM#1: ${fmt(stageDurations['llm'])} | enrich: ${fmt(stageDurations['enrich'])} | render: ${fmt(stageDurations['render'])} | total: ${fmt(totalMs)}\n`);
660
+ moduleSuccess = true;
661
+ }
662
+ catch (error) {
663
+ retryCount++;
664
+ // Bug 142:LLM 调用本身抛异常时(最常见失败模式),无法从 result.costMetadata 取到 token,
665
+ // 按估算值累积。这是关键修复点:仅靠成功路径累积无法覆盖此场景。
666
+ cumulativeInputTokens += ESTIMATED_FAILED_CALL_INPUT;
667
+ // Bug 142 hotfix(v4.0.2):把 budget 检查从 retrospective 改为 forecast。
668
+ // 旧逻辑 `cumulativeInputTokens > RETRY_TOKEN_BUDGET` 是事后判断:
669
+ // default 配置下(maxRetries=3, ESTIMATED=15k, BUDGET=40k)3 次失败后 cumulative=45k
670
+ // 才触发 break,但此时 retryCount 已经达到 maxRetries 本来就会停,
671
+ // budget 检查只是给最后一次失败贴个不同 label,实际省 0 个 token。
672
+ // 新逻辑:再做一次重试是否会超预算?(forecast) 如果超 → 不再重试,标 reason 退出。
673
+ // 按 default 配置:第 2 次失败 cumulative=30k → 30k+15k=45k > 40k → break,
674
+ // 不进第 3 次,省 1 次 LLM 调用(~15k tokens)。
675
+ if (cumulativeInputTokens + ESTIMATED_FAILED_CALL_INPUT > RETRY_TOKEN_BUDGET) {
676
+ moduleTokenBudgetExceeded = true;
677
+ const failedModule = {
678
+ path: moduleName,
679
+ error: `累计 input token ${cumulativeInputTokens} 已达预算上限 ${RETRY_TOKEN_BUDGET},` +
680
+ `下一次重试预计将超出预算,提前终止重试。原始错误:${error.message ?? String(error)}`,
681
+ failedAt: new Date().toISOString(),
682
+ retryCount,
683
+ degradedToAstOnly: false,
684
+ reason: 'retry-budget-exceeded',
685
+ };
686
+ failed.push(failedModule);
687
+ checkedState.failedModules.push(failedModule);
688
+ reporter.complete(moduleName, 'failed');
689
+ break;
690
+ }
691
+ // Budget 与 maxRetries 互补:budget 控制 token 总量,maxRetries 控制失败次数。
692
+ if (retryCount >= maxRetries) {
693
+ const failedModule = {
694
+ path: moduleName,
695
+ error: error.message ?? String(error),
696
+ failedAt: new Date().toISOString(),
697
+ retryCount,
698
+ degradedToAstOnly: false,
699
+ };
700
+ failed.push(failedModule);
701
+ checkedState.failedModules.push(failedModule);
702
+ reporter.complete(moduleName, 'failed');
703
+ }
704
+ }
705
+ }
706
+ // 安全保险:moduleTokenBudgetExceeded 在 catch 块已 break,
707
+ // 此处仅用于消除"已声明未使用"的 TS 警告(保留变量便于未来观测性扩展)。
708
+ void moduleTokenBudgetExceeded;
709
+ checkedState.lastUpdatedAt = new Date().toISOString();
710
+ saveCheckpoint(checkedState, checkpointPath);
711
+ options.onProgress?.(checkedState.completedModules.length + failed.length + skipped.length, processingOrder.length);
712
+ }
713
+ // 步骤 4:并发调度(Feature 146 — 使用 p-limit 替换手写信号量)
714
+ // 历史背景:原手写信号量(pending 队列 + 活跃计数 + race 等待)出现过死锁 bug(H2 修复痕迹),
715
+ // 且 concurrency<=1 与并发分支双路径增加维护成本。
716
+ // clarify.md AU-005 决议:统一走 pLimit(concurrency) 路径,pLimit(1) 语义等同顺序执行(队列串行)。
717
+ // FR-006/FR-007:limit 内部捕获异常 + Promise.allSettled 双重保护,确保单模块失败不阻塞其他模块。
718
+ // FR-008(并发安全性):JS 单线程事件循环保证:所有 successful.push / failed.push / costRecords.push /
719
+ // cumulativeInputTokens += 等共享状态修改,均发生在 await 返回后的同步执行段,
720
+ // 多个模块的修改语句不会在指令级交错(不存在原生意义的「数据竞态」)。
721
+ // FR-009:BatchResult.duration 由 startTime/endTime 在 runBatch 入口/出口取一次 Date.now() 计算,
722
+ // 反映墙钟耗时(并发下小于各模块耗时之和),无需额外修改。
723
+ const limit = pLimit(concurrency);
724
+ limitRef = limit; // 注入到 reporter 的 getActiveCount getter(FR-010)
725
+ const tasks = processingOrder.map((moduleName) => limit(async () => {
726
+ try {
727
+ await processOneModule(moduleName);
728
+ }
729
+ catch (err) {
730
+ // 兜底:processOneModule 内部已捕获 LLM 重试失败并写入 failed[],但
731
+ // saveCheckpoint / onProgress / reporter.complete 等 try 之外的副作用调用
732
+ // 仍可能抛出未预期错误(如 EACCES / 磁盘满)。Codex 对抗审查指出,仅
733
+ // logger.warn 而不写 failed[] 会让这类模块从最终结果中静默消失,破坏
734
+ // BatchResult 的 totalModules == successful + failed + skipped 不变量。
735
+ // 此处补齐 failed[] + reporter.complete,保证「每个模块都有最终状态」。
736
+ logger.warn(`模块 ${moduleName} 出现未捕获异常: ${String(err)}`);
737
+ const failedModule = {
738
+ path: moduleName,
739
+ error: err instanceof Error ? err.message : String(err),
740
+ failedAt: new Date().toISOString(),
741
+ retryCount: 0,
742
+ degradedToAstOnly: false,
743
+ reason: 'unhandled-exception',
744
+ };
745
+ failed.push(failedModule);
746
+ checkedState.failedModules.push(failedModule);
747
+ try {
748
+ reporter.complete(moduleName, 'failed');
749
+ }
750
+ catch {
751
+ // reporter.complete 自身抛出(如 TTY 已关闭)不能再向外冒泡。
752
+ }
753
+ }
754
+ }));
755
+ await Promise.allSettled(tasks);
756
+ // 步骤 5:生成架构索引(使用收集的 ModuleSpec)
757
+ let deltaReportPath;
758
+ let docGraphPath;
759
+ let coverageReportPath;
760
+ let projectDocs;
761
+ let graphHtmlPath;
762
+ let projectDocsResult;
763
+ let docsBundleManifestPath;
764
+ let docsBundleProfiles;
765
+ // SpecStore 统一查询入口:所有消费方(README、graph、coverage、index、cross-ref)共享此源
766
+ const specStore = new SpecStore({
767
+ currentSpecs: collectedModuleSpecs,
768
+ storedSpecs: existingStoredSpecs,
769
+ projectRoot: resolvedRoot,
770
+ toProjectPath,
771
+ });
772
+ const projectDir = path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.PROJECT);
773
+ const metaDir = path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.META);
774
+ try {
775
+ // 通过 SpecStore.asDocGraphInput() 获取:已过滤 orphan/bundle_copy/derived
776
+ const { moduleSpecs: docGraphModuleSpecs, existingSpecs: docGraphExistingSpecs } = specStore.asDocGraphInput();
777
+ const docGraph = buildDocGraph({
778
+ projectRoot: resolvedRoot,
779
+ dependencyGraph: mergedGraph,
780
+ moduleSpecs: docGraphModuleSpecs,
781
+ existingSpecs: docGraphExistingSpecs,
782
+ });
783
+ for (const moduleSpec of collectedModuleSpecs) {
784
+ moduleSpec.crossReferenceIndex = buildCrossReferenceIndex(moduleSpec, docGraph);
785
+ const specOutputPath = path.isAbsolute(moduleSpec.outputPath)
786
+ ? moduleSpec.outputPath
787
+ : path.join(resolvedRoot, moduleSpec.outputPath);
788
+ fs.mkdirSync(path.dirname(specOutputPath), { recursive: true });
789
+ fs.writeFileSync(specOutputPath, renderSpec(moduleSpec), 'utf-8');
790
+ }
791
+ // 注意:不再生成 _doc-graph.json(Feature 098 — 结构化数据通过内存传递,减少输出冗余)
792
+ if (deltaReport) {
793
+ try {
794
+ const deltaRegenerator = new DeltaRegenerator();
795
+ const deltaMarkdown = deltaRegenerator.render(deltaReport);
796
+ const deltaMarkdownPathAbs = path.join(metaDir, '_delta-report.md');
797
+ fs.mkdirSync(metaDir, { recursive: true });
798
+ fs.writeFileSync(deltaMarkdownPathAbs, deltaMarkdown, 'utf-8');
799
+ deltaReportPath = toProjectPath(deltaMarkdownPathAbs);
800
+ }
801
+ catch (err) {
802
+ logger.warn(`差量报告生成失败: ${String(err)}`);
803
+ }
804
+ }
805
+ let projectContext = await buildProjectContext(resolvedRoot);
806
+ // Feature 140 T22/T24 — 读取 README 全量内容,供 architecture-narrative 在
807
+ // generateBatchProjectDocs 阶段使用(早于下方 multimodal extraction-pipeline)。
808
+ // 仅 --include-docs=true 时读取;下方 extraction-pipeline 仍会返回相同 readmeContent
809
+ // 供 hyperedge integration 使用,二者读取的是同一文件,无冲突。
810
+ //
811
+ // 共享 findReadmePath(来自 extraction-pipeline)确保大小写匹配候选列表口径一致
812
+ // (修复 Codex review CRITICAL 2 — 之前的硬编码列表 ['README.md', 'readme.md', 'Readme.md']
813
+ // 漏掉 README.MD / Readme.MD 等其他大小写组合)。
814
+ let earlyReadmeContent;
815
+ if (options.includeDocs) {
816
+ try {
817
+ const { findReadmePath } = await import('../extraction/index.js');
818
+ const readmePath = findReadmePath(resolvedRoot);
819
+ if (readmePath) {
820
+ earlyReadmeContent = fs.readFileSync(readmePath, 'utf-8');
821
+ }
822
+ }
823
+ catch (readmeErr) {
824
+ logger.warn(`README 早期读取失败(不阻断 narrative 主流程): ${String(readmeErr)}`);
825
+ }
826
+ }
827
+ try {
828
+ projectDocsResult = await generateBatchProjectDocs({
829
+ projectRoot: resolvedRoot,
830
+ outputDir: projectDir,
831
+ specsRootDir: resolvedOutputDir,
832
+ mode: effectiveMode,
833
+ enableAdr: options.enableAdr,
834
+ // Feature 140 T22/T24:透传 readmeContent 给 architecture-narrative
835
+ ...(earlyReadmeContent !== undefined ? { readmeContent: earlyReadmeContent } : {}),
836
+ });
837
+ projectContext = projectDocsResult.projectContext;
838
+ projectDocs = projectDocsResult.generatedDocs
839
+ .flatMap((doc) => doc.writtenFiles)
840
+ .filter((filePath) => filePath.endsWith('.md'))
841
+ .map(toProjectPath)
842
+ .sort((a, b) => a.localeCompare(b));
843
+ }
844
+ catch (err) {
845
+ logger.warn(`项目级 panoramic 文档生成失败: ${String(err)}`);
846
+ }
847
+ // Feature 101: 知识图谱持久化(graph-persistence)
848
+ // 注入位置:generateBatchProjectDocs 之后,可获取 architectureIR
849
+ try {
850
+ const crossReferenceLinks = collectedModuleSpecs
851
+ .flatMap((spec) => spec.crossReferenceIndex
852
+ ? [...spec.crossReferenceIndex.sameModule, ...spec.crossReferenceIndex.crossModule]
853
+ : []);
854
+ // Feature 145 P0:Python 符号提取(不依赖 flag,始终执行)
855
+ // 从所有 .py 文件提取函数/类符号节点,注入 buildKnowledgeGraph 第四路
856
+ let pythonSymbolResults = [];
857
+ try {
858
+ const { PythonLanguageAdapter } = await import('../adapters/python-adapter.js');
859
+ const pythonAdapter = new PythonLanguageAdapter();
860
+ pythonSymbolResults = await pythonAdapter.extractSymbolNodes(resolvedRoot);
861
+ if (pythonSymbolResults.length > 0) {
862
+ const symbolCount = pythonSymbolResults.reduce((sum, r) => sum + r.nodes.filter(n => n.kind === 'component').length, 0);
863
+ // Codex 对抗审查 C001 修复:聚合 parseError 数,避免"全失败伪装成功"
864
+ const filesFailed = pythonSymbolResults.reduce((sum, r) => sum + r.nodes.filter(n => n.kind === 'module' && n.metadata?.['parseError'] === true).length, 0);
865
+ const totalFiles = pythonSymbolResults.length;
866
+ if (filesFailed === totalFiles && totalFiles > 0) {
867
+ // 所有 .py 文件都解析失败 — 强信号,必须 warn
868
+ logger.warn(`Python 符号提取:${totalFiles} 个文件全部解析失败(可能是 tree-sitter Python WASM 加载或 grammar 问题);` +
869
+ `graph.json 仅含 module 节点,缺失全部函数/类 component 节点`);
870
+ }
871
+ else if (filesFailed > 0) {
872
+ logger.warn(`Python 符号提取部分失败:${filesFailed}/${totalFiles} 个文件解析失败,` +
873
+ `成功提取 ${symbolCount} 个符号节点`);
874
+ }
875
+ else {
876
+ logger.info(`Python 符号提取完成:${totalFiles} 个文件,${symbolCount} 个符号节点`);
877
+ }
878
+ }
879
+ }
880
+ catch (pyErr) {
881
+ logger.warn(`Python 符号提取失败,跳过: ${String(pyErr)}`);
882
+ }
883
+ // Feature 107: 多模态提取管道(--include-docs / --include-images)
884
+ // Feature 140 T21/T22:返回类型改为 { results, readmeContent? } 包装对象
885
+ let extractionResults;
886
+ let extractedReadmeContent;
887
+ if (options.includeDocs || options.includeImages) {
888
+ try {
889
+ const { runExtractionPipeline } = await import('../extraction/index.js');
890
+ const extractionOutput = await runExtractionPipeline({
891
+ projectRoot: resolvedRoot,
892
+ outputDir: resolvedOutputDir,
893
+ includeDocs: options.includeDocs ?? false,
894
+ includeImages: options.includeImages ?? false,
895
+ });
896
+ extractionResults = extractionOutput.results;
897
+ extractedReadmeContent = extractionOutput.readmeContent;
898
+ // Feature 140 FR-010:用户开启 --include-docs 时,明确告知"已加入 N 份 .md 作为
899
+ // 语义上下文"(替代 v4.0.x 时代误导性的"跳过 .md 文件(不支持)")。
900
+ // N = ExtractionResult 中 kind=document 的节点数 + (有 README 时 +1)。
901
+ if (options.includeDocs) {
902
+ const docNodeCount = (extractionResults ?? []).reduce((sum, r) => sum + r.nodes.filter((n) => n.kind === 'document').length, 0);
903
+ const totalDocs = docNodeCount + (extractedReadmeContent ? 1 : 0);
904
+ logger.info(`include-docs: 已加入 ${totalDocs} 份 .md 作为语义上下文(含 README: ${extractedReadmeContent ? '是' : '否'})`);
905
+ }
906
+ }
907
+ catch (extractErr) {
908
+ logger.warn(`多模态提取失败,跳过: ${String(extractErr)}`);
909
+ }
910
+ }
911
+ // 合并 Python 符号提取结果和多模态提取结果(Feature 145 ADR-002)
912
+ const mergedResults = [
913
+ ...pythonSymbolResults,
914
+ ...(extractionResults ?? []),
915
+ ];
916
+ const graphJson = buildKnowledgeGraph({
917
+ architectureIR: projectDocsResult?.architectureIR,
918
+ docGraph,
919
+ crossReferenceLinks,
920
+ extractionResults: mergedResults.length > 0 ? mergedResults : undefined, // Feature 107 + 143 第四路数据源
921
+ });
922
+ // Feature 133 P1-1(adversarial-review post-fix):anchor + hyperedge 集成
923
+ // F4 提供了 runAnchorIntegration / runHyperedgeIntegration 集成函数,
924
+ // 但 batch 编排器从未调用过它们,导致 graph.json 不含 references /
925
+ // conceptually_related_to 边和 hyperedges。本块接通生产路径。
926
+ //
927
+ // Codex adversarial-review 收紧的守卫:
928
+ // - 只在 mode === 'full' 时跑(reading/code-only 不应做 LLM-heavy 富化)
929
+ // - 只在未触发 budget gate skip-enrichment 降级时跑(与模块 spec enrichment
930
+ // 降级策略一致,避免成本超预算)
931
+ // - hyperedge 集成默认 false,需要显式 opt-in(CLI `--hyperedges` 或 env
932
+ // `SPECTRA_HYPEREDGES_ENABLED=true`);即使 mode/budget 允许,未 opt-in
933
+ // 也只跑 anchor,不跑 hyperedge
934
+ const semanticIntegrationAllowed = effectiveMode === 'full' && !budgetSkipEnrichmentAll;
935
+ // Bug 2(Feature 135):hyperedgesOptIn 需要在此提前解析,用于 WARNING 可观测性
936
+ const hyperedgesOptInEarly = options.hyperedgesEnabled === true
937
+ || process.env['SPECTRA_HYPEREDGES_ENABLED'] === 'true';
938
+ if (!semanticIntegrationAllowed) {
939
+ const reason = effectiveMode !== 'full'
940
+ ? `mode=${effectiveMode}(非 full)`
941
+ : 'budget gate 已触发 skip-enrichment 降级';
942
+ // 升级为 warn 级别(Bug 2 T09),确保用户能感知到 hyperedges 被静默跳过
943
+ logger.warn(`semantic-integration: 跳过 anchor + hyperedge 集成 — ${reason}(保持 graph.json 仅含静态边)`);
944
+ // 若用户显式请求了 --hyperedges 但条件不允许,向 stderr 打印可见 WARNING
945
+ if (hyperedgesOptInEarly) {
946
+ process.stderr.write(`[WARNING] --hyperedges 已启用但当前运行条件不满足(${reason}),hyperedge 集成已跳过。\n` +
947
+ ` 如需 hyperedge,请使用 --mode full 且未触发 budget gate skip-enrichment。\n`);
948
+ }
949
+ }
950
+ else {
951
+ try {
952
+ // Feature 140 T27 — 启用扩展来源(README + docs/ + module specs + project-context)
953
+ // 让 hyperedge 在新项目首次 batch 也能产出非空 designDocAbsPaths(FR-007)。
954
+ const designDocResult = buildDesignDocAbsPaths(projectDocs ?? [], resolvedRoot, resolvedOutputDir, {
955
+ includeReadme: true,
956
+ includeDocs: options.includeDocs ?? false,
957
+ modulesDir,
958
+ includeProjectContext: true,
959
+ });
960
+ const { paths: designDocAbsPaths, fromDocsCount, fromDiskCount, nestedDirsDetected } = designDocResult;
961
+ // FR-007:诊断日志,显示 designDocAbsPaths 来源与数量
962
+ logger.info(`hyperedge: designDocAbsPaths.length=${designDocAbsPaths.length} ` +
963
+ `(fromDocs=${fromDocsCount}, fromDisk=${fromDiskCount}, ` +
964
+ `fromReadme=${designDocResult.fromReadmeCount}, ` +
965
+ `fromDocsDir=${designDocResult.fromDocsDirCount}, ` +
966
+ `fromModuleSpecs=${designDocResult.fromModuleSpecsCount}, ` +
967
+ `fromProjectContext=${designDocResult.fromProjectContextCount})`);
968
+ // Codex 对抗审查 W002 修复:嵌套子目录的 .md 不参与 anchor/hyperedge 集成,向用户暴露
969
+ if (nestedDirsDetected.length > 0) {
970
+ logger.warn(`hyperedge: outputDir/project/ 下检测到 ${nestedDirsDetected.length} 个子目录` +
971
+ `(${nestedDirsDetected.join(', ')}),其中嵌套的 .md 文件未被 anchor/hyperedge 集成扫描。` +
972
+ `当前实现只支持扁平 project 目录;如需支持嵌套,请在 spec 中提交需求。`);
973
+ }
974
+ const codeNodes = graphJson.nodes.filter((n) => !DOC_NODE_KINDS.has(n.kind));
975
+ // Bug 2(T11):hyperedge 数量状态变量(用于 batch summary 末尾输出)
976
+ let hyperedgeCount = 0;
977
+ let hyperedgeWarningReason;
978
+ if (designDocAbsPaths.length > 0 && codeNodes.length > 0) {
979
+ // 1) anchor 集成 — references / conceptually_related_to 边
980
+ // anchor 用 embedding(local 不计费 / openai 按字符计费),不需要
981
+ // 单独 opt-in,但仍受 mode + budget 守卫保护
982
+ try {
983
+ const provider = createEmbeddingProvider();
984
+ const anchorResult = await runAnchorIntegration(resolvedRoot, {
985
+ markdownFiles: designDocAbsPaths,
986
+ graphNodes: codeNodes,
987
+ provider,
988
+ });
989
+ if (anchorResult.semanticEdges.length > 0) {
990
+ graphJson.links.push(...anchorResult.semanticEdges);
991
+ logger.info(`anchor-integration: 追加 ${anchorResult.semanticEdges.length} 条语义边到 graph.json`);
992
+ }
993
+ }
994
+ catch (anchorErr) {
995
+ logger.warn(`anchor-integration: 失败,跳过语义边生成: ${anchorErr instanceof Error ? anchorErr.message : String(anchorErr)}`);
996
+ }
997
+ // 2) hyperedge 集成 — LLM 提取超边(显式 opt-in 控制)
998
+ // 使用提前解析的 hyperedgesOptInEarly 避免重复声明
999
+ if (!hyperedgesOptInEarly) {
1000
+ logger.info('hyperedge-integration: 跳过 — 未显式 opt-in(用 --hyperedges 或 SPECTRA_HYPEREDGES_ENABLED=true 启用)');
1001
+ }
1002
+ else {
1003
+ try {
1004
+ const docChunks = chunkMarkdownFiles(designDocAbsPaths, resolvedRoot);
1005
+ // Feature 140 T26 — 注入 README 全量内容作为虚拟 DocChunk(最高优先级,
1006
+ // 放在 docChunks 数组首位)。这让 hyperedge extractor 在 LLM 调用中始终
1007
+ // 能看到项目顶层叙述(README),不依赖 designDocAbsPaths 的扫描覆盖度。
1008
+ // 仅 --include-docs=true 且 README 实际读取成功时注入;未注入时行为完全不变。
1009
+ if (extractedReadmeContent && extractedReadmeContent.trim().length > 0) {
1010
+ const readmeText = extractedReadmeContent;
1011
+ const readmeChunk = {
1012
+ filePath: 'README.md',
1013
+ startLine: 1,
1014
+ endLine: readmeText.split('\n').length,
1015
+ headingPath: 'README',
1016
+ text: readmeText,
1017
+ tokenCount: Math.ceil(readmeText.length / 4),
1018
+ };
1019
+ docChunks.unshift(readmeChunk);
1020
+ logger.info(`hyperedge-integration: 注入 README 作为虚拟 DocChunk(${readmeChunk.tokenCount} tokens 估算)`);
1021
+ }
1022
+ const hyperResult = await runHyperedgeIntegration({
1023
+ hyperedgesEnabled: true,
1024
+ graphNodes: codeNodes,
1025
+ docChunks,
1026
+ });
1027
+ if (hyperResult.hyperedges.length > 0) {
1028
+ graphJson.hyperedges = hyperResult.hyperedges;
1029
+ hyperedgeCount = hyperResult.hyperedges.length;
1030
+ logger.info(`hyperedge-integration: 写入 ${hyperResult.hyperedges.length} 条 hyperedge 到 graph.json`);
1031
+ }
1032
+ }
1033
+ catch (hyperErr) {
1034
+ logger.warn(`hyperedge-integration: 失败,跳过超边生成: ${hyperErr instanceof Error ? hyperErr.message : String(hyperErr)}`);
1035
+ }
1036
+ }
1037
+ }
1038
+ else if (hyperedgesOptInEarly) {
1039
+ // Bug 2 T10:用户启用了 --hyperedges 但前置条件未满足(无 projectDocs)
1040
+ hyperedgeWarningReason = '前置条件未满足:designDocAbsPaths 为空';
1041
+ const warnMsg = '[WARNING] --hyperedges 已启用但前置条件未满足:designDocAbsPaths 为空。\n' +
1042
+ ' 请先不带 --hyperedges 完整运行一次 batch(mode=full),生成项目文档后再启用。\n';
1043
+ logger.warn(warnMsg.trim());
1044
+ process.stderr.write(warnMsg);
1045
+ }
1046
+ // Bug 2 T11:batch summary hyperedge 状态行(仅当用户 opt-in 时打印)
1047
+ // Codex adversarial review 追加修复:opt-in 时默认 logger level=warn,
1048
+ // logger.info 在生产环境不可见,改用 process.stderr.write 强制输出
1049
+ if (hyperedgesOptInEarly) {
1050
+ if (hyperedgeWarningReason) {
1051
+ const msg = `[hyperedges] 已提取 0 条(WARNING: ${hyperedgeWarningReason})`;
1052
+ process.stderr.write(`${msg}\n`);
1053
+ logger.warn(msg);
1054
+ }
1055
+ else {
1056
+ const msg = hyperedgeCount > 0
1057
+ ? `[hyperedges] 已提取 ${hyperedgeCount} 条`
1058
+ : `[hyperedges] 已提取 0 条(LLM 未返回有效候选;可在 graph.json 验证)`;
1059
+ process.stderr.write(`${msg}\n`);
1060
+ logger.warn(msg);
1061
+ }
1062
+ }
1063
+ }
1064
+ catch (integrationErr) {
1065
+ logger.warn(`semantic-integration: 整体失败,graph.json 将不含 anchor/hyperedge 数据: ${integrationErr instanceof Error ? integrationErr.message : String(integrationErr)}`);
1066
+ }
1067
+ }
1068
+ // Feature 102: 社区分析(写盘前执行,使 degree 信息写入 graph.json)
1069
+ try {
1070
+ const { runCommunityAnalysis } = await import('../panoramic/community/index.js');
1071
+ const reportPath = runCommunityAnalysis(graphJson, resolvedOutputDir);
1072
+ logger.info(`community-analysis: GRAPH_REPORT.md 已生成: ${reportPath}`);
1073
+ }
1074
+ catch (communityErr) {
1075
+ logger.warn(`community-analysis: 社区分析失败,跳过报告生成: ${communityErr instanceof Error ? communityErr.message : String(communityErr)}`);
1076
+ }
1077
+ // 社区分析完成后写盘(graphJson 已含 degree metadata)
1078
+ const graphWrittenPath = writeKnowledgeGraph(graphJson, resolvedOutputDir);
1079
+ docGraphPath = toProjectPath(graphWrittenPath);
1080
+ // Feature 140 FR-011:graph.html 始终生成(之前 `if (options.generateHtml)` 是
1081
+ // `--html` flag opt-in,导致大量 batch 输出缺失 graph.html)。改用 `?? true` 默认
1082
+ // 生成,调用方仍可显式 false 跳过。极小图(< 3 节点)由 buildHtmlTemplate 注入 banner。
1083
+ if (options.generateHtml ?? true) {
1084
+ try {
1085
+ // T-036:为每个节点注入 specPath 和 specPathExists 字段
1086
+ // spec 类型节点:id 本身就是 specPath(形如 "specs/modules/xxx.spec.md")
1087
+ // module/component 类型节点:尝试从 metadata 推导对应的 spec 文件路径
1088
+ const enrichedNodes = graphJson.nodes.map((node) => {
1089
+ let specPath;
1090
+ if (node.kind === 'spec') {
1091
+ // spec 节点的 id 就是 spec 文件的 repo-relative 路径
1092
+ specPath = node.id;
1093
+ }
1094
+ else if (typeof node.metadata?.sourceTarget === 'string' &&
1095
+ node.metadata.sourceTarget.endsWith('.spec.md')) {
1096
+ specPath = node.metadata.sourceTarget;
1097
+ }
1098
+ if (!specPath)
1099
+ return node;
1100
+ const absSpecPath = path.join(resolvedRoot, specPath);
1101
+ const specPathExists = fs.existsSync(absSpecPath);
1102
+ return { ...node, specPath: absSpecPath, specPathExists };
1103
+ });
1104
+ const enrichedGraphJson = { ...graphJson, nodes: enrichedNodes };
1105
+ const graphDataJson = JSON.stringify(enrichedGraphJson);
1106
+ // FR-023:节点数 >= 2000 时输出 warn 提示(大图性能风险)
1107
+ if (enrichedNodes.length >= 2000) {
1108
+ logger.warn('[warn] graph node count exceeds 2000, force layout disabled, using static layout');
1109
+ }
1110
+ // Feature 140 T19:传入 nodeCount,让 buildHtmlTemplate 在极小图(< 3 节点)时注入说明 banner
1111
+ const htmlContent = buildHtmlTemplate(graphDataJson, {
1112
+ forceLayoutThreshold: 2000,
1113
+ nodeCount: enrichedNodes.length,
1114
+ });
1115
+ const htmlPath = path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.META, 'graph.html');
1116
+ fs.mkdirSync(path.dirname(htmlPath), { recursive: true });
1117
+ fs.writeFileSync(htmlPath, htmlContent, 'utf-8');
1118
+ graphHtmlPath = toProjectPath(htmlPath);
1119
+ logger.info(`graph.html 已生成: ${graphHtmlPath}`);
1120
+ // FR-024:体积超 5 MB 输出 warn(不阻断)
1121
+ const htmlSize = Buffer.byteLength(htmlContent, 'utf-8');
1122
+ if (htmlSize >= 5 * 1024 * 1024) {
1123
+ logger.warn(`[warn] graph.html 体积 ${(htmlSize / (1024 * 1024)).toFixed(1)} MB 超过 5 MB,建议考虑减少节点数量`);
1124
+ }
1125
+ }
1126
+ catch (htmlErr) {
1127
+ logger.warn(`graph.html 生成失败,跳过: ${htmlErr instanceof Error ? htmlErr.message : String(htmlErr)}`);
1128
+ }
1129
+ }
1130
+ }
1131
+ catch (graphErr) {
1132
+ logger.warn(`graph-persistence: 图构建失败,跳过 graph.json 生成: ${graphErr instanceof Error ? graphErr.message : String(graphErr)}`);
1133
+ }
1134
+ // F5:reading/code-only 模式跳过 Coverage Audit(依赖完整产品文档集)
1135
+ if (effectiveMode === 'full') {
1136
+ try {
1137
+ const coverageAuditor = new CoverageAuditor();
1138
+ const coverageAudit = await coverageAuditor.audit({
1139
+ projectRoot: resolvedRoot,
1140
+ outputDir: resolvedOutputDir,
1141
+ projectContext,
1142
+ docGraph,
1143
+ moduleGroups: groupResult.groups,
1144
+ });
1145
+ const coverageMarkdown = coverageAuditor.render(coverageAudit);
1146
+ const coverageMarkdownPathAbs = path.join(projectDir, '_coverage-report.md');
1147
+ fs.mkdirSync(projectDir, { recursive: true });
1148
+ fs.writeFileSync(coverageMarkdownPathAbs, coverageMarkdown, 'utf-8');
1149
+ coverageReportPath = toProjectPath(coverageMarkdownPathAbs);
1150
+ }
1151
+ catch (err) {
1152
+ logger.warn(`覆盖率审计生成失败: ${String(err)}`);
1153
+ }
1154
+ }
1155
+ }
1156
+ catch (err) {
1157
+ logger.warn(`文档图谱生成失败: ${String(err)}`);
1158
+ }
1159
+ // 步骤 6:生成架构索引(使用收集的 ModuleSpec)
1160
+ let indexGenerated = false;
1161
+ try {
1162
+ initRenderer();
1163
+ // 通过 SpecStore.allKnownSpecs() 获取:已过滤 orphan/bundle_copy/derived
1164
+ const index = generateIndex(specStore.allKnownSpecs(), mergedGraph, languageStats, processedLanguages);
1165
+ const indexMarkdown = renderIndex(index);
1166
+ const indexPath = path.join(resolvedOutputDir, BATCH_OUTPUT_SUBDIRS.MODULES, '_index.spec.md');
1167
+ fs.mkdirSync(path.dirname(indexPath), { recursive: true });
1168
+ fs.writeFileSync(indexPath, indexMarkdown, 'utf-8');
1169
+ indexGenerated = true;
1170
+ }
1171
+ catch (err) {
1172
+ logger.warn(`架构索引生成失败: ${String(err)}`);
1173
+ }
1174
+ // F5:reading/code-only 模式跳过 Docs Bundle(依赖完整产品文档集)
1175
+ if (effectiveMode === 'full') {
1176
+ try {
1177
+ const docsBundleResult = orchestrateDocsBundle({
1178
+ projectRoot: resolvedRoot,
1179
+ outputDir: resolvedOutputDir,
1180
+ metaDir,
1181
+ });
1182
+ docsBundleManifestPath = docsBundleResult.manifestPath;
1183
+ docsBundleProfiles = docsBundleResult.profiles;
1184
+ }
1185
+ catch (err) {
1186
+ logger.warn(`文档 bundle 编排失败: ${String(err)}`);
1187
+ }
1188
+ }
1189
+ // Feature 127:聚合 LLM 成本(在质量报告前计算,供其追加成本节)
1190
+ const costSummary = aggregateCostSummary(costRecords);
1191
+ // Feature 133(adversarial-review post-fix):reading / code-only 模式跳过
1192
+ // docs-quality-evaluator 调用——该评估器依赖 architectureNarrative + 完整产
1193
+ // 品文档集,在 mode !== 'full' 时这些上游产物已被跳过,强行调用会得到空报告
1194
+ if (projectDocsResult && effectiveMode === 'full') {
1195
+ try {
1196
+ // 传入 manifestSearchDir 以便质量报告找到 _meta/ 中的 docs-bundle.yaml
1197
+ projectDocsResult.qualityInputs.manifestSearchDir = metaDir;
1198
+ // Feature 127:将成本汇总注入质量报告
1199
+ projectDocsResult.qualityInputs.costSummary = costSummary;
1200
+ const qualityDoc = generateDocsQualityReport(projectDocsResult.qualityInputs);
1201
+ projectDocs = Array.from(new Set([
1202
+ ...(projectDocs ?? []),
1203
+ ...qualityDoc.writtenFiles
1204
+ .filter((filePath) => filePath.endsWith('.md'))
1205
+ .map(toProjectPath),
1206
+ ])).sort((a, b) => a.localeCompare(b));
1207
+ }
1208
+ catch (err) {
1209
+ logger.warn(`文档质量报告生成失败: ${String(err)}`);
1210
+ }
1211
+ }
1212
+ // Feature 130:债务情报 pipeline(写入 project/technical-debt.md + 追加 quality-report)
1213
+ let debtResult;
1214
+ if (options.enableDebtIntelligence !== false) {
1215
+ try {
1216
+ // Codex review:CLI 不会显式构造 SimpleLLMClient;若环境变量可用则自动注入默认实现,
1217
+ // 确保生产路径下 `?` 结尾的 design-doc open question 能走 LLM 主题推断而非被降级丢弃。
1218
+ const { tryCreateDefaultLLMClient } = await import('../debt-scanner/llm-clients.js');
1219
+ const llmClient = options.debtLlmClient ?? tryCreateDefaultLLMClient();
1220
+ debtResult = await generateDebtIntelligence({
1221
+ projectRoot: resolvedRoot,
1222
+ specsDir: resolvedOutputDir,
1223
+ registry: LanguageAdapterRegistry.getInstance(),
1224
+ // Codex review:batch 的 --languages 过滤必须传到 debt 扫描,否则 filtered 运行
1225
+ // 会扫出并发布不在本次处理范围的债务条目。
1226
+ languages: options.languages,
1227
+ llmClient,
1228
+ budgetLimit: options.budget,
1229
+ dryRun: options.dryRun,
1230
+ });
1231
+ // 把 debt 的 tokenUsage 汇入 cost 汇总(以 debt-intelligence 为模块标签)
1232
+ if (debtResult.tokenUsage.input > 0 || debtResult.tokenUsage.output > 0) {
1233
+ costRecords.push({
1234
+ moduleName: 'debt-intelligence',
1235
+ loc: 0,
1236
+ cost: {
1237
+ tokenUsage: {
1238
+ input: debtResult.tokenUsage.input,
1239
+ output: debtResult.tokenUsage.output,
1240
+ },
1241
+ durationMs: debtResult.durationMs,
1242
+ llmModel: resolveReverseSpecModel().model,
1243
+ fallbackReason: debtResult.fallbackReason ?? null,
1244
+ },
1245
+ });
1246
+ // 重新聚合 cost summary(含 debt tokens)
1247
+ Object.assign(costSummary, aggregateCostSummary(costRecords));
1248
+ }
1249
+ }
1250
+ catch (err) {
1251
+ logger.warn(`debt-intelligence pipeline 失败: ${String(err)}`);
1252
+ }
1253
+ }
1254
+ // Feature 140 FR-013:Top 5 contextAssembly token 消费模块
1255
+ // 用途:让用户在 batch 末尾直观看到哪些模块在跨模块上下文上消耗最多 token,
1256
+ // 便于针对性优化(拆分大模块 / 减少 dependency / 启用 --no-include-docs 等)。
1257
+ // 数据源:collectedModuleSpecs[].frontmatter.costBreakdown.contextAssembly(Feature 140 T17 写入)。
1258
+ // 缺失字段(mock 路径 / AST-only 降级 / 旧 cache 命中)的模块会被跳过,不参与排序。
1259
+ // 输出渠道:process.stderr(与现有 batch summary 行约定一致,避免污染 stdout 数据流)。
1260
+ try {
1261
+ const topModules = collectedModuleSpecs
1262
+ .map((spec) => ({
1263
+ sourceTarget: spec.frontmatter.sourceTarget,
1264
+ contextAssembly: spec.frontmatter.costBreakdown?.contextAssembly,
1265
+ }))
1266
+ .filter((m) => typeof m.contextAssembly === 'number' && m.contextAssembly > 0)
1267
+ .sort((a, b) => b.contextAssembly - a.contextAssembly)
1268
+ .slice(0, 5);
1269
+ if (topModules.length > 0) {
1270
+ const lines = ['Top 5 input token 消费模块:'];
1271
+ topModules.forEach((m, idx) => {
1272
+ // 锁定 'en-US' locale,确保 CI(en_US.UTF-8)和开发环境(zh_CN.UTF-8 / de_DE 等)
1273
+ // 输出一致的千分位分隔符("8,500" 而非 "8.500" / "8 500"),便于 grep 与 fixture 断言
1274
+ lines.push(` ${idx + 1}. ${m.sourceTarget}: ${m.contextAssembly.toLocaleString('en-US')} tokens`);
1275
+ });
1276
+ process.stderr.write(lines.join('\n') + '\n');
1277
+ }
1278
+ }
1279
+ catch (err) {
1280
+ // 聚合失败不应阻断主流程(Top 5 是观测,不是核心交付)
1281
+ logger.warn(`Top 5 token 消费模块聚合失败,跳过: ${err instanceof Error ? err.message : String(err)}`);
1282
+ }
1283
+ // 步骤 6:写入摘要日志(输出到 _meta/ 子目录)
1284
+ const summary = reporter.finish();
1285
+ fs.mkdirSync(metaDir, { recursive: true });
1286
+ const summaryLogPathAbs = path.join(metaDir, `batch-summary-${Date.now()}.md`);
1287
+ fs.mkdirSync(path.dirname(summaryLogPathAbs), { recursive: true });
1288
+ // Bug 142:传入 failedModules,让 batch-summary markdown 含 "## 失败详情" 节,
1289
+ // 用户能直接看到 reason(如 retry-budget-exceeded),不必翻 checkpoint。
1290
+ writeSummaryLog(summary, summaryLogPathAbs, costSummary, checkedState.failedModules);
1291
+ // 步骤 7:生成人类友好的 README.md 索引
1292
+ try {
1293
+ const { generateBatchReadme } = await import('./batch-readme-generator.js');
1294
+ const readmeContent = generateBatchReadme({
1295
+ projectName: path.basename(resolvedRoot),
1296
+ version: SPECTRA_VERSION,
1297
+ // 通过 SpecStore.allKnownSpecs() 获取:新生成 + 历史存储,已排除 orphan/bundle_copy/derived
1298
+ // 精确匹配 modulesDir 前缀(相对于 resolvedRoot),避免将 bundles/*/docs/modules/ 误计入
1299
+ moduleSpecs: (() => {
1300
+ const modulesDirRel = path.relative(resolvedRoot, modulesDir).split(path.sep).join('/') + '/';
1301
+ return specStore.allKnownSpecs()
1302
+ .filter(s => {
1303
+ const p = s.outputPath.replace(/\\/g, '/');
1304
+ return p.startsWith(modulesDirRel) && !path.basename(s.outputPath).startsWith('_');
1305
+ })
1306
+ .map(s => path.basename(s.outputPath, '.spec.md'));
1307
+ })(),
1308
+ projectDocs: projectDocs ?? [],
1309
+ bundles: docsBundleProfiles,
1310
+ outputDir: resolvedOutputDir,
1311
+ });
1312
+ fs.writeFileSync(path.join(resolvedOutputDir, 'README.md'), readmeContent, 'utf-8');
1313
+ logger.info('README.md 索引已生成');
1314
+ }
1315
+ catch (err) {
1316
+ logger.warn(`README.md 生成失败: ${String(err)}`);
1317
+ }
1318
+ // 步骤 8:成功后清理检查点
1319
+ if (failed.length === 0) {
1320
+ clearCheckpoint(checkpointPath);
1321
+ }
1322
+ return {
1323
+ totalModules: processingOrder.length,
1324
+ successful,
1325
+ failed,
1326
+ skipped,
1327
+ degraded,
1328
+ duration: Date.now() - startTime,
1329
+ indexGenerated,
1330
+ summaryLogPath: toProjectPath(summaryLogPathAbs),
1331
+ detectedLanguages: isMultiLang ? processedLanguages : undefined,
1332
+ languageStats,
1333
+ docGraphPath,
1334
+ coverageReportPath,
1335
+ deltaReportPath,
1336
+ projectDocs,
1337
+ docsBundleManifestPath,
1338
+ docsBundleProfiles,
1339
+ costSummary,
1340
+ budgetDecision: budgetDecisionResult,
1341
+ debt: debtResult,
1342
+ graphHtmlPath,
1343
+ };
1344
+ }
1345
+ async function buildGraphForLanguageGroup(langGroup, projectRoot) {
1346
+ const registry = LanguageAdapterRegistry.getInstance();
1347
+ const adapter = registry.getAllAdapters().find((item) => item.id === langGroup.adapterId);
1348
+ if (adapter?.buildDependencyGraph) {
1349
+ try {
1350
+ const langGraph = await adapter.buildDependencyGraph(projectRoot);
1351
+ for (const node of langGraph.modules) {
1352
+ node.language = langGroup.adapterId;
1353
+ }
1354
+ return langGraph;
1355
+ }
1356
+ catch (err) {
1357
+ // Codex 对抗审查 W004 修复:升 warn 级别,避免静默回落到不含 import 边的目录图
1358
+ logger.warn(`语言专属依赖图构建失败(${langGroup.adapterId}),回落到目录图(不含 import 边): ${String(err)}`);
1359
+ }
1360
+ }
1361
+ return buildFallbackGraph(langGroup, projectRoot);
1362
+ }
1363
+ /**
1364
+ * 使用 buildDirectoryGraph 为语言组构建兜底依赖图
1365
+ */
1366
+ async function buildFallbackGraph(langGroup, projectRoot) {
1367
+ // buildDirectoryGraph 需要 CodeSkeleton,但此处我们没有骨架
1368
+ // 创建最小化的图(仅节点,无边)
1369
+ const { buildDirectoryGraph } = await import('../graph/directory-graph.js');
1370
+ const emptySkeletons = langGroup.files.map((f) => ({
1371
+ filePath: f,
1372
+ language: langGroup.languageName,
1373
+ loc: 0,
1374
+ exports: [],
1375
+ imports: [],
1376
+ hash: '0'.repeat(64),
1377
+ analyzedAt: new Date().toISOString(),
1378
+ parserUsed: 'tree-sitter',
1379
+ }));
1380
+ return buildDirectoryGraph(langGroup.files, projectRoot, emptySkeletons);
1381
+ }
1382
+ // ============================================================
1383
+ // Feature 145 P1:designDocAbsPaths "磁盘优先"合并策略
1384
+ // ============================================================
1385
+ /**
1386
+ * 构建 hyperedge/anchor 集成所需的设计文档绝对路径列表
1387
+ *
1388
+ * **Feature 145 合并策略**(基线,向后兼容):
1389
+ * 1. fromDocs:本轮 generateBatchProjectDocs 写出的文件(来自 writtenFiles)
1390
+ * 2. fromDisk:主动扫描 outputDir/project/ 目录下已存在的 .md 文件(磁盘优先)
1391
+ *
1392
+ * **Feature 140 T27 扩展**(spec FR-007 — 扩展 design doc 来源):
1393
+ * 通过 `extraOptions` 启用以下额外来源(默认全部启用,给 caller 显式 opt-out 的能力):
1394
+ * 3. fromReadme: 根目录 README.md(最高语义价值,作为顶层叙述)
1395
+ * 4. fromDocsDir: `docs/` 目录下递归扫描的 .md(仅 `--include-docs=true` 时启用)
1396
+ * 5. fromModuleSpecs: `<modulesDir>/*.spec.md`(当前 batch 产物,每次 batch 后存在)
1397
+ * 6. fromProjectContext: `.specify/project-context.{yaml,md}`
1398
+ *
1399
+ * 解决 spec FR-007 的"hyperedge 在新项目首次 batch 后产出 0 条 hyperedge"问题:
1400
+ * 之前 designDocAbsPaths 仅依赖 outputDir/project/,对从未 batch 过的新项目结果为空。
1401
+ * 扩展后即使新项目,仅有 README.md 也能产出 ≥ 1 条 hyperedge。
1402
+ *
1403
+ * @param projectDocs 本轮 generator 输出的相对路径列表
1404
+ * @param resolvedRoot 项目根目录绝对路径
1405
+ * @param resolvedOutputDir 输出目录绝对路径(含 `project/` 子目录)
1406
+ * @param extraOptions Feature 140 T27 扩展配置;不传时只走基线行为(向后兼容)
1407
+ * @returns paths 列表 + 各来源 count + 检测到的嵌套子目录
1408
+ */
1409
+ export function buildDesignDocAbsPaths(projectDocs, resolvedRoot, resolvedOutputDir, extraOptions) {
1410
+ // 来自本轮 generator 输出(以 resolvedRoot 为基准解析相对路径)
1411
+ const fromProjectDocs = projectDocs
1412
+ .map(rel => path.isAbsolute(rel) ? rel : path.join(resolvedRoot, rel))
1413
+ .filter(abs => fs.existsSync(abs));
1414
+ // 主动扫描 outputDir/project/ 目录下已存在的 .md 文件(磁盘优先)
1415
+ // 架构假设:outputDir/project/ 为扁平结构(无子目录),readdirSync 非递归覆盖全部产物 .md
1416
+ // Codex 对抗审查 W002 修复:检测到子目录时返回告警信号,调用方负责输出 warn
1417
+ const projectDir = path.join(resolvedOutputDir, 'project');
1418
+ const fromDisk = [];
1419
+ const nestedDirsDetected = [];
1420
+ if (fs.existsSync(projectDir)) {
1421
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
1422
+ if (entry.isFile() && entry.name.endsWith('.md')) {
1423
+ fromDisk.push(path.join(projectDir, entry.name));
1424
+ }
1425
+ else if (entry.isDirectory()) {
1426
+ nestedDirsDetected.push(entry.name);
1427
+ }
1428
+ }
1429
+ }
1430
+ // ============================================================
1431
+ // Feature 140 T27 — 扩展来源(spec FR-007)
1432
+ // ============================================================
1433
+ const includeReadme = extraOptions?.includeReadme ?? true;
1434
+ const includeDocsDir = extraOptions?.includeDocs ?? false;
1435
+ const includeProjectContext = extraOptions?.includeProjectContext ?? true;
1436
+ // 来源 3:根 README.md(共享 extraction-pipeline 的 findReadmePath,确保 canonical 优先级一致;
1437
+ // 修复 Codex W-1 — 之前内联实现遇首匹配就 break,与 findReadmePath 的 canonical 优先逻辑漂移)
1438
+ const fromReadme = [];
1439
+ if (includeReadme) {
1440
+ try {
1441
+ const readmePath = findReadmePath(resolvedRoot);
1442
+ if (readmePath)
1443
+ fromReadme.push(readmePath);
1444
+ }
1445
+ catch {
1446
+ /* projectRoot 不可读取时静默忽略 */
1447
+ }
1448
+ }
1449
+ // 来源 4:docs/**/*.md(仅 --include-docs=true)
1450
+ const fromDocsDir = [];
1451
+ if (includeDocsDir) {
1452
+ const docsDir = path.join(resolvedRoot, 'docs');
1453
+ if (fs.existsSync(docsDir)) {
1454
+ collectMdRecursive(docsDir, fromDocsDir);
1455
+ }
1456
+ }
1457
+ // 来源 5:modulesDir/*.spec.md(当前 batch 产物)
1458
+ const fromModuleSpecs = [];
1459
+ if (extraOptions?.modulesDir && fs.existsSync(extraOptions.modulesDir)) {
1460
+ try {
1461
+ for (const entry of fs.readdirSync(extraOptions.modulesDir, { withFileTypes: true })) {
1462
+ if (entry.isFile() && entry.name.endsWith('.spec.md')) {
1463
+ fromModuleSpecs.push(path.join(extraOptions.modulesDir, entry.name));
1464
+ }
1465
+ }
1466
+ }
1467
+ catch {
1468
+ /* 不可读取时静默忽略 */
1469
+ }
1470
+ }
1471
+ // 来源 6:.specify/project-context.{yaml,md}
1472
+ // 修复 Codex C-2:yaml 是 canonical source,md 仅 legacy fallback。
1473
+ // docs/shared/agent-context-layering.md 明确:".specify/project-context.yaml 是 canonical
1474
+ // Project Context;.specify/project-context.md 仅作为 legacy fallback"。
1475
+ // 此处遵循同一规则:yaml 存在时只取 yaml;不存在时 fallback 到 md;都不存在时返回 0。
1476
+ const fromProjectContext = [];
1477
+ if (includeProjectContext) {
1478
+ const yamlPath = path.join(resolvedRoot, '.specify', 'project-context.yaml');
1479
+ const mdPath = path.join(resolvedRoot, '.specify', 'project-context.md');
1480
+ if (fs.existsSync(yamlPath)) {
1481
+ fromProjectContext.push(yamlPath);
1482
+ }
1483
+ else if (fs.existsSync(mdPath)) {
1484
+ fromProjectContext.push(mdPath);
1485
+ }
1486
+ }
1487
+ // 去重合并(fromProjectDocs 优先 → fromDisk → fromReadme → fromDocsDir → fromModuleSpecs → fromProjectContext)
1488
+ const merged = [
1489
+ ...new Set([
1490
+ ...fromProjectDocs,
1491
+ ...fromDisk,
1492
+ ...fromReadme,
1493
+ ...fromDocsDir,
1494
+ ...fromModuleSpecs,
1495
+ ...fromProjectContext,
1496
+ ]),
1497
+ ];
1498
+ return {
1499
+ paths: merged,
1500
+ fromDocsCount: fromProjectDocs.length,
1501
+ fromDiskCount: fromDisk.length,
1502
+ fromReadmeCount: fromReadme.length,
1503
+ fromDocsDirCount: fromDocsDir.length,
1504
+ fromModuleSpecsCount: fromModuleSpecs.length,
1505
+ fromProjectContextCount: fromProjectContext.length,
1506
+ nestedDirsDetected,
1507
+ };
1508
+ }
1509
+ /**
1510
+ * 递归收集目录下所有 .md 文件(Feature 140 T27 — fromDocsDir 实现)。
1511
+ *
1512
+ * 跳过常见生成目录避免把 build artifact 的 markdown 误送给 LLM。
1513
+ * 黑名单设计原则:覆盖 JS/TS / Python / Rust / Go / Java / 通用缓存目录的产物路径。
1514
+ * 修复 Codex W-2:之前的 5 项黑名单遗漏 `__pycache__` / `target` / `.cache` / `tmp` 等。
1515
+ */
1516
+ const MD_SCAN_DIR_BLACKLIST = new Set([
1517
+ 'node_modules', // npm/yarn/pnpm
1518
+ '.git', // git
1519
+ '.cache', // 通用缓存(npm/yarn/parcel/etc)
1520
+ 'dist', // JS/TS 构建产物
1521
+ 'build', // 通用构建产物(CMake/Java/etc)
1522
+ 'coverage', // 测试覆盖率报告
1523
+ 'out', // Next.js / 通用输出
1524
+ 'target', // Rust / Java/Maven
1525
+ '__pycache__', // Python
1526
+ '.pytest_cache',
1527
+ 'tmp', // 临时文件
1528
+ '.tmp',
1529
+ '.next', // Next.js
1530
+ '.nuxt', // Nuxt.js
1531
+ '.turbo', // Turborepo
1532
+ ]);
1533
+ function collectMdRecursive(dir, out) {
1534
+ let entries;
1535
+ try {
1536
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1537
+ }
1538
+ catch {
1539
+ return;
1540
+ }
1541
+ for (const entry of entries) {
1542
+ if (entry.isDirectory()) {
1543
+ if (MD_SCAN_DIR_BLACKLIST.has(entry.name))
1544
+ continue;
1545
+ collectMdRecursive(path.join(dir, entry.name), out);
1546
+ }
1547
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
1548
+ out.push(path.join(dir, entry.name));
1549
+ }
1550
+ }
1551
+ }
1552
+ //# sourceMappingURL=batch-orchestrator.js.map