@shirokuma-library/shirokuma-docs 0.1.0-alpha.5

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.

Potentially problematic release.


This version of @shirokuma-library/shirokuma-docs might be problematic. Click here for more details.

Files changed (753) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +308 -0
  3. package/README.md +308 -0
  4. package/THIRD_PARTY_NOTICES.md +18 -0
  5. package/bin/shirokuma-docs +2 -0
  6. package/dist/analyzers/details-test-analysis.d.ts +31 -0
  7. package/dist/analyzers/details-test-analysis.d.ts.map +1 -0
  8. package/dist/analyzers/details-test-analysis.js +172 -0
  9. package/dist/analyzers/details-test-analysis.js.map +1 -0
  10. package/dist/analyzers/feature-map-builder.d.ts +20 -0
  11. package/dist/analyzers/feature-map-builder.d.ts.map +1 -0
  12. package/dist/analyzers/feature-map-builder.js +154 -0
  13. package/dist/analyzers/feature-map-builder.js.map +1 -0
  14. package/dist/analyzers/feature-map-references.d.ts +34 -0
  15. package/dist/analyzers/feature-map-references.d.ts.map +1 -0
  16. package/dist/analyzers/feature-map-references.js +249 -0
  17. package/dist/analyzers/feature-map-references.js.map +1 -0
  18. package/dist/analyzers/reference-analyzer.d.ts +95 -0
  19. package/dist/analyzers/reference-analyzer.d.ts.map +1 -0
  20. package/dist/analyzers/reference-analyzer.js +372 -0
  21. package/dist/analyzers/reference-analyzer.js.map +1 -0
  22. package/dist/commands/adr.d.ts +26 -0
  23. package/dist/commands/adr.d.ts.map +1 -0
  24. package/dist/commands/adr.js +129 -0
  25. package/dist/commands/adr.js.map +1 -0
  26. package/dist/commands/api-tools.d.ts +83 -0
  27. package/dist/commands/api-tools.d.ts.map +1 -0
  28. package/dist/commands/api-tools.js +775 -0
  29. package/dist/commands/api-tools.js.map +1 -0
  30. package/dist/commands/coverage.d.ts +139 -0
  31. package/dist/commands/coverage.d.ts.map +1 -0
  32. package/dist/commands/coverage.js +481 -0
  33. package/dist/commands/coverage.js.map +1 -0
  34. package/dist/commands/deps.d.ts +24 -0
  35. package/dist/commands/deps.d.ts.map +1 -0
  36. package/dist/commands/deps.js +211 -0
  37. package/dist/commands/deps.js.map +1 -0
  38. package/dist/commands/details-context.d.ts +38 -0
  39. package/dist/commands/details-context.d.ts.map +1 -0
  40. package/dist/commands/details-context.js +193 -0
  41. package/dist/commands/details-context.js.map +1 -0
  42. package/dist/commands/details-types.d.ts +315 -0
  43. package/dist/commands/details-types.d.ts.map +1 -0
  44. package/dist/commands/details-types.js +7 -0
  45. package/dist/commands/details-types.js.map +1 -0
  46. package/dist/commands/details.d.ts +24 -0
  47. package/dist/commands/details.d.ts.map +1 -0
  48. package/dist/commands/details.js +299 -0
  49. package/dist/commands/details.js.map +1 -0
  50. package/dist/commands/discussion-templates.d.ts +26 -0
  51. package/dist/commands/discussion-templates.d.ts.map +1 -0
  52. package/dist/commands/discussion-templates.js +270 -0
  53. package/dist/commands/discussion-templates.js.map +1 -0
  54. package/dist/commands/discussions.d.ts +31 -0
  55. package/dist/commands/discussions.d.ts.map +1 -0
  56. package/dist/commands/discussions.js +743 -0
  57. package/dist/commands/discussions.js.map +1 -0
  58. package/dist/commands/feature-map-types.d.ts +294 -0
  59. package/dist/commands/feature-map-types.d.ts.map +1 -0
  60. package/dist/commands/feature-map-types.js +8 -0
  61. package/dist/commands/feature-map-types.js.map +1 -0
  62. package/dist/commands/feature-map.d.ts +30 -0
  63. package/dist/commands/feature-map.d.ts.map +1 -0
  64. package/dist/commands/feature-map.js +137 -0
  65. package/dist/commands/feature-map.js.map +1 -0
  66. package/dist/commands/generate.d.ts +16 -0
  67. package/dist/commands/generate.d.ts.map +1 -0
  68. package/dist/commands/generate.js +88 -0
  69. package/dist/commands/generate.js.map +1 -0
  70. package/dist/commands/gh-discussions.d.ts +31 -0
  71. package/dist/commands/gh-discussions.d.ts.map +1 -0
  72. package/dist/commands/gh-discussions.js +743 -0
  73. package/dist/commands/gh-discussions.js.map +1 -0
  74. package/dist/commands/gh-issues-pr.d.ts +74 -0
  75. package/dist/commands/gh-issues-pr.d.ts.map +1 -0
  76. package/dist/commands/gh-issues-pr.js +417 -0
  77. package/dist/commands/gh-issues-pr.js.map +1 -0
  78. package/dist/commands/gh-issues.d.ts +90 -0
  79. package/dist/commands/gh-issues.d.ts.map +1 -0
  80. package/dist/commands/gh-issues.js +1297 -0
  81. package/dist/commands/gh-issues.js.map +1 -0
  82. package/dist/commands/gh-projects.d.ts +54 -0
  83. package/dist/commands/gh-projects.d.ts.map +1 -0
  84. package/dist/commands/gh-projects.js +966 -0
  85. package/dist/commands/gh-projects.js.map +1 -0
  86. package/dist/commands/gh-repo.d.ts +18 -0
  87. package/dist/commands/gh-repo.d.ts.map +1 -0
  88. package/dist/commands/gh-repo.js +253 -0
  89. package/dist/commands/gh-repo.js.map +1 -0
  90. package/dist/commands/github-data.d.ts +67 -0
  91. package/dist/commands/github-data.d.ts.map +1 -0
  92. package/dist/commands/github-data.js +361 -0
  93. package/dist/commands/github-data.js.map +1 -0
  94. package/dist/commands/i18n.d.ts +102 -0
  95. package/dist/commands/i18n.d.ts.map +1 -0
  96. package/dist/commands/i18n.js +829 -0
  97. package/dist/commands/i18n.js.map +1 -0
  98. package/dist/commands/impact.d.ts +14 -0
  99. package/dist/commands/impact.d.ts.map +1 -0
  100. package/dist/commands/impact.js +263 -0
  101. package/dist/commands/impact.js.map +1 -0
  102. package/dist/commands/init.d.ts +53 -0
  103. package/dist/commands/init.d.ts.map +1 -0
  104. package/dist/commands/init.js +429 -0
  105. package/dist/commands/init.js.map +1 -0
  106. package/dist/commands/issues-pr.d.ts +74 -0
  107. package/dist/commands/issues-pr.d.ts.map +1 -0
  108. package/dist/commands/issues-pr.js +417 -0
  109. package/dist/commands/issues-pr.js.map +1 -0
  110. package/dist/commands/issues.d.ts +76 -0
  111. package/dist/commands/issues.d.ts.map +1 -0
  112. package/dist/commands/issues.js +1285 -0
  113. package/dist/commands/issues.js.map +1 -0
  114. package/dist/commands/link-docs.d.ts +21 -0
  115. package/dist/commands/link-docs.d.ts.map +1 -0
  116. package/dist/commands/link-docs.js +990 -0
  117. package/dist/commands/link-docs.js.map +1 -0
  118. package/dist/commands/lint-annotations.d.ts +28 -0
  119. package/dist/commands/lint-annotations.d.ts.map +1 -0
  120. package/dist/commands/lint-annotations.js +511 -0
  121. package/dist/commands/lint-annotations.js.map +1 -0
  122. package/dist/commands/lint-code.d.ts +26 -0
  123. package/dist/commands/lint-code.d.ts.map +1 -0
  124. package/dist/commands/lint-code.js +428 -0
  125. package/dist/commands/lint-code.js.map +1 -0
  126. package/dist/commands/lint-coverage.d.ts +33 -0
  127. package/dist/commands/lint-coverage.d.ts.map +1 -0
  128. package/dist/commands/lint-coverage.js +379 -0
  129. package/dist/commands/lint-coverage.js.map +1 -0
  130. package/dist/commands/lint-docs.d.ts +23 -0
  131. package/dist/commands/lint-docs.d.ts.map +1 -0
  132. package/dist/commands/lint-docs.js +338 -0
  133. package/dist/commands/lint-docs.js.map +1 -0
  134. package/dist/commands/lint-structure.d.ts +38 -0
  135. package/dist/commands/lint-structure.d.ts.map +1 -0
  136. package/dist/commands/lint-structure.js +350 -0
  137. package/dist/commands/lint-structure.js.map +1 -0
  138. package/dist/commands/lint-tests.d.ts +25 -0
  139. package/dist/commands/lint-tests.d.ts.map +1 -0
  140. package/dist/commands/lint-tests.js +105 -0
  141. package/dist/commands/lint-tests.js.map +1 -0
  142. package/dist/commands/lint-workflow.d.ts +36 -0
  143. package/dist/commands/lint-workflow.d.ts.map +1 -0
  144. package/dist/commands/lint-workflow.js +255 -0
  145. package/dist/commands/lint-workflow.js.map +1 -0
  146. package/dist/commands/overview.d.ts +21 -0
  147. package/dist/commands/overview.d.ts.map +1 -0
  148. package/dist/commands/overview.js +1300 -0
  149. package/dist/commands/overview.js.map +1 -0
  150. package/dist/commands/packages.d.ts +107 -0
  151. package/dist/commands/packages.d.ts.map +1 -0
  152. package/dist/commands/packages.js +308 -0
  153. package/dist/commands/packages.js.map +1 -0
  154. package/dist/commands/portal-nextjs.d.ts +23 -0
  155. package/dist/commands/portal-nextjs.d.ts.map +1 -0
  156. package/dist/commands/portal-nextjs.js +336 -0
  157. package/dist/commands/portal-nextjs.js.map +1 -0
  158. package/dist/commands/portal.d.ts +24 -0
  159. package/dist/commands/portal.d.ts.map +1 -0
  160. package/dist/commands/portal.js +16 -0
  161. package/dist/commands/portal.js.map +1 -0
  162. package/dist/commands/projects.d.ts +54 -0
  163. package/dist/commands/projects.d.ts.map +1 -0
  164. package/dist/commands/projects.js +969 -0
  165. package/dist/commands/projects.js.map +1 -0
  166. package/dist/commands/repo-pairs.d.ts +19 -0
  167. package/dist/commands/repo-pairs.d.ts.map +1 -0
  168. package/dist/commands/repo-pairs.js +529 -0
  169. package/dist/commands/repo-pairs.js.map +1 -0
  170. package/dist/commands/repo.d.ts +18 -0
  171. package/dist/commands/repo.d.ts.map +1 -0
  172. package/dist/commands/repo.js +253 -0
  173. package/dist/commands/repo.js.map +1 -0
  174. package/dist/commands/schema.d.ts +49 -0
  175. package/dist/commands/schema.d.ts.map +1 -0
  176. package/dist/commands/schema.js +830 -0
  177. package/dist/commands/schema.js.map +1 -0
  178. package/dist/commands/screenshots.d.ts +203 -0
  179. package/dist/commands/screenshots.d.ts.map +1 -0
  180. package/dist/commands/screenshots.js +1234 -0
  181. package/dist/commands/screenshots.js.map +1 -0
  182. package/dist/commands/search-index.d.ts +83 -0
  183. package/dist/commands/search-index.d.ts.map +1 -0
  184. package/dist/commands/search-index.js +389 -0
  185. package/dist/commands/search-index.js.map +1 -0
  186. package/dist/commands/session.d.ts +153 -0
  187. package/dist/commands/session.d.ts.map +1 -0
  188. package/dist/commands/session.js +1243 -0
  189. package/dist/commands/session.js.map +1 -0
  190. package/dist/commands/test-cases-types.d.ts +154 -0
  191. package/dist/commands/test-cases-types.d.ts.map +1 -0
  192. package/dist/commands/test-cases-types.js +7 -0
  193. package/dist/commands/test-cases-types.js.map +1 -0
  194. package/dist/commands/test-cases.d.ts +28 -0
  195. package/dist/commands/test-cases.d.ts.map +1 -0
  196. package/dist/commands/test-cases.js +192 -0
  197. package/dist/commands/test-cases.js.map +1 -0
  198. package/dist/commands/typedoc.d.ts +21 -0
  199. package/dist/commands/typedoc.d.ts.map +1 -0
  200. package/dist/commands/typedoc.js +192 -0
  201. package/dist/commands/typedoc.js.map +1 -0
  202. package/dist/commands/update-skills.d.ts +56 -0
  203. package/dist/commands/update-skills.d.ts.map +1 -0
  204. package/dist/commands/update-skills.js +620 -0
  205. package/dist/commands/update-skills.js.map +1 -0
  206. package/dist/generators/details-entity-pages.d.ts +40 -0
  207. package/dist/generators/details-entity-pages.d.ts.map +1 -0
  208. package/dist/generators/details-entity-pages.js +301 -0
  209. package/dist/generators/details-entity-pages.js.map +1 -0
  210. package/dist/generators/details-html.d.ts +23 -0
  211. package/dist/generators/details-html.d.ts.map +1 -0
  212. package/dist/generators/details-html.js +324 -0
  213. package/dist/generators/details-html.js.map +1 -0
  214. package/dist/generators/details-module-page.d.ts +33 -0
  215. package/dist/generators/details-module-page.d.ts.map +1 -0
  216. package/dist/generators/details-module-page.js +408 -0
  217. package/dist/generators/details-module-page.js.map +1 -0
  218. package/dist/generators/details-styles.d.ts +39 -0
  219. package/dist/generators/details-styles.d.ts.map +1 -0
  220. package/dist/generators/details-styles.js +409 -0
  221. package/dist/generators/details-styles.js.map +1 -0
  222. package/dist/generators/feature-map-html.d.ts +66 -0
  223. package/dist/generators/feature-map-html.d.ts.map +1 -0
  224. package/dist/generators/feature-map-html.js +569 -0
  225. package/dist/generators/feature-map-html.js.map +1 -0
  226. package/dist/generators/feature-map-styles.d.ts +39 -0
  227. package/dist/generators/feature-map-styles.d.ts.map +1 -0
  228. package/dist/generators/feature-map-styles.js +449 -0
  229. package/dist/generators/feature-map-styles.js.map +1 -0
  230. package/dist/generators/test-cases-hierarchy.d.ts +21 -0
  231. package/dist/generators/test-cases-hierarchy.d.ts.map +1 -0
  232. package/dist/generators/test-cases-hierarchy.js +336 -0
  233. package/dist/generators/test-cases-hierarchy.js.map +1 -0
  234. package/dist/generators/test-cases-main.d.ts +20 -0
  235. package/dist/generators/test-cases-main.d.ts.map +1 -0
  236. package/dist/generators/test-cases-main.js +439 -0
  237. package/dist/generators/test-cases-main.js.map +1 -0
  238. package/dist/generators/test-cases-styles.d.ts +64 -0
  239. package/dist/generators/test-cases-styles.d.ts.map +1 -0
  240. package/dist/generators/test-cases-styles.js +1277 -0
  241. package/dist/generators/test-cases-styles.js.map +1 -0
  242. package/dist/index.d.ts +13 -0
  243. package/dist/index.d.ts.map +1 -0
  244. package/dist/index.js +517 -0
  245. package/dist/index.js.map +1 -0
  246. package/dist/lint/annotation-lint.d.ts +198 -0
  247. package/dist/lint/annotation-lint.d.ts.map +1 -0
  248. package/dist/lint/annotation-lint.js +510 -0
  249. package/dist/lint/annotation-lint.js.map +1 -0
  250. package/dist/lint/annotation-types.d.ts +161 -0
  251. package/dist/lint/annotation-types.d.ts.map +1 -0
  252. package/dist/lint/annotation-types.js +31 -0
  253. package/dist/lint/annotation-types.js.map +1 -0
  254. package/dist/lint/code-types.d.ts +135 -0
  255. package/dist/lint/code-types.d.ts.map +1 -0
  256. package/dist/lint/code-types.js +25 -0
  257. package/dist/lint/code-types.js.map +1 -0
  258. package/dist/lint/coverage-types.d.ts +128 -0
  259. package/dist/lint/coverage-types.d.ts.map +1 -0
  260. package/dist/lint/coverage-types.js +24 -0
  261. package/dist/lint/coverage-types.js.map +1 -0
  262. package/dist/lint/docs-types.d.ts +214 -0
  263. package/dist/lint/docs-types.d.ts.map +1 -0
  264. package/dist/lint/docs-types.js +18 -0
  265. package/dist/lint/docs-types.js.map +1 -0
  266. package/dist/lint/formatters/index.d.ts +14 -0
  267. package/dist/lint/formatters/index.d.ts.map +1 -0
  268. package/dist/lint/formatters/index.js +28 -0
  269. package/dist/lint/formatters/index.js.map +1 -0
  270. package/dist/lint/formatters/json.d.ts +11 -0
  271. package/dist/lint/formatters/json.d.ts.map +1 -0
  272. package/dist/lint/formatters/json.js +12 -0
  273. package/dist/lint/formatters/json.js.map +1 -0
  274. package/dist/lint/formatters/summary.d.ts +11 -0
  275. package/dist/lint/formatters/summary.d.ts.map +1 -0
  276. package/dist/lint/formatters/summary.js +37 -0
  277. package/dist/lint/formatters/summary.js.map +1 -0
  278. package/dist/lint/formatters/terminal.d.ts +11 -0
  279. package/dist/lint/formatters/terminal.d.ts.map +1 -0
  280. package/dist/lint/formatters/terminal.js +99 -0
  281. package/dist/lint/formatters/terminal.js.map +1 -0
  282. package/dist/lint/index.d.ts +18 -0
  283. package/dist/lint/index.d.ts.map +1 -0
  284. package/dist/lint/index.js +103 -0
  285. package/dist/lint/index.js.map +1 -0
  286. package/dist/lint/rules/annotation-required.d.ts +35 -0
  287. package/dist/lint/rules/annotation-required.d.ts.map +1 -0
  288. package/dist/lint/rules/annotation-required.js +127 -0
  289. package/dist/lint/rules/annotation-required.js.map +1 -0
  290. package/dist/lint/rules/code-rules.d.ts +12 -0
  291. package/dist/lint/rules/code-rules.d.ts.map +1 -0
  292. package/dist/lint/rules/code-rules.js +11 -0
  293. package/dist/lint/rules/code-rules.js.map +1 -0
  294. package/dist/lint/rules/describe-coverage.d.ts +8 -0
  295. package/dist/lint/rules/describe-coverage.d.ts.map +1 -0
  296. package/dist/lint/rules/describe-coverage.js +43 -0
  297. package/dist/lint/rules/describe-coverage.js.map +1 -0
  298. package/dist/lint/rules/duplicate-testdoc.d.ts +8 -0
  299. package/dist/lint/rules/duplicate-testdoc.d.ts.map +1 -0
  300. package/dist/lint/rules/duplicate-testdoc.js +38 -0
  301. package/dist/lint/rules/duplicate-testdoc.js.map +1 -0
  302. package/dist/lint/rules/index.d.ts +29 -0
  303. package/dist/lint/rules/index.d.ts.map +1 -0
  304. package/dist/lint/rules/index.js +55 -0
  305. package/dist/lint/rules/index.js.map +1 -0
  306. package/dist/lint/rules/server-action-structure.d.ts +37 -0
  307. package/dist/lint/rules/server-action-structure.d.ts.map +1 -0
  308. package/dist/lint/rules/server-action-structure.js +151 -0
  309. package/dist/lint/rules/server-action-structure.js.map +1 -0
  310. package/dist/lint/rules/skipped-test-report.d.ts +11 -0
  311. package/dist/lint/rules/skipped-test-report.d.ts.map +1 -0
  312. package/dist/lint/rules/skipped-test-report.js +31 -0
  313. package/dist/lint/rules/skipped-test-report.js.map +1 -0
  314. package/dist/lint/rules/structure-rules.d.ts +67 -0
  315. package/dist/lint/rules/structure-rules.d.ts.map +1 -0
  316. package/dist/lint/rules/structure-rules.js +615 -0
  317. package/dist/lint/rules/structure-rules.js.map +1 -0
  318. package/dist/lint/rules/testdoc-japanese.d.ts +8 -0
  319. package/dist/lint/rules/testdoc-japanese.d.ts.map +1 -0
  320. package/dist/lint/rules/testdoc-japanese.js +31 -0
  321. package/dist/lint/rules/testdoc-japanese.js.map +1 -0
  322. package/dist/lint/rules/testdoc-min-length.d.ts +8 -0
  323. package/dist/lint/rules/testdoc-min-length.d.ts.map +1 -0
  324. package/dist/lint/rules/testdoc-min-length.js +31 -0
  325. package/dist/lint/rules/testdoc-min-length.js.map +1 -0
  326. package/dist/lint/rules/testdoc-required.d.ts +8 -0
  327. package/dist/lint/rules/testdoc-required.d.ts.map +1 -0
  328. package/dist/lint/rules/testdoc-required.js +27 -0
  329. package/dist/lint/rules/testdoc-required.js.map +1 -0
  330. package/dist/lint/rules/workflow-branch-naming.d.ts +20 -0
  331. package/dist/lint/rules/workflow-branch-naming.d.ts.map +1 -0
  332. package/dist/lint/rules/workflow-branch-naming.js +85 -0
  333. package/dist/lint/rules/workflow-branch-naming.js.map +1 -0
  334. package/dist/lint/rules/workflow-commit-format.d.ts +27 -0
  335. package/dist/lint/rules/workflow-commit-format.d.ts.map +1 -0
  336. package/dist/lint/rules/workflow-commit-format.js +92 -0
  337. package/dist/lint/rules/workflow-commit-format.js.map +1 -0
  338. package/dist/lint/rules/workflow-issue-fields.d.ts +24 -0
  339. package/dist/lint/rules/workflow-issue-fields.d.ts.map +1 -0
  340. package/dist/lint/rules/workflow-issue-fields.js +89 -0
  341. package/dist/lint/rules/workflow-issue-fields.js.map +1 -0
  342. package/dist/lint/rules/workflow-main-protection.d.ts +32 -0
  343. package/dist/lint/rules/workflow-main-protection.d.ts.map +1 -0
  344. package/dist/lint/rules/workflow-main-protection.js +114 -0
  345. package/dist/lint/rules/workflow-main-protection.js.map +1 -0
  346. package/dist/lint/structure-types.d.ts +216 -0
  347. package/dist/lint/structure-types.d.ts.map +1 -0
  348. package/dist/lint/structure-types.js +96 -0
  349. package/dist/lint/structure-types.js.map +1 -0
  350. package/dist/lint/types.d.ts +154 -0
  351. package/dist/lint/types.d.ts.map +1 -0
  352. package/dist/lint/types.js +21 -0
  353. package/dist/lint/types.js.map +1 -0
  354. package/dist/lint/workflow-types.d.ts +90 -0
  355. package/dist/lint/workflow-types.d.ts.map +1 -0
  356. package/dist/lint/workflow-types.js +7 -0
  357. package/dist/lint/workflow-types.js.map +1 -0
  358. package/dist/md/analyzer/index.d.ts +46 -0
  359. package/dist/md/analyzer/index.d.ts.map +1 -0
  360. package/dist/md/analyzer/index.js +288 -0
  361. package/dist/md/analyzer/index.js.map +1 -0
  362. package/dist/md/builder/index.d.ts +91 -0
  363. package/dist/md/builder/index.d.ts.map +1 -0
  364. package/dist/md/builder/index.js +446 -0
  365. package/dist/md/builder/index.js.map +1 -0
  366. package/dist/md/cli/analyze.d.ts +11 -0
  367. package/dist/md/cli/analyze.d.ts.map +1 -0
  368. package/dist/md/cli/analyze.js +118 -0
  369. package/dist/md/cli/analyze.js.map +1 -0
  370. package/dist/md/cli/build.d.ts +11 -0
  371. package/dist/md/cli/build.d.ts.map +1 -0
  372. package/dist/md/cli/build.js +74 -0
  373. package/dist/md/cli/build.js.map +1 -0
  374. package/dist/md/cli/extract.d.ts +25 -0
  375. package/dist/md/cli/extract.d.ts.map +1 -0
  376. package/dist/md/cli/extract.js +230 -0
  377. package/dist/md/cli/extract.js.map +1 -0
  378. package/dist/md/cli/index.d.ts +3 -0
  379. package/dist/md/cli/index.d.ts.map +1 -0
  380. package/dist/md/cli/index.js +99 -0
  381. package/dist/md/cli/index.js.map +1 -0
  382. package/dist/md/cli/lint.d.ts +11 -0
  383. package/dist/md/cli/lint.d.ts.map +1 -0
  384. package/dist/md/cli/lint.js +165 -0
  385. package/dist/md/cli/lint.js.map +1 -0
  386. package/dist/md/cli/list.d.ts +16 -0
  387. package/dist/md/cli/list.d.ts.map +1 -0
  388. package/dist/md/cli/list.js +85 -0
  389. package/dist/md/cli/list.js.map +1 -0
  390. package/dist/md/cli/program.d.ts +11 -0
  391. package/dist/md/cli/program.d.ts.map +1 -0
  392. package/dist/md/cli/program.js +104 -0
  393. package/dist/md/cli/program.js.map +1 -0
  394. package/dist/md/cli/validate.d.ts +8 -0
  395. package/dist/md/cli/validate.d.ts.map +1 -0
  396. package/dist/md/cli/validate.js +82 -0
  397. package/dist/md/cli/validate.js.map +1 -0
  398. package/dist/md/constants.d.ts +69 -0
  399. package/dist/md/constants.d.ts.map +1 -0
  400. package/dist/md/constants.js +69 -0
  401. package/dist/md/constants.js.map +1 -0
  402. package/dist/md/extractor/index.d.ts +57 -0
  403. package/dist/md/extractor/index.d.ts.map +1 -0
  404. package/dist/md/extractor/index.js +359 -0
  405. package/dist/md/extractor/index.js.map +1 -0
  406. package/dist/md/index.d.ts +26 -0
  407. package/dist/md/index.d.ts.map +1 -0
  408. package/dist/md/index.js +30 -0
  409. package/dist/md/index.js.map +1 -0
  410. package/dist/md/linter/index.d.ts +20 -0
  411. package/dist/md/linter/index.d.ts.map +1 -0
  412. package/dist/md/linter/index.js +412 -0
  413. package/dist/md/linter/index.js.map +1 -0
  414. package/dist/md/linter/token-optimizer.d.ts +66 -0
  415. package/dist/md/linter/token-optimizer.d.ts.map +1 -0
  416. package/dist/md/linter/token-optimizer.js +292 -0
  417. package/dist/md/linter/token-optimizer.js.map +1 -0
  418. package/dist/md/lister/index.d.ts +42 -0
  419. package/dist/md/lister/index.d.ts.map +1 -0
  420. package/dist/md/lister/index.js +317 -0
  421. package/dist/md/lister/index.js.map +1 -0
  422. package/dist/md/parser/heading-numbers.d.ts +43 -0
  423. package/dist/md/parser/heading-numbers.d.ts.map +1 -0
  424. package/dist/md/parser/heading-numbers.js +97 -0
  425. package/dist/md/parser/heading-numbers.js.map +1 -0
  426. package/dist/md/parser/section-meta.d.ts +50 -0
  427. package/dist/md/parser/section-meta.d.ts.map +1 -0
  428. package/dist/md/parser/section-meta.js +212 -0
  429. package/dist/md/parser/section-meta.js.map +1 -0
  430. package/dist/md/parser/template.d.ts +56 -0
  431. package/dist/md/parser/template.d.ts.map +1 -0
  432. package/dist/md/parser/template.js +122 -0
  433. package/dist/md/parser/template.js.map +1 -0
  434. package/dist/md/plugins/loader.d.ts +15 -0
  435. package/dist/md/plugins/loader.d.ts.map +1 -0
  436. package/dist/md/plugins/loader.js +80 -0
  437. package/dist/md/plugins/loader.js.map +1 -0
  438. package/dist/md/plugins/normalize-headings.d.ts +43 -0
  439. package/dist/md/plugins/normalize-headings.d.ts.map +1 -0
  440. package/dist/md/plugins/normalize-headings.js +51 -0
  441. package/dist/md/plugins/normalize-headings.js.map +1 -0
  442. package/dist/md/plugins/normalize-whitespace.d.ts +46 -0
  443. package/dist/md/plugins/normalize-whitespace.d.ts.map +1 -0
  444. package/dist/md/plugins/normalize-whitespace.js +86 -0
  445. package/dist/md/plugins/normalize-whitespace.js.map +1 -0
  446. package/dist/md/plugins/remove-badges.d.ts +36 -0
  447. package/dist/md/plugins/remove-badges.d.ts.map +1 -0
  448. package/dist/md/plugins/remove-badges.js +59 -0
  449. package/dist/md/plugins/remove-badges.js.map +1 -0
  450. package/dist/md/plugins/remove-comments.d.ts +27 -0
  451. package/dist/md/plugins/remove-comments.d.ts.map +1 -0
  452. package/dist/md/plugins/remove-comments.js +40 -0
  453. package/dist/md/plugins/remove-comments.js.map +1 -0
  454. package/dist/md/plugins/remove-duplicates.d.ts +40 -0
  455. package/dist/md/plugins/remove-duplicates.d.ts.map +1 -0
  456. package/dist/md/plugins/remove-duplicates.js +72 -0
  457. package/dist/md/plugins/remove-duplicates.js.map +1 -0
  458. package/dist/md/plugins/remove-internal-links.d.ts +38 -0
  459. package/dist/md/plugins/remove-internal-links.d.ts.map +1 -0
  460. package/dist/md/plugins/remove-internal-links.js +66 -0
  461. package/dist/md/plugins/remove-internal-links.js.map +1 -0
  462. package/dist/md/plugins/strip-heading-numbers.d.ts +35 -0
  463. package/dist/md/plugins/strip-heading-numbers.d.ts.map +1 -0
  464. package/dist/md/plugins/strip-heading-numbers.js +59 -0
  465. package/dist/md/plugins/strip-heading-numbers.js.map +1 -0
  466. package/dist/md/plugins/strip-section-meta.d.ts +37 -0
  467. package/dist/md/plugins/strip-section-meta.d.ts.map +1 -0
  468. package/dist/md/plugins/strip-section-meta.js +62 -0
  469. package/dist/md/plugins/strip-section-meta.js.map +1 -0
  470. package/dist/md/types/config.d.ts +260 -0
  471. package/dist/md/types/config.d.ts.map +1 -0
  472. package/dist/md/types/config.js +156 -0
  473. package/dist/md/types/config.js.map +1 -0
  474. package/dist/md/types/document.d.ts +37 -0
  475. package/dist/md/types/document.d.ts.map +1 -0
  476. package/dist/md/types/document.js +2 -0
  477. package/dist/md/types/document.js.map +1 -0
  478. package/dist/md/types/validation.d.ts +107 -0
  479. package/dist/md/types/validation.d.ts.map +1 -0
  480. package/dist/md/types/validation.js +2 -0
  481. package/dist/md/types/validation.js.map +1 -0
  482. package/dist/md/utils/code-blocks.d.ts +136 -0
  483. package/dist/md/utils/code-blocks.d.ts.map +1 -0
  484. package/dist/md/utils/code-blocks.js +178 -0
  485. package/dist/md/utils/code-blocks.js.map +1 -0
  486. package/dist/md/utils/config.d.ts +10 -0
  487. package/dist/md/utils/config.d.ts.map +1 -0
  488. package/dist/md/utils/config.js +99 -0
  489. package/dist/md/utils/config.js.map +1 -0
  490. package/dist/md/utils/file-collector.d.ts +78 -0
  491. package/dist/md/utils/file-collector.d.ts.map +1 -0
  492. package/dist/md/utils/file-collector.js +100 -0
  493. package/dist/md/utils/file-collector.js.map +1 -0
  494. package/dist/md/utils/markdown.d.ts +18 -0
  495. package/dist/md/utils/markdown.d.ts.map +1 -0
  496. package/dist/md/utils/markdown.js +93 -0
  497. package/dist/md/utils/markdown.js.map +1 -0
  498. package/dist/md/utils/remark.d.ts +91 -0
  499. package/dist/md/utils/remark.d.ts.map +1 -0
  500. package/dist/md/utils/remark.js +125 -0
  501. package/dist/md/utils/remark.js.map +1 -0
  502. package/dist/md/utils/tokens.d.ts +9 -0
  503. package/dist/md/utils/tokens.d.ts.map +1 -0
  504. package/dist/md/utils/tokens.js +31 -0
  505. package/dist/md/utils/tokens.js.map +1 -0
  506. package/dist/md/validator/index.d.ts +40 -0
  507. package/dist/md/validator/index.d.ts.map +1 -0
  508. package/dist/md/validator/index.js +289 -0
  509. package/dist/md/validator/index.js.map +1 -0
  510. package/dist/parsers/details-jsdoc.d.ts +46 -0
  511. package/dist/parsers/details-jsdoc.d.ts.map +1 -0
  512. package/dist/parsers/details-jsdoc.js +262 -0
  513. package/dist/parsers/details-jsdoc.js.map +1 -0
  514. package/dist/parsers/details-zod.d.ts +22 -0
  515. package/dist/parsers/details-zod.d.ts.map +1 -0
  516. package/dist/parsers/details-zod.js +145 -0
  517. package/dist/parsers/details-zod.js.map +1 -0
  518. package/dist/parsers/drizzle-schema.d.ts +92 -0
  519. package/dist/parsers/drizzle-schema.d.ts.map +1 -0
  520. package/dist/parsers/drizzle-schema.js +376 -0
  521. package/dist/parsers/drizzle-schema.js.map +1 -0
  522. package/dist/parsers/feature-map-tags.d.ts +45 -0
  523. package/dist/parsers/feature-map-tags.d.ts.map +1 -0
  524. package/dist/parsers/feature-map-tags.js +292 -0
  525. package/dist/parsers/feature-map-tags.js.map +1 -0
  526. package/dist/parsers/feature-map-type-extraction.d.ts +62 -0
  527. package/dist/parsers/feature-map-type-extraction.d.ts.map +1 -0
  528. package/dist/parsers/feature-map-type-extraction.js +347 -0
  529. package/dist/parsers/feature-map-type-extraction.js.map +1 -0
  530. package/dist/parsers/feature-map-utils.d.ts +34 -0
  531. package/dist/parsers/feature-map-utils.d.ts.map +1 -0
  532. package/dist/parsers/feature-map-utils.js +101 -0
  533. package/dist/parsers/feature-map-utils.js.map +1 -0
  534. package/dist/parsers/jsdoc-common.d.ts +209 -0
  535. package/dist/parsers/jsdoc-common.d.ts.map +1 -0
  536. package/dist/parsers/jsdoc-common.js +655 -0
  537. package/dist/parsers/jsdoc-common.js.map +1 -0
  538. package/dist/parsers/jsdoc.d.ts +76 -0
  539. package/dist/parsers/jsdoc.d.ts.map +1 -0
  540. package/dist/parsers/jsdoc.js +238 -0
  541. package/dist/parsers/jsdoc.js.map +1 -0
  542. package/dist/parsers/screenshot-annotations.d.ts +96 -0
  543. package/dist/parsers/screenshot-annotations.d.ts.map +1 -0
  544. package/dist/parsers/screenshot-annotations.js +227 -0
  545. package/dist/parsers/screenshot-annotations.js.map +1 -0
  546. package/dist/parsers/test-annotations.d.ts +46 -0
  547. package/dist/parsers/test-annotations.d.ts.map +1 -0
  548. package/dist/parsers/test-annotations.js +393 -0
  549. package/dist/parsers/test-annotations.js.map +1 -0
  550. package/dist/parsers/test-categorization.d.ts +42 -0
  551. package/dist/parsers/test-categorization.d.ts.map +1 -0
  552. package/dist/parsers/test-categorization.js +182 -0
  553. package/dist/parsers/test-categorization.js.map +1 -0
  554. package/dist/parsers/zod-schema.d.ts +105 -0
  555. package/dist/parsers/zod-schema.d.ts.map +1 -0
  556. package/dist/parsers/zod-schema.js +270 -0
  557. package/dist/parsers/zod-schema.js.map +1 -0
  558. package/dist/utils/action-inference.d.ts +23 -0
  559. package/dist/utils/action-inference.d.ts.map +1 -0
  560. package/dist/utils/action-inference.js +36 -0
  561. package/dist/utils/action-inference.js.map +1 -0
  562. package/dist/utils/app-inference.d.ts +31 -0
  563. package/dist/utils/app-inference.d.ts.map +1 -0
  564. package/dist/utils/app-inference.js +41 -0
  565. package/dist/utils/app-inference.js.map +1 -0
  566. package/dist/utils/auto-infer.d.ts +93 -0
  567. package/dist/utils/auto-infer.d.ts.map +1 -0
  568. package/dist/utils/auto-infer.js +184 -0
  569. package/dist/utils/auto-infer.js.map +1 -0
  570. package/dist/utils/config.d.ts +709 -0
  571. package/dist/utils/config.d.ts.map +1 -0
  572. package/dist/utils/config.js +504 -0
  573. package/dist/utils/config.js.map +1 -0
  574. package/dist/utils/file.d.ts +46 -0
  575. package/dist/utils/file.d.ts.map +1 -0
  576. package/dist/utils/file.js +103 -0
  577. package/dist/utils/file.js.map +1 -0
  578. package/dist/utils/formatters.d.ts +111 -0
  579. package/dist/utils/formatters.d.ts.map +1 -0
  580. package/dist/utils/formatters.js +164 -0
  581. package/dist/utils/formatters.js.map +1 -0
  582. package/dist/utils/gh-config.d.ts +99 -0
  583. package/dist/utils/gh-config.d.ts.map +1 -0
  584. package/dist/utils/gh-config.js +247 -0
  585. package/dist/utils/gh-config.js.map +1 -0
  586. package/dist/utils/github.d.ts +98 -0
  587. package/dist/utils/github.d.ts.map +1 -0
  588. package/dist/utils/github.js +295 -0
  589. package/dist/utils/github.js.map +1 -0
  590. package/dist/utils/html.d.ts +107 -0
  591. package/dist/utils/html.d.ts.map +1 -0
  592. package/dist/utils/html.js +376 -0
  593. package/dist/utils/html.js.map +1 -0
  594. package/dist/utils/i18n.d.ts +40 -0
  595. package/dist/utils/i18n.d.ts.map +1 -0
  596. package/dist/utils/i18n.js +148 -0
  597. package/dist/utils/i18n.js.map +1 -0
  598. package/dist/utils/logger.d.ts +20 -0
  599. package/dist/utils/logger.d.ts.map +1 -0
  600. package/dist/utils/logger.js +49 -0
  601. package/dist/utils/logger.js.map +1 -0
  602. package/dist/utils/project-fields.d.ts +71 -0
  603. package/dist/utils/project-fields.d.ts.map +1 -0
  604. package/dist/utils/project-fields.js +318 -0
  605. package/dist/utils/project-fields.js.map +1 -0
  606. package/dist/utils/repo-pairs.d.ts +94 -0
  607. package/dist/utils/repo-pairs.d.ts.map +1 -0
  608. package/dist/utils/repo-pairs.js +196 -0
  609. package/dist/utils/repo-pairs.js.map +1 -0
  610. package/dist/utils/route-inference.d.ts +81 -0
  611. package/dist/utils/route-inference.d.ts.map +1 -0
  612. package/dist/utils/route-inference.js +137 -0
  613. package/dist/utils/route-inference.js.map +1 -0
  614. package/dist/utils/setup-check.d.ts +34 -0
  615. package/dist/utils/setup-check.d.ts.map +1 -0
  616. package/dist/utils/setup-check.js +136 -0
  617. package/dist/utils/setup-check.js.map +1 -0
  618. package/dist/utils/shirokumaignore.d.ts +55 -0
  619. package/dist/utils/shirokumaignore.d.ts.map +1 -0
  620. package/dist/utils/shirokumaignore.js +94 -0
  621. package/dist/utils/shirokumaignore.js.map +1 -0
  622. package/dist/utils/skills-repo.d.ts +353 -0
  623. package/dist/utils/skills-repo.d.ts.map +1 -0
  624. package/dist/utils/skills-repo.js +793 -0
  625. package/dist/utils/skills-repo.js.map +1 -0
  626. package/dist/utils/status-workflow.d.ts +54 -0
  627. package/dist/utils/status-workflow.d.ts.map +1 -0
  628. package/dist/utils/status-workflow.js +103 -0
  629. package/dist/utils/status-workflow.js.map +1 -0
  630. package/dist/validators/frontmatter.d.ts +41 -0
  631. package/dist/validators/frontmatter.d.ts.map +1 -0
  632. package/dist/validators/frontmatter.js +117 -0
  633. package/dist/validators/frontmatter.js.map +1 -0
  634. package/dist/validators/link-checker.d.ts +48 -0
  635. package/dist/validators/link-checker.d.ts.map +1 -0
  636. package/dist/validators/link-checker.js +108 -0
  637. package/dist/validators/link-checker.js.map +1 -0
  638. package/dist/validators/markdown-structure.d.ts +50 -0
  639. package/dist/validators/markdown-structure.d.ts.map +1 -0
  640. package/dist/validators/markdown-structure.js +253 -0
  641. package/dist/validators/markdown-structure.js.map +1 -0
  642. package/i18n/cli/en.json +155 -0
  643. package/i18n/cli/ja.json +155 -0
  644. package/i18n/discussion/en.json +191 -0
  645. package/i18n/discussion/ja.json +191 -0
  646. package/package.json +113 -0
  647. package/portal/app/api-tools/api-tools-client.tsx +411 -0
  648. package/portal/app/api-tools/api-tools-document.tsx +240 -0
  649. package/portal/app/api-tools/page.tsx +56 -0
  650. package/portal/app/api-tools/swagger-view.tsx +114 -0
  651. package/portal/app/apps/[appId]/[type]/[module]/[item]/item-tabs-client.tsx +71 -0
  652. package/portal/app/apps/[appId]/[type]/[module]/[item]/page.tsx +1422 -0
  653. package/portal/app/apps/[appId]/[type]/[module]/page.tsx +373 -0
  654. package/portal/app/apps/[appId]/feature-map/feature-map-app-document.tsx +298 -0
  655. package/portal/app/apps/[appId]/feature-map/page.tsx +224 -0
  656. package/portal/app/apps/[appId]/i18n/page.tsx +139 -0
  657. package/portal/app/apps/[appId]/test-cases/page.tsx +840 -0
  658. package/portal/app/apps/[appId]/tools/[tool]/page.tsx +351 -0
  659. package/portal/app/apps/[appId]/tools/api-tools-client.tsx +429 -0
  660. package/portal/app/apps/[appId]/tools/page.tsx +119 -0
  661. package/portal/app/db-schema/[db]/[table]/page.tsx +235 -0
  662. package/portal/app/db-schema/[db]/diagram/page.tsx +81 -0
  663. package/portal/app/db-schema/[db]/page.tsx +148 -0
  664. package/portal/app/db-schema/db-schema-document.tsx +100 -0
  665. package/portal/app/db-schema/diagram/client.tsx +211 -0
  666. package/portal/app/db-schema/diagram/page.tsx +20 -0
  667. package/portal/app/db-schema/page.tsx +145 -0
  668. package/portal/app/db-schema/table-detail-document.tsx +710 -0
  669. package/portal/app/db-schema/table-detail.tsx +747 -0
  670. package/portal/app/db-schema/table-list-document.tsx +224 -0
  671. package/portal/app/db-schema/table-list.tsx +247 -0
  672. package/portal/app/details/[type]/[module]/[item]/item-tabs-client.tsx +71 -0
  673. package/portal/app/details/[type]/[module]/[item]/page.tsx +1286 -0
  674. package/portal/app/details/[type]/[module]/page.tsx +884 -0
  675. package/portal/app/feature-map/feature-map-client.tsx +681 -0
  676. package/portal/app/feature-map/feature-map-document.tsx +313 -0
  677. package/portal/app/feature-map/page.tsx +438 -0
  678. package/portal/app/globals.css +205 -0
  679. package/portal/app/i18n/[...namespace]/page.tsx +190 -0
  680. package/portal/app/i18n/i18n-client.tsx +369 -0
  681. package/portal/app/i18n/page.tsx +339 -0
  682. package/portal/app/layout.tsx +37 -0
  683. package/portal/app/overview/page.tsx +65 -0
  684. package/portal/app/packages/[packageId]/page.tsx +201 -0
  685. package/portal/app/packages/page.tsx +148 -0
  686. package/portal/app/page.tsx +568 -0
  687. package/portal/app/test-cases/[file]/[line]/page.tsx +455 -0
  688. package/portal/app/test-cases/[file]/[line]/test-detail-document.tsx +335 -0
  689. package/portal/app/test-cases/[file]/page.tsx +323 -0
  690. package/portal/app/test-cases/[file]/test-file-document.tsx +335 -0
  691. package/portal/app/test-cases/page.tsx +546 -0
  692. package/portal/app/test-cases/test-cases-document.tsx +384 -0
  693. package/portal/components/code-block.tsx +57 -0
  694. package/portal/components/document/doc-params-table.tsx +71 -0
  695. package/portal/components/document/doc-section.tsx +133 -0
  696. package/portal/components/document/doc-table.tsx +119 -0
  697. package/portal/components/document/index.ts +9 -0
  698. package/portal/components/drawflow-er-diagram.tsx +607 -0
  699. package/portal/components/interactive-er-diagram.tsx +228 -0
  700. package/portal/components/layout/app-sidebar.tsx +490 -0
  701. package/portal/components/layout/er-sidebar.tsx +116 -0
  702. package/portal/components/layout/global-header.tsx +117 -0
  703. package/portal/components/layout/layout-content.tsx +48 -0
  704. package/portal/components/markdown-content.tsx +120 -0
  705. package/portal/components/mermaid-diagram.tsx +83 -0
  706. package/portal/components/reactflow-er-diagram.tsx +475 -0
  707. package/portal/components/search-dialog.tsx +268 -0
  708. package/portal/components/shared/coverage-score-bar.tsx +144 -0
  709. package/portal/components/swagger/endpoint-accordion.tsx +117 -0
  710. package/portal/components/swagger/index.ts +7 -0
  711. package/portal/components/swagger/method-badge.tsx +55 -0
  712. package/portal/components/swagger/params-table.tsx +78 -0
  713. package/portal/components/tabs-with-hash.tsx +43 -0
  714. package/portal/components/test/index.ts +2 -0
  715. package/portal/components/test/test-bdd-card.tsx +192 -0
  716. package/portal/components/test/test-matrix.tsx +242 -0
  717. package/portal/components/ui/accordion.tsx +66 -0
  718. package/portal/components/ui/badge.tsx +46 -0
  719. package/portal/components/ui/breadcrumb.tsx +109 -0
  720. package/portal/components/ui/button.tsx +62 -0
  721. package/portal/components/ui/card.tsx +92 -0
  722. package/portal/components/ui/collapsible.tsx +33 -0
  723. package/portal/components/ui/dialog.tsx +118 -0
  724. package/portal/components/ui/progress.tsx +28 -0
  725. package/portal/components/ui/scroll-area.tsx +58 -0
  726. package/portal/components/ui/sheet.tsx +139 -0
  727. package/portal/components/ui/table.tsx +116 -0
  728. package/portal/components/ui/tabs.tsx +66 -0
  729. package/portal/components.json +21 -0
  730. package/portal/lib/constants/test-categories.ts +186 -0
  731. package/portal/lib/data-loader.ts +1181 -0
  732. package/portal/lib/db-schema-utils.ts +182 -0
  733. package/portal/lib/format.ts +43 -0
  734. package/portal/lib/hooks/use-hash-tab.ts +144 -0
  735. package/portal/lib/path-utils.ts +25 -0
  736. package/portal/lib/search-index-generator.ts +214 -0
  737. package/portal/lib/search.ts +126 -0
  738. package/portal/lib/sidebar-context.tsx +111 -0
  739. package/portal/lib/types.ts +740 -0
  740. package/portal/lib/utils.ts +6 -0
  741. package/portal/next.config.ts +21 -0
  742. package/portal/package.json +45 -0
  743. package/portal/postcss.config.mjs +8 -0
  744. package/portal/tsconfig.json +41 -0
  745. package/portal/types/drawflow.d.ts +80 -0
  746. package/templates/README.md +73 -0
  747. package/templates/coverage.html +367 -0
  748. package/templates/dark-theme.css +443 -0
  749. package/templates/discussion/adr.yml.hbs +65 -0
  750. package/templates/discussion/handovers.yml.hbs +57 -0
  751. package/templates/discussion/knowledge.yml.hbs +60 -0
  752. package/templates/discussion/reports.yml.hbs +68 -0
  753. package/templates/discussion/research.yml.hbs +61 -0
@@ -0,0 +1,1243 @@
1
+ /**
2
+ * session command - Unified session management
3
+ *
4
+ * Subcommands:
5
+ * - start: Fetch session context (latest handover + active issues with project fields)
6
+ * - end: Save handover discussion + update issue statuses
7
+ * - check: Detect inconsistencies between Issue state and Project Status
8
+ *
9
+ * Design:
10
+ * - Combines multiple API calls into a single command
11
+ * - Excludes Done/Released items by default
12
+ * - Used internally by starting-session / ending-session skills
13
+ */
14
+ import { spawnSync } from "node:child_process";
15
+ import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { createLogger } from "../utils/logger.js";
18
+ import { runGhCommand, runGraphQL, getRepoInfo, validateTitle, validateBody, isIssueNumber, parseIssueNumber, } from "../utils/github.js";
19
+ import { loadGhConfig, getDefaultCategory, getDefaultLimit, getMetricsConfig, } from "../utils/gh-config.js";
20
+ import { formatOutput, toTableJson } from "../utils/formatters.js";
21
+ import { fetchOpenPRs, parseLinkedIssues } from "./issues-pr.js";
22
+ import { getIssueId, } from "./issues.js";
23
+ import { getProjectFields, autoSetTimestamps, updateTextField, updateSelectField, generateTimestamp, } from "../utils/project-fields.js";
24
+ import { WORK_STARTED_STATUSES } from "../utils/status-workflow.js";
25
+ import { getProjectId, fetchWorkflows, RECOMMENDED_WORKFLOWS, } from "./projects.js";
26
+ import { validateGitHubSetup, printSetupCheckResults, } from "../utils/setup-check.js";
27
+ /** Statuses to exclude from session start results */
28
+ export const DEFAULT_EXCLUDE_STATUSES = ["Done", "Released"];
29
+ /**
30
+ * Classify inconsistencies from a list of issues with project data.
31
+ * Pure function - no API calls, fully testable.
32
+ *
33
+ * Detects two types of inconsistencies:
34
+ * 1. OPEN issue with terminal status (Done/Released) → should be closed (error)
35
+ * 2. CLOSED issue with work-started status (In Progress/Review/etc.) → status should be Done (error)
36
+ * 3. CLOSED issue with pre-work status (Backlog/Icebox/etc.) → may be intentional (info)
37
+ */
38
+ export function classifyInconsistencies(issues, doneStatuses = DEFAULT_EXCLUDE_STATUSES) {
39
+ const inconsistencies = [];
40
+ for (const issue of issues) {
41
+ const status = issue.status ?? "";
42
+ const isDoneStatus = doneStatuses.includes(status);
43
+ // OPEN issue with Done/Released status
44
+ if (issue.state === "OPEN" && isDoneStatus) {
45
+ inconsistencies.push({
46
+ number: issue.number,
47
+ title: issue.title,
48
+ url: issue.url,
49
+ issueState: issue.state,
50
+ projectStatus: issue.status,
51
+ severity: "error",
52
+ description: `Issue is OPEN but Project Status is "${issue.status}"`,
53
+ });
54
+ }
55
+ // CLOSED issue with non-terminal status
56
+ if (issue.state === "CLOSED" && status !== "" && !isDoneStatus) {
57
+ const isWorkStarted = WORK_STARTED_STATUSES.includes(status);
58
+ inconsistencies.push({
59
+ number: issue.number,
60
+ title: issue.title,
61
+ url: issue.url,
62
+ issueState: issue.state,
63
+ projectStatus: issue.status,
64
+ severity: isWorkStarted ? "error" : "info",
65
+ description: `Issue is CLOSED but Project Status is "${issue.status}" (expected Done/Released)`,
66
+ });
67
+ }
68
+ }
69
+ return inconsistencies;
70
+ }
71
+ // =============================================================================
72
+ // GraphQL Queries - Discussions (Handovers)
73
+ // =============================================================================
74
+ /** Fetch discussion categories to resolve Handovers category ID */
75
+ const GRAPHQL_QUERY_CATEGORIES = `
76
+ query($owner: String!, $name: String!) {
77
+ repository(owner: $owner, name: $name) {
78
+ discussionCategories(first: 20) {
79
+ nodes {
80
+ id
81
+ name
82
+ }
83
+ }
84
+ }
85
+ }
86
+ `;
87
+ /** Fetch recent discussions from a category (for handover filtering) */
88
+ const GRAPHQL_QUERY_RECENT_HANDOVERS = `
89
+ query($owner: String!, $name: String!, $categoryId: ID) {
90
+ repository(owner: $owner, name: $name) {
91
+ discussions(first: 10, categoryId: $categoryId, orderBy: {field: CREATED_AT, direction: DESC}) {
92
+ nodes {
93
+ number
94
+ title
95
+ body
96
+ url
97
+ createdAt
98
+ author { login }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ `;
104
+ /** Get repository ID for mutations */
105
+ const GRAPHQL_QUERY_REPO_ID = `
106
+ query($owner: String!, $name: String!) {
107
+ repository(owner: $owner, name: $name) {
108
+ id
109
+ }
110
+ }
111
+ `;
112
+ /** Create a discussion */
113
+ const GRAPHQL_MUTATION_CREATE_DISCUSSION = `
114
+ mutation($repositoryId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
115
+ createDiscussion(input: {repositoryId: $repositoryId, categoryId: $categoryId, title: $title, body: $body}) {
116
+ discussion {
117
+ id
118
+ number
119
+ url
120
+ title
121
+ }
122
+ }
123
+ }
124
+ `;
125
+ // =============================================================================
126
+ // GraphQL Queries - Issues with Projects
127
+ // =============================================================================
128
+ /** Fetch issues with project field data */
129
+ const GRAPHQL_QUERY_ISSUES_WITH_PROJECTS = `
130
+ query($owner: String!, $name: String!, $first: Int!, $cursor: String, $states: [IssueState!]) {
131
+ repository(owner: $owner, name: $name) {
132
+ issues(first: $first, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}, states: $states) {
133
+ pageInfo { hasNextPage endCursor }
134
+ nodes {
135
+ number
136
+ title
137
+ url
138
+ state
139
+ closedAt
140
+ assignees(first: 5) {
141
+ nodes { login }
142
+ }
143
+ labels(first: 10) {
144
+ nodes { name }
145
+ }
146
+ projectItems(first: 5) {
147
+ nodes {
148
+ id
149
+ project { id title }
150
+ status: fieldValueByName(name: "Status") {
151
+ ... on ProjectV2ItemFieldSingleSelectValue { name }
152
+ }
153
+ priority: fieldValueByName(name: "Priority") {
154
+ ... on ProjectV2ItemFieldSingleSelectValue { name }
155
+ }
156
+ type: fieldValueByName(name: "Type") {
157
+ ... on ProjectV2ItemFieldSingleSelectValue { name }
158
+ }
159
+ itemType: fieldValueByName(name: "Item Type") {
160
+ ... on ProjectV2ItemFieldSingleSelectValue { name }
161
+ }
162
+ size: fieldValueByName(name: "Size") {
163
+ ... on ProjectV2ItemFieldSingleSelectValue { name }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+ `;
172
+ // =============================================================================
173
+ // Helper: Get current GitHub username
174
+ // =============================================================================
175
+ function getCurrentUsername() {
176
+ try {
177
+ const result = spawnSync("gh", ["api", "user", "-q", ".login"], {
178
+ encoding: "utf-8",
179
+ timeout: 10000,
180
+ });
181
+ if (result.status === 0 && result.stdout.trim()) {
182
+ return result.stdout.trim();
183
+ }
184
+ return null;
185
+ }
186
+ catch {
187
+ return null;
188
+ }
189
+ }
190
+ // =============================================================================
191
+ // Helper: Resolve Handovers category ID
192
+ // =============================================================================
193
+ function getHandoversCategoryId(owner, repo, categoryName) {
194
+ const result = runGraphQL(GRAPHQL_QUERY_CATEGORIES, {
195
+ owner,
196
+ name: repo,
197
+ });
198
+ if (!result.success)
199
+ return null;
200
+ const nodes = result.data?.data?.repository?.discussionCategories?.nodes ?? [];
201
+ const category = nodes.find((n) => n?.name === categoryName);
202
+ return category?.id ?? null;
203
+ }
204
+ // =============================================================================
205
+ // Helper: Get repository GraphQL ID
206
+ // =============================================================================
207
+ function getRepoId(owner, repo) {
208
+ const result = runGraphQL(GRAPHQL_QUERY_REPO_ID, {
209
+ owner,
210
+ name: repo,
211
+ });
212
+ if (!result.success)
213
+ return null;
214
+ return result.data?.data?.repository?.id ?? null;
215
+ }
216
+ /**
217
+ * Fetch handovers from the Handovers category, optionally filtered by author.
218
+ *
219
+ * @param authorFilter - Username to filter by, or null for all
220
+ * @returns The most recent matching handover, or null
221
+ */
222
+ function fetchLatestHandover(owner, repo, categoryId, authorFilter) {
223
+ const result = runGraphQL(GRAPHQL_QUERY_RECENT_HANDOVERS, {
224
+ owner,
225
+ name: repo,
226
+ categoryId,
227
+ });
228
+ if (!result.success)
229
+ return null;
230
+ const nodes = result.data?.data?.repository?.discussions?.nodes ?? [];
231
+ // Filter by author if specified
232
+ const filtered = authorFilter
233
+ ? nodes.filter((n) => n?.author?.login === authorFilter)
234
+ : nodes;
235
+ const first = filtered[0];
236
+ if (!first?.number)
237
+ return null;
238
+ return {
239
+ number: first.number,
240
+ title: first.title ?? "",
241
+ body: first.body ?? "",
242
+ url: first.url ?? "",
243
+ author: first.author?.login ?? null,
244
+ };
245
+ }
246
+ // =============================================================================
247
+ // Helper: Fetch all recent handovers (for --team mode)
248
+ // =============================================================================
249
+ /**
250
+ * Fetch all recent handovers and group by author (latest per author).
251
+ */
252
+ function fetchTeamHandovers(owner, repo, categoryId) {
253
+ const result = runGraphQL(GRAPHQL_QUERY_RECENT_HANDOVERS, {
254
+ owner,
255
+ name: repo,
256
+ categoryId,
257
+ });
258
+ if (!result.success)
259
+ return [];
260
+ const nodes = result.data?.data?.repository?.discussions?.nodes ?? [];
261
+ // Group by author: keep only the latest per author
262
+ const byAuthor = new Map();
263
+ for (const node of nodes) {
264
+ if (!node?.number)
265
+ continue;
266
+ const author = node.author?.login ?? "unknown";
267
+ if (!byAuthor.has(author)) {
268
+ byAuthor.set(author, {
269
+ number: node.number,
270
+ title: node.title ?? "",
271
+ body: node.body ?? "",
272
+ url: node.url ?? "",
273
+ author,
274
+ });
275
+ }
276
+ }
277
+ return Array.from(byAuthor.values());
278
+ }
279
+ function fetchActiveIssues(owner, repo, limit, states = ["OPEN"]) {
280
+ const allIssues = [];
281
+ let cursor = null;
282
+ while (allIssues.length < limit) {
283
+ const fetchCount = Math.min(100, limit - allIssues.length);
284
+ const result = runGraphQL(GRAPHQL_QUERY_ISSUES_WITH_PROJECTS, {
285
+ owner,
286
+ name: repo,
287
+ first: fetchCount,
288
+ cursor: cursor,
289
+ states,
290
+ });
291
+ if (!result.success || !result.data?.data?.repository?.issues)
292
+ break;
293
+ const issuesData = result.data.data.repository.issues;
294
+ const nodes = issuesData.nodes ?? [];
295
+ for (const node of nodes) {
296
+ if (!node?.number)
297
+ continue;
298
+ const projectItems = node.projectItems?.nodes ?? [];
299
+ const matchingItem = projectItems.find((p) => p?.project?.title === repo) ?? projectItems[0];
300
+ const labelNodes = node.labels?.nodes ?? [];
301
+ const issueLabels = labelNodes.map((l) => l?.name ?? "").filter(Boolean);
302
+ const assigneeNodes = node.assignees?.nodes ?? [];
303
+ const issueAssignees = assigneeNodes.map((a) => a?.login ?? "").filter(Boolean);
304
+ allIssues.push({
305
+ number: node.number,
306
+ title: node.title ?? "",
307
+ url: node.url ?? "",
308
+ state: node.state ?? "OPEN",
309
+ closedAt: node.closedAt ?? null,
310
+ labels: issueLabels,
311
+ assignees: issueAssignees,
312
+ status: matchingItem?.status?.name ?? null,
313
+ priority: matchingItem?.priority?.name ?? null,
314
+ type: matchingItem?.type?.name ?? matchingItem?.itemType?.name ?? null,
315
+ size: matchingItem?.size?.name ?? null,
316
+ projectItemId: matchingItem?.id ?? null,
317
+ projectId: matchingItem?.project?.id ?? null,
318
+ });
319
+ }
320
+ const pageInfo = issuesData.pageInfo ?? {};
321
+ if (!pageInfo.hasNextPage)
322
+ break;
323
+ cursor = pageInfo.endCursor ?? null;
324
+ }
325
+ return allIssues;
326
+ }
327
+ // =============================================================================
328
+ // Helper: Update issue status in project
329
+ // =============================================================================
330
+ function updateIssueStatus(projectId, itemId, statusValue, projectFields, logger) {
331
+ const statusField = projectFields["Status"];
332
+ if (!statusField) {
333
+ logger.warn("Status field not found in project");
334
+ return false;
335
+ }
336
+ const optionId = statusField.options[statusValue];
337
+ if (!optionId) {
338
+ const available = Object.keys(statusField.options).sort().join(", ");
339
+ logger.error(`Invalid Status value '${statusValue}'`);
340
+ logger.info(` Available options: ${available}`);
341
+ return false;
342
+ }
343
+ return updateSelectField(projectId, itemId, statusField.id, optionId, logger);
344
+ }
345
+ // =============================================================================
346
+ // PR merge detection (#220)
347
+ // =============================================================================
348
+ /**
349
+ * Issue に紐づくマージ済み PR を検出する。
350
+ *
351
+ * 検出戦略:
352
+ * 1. ブランチ名検索: 現在のブランチに対応する merged PR を探す
353
+ * 2. Issue リンク逆引き: マージ済み PR の body から "Closes #N" 等を検索
354
+ *
355
+ * @returns マージ済み PR 番号。見つからない場合は null
356
+ */
357
+ export function findMergedPrForIssue(owner, repo, issueNumber, logger) {
358
+ // Strategy 1: ブランチ名ベースの検出
359
+ // 現在のブランチに紐づくマージ済み PR を探す
360
+ try {
361
+ const branchResult = spawnSync("git", ["branch", "--show-current"], {
362
+ encoding: "utf-8",
363
+ timeout: 5000,
364
+ });
365
+ const currentBranch = branchResult.stdout?.trim();
366
+ const baseBranches = ["main", "master", "develop"];
367
+ if (currentBranch && !baseBranches.includes(currentBranch)) {
368
+ const prResult = runGhCommand([
369
+ "pr", "list",
370
+ "--head", currentBranch,
371
+ "--state", "merged",
372
+ "--json", "number",
373
+ "--repo", `${owner}/${repo}`,
374
+ "-L", "1",
375
+ ], { silent: true });
376
+ if (prResult.success && Array.isArray(prResult.data) && prResult.data.length > 0) {
377
+ const prNum = prResult.data[0].number;
378
+ logger.debug(`Merged PR #${prNum} found for branch ${currentBranch}`);
379
+ return prNum;
380
+ }
381
+ }
382
+ }
383
+ catch {
384
+ // git コマンド失敗時は次の戦略へ
385
+ }
386
+ // Strategy 2: Issue リンク逆引き
387
+ // 最近マージされた PR の body を検索して、対象 Issue への参照を探す
388
+ const searchResult = runGhCommand([
389
+ "pr", "list",
390
+ "--state", "merged",
391
+ "--search", `#${issueNumber}`,
392
+ "--json", "number,body",
393
+ "--repo", `${owner}/${repo}`,
394
+ "-L", "10",
395
+ ], { silent: true });
396
+ if (searchResult.success && Array.isArray(searchResult.data)) {
397
+ for (const pr of searchResult.data) {
398
+ const linked = parseLinkedIssues(pr.body);
399
+ if (linked.includes(issueNumber)) {
400
+ logger.debug(`Merged PR #${pr.number} links to issue #${issueNumber}`);
401
+ return pr.number;
402
+ }
403
+ }
404
+ }
405
+ return null;
406
+ }
407
+ // =============================================================================
408
+ // Git state helpers
409
+ // =============================================================================
410
+ /**
411
+ * Get current git repository state (branch + uncommitted changes).
412
+ * Returns safe defaults if git commands fail.
413
+ */
414
+ export function getGitState() {
415
+ let currentBranch = null;
416
+ let uncommittedChanges = [];
417
+ try {
418
+ const branchResult = spawnSync("git", ["branch", "--show-current"], {
419
+ encoding: "utf-8",
420
+ timeout: 5000,
421
+ });
422
+ if (branchResult.status === 0 && branchResult.stdout.trim()) {
423
+ currentBranch = branchResult.stdout.trim();
424
+ }
425
+ }
426
+ catch {
427
+ // Git not available or not in a repo - return defaults
428
+ }
429
+ try {
430
+ const statusResult = spawnSync("git", ["status", "--short"], {
431
+ encoding: "utf-8",
432
+ timeout: 5000,
433
+ });
434
+ if (statusResult.status === 0 && statusResult.stdout.trim()) {
435
+ uncommittedChanges = statusResult.stdout
436
+ .trim()
437
+ .split("\n")
438
+ .filter((line) => line.length > 0);
439
+ }
440
+ }
441
+ catch {
442
+ // Git not available or not in a repo - return defaults
443
+ }
444
+ return {
445
+ currentBranch,
446
+ uncommittedChanges,
447
+ hasUncommittedChanges: uncommittedChanges.length > 0,
448
+ };
449
+ }
450
+ // =============================================================================
451
+ // Session backup helpers (#251)
452
+ // =============================================================================
453
+ const SESSIONS_DIR = ".claude/sessions";
454
+ const BACKUP_SUFFIX = "-precompact-backup.md";
455
+ /**
456
+ * Check for PreCompact session backups in .claude/sessions/.
457
+ * Returns backups sorted by timestamp (most recent first).
458
+ */
459
+ export function getSessionBackups() {
460
+ if (!existsSync(SESSIONS_DIR))
461
+ return [];
462
+ try {
463
+ const files = readdirSync(SESSIONS_DIR)
464
+ .filter((f) => f.endsWith(BACKUP_SUFFIX))
465
+ .sort()
466
+ .reverse();
467
+ return files.map((f) => ({
468
+ filename: f,
469
+ timestamp: f.replace(BACKUP_SUFFIX, ""),
470
+ content: readFileSync(join(SESSIONS_DIR, f), "utf-8"),
471
+ }));
472
+ }
473
+ catch {
474
+ return [];
475
+ }
476
+ }
477
+ /**
478
+ * Remove all PreCompact session backups from .claude/sessions/.
479
+ * Called after a successful handover to prevent stale backups.
480
+ *
481
+ * @returns Number of files cleaned up
482
+ */
483
+ export function cleanupSessionBackups() {
484
+ if (!existsSync(SESSIONS_DIR))
485
+ return 0;
486
+ try {
487
+ const files = readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(BACKUP_SUFFIX));
488
+ for (const f of files) {
489
+ unlinkSync(join(SESSIONS_DIR, f));
490
+ }
491
+ return files.length;
492
+ }
493
+ catch {
494
+ return 0;
495
+ }
496
+ }
497
+ // =============================================================================
498
+ // session start
499
+ // =============================================================================
500
+ async function cmdStart(options, logger) {
501
+ const config = loadGhConfig();
502
+ const repoInfo = getRepoInfo();
503
+ if (!repoInfo) {
504
+ logger.error("Could not determine repository");
505
+ return 1;
506
+ }
507
+ const { owner: repoOwner, name: repo } = repoInfo;
508
+ const owner = options.owner || repoOwner;
509
+ const categoryName = getDefaultCategory(config);
510
+ const limit = getDefaultLimit(config);
511
+ logger.debug(`Repository: ${owner}/${repo}`);
512
+ logger.debug(`Handover category: ${categoryName}`);
513
+ // Team mode: delegate to cmdStartTeam
514
+ if (options.team) {
515
+ return cmdStartTeam(owner, repo, categoryName, limit, options, logger);
516
+ }
517
+ // 1. Resolve author filter for handovers
518
+ let authorFilter = null;
519
+ if (options.all) {
520
+ authorFilter = null;
521
+ }
522
+ else if (options.user) {
523
+ authorFilter = options.user;
524
+ }
525
+ else {
526
+ // Default: filter by current GitHub user
527
+ authorFilter = getCurrentUsername();
528
+ if (authorFilter) {
529
+ logger.debug(`Filtering handovers by author: ${authorFilter}`);
530
+ }
531
+ }
532
+ // 2. Fetch latest handover (filtered)
533
+ let lastHandover = null;
534
+ const categoryId = getHandoversCategoryId(owner, repo, categoryName);
535
+ if (categoryId) {
536
+ lastHandover = fetchLatestHandover(owner, repo, categoryId, authorFilter);
537
+ if (lastHandover) {
538
+ logger.debug(`Found handover #${lastHandover.number} by ${lastHandover.author ?? "unknown"}`);
539
+ }
540
+ else {
541
+ logger.debug("No handover found");
542
+ }
543
+ }
544
+ else {
545
+ logger.debug(`Category '${categoryName}' not found, skipping handover`);
546
+ }
547
+ // 2. Fetch active issues with project fields
548
+ const allIssues = fetchActiveIssues(owner, repo, limit);
549
+ // Filter out Done/Released
550
+ const activeIssues = allIssues.filter((i) => !DEFAULT_EXCLUDE_STATUSES.includes(i.status ?? ""));
551
+ logger.debug(`Issues: ${allIssues.length} total, ${activeIssues.length} active`);
552
+ // 3. Fetch open PRs
553
+ const openPRs = fetchOpenPRs(owner, repo);
554
+ logger.debug(`Open PRs: ${openPRs.length}`);
555
+ // 4. Get git state
556
+ const git = getGitState();
557
+ logger.debug(`Branch: ${git.currentBranch ?? "(detached)"}`);
558
+ logger.debug(`Uncommitted changes: ${git.uncommittedChanges.length}`);
559
+ // 4b. Workflow warnings
560
+ const warnings = [];
561
+ const protectedBranches = ["main", "develop"];
562
+ if (git.currentBranch && protectedBranches.includes(git.currentBranch)) {
563
+ warnings.push(`On protected branch "${git.currentBranch}". Create a feature branch before committing.`);
564
+ logger.warn(`Warning: On protected branch "${git.currentBranch}". Create a feature branch before committing.`);
565
+ }
566
+ if (git.hasUncommittedChanges) {
567
+ warnings.push(`${git.uncommittedChanges.length} uncommitted change(s) detected.`);
568
+ }
569
+ // 5. Check for session backups (#251)
570
+ const backups = getSessionBackups();
571
+ if (backups.length > 0) {
572
+ warnings.push(`${backups.length} PreCompact backup(s) found in .claude/sessions/. A previous session may have been interrupted.`);
573
+ logger.warn(`Found ${backups.length} PreCompact backup(s) from interrupted session(s)`);
574
+ }
575
+ // 6. Build output (TableJSON for lists, plain object for single items)
576
+ const issueColumns = ["number", "title", "status", "priority", "type", "size", "assignees", "labels"];
577
+ const prColumns = ["number", "title", "review_decision", "review_thread_count", "review_count"];
578
+ const output = {
579
+ repository: `${owner}/${repo}`,
580
+ warnings: warnings.length > 0 ? warnings : undefined,
581
+ git,
582
+ lastHandover: lastHandover
583
+ ? {
584
+ number: lastHandover.number,
585
+ title: lastHandover.title,
586
+ body: lastHandover.body,
587
+ url: lastHandover.url,
588
+ }
589
+ : null,
590
+ backups: backups.length > 0
591
+ ? {
592
+ count: backups.length,
593
+ latest: {
594
+ filename: backups[0].filename,
595
+ timestamp: backups[0].timestamp,
596
+ content: backups[0].content,
597
+ },
598
+ }
599
+ : undefined,
600
+ issues: toTableJson(activeIssues.map((i) => ({
601
+ number: i.number,
602
+ title: i.title,
603
+ status: i.status,
604
+ priority: i.priority,
605
+ type: i.type,
606
+ size: i.size,
607
+ assignees: i.assignees,
608
+ labels: i.labels,
609
+ })), issueColumns),
610
+ total_issues: activeIssues.length,
611
+ openPRs: toTableJson(openPRs.map((pr) => ({
612
+ number: pr.number,
613
+ title: pr.title,
614
+ review_decision: pr.reviewDecision,
615
+ review_thread_count: pr.reviewThreadCount,
616
+ review_count: pr.reviewCount,
617
+ })), prColumns),
618
+ };
619
+ const outputFormat = options.format ?? "json";
620
+ const formatted = formatOutput(output, outputFormat);
621
+ console.log(formatted);
622
+ return 0;
623
+ }
624
+ // =============================================================================
625
+ // session start --team (team dashboard)
626
+ // =============================================================================
627
+ /** Group issues by assignee for team view */
628
+ export function groupIssuesByAssignee(issues) {
629
+ const groups = {};
630
+ for (const issue of issues) {
631
+ if (issue.assignees.length === 0) {
632
+ const key = "unassigned";
633
+ if (!groups[key])
634
+ groups[key] = [];
635
+ groups[key].push(issue);
636
+ }
637
+ else {
638
+ for (const assignee of issue.assignees) {
639
+ if (!groups[assignee])
640
+ groups[assignee] = [];
641
+ groups[assignee].push(issue);
642
+ }
643
+ }
644
+ }
645
+ return groups;
646
+ }
647
+ /**
648
+ * Team dashboard mode for session start.
649
+ * Shows all members' handovers and issues grouped by assignee.
650
+ */
651
+ async function cmdStartTeam(owner, repo, categoryName, limit, options, logger) {
652
+ logger.debug("Team dashboard mode");
653
+ // 1. Fetch all team handovers (latest per author)
654
+ const categoryId = getHandoversCategoryId(owner, repo, categoryName);
655
+ let teamHandovers = [];
656
+ if (categoryId) {
657
+ teamHandovers = fetchTeamHandovers(owner, repo, categoryId);
658
+ logger.debug(`Team handovers: ${teamHandovers.length} members`);
659
+ }
660
+ else {
661
+ logger.debug(`Category '${categoryName}' not found, skipping handovers`);
662
+ }
663
+ // 2. Fetch active issues with project fields
664
+ const allIssues = fetchActiveIssues(owner, repo, limit);
665
+ const activeIssues = allIssues.filter((i) => !DEFAULT_EXCLUDE_STATUSES.includes(i.status ?? ""));
666
+ // 3. Group issues by assignee
667
+ const issuesByAssignee = groupIssuesByAssignee(activeIssues);
668
+ // 4. Fetch open PRs
669
+ const openPRs = fetchOpenPRs(owner, repo);
670
+ // 5. Build team dashboard output
671
+ const issueColumns = ["number", "title", "status", "priority", "type", "size"];
672
+ const memberDashboards = {};
673
+ // Collect all member names from both handovers and issues
674
+ const allMembers = new Set();
675
+ for (const h of teamHandovers) {
676
+ if (h.author)
677
+ allMembers.add(h.author);
678
+ }
679
+ for (const assignee of Object.keys(issuesByAssignee)) {
680
+ allMembers.add(assignee);
681
+ }
682
+ for (const member of allMembers) {
683
+ const handover = teamHandovers.find((h) => h.author === member);
684
+ const memberIssues = issuesByAssignee[member] ?? [];
685
+ memberDashboards[member] = {
686
+ handover: handover
687
+ ? {
688
+ number: handover.number,
689
+ title: handover.title,
690
+ body: handover.body,
691
+ url: handover.url,
692
+ }
693
+ : null,
694
+ issues: toTableJson(memberIssues.map((i) => ({
695
+ number: i.number,
696
+ title: i.title,
697
+ status: i.status,
698
+ priority: i.priority,
699
+ type: i.type,
700
+ size: i.size,
701
+ })), issueColumns),
702
+ issue_count: memberIssues.length,
703
+ };
704
+ }
705
+ const prColumns = ["number", "title", "review_decision", "review_thread_count", "review_count"];
706
+ const output = {
707
+ repository: `${owner}/${repo}`,
708
+ mode: "team",
709
+ members: memberDashboards,
710
+ total_members: allMembers.size,
711
+ total_issues: activeIssues.length,
712
+ openPRs: toTableJson(openPRs.map((pr) => ({
713
+ number: pr.number,
714
+ title: pr.title,
715
+ review_decision: pr.reviewDecision,
716
+ review_thread_count: pr.reviewThreadCount,
717
+ review_count: pr.reviewCount,
718
+ })), prColumns),
719
+ };
720
+ const outputFormat = options.format ?? "json";
721
+ const formatted = formatOutput(output, outputFormat);
722
+ console.log(formatted);
723
+ return 0;
724
+ }
725
+ // =============================================================================
726
+ // session end
727
+ // =============================================================================
728
+ async function cmdEnd(options, logger) {
729
+ const config = loadGhConfig();
730
+ const repoInfo = getRepoInfo();
731
+ if (!repoInfo) {
732
+ logger.error("Could not determine repository");
733
+ return 1;
734
+ }
735
+ const { owner: repoOwner, name: repo } = repoInfo;
736
+ const owner = options.owner || repoOwner;
737
+ // Check for uncommitted changes and warn
738
+ const git = getGitState();
739
+ const endWarnings = [];
740
+ if (git.hasUncommittedChanges) {
741
+ endWarnings.push(`${git.uncommittedChanges.length} uncommitted change(s) detected. Consider committing or stashing before ending session.`);
742
+ logger.warn(`Warning: ${git.uncommittedChanges.length} uncommitted change(s) detected. Consider committing or stashing.`);
743
+ }
744
+ // Validate required inputs
745
+ if (!options.title) {
746
+ logger.error("--title is required for session end");
747
+ return 1;
748
+ }
749
+ // Auto-insert [username] into handover title if not already present (#196)
750
+ // Format: "YYYY-MM-DD - summary" → "YYYY-MM-DD [username] - summary"
751
+ let title = options.title;
752
+ if (/^\d{4}-\d{2}-\d{2} - /.test(title) && !title.includes("[")) {
753
+ const username = getCurrentUsername();
754
+ if (username) {
755
+ title = title.replace(/^(\d{4}-\d{2}-\d{2}) - /, `$1 [${username}] - `);
756
+ logger.debug(`Title updated with username: ${title}`);
757
+ }
758
+ }
759
+ const titleError = validateTitle(title);
760
+ if (titleError) {
761
+ logger.error(titleError);
762
+ return 1;
763
+ }
764
+ const bodyError = validateBody(options.body);
765
+ if (bodyError) {
766
+ logger.error(bodyError);
767
+ return 1;
768
+ }
769
+ const updatedIssues = [];
770
+ // 1. Update issue statuses (--done, --review)
771
+ const doneNumbers = (options.done ?? []).filter(isIssueNumber).map(parseIssueNumber);
772
+ const reviewNumbers = (options.review ?? []).filter(isIssueNumber).map(parseIssueNumber);
773
+ if (doneNumbers.length > 0 || reviewNumbers.length > 0) {
774
+ // Fetch issues to get project item IDs
775
+ const limit = getDefaultLimit(config);
776
+ const issues = fetchActiveIssues(owner, repo, limit);
777
+ // Get project fields once
778
+ const projectIds = new Set();
779
+ for (const issue of issues) {
780
+ if (issue.projectId)
781
+ projectIds.add(issue.projectId);
782
+ }
783
+ // Cache project fields per project
784
+ const fieldsCache = {};
785
+ for (const pid of projectIds) {
786
+ fieldsCache[pid] = getProjectFields(pid);
787
+ }
788
+ // Update Done issues
789
+ for (const num of doneNumbers) {
790
+ const issue = issues.find((i) => i.number === num);
791
+ if (!issue?.projectItemId || !issue?.projectId) {
792
+ logger.warn(`Issue #${num}: not found in project, skipping status update`);
793
+ continue;
794
+ }
795
+ const fields = fieldsCache[issue.projectId] ?? {};
796
+ if (updateIssueStatus(issue.projectId, issue.projectItemId, "Done", fields, logger)) {
797
+ updatedIssues.push({ number: num, status: "Done" });
798
+ logger.success(`Issue #${num} → Done`);
799
+ // Auto-set timestamp (#342) - reuse cached fields
800
+ autoSetTimestamps(issue.projectId, issue.projectItemId, "Done", fields, logger);
801
+ }
802
+ }
803
+ // Update Review issues (auto-promote to Done if PR is already merged, #220)
804
+ for (const num of reviewNumbers) {
805
+ const issue = issues.find((i) => i.number === num);
806
+ if (!issue?.projectItemId || !issue?.projectId) {
807
+ logger.warn(`Issue #${num}: not found in project, skipping status update`);
808
+ continue;
809
+ }
810
+ const fields = fieldsCache[issue.projectId] ?? {};
811
+ // Check if a merged PR exists for this issue (#220)
812
+ const mergedPr = findMergedPrForIssue(owner, repo, num, logger);
813
+ const targetStatus = mergedPr ? "Done" : "Review";
814
+ if (updateIssueStatus(issue.projectId, issue.projectItemId, targetStatus, fields, logger)) {
815
+ updatedIssues.push({ number: num, status: targetStatus });
816
+ if (mergedPr) {
817
+ logger.success(`Issue #${num} → Done (PR #${mergedPr} merged)`);
818
+ }
819
+ else {
820
+ logger.success(`Issue #${num} → Review`);
821
+ }
822
+ // Auto-set timestamp (#342) - reuse cached fields
823
+ autoSetTimestamps(issue.projectId, issue.projectItemId, targetStatus, fields, logger);
824
+ }
825
+ }
826
+ }
827
+ // 2. Create handover discussion
828
+ const categoryName = getDefaultCategory(config);
829
+ const categoryId = getHandoversCategoryId(owner, repo, categoryName);
830
+ let handoverOutput = null;
831
+ if (categoryId) {
832
+ const repoId = getRepoId(owner, repo);
833
+ if (!repoId) {
834
+ logger.error("Could not get repository ID");
835
+ return 1;
836
+ }
837
+ const result = runGraphQL(GRAPHQL_MUTATION_CREATE_DISCUSSION, {
838
+ repositoryId: repoId,
839
+ categoryId: categoryId,
840
+ title: title,
841
+ body: options.body ?? "",
842
+ });
843
+ if (!result.success) {
844
+ logger.error("Failed to create handover discussion");
845
+ return 1;
846
+ }
847
+ const discussion = result.data?.data?.createDiscussion?.discussion;
848
+ if (discussion?.number) {
849
+ handoverOutput = {
850
+ number: discussion.number,
851
+ title: discussion.title ?? title,
852
+ url: discussion.url ?? "",
853
+ };
854
+ logger.success(`Handover saved: #${discussion.number}`);
855
+ }
856
+ else {
857
+ logger.error("Failed to create handover discussion");
858
+ return 1;
859
+ }
860
+ }
861
+ else {
862
+ logger.error(`Category '${categoryName}' not found. Cannot create handover.`);
863
+ logger.info("Ensure Discussions are enabled and Handovers category exists.");
864
+ return 1;
865
+ }
866
+ // 3. Clean up session backups (#251)
867
+ const cleanedBackups = cleanupSessionBackups();
868
+ if (cleanedBackups > 0) {
869
+ logger.debug(`Cleaned up ${cleanedBackups} PreCompact backup(s)`);
870
+ }
871
+ // 4. Build output
872
+ const output = {
873
+ warnings: endWarnings.length > 0 ? endWarnings : undefined,
874
+ handover: handoverOutput,
875
+ updatedIssues,
876
+ cleanedBackups: cleanedBackups > 0 ? cleanedBackups : undefined,
877
+ };
878
+ console.log(JSON.stringify(output, null, 2));
879
+ return 0;
880
+ }
881
+ // =============================================================================
882
+ // session check - Metrics helpers (#342)
883
+ // =============================================================================
884
+ /** Fetch Text field values for all project items (batch, 1 query per project) */
885
+ const GRAPHQL_QUERY_PROJECT_ITEM_TEXT_VALUES = `
886
+ query($projectId: ID!, $first: Int!) {
887
+ node(id: $projectId) {
888
+ ... on ProjectV2 {
889
+ items(first: $first) {
890
+ nodes {
891
+ id
892
+ fieldValues(first: 20) {
893
+ nodes {
894
+ ... on ProjectV2ItemFieldTextValue {
895
+ text
896
+ field { ... on ProjectV2Field { name } }
897
+ }
898
+ }
899
+ }
900
+ }
901
+ }
902
+ }
903
+ }
904
+ }
905
+ `;
906
+ /**
907
+ * Batch-fetch Text field values for all items in a project.
908
+ * Returns map: itemId → { fieldName → textValue }
909
+ */
910
+ function fetchItemTextFieldValues(projectId) {
911
+ const result = runGraphQL(GRAPHQL_QUERY_PROJECT_ITEM_TEXT_VALUES, {
912
+ projectId,
913
+ first: 100,
914
+ });
915
+ if (!result.success)
916
+ return {};
917
+ const itemMap = {};
918
+ const items = result.data?.data?.node?.items?.nodes ?? [];
919
+ for (const item of items) {
920
+ if (!item?.id)
921
+ continue;
922
+ const textValues = {};
923
+ const fieldValues = item.fieldValues?.nodes ?? [];
924
+ for (const fv of fieldValues) {
925
+ if (fv?.field?.name && fv?.text) {
926
+ textValues[fv.field.name] = fv.text;
927
+ }
928
+ }
929
+ if (Object.keys(textValues).length > 0) {
930
+ itemMap[item.id] = textValues;
931
+ }
932
+ }
933
+ return itemMap;
934
+ }
935
+ /**
936
+ * Classify metrics-related inconsistencies.
937
+ * Pure function - no API calls, fully testable.
938
+ *
939
+ * Detects:
940
+ * 1. Done/Released issues missing Completed At timestamp
941
+ * 2. In Progress issues that are stale (In Progress At older than threshold)
942
+ */
943
+ export function classifyMetricsInconsistencies(issues, textFieldValues, metricsConfig, now) {
944
+ const inconsistencies = [];
945
+ const currentTime = now ?? new Date();
946
+ const mapping = metricsConfig.statusToDateMapping ?? {};
947
+ const staleThreshold = metricsConfig.staleThresholdDays ?? 14;
948
+ for (const issue of issues) {
949
+ const status = issue.status ?? "";
950
+ const itemId = issue.projectItemId;
951
+ if (!itemId)
952
+ continue;
953
+ const textValues = textFieldValues[itemId] ?? {};
954
+ // Done/Released issues missing Completed At timestamp
955
+ if (["Done", "Released"].includes(status)) {
956
+ const completedAtField = mapping["Done"];
957
+ if (completedAtField && !textValues[completedAtField]) {
958
+ inconsistencies.push({
959
+ number: issue.number,
960
+ title: issue.title,
961
+ url: issue.url,
962
+ issueState: issue.state,
963
+ projectStatus: issue.status,
964
+ severity: "info",
965
+ description: `Metrics: Missing '${completedAtField}' timestamp for ${status} issue`,
966
+ });
967
+ }
968
+ }
969
+ // In Progress issues - stale check
970
+ if (status === "In Progress") {
971
+ const inProgressAtField = mapping["In Progress"];
972
+ if (inProgressAtField && textValues[inProgressAtField]) {
973
+ const inProgressAt = new Date(textValues[inProgressAtField]);
974
+ if (!isNaN(inProgressAt.getTime())) {
975
+ const daysSinceStart = Math.floor((currentTime.getTime() - inProgressAt.getTime()) / (1000 * 60 * 60 * 24));
976
+ if (daysSinceStart > staleThreshold) {
977
+ inconsistencies.push({
978
+ number: issue.number,
979
+ title: issue.title,
980
+ url: issue.url,
981
+ issueState: issue.state,
982
+ projectStatus: issue.status,
983
+ severity: "info",
984
+ description: `Metrics: In Progress for ${daysSinceStart} days (stale threshold: ${staleThreshold} days)`,
985
+ });
986
+ }
987
+ }
988
+ }
989
+ }
990
+ }
991
+ return inconsistencies;
992
+ }
993
+ // =============================================================================
994
+ // session check - Integrity check
995
+ // =============================================================================
996
+ const GRAPHQL_MUTATION_CLOSE_ISSUE = `
997
+ mutation($issueId: ID!, $stateReason: IssueClosedStateReason) {
998
+ closeIssue(input: {issueId: $issueId, stateReason: $stateReason}) {
999
+ issue { id number state }
1000
+ }
1001
+ }
1002
+ `;
1003
+ function closeIssueById(issueId) {
1004
+ const result = runGraphQL(GRAPHQL_MUTATION_CLOSE_ISSUE, {
1005
+ issueId,
1006
+ stateReason: "COMPLETED",
1007
+ });
1008
+ return result.success;
1009
+ }
1010
+ /**
1011
+ * Check for inconsistencies between GitHub Issue state and Project Status.
1012
+ *
1013
+ * Detects two types of inconsistencies:
1014
+ * 1. OPEN issues with terminal Project Status (Done/Released) → fix: close issue
1015
+ * 2. CLOSED issues with active Project Status (Review/In Progress/etc.) → fix: set status to Done
1016
+ */
1017
+ async function cmdCheck(options, logger) {
1018
+ // --setup mode: validate GitHub manual setup items (#345)
1019
+ if (options.setup) {
1020
+ const setupResult = validateGitHubSetup(logger);
1021
+ if (!setupResult)
1022
+ return 1;
1023
+ printSetupCheckResults(setupResult, logger);
1024
+ console.log(JSON.stringify(setupResult, null, 2));
1025
+ return setupResult.summary.missing > 0 ? 1 : 0;
1026
+ }
1027
+ const config = loadGhConfig();
1028
+ const repoInfo = getRepoInfo();
1029
+ if (!repoInfo) {
1030
+ logger.error("Could not determine repository");
1031
+ return 1;
1032
+ }
1033
+ const { owner: repoOwner, name: repo } = repoInfo;
1034
+ const owner = options.owner || repoOwner;
1035
+ const limit = getDefaultLimit(config);
1036
+ logger.debug(`Repository: ${owner}/${repo}`);
1037
+ // 1. Fetch both OPEN and CLOSED issues in a single query
1038
+ const allIssues = fetchActiveIssues(owner, repo, limit, ["OPEN", "CLOSED"]);
1039
+ logger.debug(`Issues fetched: ${allIssues.length}`);
1040
+ // 2. Classify inconsistencies (pure function)
1041
+ const inconsistencies = classifyInconsistencies(allIssues);
1042
+ logger.debug(`Inconsistencies found: ${inconsistencies.length}`);
1043
+ // 3. Fix if --fix is specified
1044
+ const fixes = [];
1045
+ if (options.fix && inconsistencies.length > 0) {
1046
+ // Pre-fetch project fields for status updates (needed for CLOSED + active status fixes)
1047
+ const projectFieldsCache = {};
1048
+ const errorItems = inconsistencies.filter((i) => i.severity === "error");
1049
+ for (const item of errorItems) {
1050
+ if (item.issueState === "OPEN") {
1051
+ // OPEN + Done/Released → close the issue
1052
+ logger.info(`Closing #${item.number}: ${item.description}`);
1053
+ const issueId = getIssueId(owner, repo, item.number);
1054
+ if (!issueId) {
1055
+ fixes.push({
1056
+ number: item.number,
1057
+ action: "close",
1058
+ success: false,
1059
+ error: "Could not resolve issue ID",
1060
+ });
1061
+ continue;
1062
+ }
1063
+ const success = closeIssueById(issueId);
1064
+ fixes.push({
1065
+ number: item.number,
1066
+ action: "close",
1067
+ success,
1068
+ error: success ? undefined : "GraphQL mutation failed",
1069
+ });
1070
+ if (success) {
1071
+ logger.success(`Closed #${item.number}`);
1072
+ }
1073
+ else {
1074
+ logger.error(`Failed to close #${item.number}`);
1075
+ }
1076
+ }
1077
+ else if (item.issueState === "CLOSED") {
1078
+ // CLOSED + active status → update status to Done
1079
+ logger.info(`Updating #${item.number} status to Done: ${item.description}`);
1080
+ const issueData = allIssues.find((i) => i.number === item.number);
1081
+ if (!issueData?.projectItemId || !issueData?.projectId) {
1082
+ fixes.push({
1083
+ number: item.number,
1084
+ action: "update-status",
1085
+ success: false,
1086
+ error: "Could not resolve project item ID",
1087
+ });
1088
+ continue;
1089
+ }
1090
+ // Cache project fields per project
1091
+ if (!projectFieldsCache[issueData.projectId]) {
1092
+ projectFieldsCache[issueData.projectId] = getProjectFields(issueData.projectId);
1093
+ }
1094
+ const fields = projectFieldsCache[issueData.projectId];
1095
+ const success = updateIssueStatus(issueData.projectId, issueData.projectItemId, "Done", fields, logger);
1096
+ fixes.push({
1097
+ number: item.number,
1098
+ action: "update-status",
1099
+ success,
1100
+ error: success ? undefined : "Failed to update project status",
1101
+ });
1102
+ if (success) {
1103
+ logger.success(`Updated #${item.number} status to Done`);
1104
+ }
1105
+ else {
1106
+ logger.error(`Failed to update #${item.number} status`);
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+ // 3b. Metrics check (#342) - if metrics enabled, detect missing timestamps and stale issues
1112
+ const metricsConfig = getMetricsConfig(config);
1113
+ if (metricsConfig.enabled) {
1114
+ logger.debug("Metrics check enabled");
1115
+ // Batch-fetch text field values per project
1116
+ const projectIds = new Set();
1117
+ for (const issue of allIssues) {
1118
+ if (issue.projectId)
1119
+ projectIds.add(issue.projectId);
1120
+ }
1121
+ let allTextFieldValues = {};
1122
+ for (const pid of projectIds) {
1123
+ const values = fetchItemTextFieldValues(pid);
1124
+ allTextFieldValues = { ...allTextFieldValues, ...values };
1125
+ }
1126
+ // Classify metrics inconsistencies (pure function)
1127
+ const metricsIssues = classifyMetricsInconsistencies(allIssues, allTextFieldValues, metricsConfig);
1128
+ logger.debug(`Metrics inconsistencies: ${metricsIssues.length}`);
1129
+ // Add to main inconsistencies list
1130
+ inconsistencies.push(...metricsIssues);
1131
+ // Fix: backfill timestamps for Done issues missing Completed At
1132
+ if (options.fix && metricsIssues.length > 0) {
1133
+ const mapping = metricsConfig.statusToDateMapping ?? {};
1134
+ for (const item of metricsIssues) {
1135
+ if (!item.description.startsWith("Metrics: Missing"))
1136
+ continue;
1137
+ const issueData = allIssues.find((i) => i.number === item.number);
1138
+ if (!issueData?.projectItemId || !issueData?.projectId)
1139
+ continue;
1140
+ const completedAtField = mapping["Done"];
1141
+ if (!completedAtField)
1142
+ continue;
1143
+ const pf = getProjectFields(issueData.projectId);
1144
+ const fieldInfo = pf[completedAtField];
1145
+ if (!fieldInfo || fieldInfo.type !== "TEXT")
1146
+ continue;
1147
+ // Use closedAt if available, otherwise current timestamp
1148
+ const ts = issueData.closedAt ?? generateTimestamp();
1149
+ const success = updateTextField(issueData.projectId, issueData.projectItemId, fieldInfo.id, ts);
1150
+ fixes.push({
1151
+ number: item.number,
1152
+ action: "backfill-timestamp",
1153
+ success,
1154
+ error: success ? undefined : "Failed to set Text field",
1155
+ });
1156
+ if (success) {
1157
+ logger.success(`Backfilled ${completedAtField} for #${item.number} (${ts})`);
1158
+ }
1159
+ else {
1160
+ logger.error(`Failed to backfill ${completedAtField} for #${item.number}`);
1161
+ }
1162
+ }
1163
+ }
1164
+ }
1165
+ // 4. Check automation status (#250)
1166
+ let automationStatus;
1167
+ const projectId = getProjectId(owner);
1168
+ if (projectId) {
1169
+ const workflows = fetchWorkflows(projectId);
1170
+ if (workflows.length > 0) {
1171
+ const workflowSummary = workflows.map((w) => ({
1172
+ name: w.name,
1173
+ enabled: w.enabled,
1174
+ recommended: RECOMMENDED_WORKFLOWS.includes(w.name),
1175
+ }));
1176
+ const missingRecommended = workflowSummary
1177
+ .filter((w) => w.recommended && !w.enabled)
1178
+ .map((w) => w.name);
1179
+ automationStatus = {
1180
+ checked: true,
1181
+ workflows: workflowSummary,
1182
+ missing_recommended: missingRecommended,
1183
+ };
1184
+ if (missingRecommended.length > 0) {
1185
+ logger.warn(`Recommended automations disabled: ${missingRecommended.join(", ")}`);
1186
+ logger.info("Enable via: GitHub Project Settings > Workflows");
1187
+ }
1188
+ else {
1189
+ logger.debug("All recommended automations are enabled");
1190
+ }
1191
+ }
1192
+ }
1193
+ // 5. Build output
1194
+ const output = {
1195
+ repository: `${owner}/${repo}`,
1196
+ inconsistencies,
1197
+ fixes,
1198
+ automations: automationStatus,
1199
+ summary: {
1200
+ total_checked: allIssues.length,
1201
+ total_inconsistencies: inconsistencies.length,
1202
+ errors: inconsistencies.filter((i) => i.severity === "error").length,
1203
+ info: inconsistencies.filter((i) => i.severity === "info").length,
1204
+ fixed: fixes.filter((f) => f.success).length,
1205
+ fix_failures: fixes.filter((f) => !f.success).length,
1206
+ },
1207
+ };
1208
+ console.log(JSON.stringify(output, null, 2));
1209
+ // Exit code 1 if: unfixed inconsistencies remain, or fix attempts failed
1210
+ if (output.summary.fix_failures > 0)
1211
+ return 1;
1212
+ if (!options.fix && output.summary.errors > 0)
1213
+ return 1;
1214
+ return 0;
1215
+ }
1216
+ // =============================================================================
1217
+ // Main Command Handler
1218
+ // =============================================================================
1219
+ export async function sessionCommand(action, options) {
1220
+ const logger = createLogger(options.verbose);
1221
+ logger.debug(`Action: ${action}`);
1222
+ logger.debug(`Owner: ${options.owner ?? "(auto)"}`);
1223
+ let exitCode = 0;
1224
+ switch (action) {
1225
+ case "start":
1226
+ exitCode = await cmdStart(options, logger);
1227
+ break;
1228
+ case "end":
1229
+ exitCode = await cmdEnd(options, logger);
1230
+ break;
1231
+ case "check":
1232
+ exitCode = await cmdCheck(options, logger);
1233
+ break;
1234
+ default:
1235
+ logger.error(`Unknown action: ${action}`);
1236
+ logger.info("Available actions: start, end, check");
1237
+ exitCode = 1;
1238
+ }
1239
+ if (exitCode !== 0) {
1240
+ process.exit(exitCode);
1241
+ }
1242
+ }
1243
+ //# sourceMappingURL=session.js.map