mergestory 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +48 -2
  4. package/assets/kokoro-plugin/package-lock.json +1139 -0
  5. package/dist/analyzer/analyze.d.ts +8 -0
  6. package/dist/analyzer/analyze.js +328 -0
  7. package/dist/analyzer/components.d.ts +18 -0
  8. package/dist/analyzer/components.js +266 -0
  9. package/dist/analyzer/dependencies.d.ts +13 -0
  10. package/dist/analyzer/dependencies.js +349 -0
  11. package/dist/analyzer/evidence.d.ts +15 -0
  12. package/dist/analyzer/evidence.js +73 -0
  13. package/dist/analyzer/hunks.d.ts +21 -0
  14. package/dist/analyzer/hunks.js +88 -0
  15. package/dist/analyzer/imports.d.ts +46 -0
  16. package/dist/analyzer/imports.js +87 -0
  17. package/dist/analyzer/index.d.ts +14 -0
  18. package/dist/analyzer/index.js +16 -0
  19. package/dist/analyzer/languages/go.d.ts +2 -0
  20. package/dist/analyzer/languages/go.js +76 -0
  21. package/dist/analyzer/languages/index.d.ts +18 -0
  22. package/dist/analyzer/languages/index.js +72 -0
  23. package/dist/analyzer/languages/javascript.d.ts +2 -0
  24. package/dist/analyzer/languages/javascript.js +336 -0
  25. package/dist/analyzer/languages/jvm.d.ts +2 -0
  26. package/dist/analyzer/languages/jvm.js +157 -0
  27. package/dist/analyzer/languages/others.d.ts +2 -0
  28. package/dist/analyzer/languages/others.js +40 -0
  29. package/dist/analyzer/languages/php.d.ts +2 -0
  30. package/dist/analyzer/languages/php.js +81 -0
  31. package/dist/analyzer/languages/python.d.ts +2 -0
  32. package/dist/analyzer/languages/python.js +180 -0
  33. package/dist/analyzer/languages/ruby.d.ts +2 -0
  34. package/dist/analyzer/languages/ruby.js +99 -0
  35. package/dist/analyzer/languages/rust.d.ts +2 -0
  36. package/dist/analyzer/languages/rust.js +164 -0
  37. package/dist/analyzer/languages/shared.d.ts +35 -0
  38. package/dist/analyzer/languages/shared.js +43 -0
  39. package/dist/analyzer/languages/types.d.ts +78 -0
  40. package/dist/analyzer/languages/types.js +2 -0
  41. package/dist/analyzer/pack-format.d.ts +27 -0
  42. package/dist/analyzer/pack-format.js +139 -0
  43. package/dist/analyzer/pack.d.ts +26 -0
  44. package/dist/analyzer/pack.js +498 -0
  45. package/dist/analyzer/relationships.d.ts +17 -0
  46. package/dist/analyzer/relationships.js +34 -0
  47. package/dist/analyzer/risk-rules.d.ts +287 -0
  48. package/dist/analyzer/risk-rules.js +373 -0
  49. package/dist/analyzer/risks.d.ts +36 -0
  50. package/dist/analyzer/risks.js +480 -0
  51. package/dist/analyzer/roles.d.ts +11 -0
  52. package/dist/analyzer/roles.js +280 -0
  53. package/dist/analyzer/scan.d.ts +26 -0
  54. package/dist/analyzer/scan.js +157 -0
  55. package/dist/analyzer/signals.d.ts +20 -0
  56. package/dist/analyzer/signals.js +51 -0
  57. package/dist/analyzer/symbol-changes.d.ts +11 -0
  58. package/dist/analyzer/symbol-changes.js +101 -0
  59. package/dist/analyzer/symbol-types.d.ts +17 -0
  60. package/dist/analyzer/symbol-types.js +9 -0
  61. package/dist/analyzer/symbols.d.ts +4 -0
  62. package/dist/analyzer/symbols.js +16 -0
  63. package/dist/analyzer/trivial.d.ts +13 -0
  64. package/dist/analyzer/trivial.js +137 -0
  65. package/dist/analyzer/util.d.ts +6 -0
  66. package/dist/analyzer/util.js +24 -0
  67. package/dist/cli/commands/authoring.d.ts +9 -0
  68. package/dist/cli/commands/authoring.js +98 -0
  69. package/dist/cli/commands/cache.d.ts +4 -0
  70. package/dist/cli/commands/cache.js +37 -0
  71. package/dist/cli/commands/doctor.d.ts +5 -0
  72. package/dist/cli/commands/doctor.js +37 -0
  73. package/dist/cli/commands/generate.d.ts +8 -0
  74. package/dist/cli/commands/generate.js +69 -0
  75. package/dist/cli/commands/jobs.d.ts +8 -0
  76. package/dist/cli/commands/jobs.js +70 -0
  77. package/dist/cli/commands/publish.d.ts +8 -0
  78. package/dist/cli/commands/publish.js +120 -0
  79. package/dist/cli/commands/serve.d.ts +4 -0
  80. package/dist/cli/commands/serve.js +69 -0
  81. package/dist/cli/commands/setup.d.ts +14 -0
  82. package/dist/cli/commands/setup.js +108 -0
  83. package/dist/cli/commands/shared.d.ts +18 -0
  84. package/dist/cli/commands/shared.js +24 -0
  85. package/dist/cli/files.d.ts +26 -0
  86. package/dist/cli/files.js +98 -0
  87. package/dist/cli/format.d.ts +55 -0
  88. package/dist/cli/format.js +295 -0
  89. package/dist/cli/inputs.d.ts +23 -0
  90. package/dist/cli/inputs.js +96 -0
  91. package/dist/cli/io.d.ts +19 -0
  92. package/dist/cli/io.js +31 -0
  93. package/dist/cli/main.d.ts +2 -0
  94. package/dist/cli/main.js +15 -0
  95. package/dist/cli/options.d.ts +105 -0
  96. package/dist/cli/options.js +324 -0
  97. package/dist/cli/program.d.ts +12 -0
  98. package/dist/cli/program.js +146 -0
  99. package/dist/cli/runtime.d.ts +59 -0
  100. package/dist/cli/runtime.js +83 -0
  101. package/dist/cli/style.d.ts +13 -0
  102. package/dist/cli/style.js +27 -0
  103. package/dist/core/binaries.d.ts +7 -0
  104. package/dist/core/binaries.js +33 -0
  105. package/dist/core/binary-paths.d.ts +5 -0
  106. package/dist/core/binary-paths.js +92 -0
  107. package/dist/core/cache.d.ts +14 -0
  108. package/dist/core/cache.js +43 -0
  109. package/dist/core/child-env.d.ts +9 -0
  110. package/dist/core/child-env.js +61 -0
  111. package/dist/core/concurrency.d.ts +13 -0
  112. package/dist/core/concurrency.js +58 -0
  113. package/dist/core/config.d.ts +223 -0
  114. package/dist/core/config.js +454 -0
  115. package/dist/core/context.d.ts +39 -0
  116. package/dist/core/context.js +44 -0
  117. package/dist/core/cost.d.ts +46 -0
  118. package/dist/core/cost.js +108 -0
  119. package/dist/core/diagram-metrics.d.ts +57 -0
  120. package/dist/core/diagram-metrics.js +63 -0
  121. package/dist/core/diff-view.d.ts +44 -0
  122. package/dist/core/diff-view.js +136 -0
  123. package/dist/core/errors.d.ts +47 -0
  124. package/dist/core/errors.js +94 -0
  125. package/dist/core/ids.d.ts +11 -0
  126. package/dist/core/ids.js +36 -0
  127. package/dist/core/json.d.ts +8 -0
  128. package/dist/core/json.js +17 -0
  129. package/dist/core/languages.d.ts +19 -0
  130. package/dist/core/languages.js +292 -0
  131. package/dist/core/logger.d.ts +29 -0
  132. package/dist/core/logger.js +68 -0
  133. package/dist/core/net.d.ts +16 -0
  134. package/dist/core/net.js +80 -0
  135. package/dist/core/path-policy.d.ts +20 -0
  136. package/dist/core/path-policy.js +202 -0
  137. package/dist/core/paths.d.ts +18 -0
  138. package/dist/core/paths.js +53 -0
  139. package/dist/core/posix.d.ts +12 -0
  140. package/dist/core/posix.js +50 -0
  141. package/dist/core/process.d.ts +22 -0
  142. package/dist/core/process.js +117 -0
  143. package/dist/core/providers.d.ts +204 -0
  144. package/dist/core/providers.js +2 -0
  145. package/dist/core/redact.d.ts +11 -0
  146. package/dist/core/redact.js +70 -0
  147. package/dist/core/render-plan.d.ts +307 -0
  148. package/dist/core/render-plan.js +7 -0
  149. package/dist/core/retry.d.ts +54 -0
  150. package/dist/core/retry.js +116 -0
  151. package/dist/core/run-folder.d.ts +74 -0
  152. package/dist/core/run-folder.js +129 -0
  153. package/dist/core/secrets.d.ts +56 -0
  154. package/dist/core/secrets.js +301 -0
  155. package/dist/core/storyboard-facts.d.ts +22 -0
  156. package/dist/core/storyboard-facts.js +61 -0
  157. package/dist/core/storyboard-schema.d.ts +1279 -0
  158. package/dist/core/storyboard-schema.js +342 -0
  159. package/dist/core/text.d.ts +43 -0
  160. package/dist/core/text.js +94 -0
  161. package/dist/core/types.d.ts +459 -0
  162. package/dist/core/types.js +17 -0
  163. package/dist/doctor/check.d.ts +6 -0
  164. package/dist/doctor/check.js +18 -0
  165. package/dist/doctor/deps.d.ts +2 -0
  166. package/dist/doctor/deps.js +90 -0
  167. package/dist/doctor/format.d.ts +9 -0
  168. package/dist/doctor/format.js +19 -0
  169. package/dist/doctor/github.d.ts +2 -0
  170. package/dist/doctor/github.js +13 -0
  171. package/dist/doctor/home.d.ts +2 -0
  172. package/dist/doctor/home.js +26 -0
  173. package/dist/doctor/index.d.ts +18 -0
  174. package/dist/doctor/index.js +81 -0
  175. package/dist/doctor/llm.d.ts +2 -0
  176. package/dist/doctor/llm.js +32 -0
  177. package/dist/doctor/publish.d.ts +2 -0
  178. package/dist/doctor/publish.js +16 -0
  179. package/dist/doctor/s3.d.ts +2 -0
  180. package/dist/doctor/s3.js +125 -0
  181. package/dist/doctor/speech.d.ts +2 -0
  182. package/dist/doctor/speech.js +112 -0
  183. package/dist/doctor/tools.d.ts +5 -0
  184. package/dist/doctor/tools.js +58 -0
  185. package/dist/doctor/types.d.ts +92 -0
  186. package/dist/doctor/types.js +2 -0
  187. package/dist/doctor/youtube.d.ts +2 -0
  188. package/dist/doctor/youtube.js +73 -0
  189. package/dist/github/client.d.ts +108 -0
  190. package/dist/github/client.js +499 -0
  191. package/dist/github/errors.d.ts +37 -0
  192. package/dist/github/errors.js +155 -0
  193. package/dist/github/index.d.ts +13 -0
  194. package/dist/github/index.js +9 -0
  195. package/dist/github/linked-issues.d.ts +37 -0
  196. package/dist/github/linked-issues.js +131 -0
  197. package/dist/github/model.d.ts +81 -0
  198. package/dist/github/model.js +114 -0
  199. package/dist/github/notify.d.ts +27 -0
  200. package/dist/github/notify.js +118 -0
  201. package/dist/github/pr-url.d.ts +27 -0
  202. package/dist/github/pr-url.js +122 -0
  203. package/dist/github/token.d.ts +16 -0
  204. package/dist/github/token.js +69 -0
  205. package/dist/index.d.ts +29 -0
  206. package/dist/index.js +19 -0
  207. package/dist/jobs/input-rules.d.ts +20 -0
  208. package/dist/jobs/input-rules.js +100 -0
  209. package/dist/jobs/model.d.ts +47 -0
  210. package/dist/jobs/model.js +18 -0
  211. package/dist/jobs/runner.d.ts +43 -0
  212. package/dist/jobs/runner.js +165 -0
  213. package/dist/jobs/store.d.ts +67 -0
  214. package/dist/jobs/store.js +314 -0
  215. package/dist/jobs/view.d.ts +48 -0
  216. package/dist/jobs/view.js +111 -0
  217. package/dist/jobs/worker.d.ts +24 -0
  218. package/dist/jobs/worker.js +47 -0
  219. package/dist/llm/anthropic.d.ts +11 -0
  220. package/dist/llm/anthropic.js +225 -0
  221. package/dist/llm/index.d.ts +10 -0
  222. package/dist/llm/index.js +27 -0
  223. package/dist/llm/openai-compatible.d.ts +33 -0
  224. package/dist/llm/openai-compatible.js +378 -0
  225. package/dist/llm/prices.d.ts +26 -0
  226. package/dist/llm/prices.js +41 -0
  227. package/dist/llm/shared.d.ts +30 -0
  228. package/dist/llm/shared.js +115 -0
  229. package/dist/narration/assemble.d.ts +36 -0
  230. package/dist/narration/assemble.js +282 -0
  231. package/dist/narration/audio.d.ts +61 -0
  232. package/dist/narration/audio.js +301 -0
  233. package/dist/narration/captions.d.ts +37 -0
  234. package/dist/narration/captions.js +195 -0
  235. package/dist/narration/chunking.d.ts +6 -0
  236. package/dist/narration/chunking.js +46 -0
  237. package/dist/narration/convert.d.ts +9 -0
  238. package/dist/narration/convert.js +90 -0
  239. package/dist/narration/elevenlabs.d.ts +5 -0
  240. package/dist/narration/elevenlabs.js +53 -0
  241. package/dist/narration/http-errors.d.ts +14 -0
  242. package/dist/narration/http-errors.js +74 -0
  243. package/dist/narration/index.d.ts +21 -0
  244. package/dist/narration/index.js +22 -0
  245. package/dist/narration/kokoro-install.d.ts +30 -0
  246. package/dist/narration/kokoro-install.js +284 -0
  247. package/dist/narration/kokoro-model.d.ts +54 -0
  248. package/dist/narration/kokoro-model.js +168 -0
  249. package/dist/narration/kokoro-plugin.d.ts +78 -0
  250. package/dist/narration/kokoro-plugin.js +245 -0
  251. package/dist/narration/kokoro.d.ts +22 -0
  252. package/dist/narration/kokoro.js +231 -0
  253. package/dist/narration/openai.d.ts +4 -0
  254. package/dist/narration/openai.js +54 -0
  255. package/dist/narration/pricing.d.ts +8 -0
  256. package/dist/narration/pricing.js +17 -0
  257. package/dist/narration/remote-speech.d.ts +53 -0
  258. package/dist/narration/remote-speech.js +100 -0
  259. package/dist/narration/say.d.ts +28 -0
  260. package/dist/narration/say.js +178 -0
  261. package/dist/narration/select.d.ts +27 -0
  262. package/dist/narration/select.js +80 -0
  263. package/dist/narration/silent.d.ts +2 -0
  264. package/dist/narration/silent.js +18 -0
  265. package/dist/narration/speakable.d.ts +20 -0
  266. package/dist/narration/speakable.js +398 -0
  267. package/dist/narration/synthesize.d.ts +25 -0
  268. package/dist/narration/synthesize.js +220 -0
  269. package/dist/narration/wav.d.ts +37 -0
  270. package/dist/narration/wav.js +170 -0
  271. package/dist/pipeline/authoring.d.ts +8 -0
  272. package/dist/pipeline/authoring.js +117 -0
  273. package/dist/pipeline/commands.d.ts +9 -0
  274. package/dist/pipeline/commands.js +21 -0
  275. package/dist/pipeline/fit-duration.d.ts +41 -0
  276. package/dist/pipeline/fit-duration.js +150 -0
  277. package/dist/pipeline/index.d.ts +9 -0
  278. package/dist/pipeline/index.js +9 -0
  279. package/dist/pipeline/inputs.d.ts +42 -0
  280. package/dist/pipeline/inputs.js +171 -0
  281. package/dist/pipeline/plan.d.ts +8 -0
  282. package/dist/pipeline/plan.js +85 -0
  283. package/dist/pipeline/planned-egress.d.ts +21 -0
  284. package/dist/pipeline/planned-egress.js +43 -0
  285. package/dist/pipeline/prepare.d.ts +26 -0
  286. package/dist/pipeline/prepare.js +84 -0
  287. package/dist/pipeline/presentation.d.ts +26 -0
  288. package/dist/pipeline/presentation.js +110 -0
  289. package/dist/pipeline/publish-run.d.ts +71 -0
  290. package/dist/pipeline/publish-run.js +295 -0
  291. package/dist/pipeline/run.d.ts +7 -0
  292. package/dist/pipeline/run.js +196 -0
  293. package/dist/pipeline/storyboard-choice.d.ts +34 -0
  294. package/dist/pipeline/storyboard-choice.js +129 -0
  295. package/dist/pipeline/types.d.ts +76 -0
  296. package/dist/pipeline/types.js +2 -0
  297. package/dist/publish/access-probe.d.ts +55 -0
  298. package/dist/publish/access-probe.js +249 -0
  299. package/dist/publish/bundle.d.ts +20 -0
  300. package/dist/publish/bundle.js +57 -0
  301. package/dist/publish/comment.d.ts +10 -0
  302. package/dist/publish/comment.js +184 -0
  303. package/dist/publish/content-types.d.ts +15 -0
  304. package/dist/publish/content-types.js +41 -0
  305. package/dist/publish/index.d.ts +18 -0
  306. package/dist/publish/index.js +30 -0
  307. package/dist/publish/keys.d.ts +10 -0
  308. package/dist/publish/keys.js +30 -0
  309. package/dist/publish/local.d.ts +33 -0
  310. package/dist/publish/local.js +143 -0
  311. package/dist/publish/privacy.d.ts +20 -0
  312. package/dist/publish/privacy.js +21 -0
  313. package/dist/publish/s3/bucket.d.ts +22 -0
  314. package/dist/publish/s3/bucket.js +82 -0
  315. package/dist/publish/s3/client.d.ts +33 -0
  316. package/dist/publish/s3/client.js +134 -0
  317. package/dist/publish/s3/failures.d.ts +22 -0
  318. package/dist/publish/s3/failures.js +110 -0
  319. package/dist/publish/s3/index.d.ts +5 -0
  320. package/dist/publish/s3/index.js +6 -0
  321. package/dist/publish/s3/links.d.ts +38 -0
  322. package/dist/publish/s3/links.js +60 -0
  323. package/dist/publish/s3/protected-links.d.ts +29 -0
  324. package/dist/publish/s3/protected-links.js +67 -0
  325. package/dist/publish/s3/publisher.d.ts +32 -0
  326. package/dist/publish/s3/publisher.js +123 -0
  327. package/dist/publish/s3/settings.d.ts +29 -0
  328. package/dist/publish/s3/settings.js +64 -0
  329. package/dist/publish/s3/upload.d.ts +29 -0
  330. package/dist/publish/s3/upload.js +145 -0
  331. package/dist/publish/severity.d.ts +9 -0
  332. package/dist/publish/severity.js +18 -0
  333. package/dist/publish/text.d.ts +23 -0
  334. package/dist/publish/text.js +94 -0
  335. package/dist/publish/types.d.ts +67 -0
  336. package/dist/publish/types.js +12 -0
  337. package/dist/publish/vtt.d.ts +9 -0
  338. package/dist/publish/vtt.js +43 -0
  339. package/dist/publish/watch-page.d.ts +4 -0
  340. package/dist/publish/watch-page.js +463 -0
  341. package/dist/publish/youtube/credentials.d.ts +33 -0
  342. package/dist/publish/youtube/credentials.js +162 -0
  343. package/dist/publish/youtube/description.d.ts +56 -0
  344. package/dist/publish/youtube/description.js +197 -0
  345. package/dist/publish/youtube/google-api.d.ts +95 -0
  346. package/dist/publish/youtube/google-api.js +339 -0
  347. package/dist/publish/youtube/index.d.ts +7 -0
  348. package/dist/publish/youtube/index.js +8 -0
  349. package/dist/publish/youtube/loopback.d.ts +13 -0
  350. package/dist/publish/youtube/loopback.js +144 -0
  351. package/dist/publish/youtube/oauth.d.ts +68 -0
  352. package/dist/publish/youtube/oauth.js +159 -0
  353. package/dist/publish/youtube/prompt.d.ts +27 -0
  354. package/dist/publish/youtube/prompt.js +94 -0
  355. package/dist/publish/youtube/publisher.d.ts +38 -0
  356. package/dist/publish/youtube/publisher.js +346 -0
  357. package/dist/publish/youtube/scopes.d.ts +32 -0
  358. package/dist/publish/youtube/scopes.js +55 -0
  359. package/dist/publish/youtube/sign-in.d.ts +37 -0
  360. package/dist/publish/youtube/sign-in.js +137 -0
  361. package/dist/publish/youtube/upload.d.ts +43 -0
  362. package/dist/publish/youtube/upload.js +210 -0
  363. package/dist/render/browser.d.ts +23 -0
  364. package/dist/render/browser.js +219 -0
  365. package/dist/render/chromium-renderer.d.ts +56 -0
  366. package/dist/render/chromium-renderer.js +519 -0
  367. package/dist/render/ffmpeg.d.ts +55 -0
  368. package/dist/render/ffmpeg.js +212 -0
  369. package/dist/render/fonts.d.ts +10 -0
  370. package/dist/render/fonts.js +42 -0
  371. package/dist/render/index.d.ts +9 -0
  372. package/dist/render/index.js +11 -0
  373. package/dist/render/page.d.ts +46 -0
  374. package/dist/render/page.js +123 -0
  375. package/dist/render/playwright.d.ts +3 -0
  376. package/dist/render/playwright.js +6 -0
  377. package/dist/render/runtime-bundle.d.ts +2 -0
  378. package/dist/render/runtime-bundle.js +72 -0
  379. package/dist/runtime/runtime.js +1626 -0
  380. package/dist/server/auth.d.ts +17 -0
  381. package/dist/server/auth.js +58 -0
  382. package/dist/server/http.d.ts +43 -0
  383. package/dist/server/http.js +119 -0
  384. package/dist/server/index.d.ts +46 -0
  385. package/dist/server/index.js +310 -0
  386. package/dist/server/queue.d.ts +30 -0
  387. package/dist/server/queue.js +76 -0
  388. package/dist/server/schema.d.ts +103 -0
  389. package/dist/server/schema.js +121 -0
  390. package/dist/server/source.d.ts +17 -0
  391. package/dist/server/source.js +100 -0
  392. package/dist/sources/assemble.d.ts +86 -0
  393. package/dist/sources/assemble.js +117 -0
  394. package/dist/sources/diff-parser.d.ts +14 -0
  395. package/dist/sources/diff-parser.js +84 -0
  396. package/dist/sources/git.d.ts +28 -0
  397. package/dist/sources/git.js +108 -0
  398. package/dist/sources/github.d.ts +20 -0
  399. package/dist/sources/github.js +192 -0
  400. package/dist/sources/hunk-selection.d.ts +25 -0
  401. package/dist/sources/hunk-selection.js +46 -0
  402. package/dist/sources/index.d.ts +23 -0
  403. package/dist/sources/index.js +62 -0
  404. package/dist/sources/limits.d.ts +27 -0
  405. package/dist/sources/limits.js +22 -0
  406. package/dist/sources/local.d.ts +34 -0
  407. package/dist/sources/local.js +555 -0
  408. package/dist/sources/reader.d.ts +13 -0
  409. package/dist/sources/reader.js +45 -0
  410. package/dist/sources/remote.d.ts +13 -0
  411. package/dist/sources/remote.js +41 -0
  412. package/dist/sources/repo-context.d.ts +34 -0
  413. package/dist/sources/repo-context.js +144 -0
  414. package/dist/sources/text.d.ts +25 -0
  415. package/dist/sources/text.js +71 -0
  416. package/dist/storyboard/authoring.d.ts +108 -0
  417. package/dist/storyboard/authoring.js +196 -0
  418. package/dist/storyboard/claims.d.ts +35 -0
  419. package/dist/storyboard/claims.js +318 -0
  420. package/dist/storyboard/coderef.d.ts +28 -0
  421. package/dist/storyboard/coderef.js +118 -0
  422. package/dist/storyboard/generate.d.ts +25 -0
  423. package/dist/storyboard/generate.js +194 -0
  424. package/dist/storyboard/heuristic-code.d.ts +91 -0
  425. package/dist/storyboard/heuristic-code.js +524 -0
  426. package/dist/storyboard/heuristic-context.d.ts +42 -0
  427. package/dist/storyboard/heuristic-context.js +102 -0
  428. package/dist/storyboard/heuristic-facts.d.ts +106 -0
  429. package/dist/storyboard/heuristic-facts.js +415 -0
  430. package/dist/storyboard/heuristic-overview.d.ts +4 -0
  431. package/dist/storyboard/heuristic-overview.js +151 -0
  432. package/dist/storyboard/heuristic-review.d.ts +10 -0
  433. package/dist/storyboard/heuristic-review.js +158 -0
  434. package/dist/storyboard/heuristic-scenes.d.ts +8 -0
  435. package/dist/storyboard/heuristic-scenes.js +357 -0
  436. package/dist/storyboard/heuristic-shared.d.ts +43 -0
  437. package/dist/storyboard/heuristic-shared.js +136 -0
  438. package/dist/storyboard/heuristic.d.ts +15 -0
  439. package/dist/storyboard/heuristic.js +324 -0
  440. package/dist/storyboard/identifiers.d.ts +51 -0
  441. package/dist/storyboard/identifiers.js +195 -0
  442. package/dist/storyboard/index.d.ts +10 -0
  443. package/dist/storyboard/index.js +10 -0
  444. package/dist/storyboard/prompts.d.ts +16 -0
  445. package/dist/storyboard/prompts.js +61 -0
  446. package/dist/storyboard/run.d.ts +82 -0
  447. package/dist/storyboard/run.js +332 -0
  448. package/dist/storyboard/text.d.ts +16 -0
  449. package/dist/storyboard/text.js +103 -0
  450. package/dist/storyboard/types.d.ts +47 -0
  451. package/dist/storyboard/types.js +2 -0
  452. package/dist/storyboard/urls.d.ts +15 -0
  453. package/dist/storyboard/urls.js +83 -0
  454. package/dist/storyboard/validate.d.ts +8 -0
  455. package/dist/storyboard/validate.js +525 -0
  456. package/dist/storyboard/visuals.d.ts +23 -0
  457. package/dist/storyboard/visuals.js +324 -0
  458. package/dist/version.d.ts +2 -0
  459. package/dist/version.js +3 -0
  460. package/dist/visuals/code.d.ts +68 -0
  461. package/dist/visuals/code.js +385 -0
  462. package/dist/visuals/highlight.d.ts +17 -0
  463. package/dist/visuals/highlight.js +85 -0
  464. package/dist/visuals/image.d.ts +12 -0
  465. package/dist/visuals/image.js +96 -0
  466. package/dist/visuals/index.d.ts +10 -0
  467. package/dist/visuals/index.js +10 -0
  468. package/dist/visuals/layout.d.ts +89 -0
  469. package/dist/visuals/layout.js +506 -0
  470. package/dist/visuals/plan.d.ts +33 -0
  471. package/dist/visuals/plan.js +511 -0
  472. package/dist/visuals/timeline.d.ts +31 -0
  473. package/dist/visuals/timeline.js +96 -0
  474. package/package.json +74 -4
@@ -0,0 +1,8 @@
1
+ import type { RunContext } from '../core/context.ts';
2
+ import type { Analysis, ChangeSet, ContextInputs, RepoReader } from '../core/types.ts';
3
+ /**
4
+ * Analyse a change set. File contents come only from `reader`, and never for a file marked
5
+ * `sensitive` (a sensitive or excluded path: the source decides). The result is deterministic: the
6
+ * same input gives the same ids.
7
+ */
8
+ export declare function analyze(changeSet: ChangeSet, reader: RepoReader, inputs: ContextInputs, ctx: RunContext): Promise<Analysis>;
@@ -0,0 +1,328 @@
1
+ /** The analysis pipeline: from a change set to the facts a storyboard may cite. */
2
+ import { mapLimit } from '../core/concurrency.js';
3
+ import { languageInfo } from '../core/languages.js';
4
+ import { compileGlobs, isProtectedFile, isShowable } from '../core/path-policy.js';
5
+ import { extname } from '../core/posix.js';
6
+ import { groupComponents } from './components.js';
7
+ import { diffManifest, manifestKind } from './dependencies.js';
8
+ import { buildEvidenceIndex } from './evidence.js';
9
+ import { rankKeyHunks } from './hunks.js';
10
+ import { ImportResolver, importLang, loadResolverOptions } from './imports.js';
11
+ import { hasImports, hasSymbols } from './languages/index.js';
12
+ import { buildRelationships } from './relationships.js';
13
+ import { detectRisks } from './risks.js';
14
+ import { detectRole, ROLE_WEIGHT } from './roles.js';
15
+ import { architectureSignals } from './signals.js';
16
+ import { classifySymbols } from './symbol-changes.js';
17
+ import { classifyTrivial } from './trivial.js';
18
+ import { round } from './util.js';
19
+ const MAX_CONTENT_FILES = 150;
20
+ const MAX_SYMBOLS = 80;
21
+ const READ_CONCURRENCY = 6;
22
+ const CONTENT_ROLES = ['source', 'test', 'migration', 'build', 'other'];
23
+ const KIND_WEIGHT = {
24
+ route: 1,
25
+ class: 0.9,
26
+ component: 0.9,
27
+ function: 0.8,
28
+ interface: 0.8,
29
+ type: 0.6,
30
+ method: 0.6,
31
+ constant: 0.4,
32
+ other: 0.3,
33
+ };
34
+ const CHANGE_WEIGHT = { added: 1, removed: 0.9, modified: 0.6 };
35
+ function sizeOf(lines) {
36
+ if (lines <= 20)
37
+ return 'xs';
38
+ if (lines <= 120)
39
+ return 's';
40
+ if (lines <= 400)
41
+ return 'm';
42
+ if (lines <= 1200)
43
+ return 'l';
44
+ return 'xl';
45
+ }
46
+ const DURATION = { xs: 45, s: 70, m: 100, l: 130, xl: 160 };
47
+ function changedText(file) {
48
+ return file.hunks.flatMap((h) => h.lines.filter((l) => l.kind !== 'ctx').map((l) => l.text)).join('\n');
49
+ }
50
+ /** Gives every changed file its role and its verdicts: protected, trivial, comment-only. */
51
+ function classifyFiles(files) {
52
+ return files.map((file, index) => {
53
+ const hidden = isProtectedFile(file);
54
+ const role = detectRole(file.path, !hidden && extname(file.path) === '.sql' ? changedText(file) : '');
55
+ const verdict = hidden
56
+ ? { trivial: false, reason: null, commentOnly: false }
57
+ : classifyTrivial(file, role);
58
+ return {
59
+ index,
60
+ file,
61
+ role,
62
+ hidden,
63
+ trivial: verdict.trivial,
64
+ trivialReason: verdict.reason,
65
+ commentOnly: verdict.commentOnly,
66
+ };
67
+ });
68
+ }
69
+ /** A file whose content may be inspected and that counts as work: not protected, binary or trivial. */
70
+ function isContent(s) {
71
+ return isShowable(s.file) && !s.trivial && CONTENT_ROLES.includes(s.role);
72
+ }
73
+ /** The files worth reading, biggest first: those that can yield symbols or imports. */
74
+ function selectContentFiles(states) {
75
+ return states
76
+ .filter((s) => isContent(s) && (hasSymbols(s.file.path) || hasImports(s.file.path)))
77
+ .sort((a, b) => b.file.additions + b.file.deletions - (a.file.additions + a.file.deletions) || a.index - b.index)
78
+ .slice(0, MAX_CONTENT_FILES);
79
+ }
80
+ /** Reads of repository files for one run: cached, and a failed read is a missing file unless the run was cancelled. */
81
+ function createFileReader(reader, ctx) {
82
+ const cache = new Map();
83
+ const read = (path, side) => {
84
+ const key = `${side}:${path}`;
85
+ let hit = cache.get(key);
86
+ if (!hit) {
87
+ hit = reader.readFile(path, side).catch((err) => {
88
+ if (ctx.signal.aborted)
89
+ throw err;
90
+ ctx.logger.debug('analyzer: could not read a file', { side });
91
+ return null;
92
+ });
93
+ cache.set(key, hit);
94
+ }
95
+ return hit;
96
+ };
97
+ return {
98
+ read,
99
+ head: (s) => s.file.status === 'deleted' ? Promise.resolve(null) : read(s.file.path, 'head'),
100
+ base: (s) => s.file.status === 'added' || s.file.status === 'copied'
101
+ ? Promise.resolve(null)
102
+ : read(s.file.oldPath ?? s.file.path, 'base'),
103
+ };
104
+ }
105
+ /** Reads head and, where deletions need it, base of each content file, and finds the symbols that changed. */
106
+ function readContent(states, files, ctx) {
107
+ return mapLimit(states, READ_CONCURRENCY, async (s) => {
108
+ ctx.signal.throwIfAborted();
109
+ const needsBase = s.file.status === 'deleted' ||
110
+ ((s.role === 'source' || s.role === 'migration') && s.file.deletions > 0 && s.file.status !== 'added');
111
+ const [head, base] = await Promise.all([files.head(s), needsBase ? files.base(s) : null]);
112
+ const reports = s.role === 'source' || s.role === 'migration' || s.role === 'other';
113
+ return { state: s, head, symbols: reports ? classifySymbols(s.file, head, base) : [] };
114
+ });
115
+ }
116
+ /** Dependency changes of the manifests in the change, numbered in file order. */
117
+ async function readDependencies(states, files) {
118
+ const manifests = states.filter((s) => !s.hidden && s.role === 'dependency-manifest' && manifestKind(s.file.path) !== null);
119
+ const diffs = await mapLimit(manifests, READ_CONCURRENCY, async (s) => {
120
+ const [base, head] = await Promise.all([files.base(s), files.head(s)]);
121
+ return diffManifest(s.file, base, head);
122
+ });
123
+ return diffs.flat().map((d, i) => ({ ...d, id: `D${i + 1}` }));
124
+ }
125
+ /** Keeps the most relevant symbols, then numbers them in file order. */
126
+ function pickSymbols(reads) {
127
+ const candidates = [...reads]
128
+ .sort((a, b) => a.state.index - b.state.index)
129
+ .flatMap(({ state, symbols }) => symbols.map((symbol) => ({ state, symbol })));
130
+ const relevance = (c) => KIND_WEIGHT[c.symbol.kind] *
131
+ CHANGE_WEIGHT[c.symbol.change] *
132
+ (c.symbol.exported ? 1 : 0.6) *
133
+ Math.max(0.1, ROLE_WEIGHT[c.state.role]);
134
+ const kept = candidates
135
+ .map((c, order) => ({ c, order, score: relevance(c) }))
136
+ .sort((a, b) => b.score - a.score || a.order - b.order)
137
+ .slice(0, MAX_SYMBOLS)
138
+ .sort((a, b) => a.order - b.order);
139
+ const identified = kept.map(({ c }, i) => {
140
+ const { signatureChanged, decl: _decl, ...rest } = c.symbol;
141
+ return { ...rest, id: `S${i + 1}`, signatureChanged };
142
+ });
143
+ return { identified, symbols: identified.map(({ signatureChanged: _s, ...rest }) => rest) };
144
+ }
145
+ /** Size class, line count and suggested length of the video. */
146
+ function pacing(states, grouping) {
147
+ let meaningfulLines = 0;
148
+ for (const s of states) {
149
+ if (isShowable(s.file) && !s.trivial)
150
+ meaningfulLines += s.file.additions + s.file.deletions;
151
+ }
152
+ const size = sizeOf(meaningfulLines);
153
+ const stateById = new Map(states.map((s) => [s.file.id, s]));
154
+ const meaningfulComponents = grouping.components.filter((m) => m.fileIds.some((id) => {
155
+ const s = stateById.get(id);
156
+ return (!!s && !s.hidden && !s.trivial && !['docs', 'test', 'asset', 'lockfile', 'generated'].includes(s.role));
157
+ })).length;
158
+ return {
159
+ meaningfulLines,
160
+ size,
161
+ suggestedDurationSec: DURATION[size] + (meaningfulComponents >= 3 ? 10 : 0),
162
+ };
163
+ }
164
+ function insightsOf(states, symbols, risks, grouping) {
165
+ const symbolsByFile = new Map();
166
+ for (const s of symbols)
167
+ symbolsByFile.set(s.fileId, [...(symbolsByFile.get(s.fileId) ?? []), s]);
168
+ return states.map((s) => {
169
+ const churn = s.file.additions + s.file.deletions;
170
+ const fileSymbols = symbolsByFile.get(s.file.id) ?? [];
171
+ let importance = 0.1;
172
+ if (!s.hidden) {
173
+ if (s.trivial)
174
+ importance = 0;
175
+ else {
176
+ importance = ROLE_WEIGHT[s.role] * (0.35 + 0.65 * Math.min(1, Math.log1p(churn) / Math.log1p(150)));
177
+ if (s.commentOnly)
178
+ importance *= 0.4;
179
+ if (fileSymbols.some((x) => x.exported && x.change === 'added'))
180
+ importance += 0.1;
181
+ importance += Math.min(0.15, 0.05 * risks.filter((r) => r.evidence.includes(s.file.id)).length);
182
+ }
183
+ }
184
+ return {
185
+ fileId: s.file.id,
186
+ path: s.file.path,
187
+ role: s.role,
188
+ componentId: grouping.byFile.get(s.file.id) ?? 'M1',
189
+ hidden: s.hidden,
190
+ trivial: s.trivial,
191
+ trivialReason: s.trivialReason,
192
+ importance: round(Math.min(1, Math.max(0, importance))),
193
+ symbolIds: fileSymbols.map((x) => x.id),
194
+ };
195
+ });
196
+ }
197
+ function testChanges(states) {
198
+ const tests = { added: [], modified: [], removed: [] };
199
+ for (const s of states) {
200
+ if (s.hidden || s.role !== 'test')
201
+ continue;
202
+ if (s.file.status === 'added' || s.file.status === 'copied')
203
+ tests.added.push(s.file.path);
204
+ else if (s.file.status === 'deleted')
205
+ tests.removed.push(s.file.path);
206
+ else
207
+ tests.modified.push(s.file.path);
208
+ }
209
+ return tests;
210
+ }
211
+ function languagesOf(states) {
212
+ const counts = new Map();
213
+ for (const s of states) {
214
+ if (!isContent(s))
215
+ continue;
216
+ const language = s.file.language ? languageInfo(s.file.language) : null;
217
+ if (language?.isCode)
218
+ counts.set(language.base, (counts.get(language.base) ?? 0) + 1);
219
+ }
220
+ return [...counts.entries()]
221
+ .map(([language, files]) => ({ language, files }))
222
+ .sort((a, b) => b.files - a.files || a.language.localeCompare(b.language));
223
+ }
224
+ /**
225
+ * Analyse a change set. File contents come only from `reader`, and never for a file marked
226
+ * `sensitive` (a sensitive or excluded path: the source decides). The result is deterministic: the
227
+ * same input gives the same ids.
228
+ */
229
+ export async function analyze(changeSet, reader, inputs, ctx) {
230
+ const states = classifyFiles(changeSet.files);
231
+ ctx.signal.throwIfAborted();
232
+ const files = createFileReader(reader, ctx);
233
+ const contentStates = selectContentFiles(states);
234
+ const grouping = groupComponents(states.map((s) => ({ file: s.file, role: s.role, trivial: s.trivial })));
235
+ const languages = new Set(contentStates.flatMap((s) => {
236
+ const lang = importLang(s.file.path);
237
+ return lang ? [lang] : [];
238
+ }));
239
+ const isExcluded = compileGlobs(ctx.config.privacy.excludePaths);
240
+ // None of these reads needs another's result.
241
+ const [contents, dependencies, resolverOptions] = await Promise.all([
242
+ readContent(contentStates, files, ctx),
243
+ readDependencies(states, files),
244
+ loadResolverOptions({
245
+ componentPaths: grouping.components.map((m) => m.path),
246
+ languages,
247
+ isExcluded,
248
+ readHead: (path) => files.read(path, 'head'),
249
+ concurrency: READ_CONCURRENCY,
250
+ }),
251
+ ]);
252
+ const { identified, symbols } = pickSymbols(contents);
253
+ ctx.signal.throwIfAborted();
254
+ const knownPaths = new Set();
255
+ for (const s of states)
256
+ if (s.file.status !== 'deleted')
257
+ knownPaths.add(s.file.path);
258
+ for (const entry of changeSet.repoContext.tree)
259
+ knownPaths.add(entry.replace(/\/+$/, ''));
260
+ const relationships = buildRelationships({
261
+ files: contents.map(({ state, head }) => ({ file: state.file, role: state.role, head })),
262
+ grouping,
263
+ resolver: new ImportResolver({ knownPaths, ...resolverOptions }),
264
+ });
265
+ ctx.signal.throwIfAborted();
266
+ const { meaningfulLines, size, suggestedDurationSec } = pacing(states, grouping);
267
+ const riskResult = detectRisks({
268
+ files: states.map((s) => ({
269
+ file: s.file,
270
+ role: s.role,
271
+ trivial: s.trivial,
272
+ commentOnly: s.commentOnly,
273
+ hidden: s.hidden,
274
+ })),
275
+ symbols: identified,
276
+ dependencies,
277
+ inputs,
278
+ meaningfulLines,
279
+ });
280
+ const keyHunks = rankKeyHunks(states, symbols, riskResult.risks);
281
+ const fileInsights = insightsOf(states, symbols, riskResult.risks, grouping);
282
+ const stateById = new Map(states.map((s) => [s.file.id, s]));
283
+ const signals = architectureSignals({
284
+ components: grouping.components,
285
+ files: fileInsights.map((f) => {
286
+ const file = stateById.get(f.fileId)?.file;
287
+ return { ...f, status: file?.status ?? 'modified', oldPath: file?.oldPath ?? null };
288
+ }),
289
+ dependencies,
290
+ symbols,
291
+ envVars: riskResult.envVars,
292
+ cliCommands: riskResult.cliCommands,
293
+ });
294
+ const evidence = buildEvidenceIndex({
295
+ changeSet,
296
+ inputs,
297
+ hiddenFileIds: new Set(states.filter((s) => s.hidden).map((s) => s.file.id)),
298
+ components: grouping.components,
299
+ symbols,
300
+ risks: riskResult.risks,
301
+ dependencies,
302
+ });
303
+ ctx.logger.debug('analyzer: done', {
304
+ files: states.length,
305
+ contentFiles: contentStates.length,
306
+ symbols: symbols.length,
307
+ risks: riskResult.risks.length,
308
+ evidence: evidence.length,
309
+ });
310
+ return {
311
+ version: 1,
312
+ size,
313
+ meaningfulLines,
314
+ files: fileInsights,
315
+ components: grouping.components,
316
+ relationships,
317
+ symbols,
318
+ keyHunks,
319
+ risks: riskResult.risks,
320
+ dependencies,
321
+ tests: testChanges(states),
322
+ languages: languagesOf(states),
323
+ architectureSignals: signals,
324
+ suggestedDurationSec,
325
+ evidence,
326
+ };
327
+ }
328
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Component (module) grouping. A component is the unit shown as one box in an architecture view:
3
+ * a monorepo package, or the first meaningful directory under a source root.
4
+ */
5
+ import type { ChangedFile, Component, FileRole } from '../core/types.ts';
6
+ export interface ComponentInput {
7
+ file: ChangedFile;
8
+ role: FileRole;
9
+ trivial: boolean;
10
+ }
11
+ export interface ComponentGrouping {
12
+ components: Component[];
13
+ /** File id -> component id. */
14
+ byFile: Map<string, string>;
15
+ /** Owning component of any repository path (changed or not), or null when no changed component owns it. */
16
+ componentForPath(path: string): string | null;
17
+ }
18
+ export declare function groupComponents(inputs: readonly ComponentInput[]): ComponentGrouping;
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Component (module) grouping. A component is the unit shown as one box in an architecture view:
3
+ * a monorepo package, or the first meaningful directory under a source root.
4
+ */
5
+ import { basename, dirname } from '../core/posix.js';
6
+ import { SOURCE_ROOTS } from './roles.js';
7
+ const MONOREPO_PREFIXES = new Set(['packages', 'apps', 'services', 'libs', 'crates', 'modules', 'cmd']);
8
+ const WRAPPER_DIRS = new Set(['features', 'modules', 'domains']);
9
+ const TEST_DIRS = new Set(['__tests__', '__mocks__', 'tests', 'test', 'spec', 'specs', 'e2e', 'testdata']);
10
+ const DOC_DIRS = new Set(['docs', 'doc', 'documentation']);
11
+ const REVERSE_DOMAIN = new Set([
12
+ 'com',
13
+ 'org',
14
+ 'net',
15
+ 'io',
16
+ 'de',
17
+ 'fr',
18
+ 'uk',
19
+ 'nl',
20
+ 'jp',
21
+ 'cn',
22
+ 'in',
23
+ 'br',
24
+ 'ch',
25
+ ]);
26
+ const ROOT = { key: '.', name: 'Project root', path: '.' };
27
+ const KIND_KEYWORDS = [
28
+ ['api', /^(api|apis|routes?|controllers?|handlers?|endpoints?)$/],
29
+ ['ui', /^(components?|ui|pages?|views?|screens?)$/],
30
+ ['data', /^(db|database|models?|migrations?|schemas?|repositories|repository)$/],
31
+ ['cli', /^(cli|bin|cmd|commands?)$/],
32
+ ['infra', /^(infra|infrastructure|terraform|k8s|kubernetes|helm|deploy|deployment)$/],
33
+ ['tests', /^(tests?|__tests__|spec|specs|e2e)$/],
34
+ ['docs', /^(docs?|documentation)$/],
35
+ ['config', /^(config|configs|configuration)$/],
36
+ ];
37
+ function tokens(text) {
38
+ return text
39
+ .toLowerCase()
40
+ .split(/[\\/\-_.\s]+/)
41
+ .filter(Boolean);
42
+ }
43
+ function kindFromTokens(segments) {
44
+ for (const segment of segments) {
45
+ const parts = tokens(segment);
46
+ for (const [kind, pattern] of KIND_KEYWORDS) {
47
+ if (pattern.test(segment.toLowerCase()) || parts.some((p) => pattern.test(p)))
48
+ return kind;
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+ /**
54
+ * First meaningful directory below a source root: skips the JVM layout (src/main/java) and
55
+ * reverse-domain package prefixes (com/acme). Returns the skipped segments and the ones kept.
56
+ */
57
+ function meaningfulUnder(dirs) {
58
+ let i = 0;
59
+ if (dirs[0] === 'main' && ['java', 'kotlin', 'scala', 'groovy'].includes(dirs[1] ?? ''))
60
+ i = 2;
61
+ if (REVERSE_DOMAIN.has(dirs[i] ?? '') && dirs.length - i >= 3)
62
+ i += 2;
63
+ const first = dirs[i];
64
+ if (first === undefined)
65
+ return null;
66
+ const skipped = dirs.slice(0, i);
67
+ if (WRAPPER_DIRS.has(first) && dirs[i + 1] !== undefined)
68
+ return { skipped, kept: [first, dirs[i + 1]] };
69
+ return { skipped, kept: [first] };
70
+ }
71
+ /** Where a path lives, by layout alone. */
72
+ function locate(path) {
73
+ const dirs = path.split('/').slice(0, -1);
74
+ const first = dirs[0];
75
+ if (first === undefined)
76
+ return ROOT;
77
+ if (MONOREPO_PREFIXES.has(first) && dirs.length >= 2) {
78
+ const second = dirs[1];
79
+ return { key: `${first}/${second}`, name: second, path: `${first}/${second}` };
80
+ }
81
+ if (SOURCE_ROOTS.has(first)) {
82
+ const meaningful = meaningfulUnder(dirs.slice(1));
83
+ if (meaningful) {
84
+ const full = [first, ...meaningful.skipped, ...meaningful.kept].join('/');
85
+ return { key: full, name: meaningful.kept[meaningful.kept.length - 1], path: full };
86
+ }
87
+ }
88
+ return { key: first, name: first, path: first };
89
+ }
90
+ function stripTestDirs(path) {
91
+ const parts = path.split('/');
92
+ return parts.filter((p, i) => i === parts.length - 1 || !TEST_DIRS.has(p.toLowerCase())).join('/');
93
+ }
94
+ function fileStem(path, testSuffixes) {
95
+ let name = basename(path)
96
+ .toLowerCase()
97
+ .replace(/\.[^.]+$/, '');
98
+ if (testSuffixes)
99
+ name = name
100
+ .replace(/\.(test|spec)$/, '')
101
+ .replace(/(_test|_spec|-test|-spec)$/, '')
102
+ .replace(/^test_/, '');
103
+ return name;
104
+ }
105
+ export function groupComponents(inputs) {
106
+ const placements = new Map();
107
+ const pending = [];
108
+ for (const input of inputs) {
109
+ const { file, role } = input;
110
+ if (role === 'ci') {
111
+ placements.set(file.id, {
112
+ key: 'ci',
113
+ name: 'CI',
114
+ path: file.path.split('/')[0]?.startsWith('.') ? file.path.split('/')[0] : '.',
115
+ ci: true,
116
+ });
117
+ }
118
+ else if (role === 'test' && stripTestDirs(file.path) !== file.path) {
119
+ pending.push(input);
120
+ }
121
+ else if (DOC_DIRS.has(file.path.split('/')[0] ?? '') && file.path.includes('/')) {
122
+ pending.push(input);
123
+ }
124
+ else {
125
+ placements.set(file.id, locate(file.path));
126
+ }
127
+ }
128
+ const byKey = new Map();
129
+ const byName = new Map();
130
+ const byStem = new Map();
131
+ const stemOwner = (stem, key) => {
132
+ byStem.set(stem, [...(byStem.get(stem) ?? []), key]);
133
+ };
134
+ for (const input of inputs) {
135
+ const p = placements.get(input.file.id);
136
+ if (!p)
137
+ continue;
138
+ byKey.set(p.key, p);
139
+ const nameKey = p.name.toLowerCase();
140
+ if (!(byName.get(nameKey) ?? []).includes(p.key))
141
+ byName.set(nameKey, [...(byName.get(nameKey) ?? []), p.key]);
142
+ if (input.role !== 'test')
143
+ stemOwner(fileStem(input.file.path, false), p.key);
144
+ }
145
+ const unique = (keys) => {
146
+ const set = [...new Set(keys ?? [])];
147
+ return set.length === 1 ? set[0] : null;
148
+ };
149
+ for (const input of pending) {
150
+ const { file, role } = input;
151
+ const original = locate(file.path);
152
+ if (role === 'test') {
153
+ const stripped = locate(stripTestDirs(file.path));
154
+ const topIsTestDir = TEST_DIRS.has(file.path.split('/')[0]?.toLowerCase() ?? '');
155
+ // A test at the repository root of its test folder says nothing about the root component.
156
+ const named = stripped.key !== ROOT.key;
157
+ const folded = (named && byKey.has(stripped.key) ? stripped.key : null) ??
158
+ (named ? unique(byName.get(stripped.name.toLowerCase())) : null) ??
159
+ unique(byStem.get(fileStem(file.path, true)));
160
+ if (folded)
161
+ placements.set(file.id, byKey.get(folded));
162
+ else
163
+ placements.set(file.id, topIsTestDir ? original : stripped);
164
+ }
165
+ else {
166
+ const folded = unique(byName.get(fileStem(file.path, false))) ?? unique(byStem.get(fileStem(file.path, false)));
167
+ placements.set(file.id, folded ? byKey.get(folded) : original);
168
+ }
169
+ }
170
+ // Duplicate short names (packages/api and services/api) fall back to the full path.
171
+ const nameCounts = new Map();
172
+ for (const p of placements.values()) {
173
+ const set = nameCounts.get(p.name) ?? new Set();
174
+ set.add(p.key);
175
+ nameCounts.set(p.name, set);
176
+ }
177
+ const buckets = new Map();
178
+ for (const input of inputs) {
179
+ const p = placements.get(input.file.id);
180
+ const bucket = buckets.get(p.key) ?? { located: p, inputs: [] };
181
+ bucket.inputs.push(input);
182
+ buckets.set(p.key, bucket);
183
+ }
184
+ const churn = (b) => b.inputs.reduce((n, i) => n + (i.trivial ? 0 : i.file.additions + i.file.deletions), 0);
185
+ const ordered = [...buckets.values()].sort((a, b) => churn(b) - churn(a) || a.located.path.localeCompare(b.located.path));
186
+ const components = [];
187
+ const keyToId = new Map();
188
+ const byFile = new Map();
189
+ ordered.forEach((bucket, index) => {
190
+ const id = `M${index + 1}`;
191
+ const { located } = bucket;
192
+ const files = bucket.inputs.map((i) => i.file);
193
+ const name = (nameCounts.get(located.name)?.size ?? 0) > 1 && !located.ci ? located.path : located.name;
194
+ components.push({
195
+ id,
196
+ name,
197
+ path: located.path,
198
+ kind: inferKind(located, bucket.inputs),
199
+ fileIds: files.map((f) => f.id),
200
+ additions: files.reduce((n, f) => n + f.additions, 0),
201
+ deletions: files.reduce((n, f) => n + f.deletions, 0),
202
+ status: files.every((f) => f.status === 'added')
203
+ ? 'added'
204
+ : files.every((f) => f.status === 'deleted')
205
+ ? 'removed'
206
+ : 'modified',
207
+ });
208
+ keyToId.set(located.key, id);
209
+ for (const f of files)
210
+ byFile.set(f.id, id);
211
+ });
212
+ const pathToFile = new Map(inputs.map((i) => [i.file.path, i.file.id]));
213
+ return {
214
+ components,
215
+ byFile,
216
+ componentForPath(path) {
217
+ const fileId = pathToFile.get(path);
218
+ if (fileId)
219
+ return byFile.get(fileId) ?? null;
220
+ return keyToId.get(locate(path).key) ?? null;
221
+ },
222
+ };
223
+ }
224
+ function inferKind(located, inputs) {
225
+ const roles = inputs.map((i) => i.role);
226
+ if (roles.every((r) => r === 'test'))
227
+ return 'tests';
228
+ if (roles.every((r) => r === 'docs'))
229
+ return 'docs';
230
+ if (roles.every((r) => r === 'asset'))
231
+ return 'ui';
232
+ if (located.ci || roles.every((r) => r === 'ci'))
233
+ return 'infra';
234
+ if (roles.every((r) => r === 'config' || r === 'dependency-manifest' || r === 'lockfile'))
235
+ return 'config';
236
+ if (located.key === '.' && !roles.some((r) => r === 'source' || r === 'migration'))
237
+ return 'config';
238
+ const fromName = kindFromTokens(located.path.split('/'));
239
+ if (fromName)
240
+ return fromName;
241
+ // Pick a kind when most source files sit in directories that name one (src/components/...).
242
+ const sources = inputs.filter((i) => i.role === 'source' || i.role === 'migration');
243
+ if (sources.length > 0 && sources.every((i) => /\.(tf|hcl)$/.test(i.file.path)))
244
+ return 'infra';
245
+ if (sources.length > 0) {
246
+ const counts = new Map();
247
+ for (const input of sources) {
248
+ const rel = dirname(input.file.path)
249
+ .split('/')
250
+ .slice(located.path === '.' ? 0 : located.path.split('/').length);
251
+ const kind = kindFromTokens(rel);
252
+ if (kind && kind !== 'tests' && kind !== 'docs' && kind !== 'config')
253
+ counts.set(kind, (counts.get(kind) ?? 0) + 1);
254
+ }
255
+ for (const [kind, n] of counts)
256
+ if (n / sources.length >= 0.6)
257
+ return kind;
258
+ }
259
+ const container = located.path.split('/')[0] ?? '';
260
+ if (container === 'services' || container === 'apps')
261
+ return 'service';
262
+ if (container === 'packages' || container === 'libs' || container === 'crates')
263
+ return 'package';
264
+ return 'module';
265
+ }
266
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1,13 @@
1
+ /** Dependency changes read from manifest files at base and head. */
2
+ import type { ChangedFile, DependencyChange } from '../core/types.ts';
3
+ export interface DependencyEntry {
4
+ name: string;
5
+ version: string;
6
+ dev: boolean;
7
+ }
8
+ type ManifestKind = 'package.json' | 'composer' | 'requirements' | 'go.mod' | 'cargo' | 'pyproject' | 'pipfile' | 'gemfile' | 'pom';
9
+ export declare function manifestKind(path: string): ManifestKind | null;
10
+ type DraftChange = Omit<DependencyChange, 'id'>;
11
+ /** Dependency changes in one manifest file. `base` and `head` are file contents (null when absent). */
12
+ export declare function diffManifest(file: ChangedFile, base: string | null, head: string | null): DraftChange[];
13
+ export {};