timsquad 3.6.0 → 3.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (433) hide show
  1. package/README.ko.md +103 -113
  2. package/README.md +100 -110
  3. package/dist/commands/init.js +4 -8
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/{upgrade.d.ts → update.d.ts} +3 -3
  6. package/dist/commands/update.d.ts.map +1 -0
  7. package/dist/commands/{upgrade.js → update.js} +12 -17
  8. package/dist/commands/update.js.map +1 -0
  9. package/dist/daemon/event-queue.d.ts +3 -11
  10. package/dist/daemon/event-queue.d.ts.map +1 -1
  11. package/dist/daemon/event-queue.js +62 -203
  12. package/dist/daemon/event-queue.js.map +1 -1
  13. package/dist/daemon/index.d.ts +1 -1
  14. package/dist/daemon/index.d.ts.map +1 -1
  15. package/dist/daemon/index.js +15 -14
  16. package/dist/daemon/index.js.map +1 -1
  17. package/dist/index.js +3 -43
  18. package/dist/index.js.map +1 -1
  19. package/dist/lib/agent-generator.d.ts.map +1 -1
  20. package/dist/lib/agent-generator.js +10 -10
  21. package/dist/lib/agent-generator.js.map +1 -1
  22. package/dist/lib/compile-rules.d.ts.map +1 -1
  23. package/dist/lib/compile-rules.js +37 -4
  24. package/dist/lib/compile-rules.js.map +1 -1
  25. package/dist/lib/compiler.d.ts +1 -0
  26. package/dist/lib/compiler.d.ts.map +1 -1
  27. package/dist/lib/compiler.js +67 -11
  28. package/dist/lib/compiler.js.map +1 -1
  29. package/dist/{commands/log.d.ts → lib/log-utils.d.ts} +7 -15
  30. package/dist/lib/log-utils.d.ts.map +1 -0
  31. package/dist/lib/log-utils.js +347 -0
  32. package/dist/lib/log-utils.js.map +1 -0
  33. package/dist/lib/skill-generator.d.ts.map +1 -1
  34. package/dist/lib/skill-generator.js +4 -44
  35. package/dist/lib/skill-generator.js.map +1 -1
  36. package/dist/lib/ssot-map.d.ts.map +1 -1
  37. package/dist/lib/ssot-map.js +3 -0
  38. package/dist/lib/ssot-map.js.map +1 -1
  39. package/dist/lib/template.d.ts +10 -3
  40. package/dist/lib/template.d.ts.map +1 -1
  41. package/dist/lib/template.js +142 -22
  42. package/dist/lib/template.js.map +1 -1
  43. package/dist/lib/upgrade-backup.js +1 -1
  44. package/dist/lib/upgrade-backup.js.map +1 -1
  45. package/dist/types/config.d.ts.map +1 -1
  46. package/dist/types/config.js +37 -34
  47. package/dist/types/config.js.map +1 -1
  48. package/dist/types/feedback.d.ts +1 -54
  49. package/dist/types/feedback.d.ts.map +1 -1
  50. package/dist/types/feedback.js +1 -22
  51. package/dist/types/feedback.js.map +1 -1
  52. package/dist/types/project.d.ts +5 -0
  53. package/dist/types/project.d.ts.map +1 -1
  54. package/dist/types/project.js +15 -0
  55. package/dist/types/project.js.map +1 -1
  56. package/dist/types/ssot-map.d.ts +2 -0
  57. package/dist/types/ssot-map.d.ts.map +1 -1
  58. package/package.json +1 -1
  59. package/templates/base/agents/base/tsq-architect.md +1 -1
  60. package/templates/base/agents/base/tsq-dba.md +3 -1
  61. package/templates/base/agents/base/tsq-designer.md +3 -1
  62. package/templates/base/agents/base/tsq-developer.md +3 -1
  63. package/templates/base/agents/base/tsq-librarian.md +1 -1
  64. package/templates/base/agents/base/tsq-qa.md +3 -1
  65. package/templates/base/agents/base/tsq-security.md +3 -1
  66. package/templates/base/agents/overlays/platform/claude-code.md +2 -2
  67. package/templates/base/config.template.yaml +17 -28
  68. package/templates/base/knowledge/templates/task-result.md +5 -10
  69. package/templates/base/skills/_template/SKILL.md +1 -3
  70. package/templates/base/skills/{architecture → tsq-architecture}/SKILL.md +2 -2
  71. package/templates/base/skills/tsq-audit/SKILL.md +74 -0
  72. package/templates/base/skills/{methodology/bdd → tsq-bdd}/SKILL.md +14 -9
  73. package/templates/base/skills/{coding → tsq-coding}/SKILL.md +2 -4
  74. package/templates/base/skills/tsq-controller/SKILL.md +81 -0
  75. package/templates/base/skills/{mobile/dart → tsq-dart}/SKILL.md +5 -3
  76. package/templates/base/skills/{database → tsq-database}/SKILL.md +5 -2
  77. package/templates/base/skills/{methodology/ddd → tsq-ddd}/SKILL.md +15 -10
  78. package/templates/base/skills/{methodology/debugging → tsq-debugging}/SKILL.md +2 -2
  79. package/templates/base/skills/tsq-decompose/SKILL.md +117 -0
  80. package/templates/base/skills/tsq-delete/SKILL.md +72 -0
  81. package/templates/base/skills/{mobile/flutter → tsq-flutter}/SKILL.md +6 -3
  82. package/templates/base/skills/tsq-full/SKILL.md +67 -0
  83. package/templates/base/skills/tsq-grill/SKILL.md +86 -0
  84. package/templates/base/skills/{backend/node → tsq-hono}/SKILL.md +6 -4
  85. package/templates/base/skills/tsq-librarian/SKILL.md +78 -0
  86. package/templates/base/skills/tsq-log/SKILL.md +30 -0
  87. package/templates/base/skills/{frontend/nextjs → tsq-nextjs}/SKILL.md +14 -9
  88. package/templates/base/skills/{planning → tsq-planning}/SKILL.md +2 -2
  89. package/templates/base/skills/{database/prisma → tsq-prisma}/SKILL.md +15 -9
  90. package/templates/base/skills/{product-audit → tsq-product-audit}/SKILL.md +2 -4
  91. package/templates/base/skills/{prompt-engineering → tsq-prompt}/SKILL.md +6 -4
  92. package/templates/base/skills/tsq-protocol/SKILL.md +85 -33
  93. package/templates/base/skills/tsq-quick/SKILL.md +58 -0
  94. package/templates/base/skills/{frontend/react → tsq-react}/SKILL.md +6 -3
  95. package/templates/base/skills/tsq-retro/SKILL.md +86 -0
  96. package/templates/base/skills/tsq-retro/references/feedback-guide.md +58 -0
  97. package/templates/base/skills/tsq-retro/references/improve-protocol.md +87 -0
  98. package/templates/base/skills/{security → tsq-security}/SKILL.md +2 -4
  99. package/templates/base/skills/{spec → tsq-spec}/SKILL.md +4 -6
  100. package/templates/base/skills/{stability-verification → tsq-stability}/SKILL.md +3 -3
  101. package/templates/base/skills/tsq-start/SKILL.md +90 -0
  102. package/templates/base/skills/tsq-start/references/onboarding-questions.md +177 -0
  103. package/templates/base/skills/tsq-status/SKILL.md +32 -0
  104. package/templates/base/skills/{methodology/tdd → tsq-tdd}/SKILL.md +6 -3
  105. package/templates/base/skills/{testing → tsq-testing}/SKILL.md +5 -7
  106. package/templates/base/skills/{typescript → tsq-typescript}/SKILL.md +2 -2
  107. package/templates/base/skills/{ui-design → tsq-ui}/SKILL.md +2 -2
  108. package/templates/base/skills/tsq-update/SKILL.md +48 -0
  109. package/templates/base/timsquad/constraints/competency-framework.xml +2 -2
  110. package/templates/base/timsquad/constraints/ssot-schema.xml +2 -2
  111. package/templates/base/timsquad/process/phase-checklist.yaml +1 -1
  112. package/templates/base/timsquad/process/state-machine.xml +2 -2
  113. package/templates/base/timsquad/process/validation-rules.xml +8 -8
  114. package/templates/base/timsquad/process/workflow-base.xml +8 -8
  115. package/templates/base/timsquad/retrospective/cycle-report.template.md +2 -2
  116. package/templates/base/timsquad/retrospective/patterns/failure-patterns.md +1 -1
  117. package/templates/base/timsquad/retrospective/patterns/success-patterns.md +2 -2
  118. package/templates/base/timsquad/retrospective/retrospective-state.xml +2 -2
  119. package/templates/base/timsquad/ssot/audit-trail-spec.template.md +155 -0
  120. package/templates/base/timsquad/ssot/compliance-matrix.template.md +105 -0
  121. package/templates/base/timsquad/ssot/component-map.template.md +181 -0
  122. package/templates/base/timsquad/ssot/data-design.template.md +4 -4
  123. package/templates/base/timsquad/ssot/deployment-spec.template.md +29 -22
  124. package/templates/base/timsquad/ssot/env-config.template.md +4 -2
  125. package/templates/base/timsquad/ssot/error-codes.template.md +3 -3
  126. package/templates/base/timsquad/ssot/functional-spec.template.md +40 -3
  127. package/templates/base/timsquad/ssot/glossary.template.md +2 -2
  128. package/templates/base/timsquad/ssot/infra-topology.template.md +191 -0
  129. package/templates/base/timsquad/ssot/integration-spec.template.md +2 -2
  130. package/templates/base/timsquad/ssot/monitoring-spec.template.md +185 -0
  131. package/templates/base/timsquad/ssot/navigation-map.template.md +154 -0
  132. package/templates/base/timsquad/ssot/performance-budget.template.md +132 -0
  133. package/templates/base/timsquad/ssot/planning.template.md +3 -3
  134. package/templates/base/timsquad/ssot/prd/_template.md +73 -0
  135. package/templates/base/timsquad/ssot/prd.template.md +10 -21
  136. package/templates/base/timsquad/ssot/requirements.template.md +3 -3
  137. package/templates/base/timsquad/ssot/sdk-spec.template.md +223 -0
  138. package/templates/base/timsquad/ssot/service-spec.template.md +3 -3
  139. package/templates/base/timsquad/ssot/state-machine.template.md +127 -0
  140. package/templates/base/timsquad/ssot/ui-ux-spec.template.md +43 -3
  141. package/templates/base/timsquad/ssot-map.template.yaml +28 -0
  142. package/templates/base/timsquad/state/workspace.xml +11 -11
  143. package/templates/platforms/claude-code/rules/adr-rules.md +1 -1
  144. package/templates/platforms/claude-code/rules/build-gate.md +1 -1
  145. package/templates/platforms/claude-code/rules/completion-verification.md +0 -2
  146. package/templates/platforms/claude-code/rules/context-monitor.md +1 -1
  147. package/templates/platforms/claude-code/rules/feedback-routing.md +2 -2
  148. package/templates/platforms/claude-code/rules/phase-management.md +2 -2
  149. package/templates/platforms/claude-code/rules/plan-review.md +2 -2
  150. package/templates/platforms/claude-code/rules/quality-guards.md +0 -2
  151. package/templates/platforms/claude-code/rules/sequence-management.md +15 -15
  152. package/templates/platforms/claude-code/rules/session-notes.md +1 -1
  153. package/templates/platforms/claude-code/rules/workspace-sync.md +1 -1
  154. package/templates/platforms/claude-code/scripts/build-gate.sh +6 -1
  155. package/templates/platforms/claude-code/scripts/change-scope-guard.sh +1 -4
  156. package/templates/platforms/claude-code/scripts/check-capability.sh +68 -0
  157. package/templates/platforms/claude-code/scripts/completion-guard.sh +62 -4
  158. package/templates/platforms/claude-code/scripts/context-restore.sh +33 -6
  159. package/templates/platforms/claude-code/scripts/phase-guard.sh +2 -5
  160. package/templates/platforms/claude-code/scripts/pre-compact.sh +3 -3
  161. package/templates/platforms/claude-code/scripts/safe-guard.sh +2 -5
  162. package/templates/platforms/claude-code/scripts/subagent-start.sh +11 -0
  163. package/templates/platforms/claude-code/scripts/subagent-stop.sh +11 -0
  164. package/templates/platforms/claude-code/settings.json +20 -74
  165. package/templates/project-types/api-backend/config.yaml +9 -5
  166. package/templates/project-types/api-backend/process/workflow.xml +2 -2
  167. package/templates/project-types/fintech/config.yaml +13 -19
  168. package/templates/project-types/fintech/ssot/audit-trail-spec.template.md +207 -0
  169. package/templates/project-types/fintech/ssot/compliance-matrix.template.md +187 -0
  170. package/templates/project-types/infra/config.yaml +7 -4
  171. package/templates/project-types/infra/process/workflow.xml +3 -3
  172. package/templates/project-types/mobile-app/config.yaml +8 -14
  173. package/templates/project-types/mobile-app/process/workflow.xml +4 -4
  174. package/templates/project-types/platform/config.yaml +8 -5
  175. package/templates/project-types/platform/process/workflow.xml +3 -3
  176. package/templates/project-types/web-app/config.yaml +9 -15
  177. package/templates/project-types/web-app/process/workflow.xml +6 -6
  178. package/templates/project-types/web-service/config.yaml +10 -19
  179. package/templates/project-types/web-service/process/workflow.xml +6 -6
  180. package/dist/commands/audit.d.ts +0 -22
  181. package/dist/commands/audit.d.ts.map +0 -1
  182. package/dist/commands/audit.js +0 -233
  183. package/dist/commands/audit.js.map +0 -1
  184. package/dist/commands/compile.d.ts +0 -3
  185. package/dist/commands/compile.d.ts.map +0 -1
  186. package/dist/commands/compile.js +0 -251
  187. package/dist/commands/compile.js.map +0 -1
  188. package/dist/commands/feedback.d.ts +0 -12
  189. package/dist/commands/feedback.d.ts.map +0 -1
  190. package/dist/commands/feedback.js +0 -382
  191. package/dist/commands/feedback.js.map +0 -1
  192. package/dist/commands/full.d.ts +0 -3
  193. package/dist/commands/full.d.ts.map +0 -1
  194. package/dist/commands/full.js +0 -88
  195. package/dist/commands/full.js.map +0 -1
  196. package/dist/commands/git/commit.d.ts +0 -3
  197. package/dist/commands/git/commit.d.ts.map +0 -1
  198. package/dist/commands/git/commit.js +0 -85
  199. package/dist/commands/git/commit.js.map +0 -1
  200. package/dist/commands/git/index.d.ts +0 -5
  201. package/dist/commands/git/index.d.ts.map +0 -1
  202. package/dist/commands/git/index.js +0 -5
  203. package/dist/commands/git/index.js.map +0 -1
  204. package/dist/commands/git/pr.d.ts +0 -3
  205. package/dist/commands/git/pr.d.ts.map +0 -1
  206. package/dist/commands/git/pr.js +0 -139
  207. package/dist/commands/git/pr.js.map +0 -1
  208. package/dist/commands/git/release.d.ts +0 -3
  209. package/dist/commands/git/release.d.ts.map +0 -1
  210. package/dist/commands/git/release.js +0 -153
  211. package/dist/commands/git/release.js.map +0 -1
  212. package/dist/commands/git/sync.d.ts +0 -3
  213. package/dist/commands/git/sync.d.ts.map +0 -1
  214. package/dist/commands/git/sync.js +0 -132
  215. package/dist/commands/git/sync.js.map +0 -1
  216. package/dist/commands/improve.d.ts +0 -3
  217. package/dist/commands/improve.d.ts.map +0 -1
  218. package/dist/commands/improve.js +0 -286
  219. package/dist/commands/improve.js.map +0 -1
  220. package/dist/commands/knowledge.d.ts +0 -3
  221. package/dist/commands/knowledge.d.ts.map +0 -1
  222. package/dist/commands/knowledge.js +0 -316
  223. package/dist/commands/knowledge.js.map +0 -1
  224. package/dist/commands/log.d.ts.map +0 -1
  225. package/dist/commands/log.js +0 -1468
  226. package/dist/commands/log.js.map +0 -1
  227. package/dist/commands/meta-index.d.ts +0 -3
  228. package/dist/commands/meta-index.d.ts.map +0 -1
  229. package/dist/commands/meta-index.js +0 -431
  230. package/dist/commands/meta-index.js.map +0 -1
  231. package/dist/commands/metrics.d.ts +0 -3
  232. package/dist/commands/metrics.d.ts.map +0 -1
  233. package/dist/commands/metrics.js +0 -843
  234. package/dist/commands/metrics.js.map +0 -1
  235. package/dist/commands/quick.d.ts +0 -3
  236. package/dist/commands/quick.d.ts.map +0 -1
  237. package/dist/commands/quick.js +0 -136
  238. package/dist/commands/quick.js.map +0 -1
  239. package/dist/commands/retro.d.ts +0 -3
  240. package/dist/commands/retro.d.ts.map +0 -1
  241. package/dist/commands/retro.js +0 -885
  242. package/dist/commands/retro.js.map +0 -1
  243. package/dist/commands/session.d.ts +0 -3
  244. package/dist/commands/session.d.ts.map +0 -1
  245. package/dist/commands/session.js +0 -346
  246. package/dist/commands/session.js.map +0 -1
  247. package/dist/commands/skills.d.ts +0 -12
  248. package/dist/commands/skills.d.ts.map +0 -1
  249. package/dist/commands/skills.js +0 -228
  250. package/dist/commands/skills.js.map +0 -1
  251. package/dist/commands/status.d.ts +0 -3
  252. package/dist/commands/status.d.ts.map +0 -1
  253. package/dist/commands/status.js +0 -127
  254. package/dist/commands/status.js.map +0 -1
  255. package/dist/commands/upgrade.d.ts.map +0 -1
  256. package/dist/commands/upgrade.js.map +0 -1
  257. package/dist/commands/watch.d.ts +0 -3
  258. package/dist/commands/watch.d.ts.map +0 -1
  259. package/dist/commands/watch.js +0 -213
  260. package/dist/commands/watch.js.map +0 -1
  261. package/dist/commands/workflow.d.ts +0 -5
  262. package/dist/commands/workflow.d.ts.map +0 -1
  263. package/dist/commands/workflow.js +0 -781
  264. package/dist/commands/workflow.js.map +0 -1
  265. package/templates/base/skills/audit/SKILL.md +0 -66
  266. package/templates/base/skills/controller/SKILL.md +0 -77
  267. package/templates/base/skills/controller/delegation/developer.md +0 -25
  268. package/templates/base/skills/controller/delegation/librarian.md +0 -33
  269. package/templates/base/skills/controller/delegation/reviewer.md +0 -19
  270. package/templates/base/skills/controller/triggers/phase-complete.md +0 -25
  271. package/templates/base/skills/controller/triggers/sequence-complete.md +0 -15
  272. package/templates/base/skills/controller/triggers/ssot-changed.md +0 -14
  273. package/templates/base/skills/controller/triggers/task-complete.md +0 -14
  274. package/templates/base/skills/librarian/SKILL.md +0 -53
  275. package/templates/base/skills/main-session-constraints/SKILL.md +0 -62
  276. package/templates/base/skills/retrospective/SKILL.md +0 -77
  277. package/templates/base/skills/review/SKILL.md +0 -72
  278. package/templates/base/skills/tsq-cli/SKILL.md +0 -73
  279. package/templates/base/skills/tsq-cli/references/cli-reference.md +0 -92
  280. package/templates/base/timsquad/feedback/feedback-router.sh +0 -341
  281. package/templates/base/timsquad/feedback/routing-rules.yaml +0 -352
  282. package/templates/platforms/claude-code/CLAUDE.md.template +0 -89
  283. package/templates/platforms/claude-code/rules/skill-suggest.md +0 -27
  284. package/templates/platforms/claude-code/scripts/skill-inject.sh +0 -216
  285. package/templates/platforms/claude-code/scripts/skill-rules.json +0 -95
  286. package/templates/platforms/claude-code/scripts/skill-suggest.sh +0 -105
  287. package/templates/platforms/claude-code/scripts/subagent-inject.sh +0 -53
  288. /package/templates/base/skills/{architecture → tsq-architecture}/references/adr-template.md +0 -0
  289. /package/templates/base/skills/{architecture → tsq-architecture}/references/api-design.md +0 -0
  290. /package/templates/base/skills/{methodology/bdd → tsq-bdd}/rules/gherkin-patterns.md +0 -0
  291. /package/templates/base/skills/{coding → tsq-coding}/rules/async-patterns.md +0 -0
  292. /package/templates/base/skills/{coding → tsq-coding}/rules/code-organization.md +0 -0
  293. /package/templates/base/skills/{coding → tsq-coding}/rules/error-handling.md +0 -0
  294. /package/templates/base/skills/{coding → tsq-coding}/rules/patterns.md +0 -0
  295. /package/templates/base/skills/{coding → tsq-coding}/rules/type-safety.md +0 -0
  296. /package/templates/base/skills/{controller → tsq-controller}/memory/.gitkeep +0 -0
  297. /package/templates/base/skills/{controller → tsq-controller}/references/README.md +0 -0
  298. /package/templates/base/skills/{controller → tsq-controller}/rules/README.md +0 -0
  299. /package/templates/base/skills/{mobile/dart → tsq-dart}/rules/async-patterns.md +0 -0
  300. /package/templates/base/skills/{mobile/dart → tsq-dart}/rules/code-style.md +0 -0
  301. /package/templates/base/skills/{mobile/dart → tsq-dart}/rules/null-safety.md +0 -0
  302. /package/templates/base/skills/{mobile/dart → tsq-dart}/rules/type-system.md +0 -0
  303. /package/templates/base/skills/{database → tsq-database}/rules/query-optimization.md +0 -0
  304. /package/templates/base/skills/{database → tsq-database}/rules/supabase-patterns.md +0 -0
  305. /package/templates/base/skills/{methodology/ddd → tsq-ddd}/rules/strategic-patterns.md +0 -0
  306. /package/templates/base/skills/{methodology/debugging → tsq-debugging}/references/root-cause-tracing.md +0 -0
  307. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/SKILL.md +0 -0
  308. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/references/ci-cd-pipeline.md +0 -0
  309. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/rules/code-signing.md +0 -0
  310. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/rules/codemagic-setup.md +0 -0
  311. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/rules/fastlane-setup.md +0 -0
  312. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/rules/github-actions.md +0 -0
  313. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/rules/store-deployment.md +0 -0
  314. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/ci-cd/rules/versioning.md +0 -0
  315. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/SKILL.md +0 -0
  316. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/references/i18n-architecture.md +0 -0
  317. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/rules/arb-files.md +0 -0
  318. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/rules/locale-switching.md +0 -0
  319. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/rules/localization-setup.md +0 -0
  320. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/rules/plural-gender.md +0 -0
  321. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/i18n/rules/text-direction.md +0 -0
  322. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/SKILL.md +0 -0
  323. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/references/monitoring-architecture.md +0 -0
  324. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/rules/analytics.md +0 -0
  325. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/rules/crashlytics-setup.md +0 -0
  326. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/rules/logging.md +0 -0
  327. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/rules/performance-monitoring.md +0 -0
  328. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/monitoring/rules/sentry-integration.md +0 -0
  329. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/SKILL.md +0 -0
  330. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/references/api-client-architecture.md +0 -0
  331. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/rules/caching.md +0 -0
  332. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/rules/connectivity.md +0 -0
  333. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/rules/dio-setup.md +0 -0
  334. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/rules/error-handling.md +0 -0
  335. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/rules/interceptors.md +0 -0
  336. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/networking/rules/retrofit-patterns.md +0 -0
  337. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/SKILL.md +0 -0
  338. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/references/notification-architecture.md +0 -0
  339. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/references/platform-setup.md +0 -0
  340. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/background-processing.md +0 -0
  341. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/deep-linking.md +0 -0
  342. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/fcm-setup.md +0 -0
  343. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/local-notifications.md +0 -0
  344. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/notification-handling.md +0 -0
  345. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/notification-permissions.md +0 -0
  346. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/push-notifications/rules/rich-notifications.md +0 -0
  347. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/references/freezed-patterns.md +0 -0
  348. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/references/project-structure.md +0 -0
  349. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/animations.md +0 -0
  350. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/architecture.md +0 -0
  351. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/navigation-routing.md +0 -0
  352. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/performance.md +0 -0
  353. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/platform-adaptive.md +0 -0
  354. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/state-management.md +0 -0
  355. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/testing.md +0 -0
  356. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/rules/widget-conventions.md +0 -0
  357. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/SKILL.md +0 -0
  358. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/references/mobile-security-checklist.md +0 -0
  359. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/rules/api-key-protection.md +0 -0
  360. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/rules/authentication.md +0 -0
  361. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/rules/data-protection.md +0 -0
  362. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/rules/obfuscation.md +0 -0
  363. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/rules/secure-storage.md +0 -0
  364. /package/templates/base/skills/{mobile/flutter → tsq-flutter}/security/rules/ssl-pinning.md +0 -0
  365. /package/templates/base/skills/{backend/node → tsq-hono}/rules/async-patterns.md +0 -0
  366. /package/templates/base/skills/{backend/node → tsq-hono}/rules/deployment.md +0 -0
  367. /package/templates/base/skills/{backend/node → tsq-hono}/rules/env-config.md +0 -0
  368. /package/templates/base/skills/{backend/node → tsq-hono}/rules/error-handling.md +0 -0
  369. /package/templates/base/skills/{backend/node → tsq-hono}/rules/hono-app-setup.md +0 -0
  370. /package/templates/base/skills/{backend/node → tsq-hono}/rules/jwt-auth.md +0 -0
  371. /package/templates/base/skills/{backend/node → tsq-hono}/rules/middleware.md +0 -0
  372. /package/templates/base/skills/{backend/node → tsq-hono}/rules/testing.md +0 -0
  373. /package/templates/base/skills/{frontend/nextjs → tsq-nextjs}/rules/app-router.md +0 -0
  374. /package/templates/base/skills/{planning → tsq-planning}/references/prd-guide.md +0 -0
  375. /package/templates/base/skills/{planning → tsq-planning}/references/requirements-guide.md +0 -0
  376. /package/templates/base/skills/{database/prisma → tsq-prisma}/rules/queries.md +0 -0
  377. /package/templates/base/skills/{database/prisma → tsq-prisma}/rules/schema-design.md +0 -0
  378. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/01-security.md +0 -0
  379. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/02-performance.md +0 -0
  380. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/03-seo.md +0 -0
  381. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/04-accessibility.md +0 -0
  382. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/05-ui-ux.md +0 -0
  383. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/06-architecture.md +0 -0
  384. /package/templates/base/skills/{product-audit → tsq-product-audit}/checklists/07-functional-requirements.md +0 -0
  385. /package/templates/base/skills/{product-audit → tsq-product-audit}/rules/audit-protocol.md +0 -0
  386. /package/templates/base/skills/{product-audit → tsq-product-audit}/rules/false-positive-guard.md +0 -0
  387. /package/templates/base/skills/{product-audit → tsq-product-audit}/rules/scoring-criteria.md +0 -0
  388. /package/templates/base/skills/{product-audit → tsq-product-audit}/templates/improvement-plan-template.md +0 -0
  389. /package/templates/base/skills/{product-audit → tsq-product-audit}/templates/report-template.md +0 -0
  390. /package/templates/base/skills/{frontend/react → tsq-react}/rules/_sections.md +0 -0
  391. /package/templates/base/skills/{frontend/react → tsq-react}/rules/anti-patterns.md +0 -0
  392. /package/templates/base/skills/{frontend/react → tsq-react}/rules/async-api-routes.md +0 -0
  393. /package/templates/base/skills/{frontend/react → tsq-react}/rules/async-defer-await.md +0 -0
  394. /package/templates/base/skills/{frontend/react → tsq-react}/rules/async-dependencies.md +0 -0
  395. /package/templates/base/skills/{frontend/react → tsq-react}/rules/async-parallel.md +0 -0
  396. /package/templates/base/skills/{frontend/react → tsq-react}/rules/async-suspense-boundaries.md +0 -0
  397. /package/templates/base/skills/{frontend/react → tsq-react}/rules/bundle-barrel-imports.md +0 -0
  398. /package/templates/base/skills/{frontend/react → tsq-react}/rules/bundle-defer-third-party.md +0 -0
  399. /package/templates/base/skills/{frontend/react → tsq-react}/rules/bundle-dynamic-imports.md +0 -0
  400. /package/templates/base/skills/{frontend/react → tsq-react}/rules/component-conventions.md +0 -0
  401. /package/templates/base/skills/{frontend/react → tsq-react}/rules/js-combine-iterations.md +0 -0
  402. /package/templates/base/skills/{frontend/react → tsq-react}/rules/js-early-exit.md +0 -0
  403. /package/templates/base/skills/{frontend/react → tsq-react}/rules/js-index-maps.md +0 -0
  404. /package/templates/base/skills/{frontend/react → tsq-react}/rules/js-set-map-lookups.md +0 -0
  405. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rendering-conditional-render.md +0 -0
  406. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rendering-content-visibility.md +0 -0
  407. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rendering-hoist-jsx.md +0 -0
  408. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rerender-defer-reads.md +0 -0
  409. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rerender-derived-state.md +0 -0
  410. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rerender-memo.md +0 -0
  411. /package/templates/base/skills/{frontend/react → tsq-react}/rules/rerender-transitions.md +0 -0
  412. /package/templates/base/skills/{frontend/react → tsq-react}/rules/server-after-nonblocking.md +0 -0
  413. /package/templates/base/skills/{frontend/react → tsq-react}/rules/server-cache-react.md +0 -0
  414. /package/templates/base/skills/{frontend/react → tsq-react}/rules/server-parallel-fetching.md +0 -0
  415. /package/templates/base/skills/{frontend/react → tsq-react}/rules/state-location.md +0 -0
  416. /package/templates/base/skills/{retrospective → tsq-retro}/references/improvement-template.md +0 -0
  417. /package/templates/base/skills/{security → tsq-security}/rules/auth-patterns.md +0 -0
  418. /package/templates/base/skills/{security → tsq-security}/rules/dependency-security.md +0 -0
  419. /package/templates/base/skills/{security → tsq-security}/rules/input-validation.md +0 -0
  420. /package/templates/base/skills/{security → tsq-security}/rules/owasp-examples.md +0 -0
  421. /package/templates/base/skills/{security → tsq-security}/rules/secrets-management.md +0 -0
  422. /package/templates/base/skills/{security → tsq-security}/scripts/check-secrets.sh +0 -0
  423. /package/templates/base/skills/{stability-verification → tsq-stability}/references/release-checklist.md +0 -0
  424. /package/templates/base/skills/{stability-verification → tsq-stability}/references/security-fix-patterns.md +0 -0
  425. /package/templates/base/skills/{stability-verification → tsq-stability}/rules/verification-layers.md +0 -0
  426. /package/templates/base/skills/{stability-verification → tsq-stability}/rules/verification-workflow.md +0 -0
  427. /package/templates/base/skills/{stability-verification → tsq-stability}/scripts/verify.sh +0 -0
  428. /package/templates/base/skills/{methodology/tdd → tsq-tdd}/rules/real-world-example.md +0 -0
  429. /package/templates/base/skills/{methodology/tdd → tsq-tdd}/rules/techniques.md +0 -0
  430. /package/templates/base/skills/{testing → tsq-testing}/references/e2e-stability.md +0 -0
  431. /package/templates/base/skills/{testing → tsq-testing}/references/testing-patterns.md +0 -0
  432. /package/templates/base/skills/{typescript → tsq-typescript}/rules/type-patterns.md +0 -0
  433. /package/templates/base/skills/{typescript → tsq-typescript}/rules/utility-types.md +0 -0
@@ -1,843 +0,0 @@
1
- import path from 'path';
2
- import fs from 'fs-extra';
3
- import { colors, printHeader, printError, printSuccess, printKeyValue } from '../utils/colors.js';
4
- import { findProjectRoot } from '../lib/project.js';
5
- import { exists, readFile, listFiles } from '../utils/fs.js';
6
- import { getDateString, getTimestamp } from '../utils/date.js';
7
- export function registerMetricsCommand(program) {
8
- const metricsCmd = program
9
- .command('metrics')
10
- .description('Collect and view project quality metrics');
11
- // tsq metrics collect
12
- metricsCmd
13
- .command('collect')
14
- .description('Collect metrics from logs and session events')
15
- .option('-d, --days <days>', 'Days to analyze', '7')
16
- .action(async (options) => {
17
- try {
18
- await collectMetrics(parseInt(options.days, 10));
19
- }
20
- catch (error) {
21
- printError(error.message);
22
- process.exit(1);
23
- }
24
- });
25
- // tsq metrics summary
26
- metricsCmd
27
- .command('summary')
28
- .description('Show latest metrics summary with explanations')
29
- .action(async () => {
30
- try {
31
- await showMetricsSummary();
32
- }
33
- catch (error) {
34
- printError(error.message);
35
- process.exit(1);
36
- }
37
- });
38
- // tsq metrics trend
39
- metricsCmd
40
- .command('trend')
41
- .description('Compare metrics across collection periods')
42
- .option('-n <count>', 'Number of periods to compare', '5')
43
- .action(async (options) => {
44
- try {
45
- await showTrend(parseInt(options.n, 10));
46
- }
47
- catch (error) {
48
- printError(error.message);
49
- process.exit(1);
50
- }
51
- });
52
- // tsq metrics export
53
- metricsCmd
54
- .command('export')
55
- .description('Export metrics to JSON')
56
- .option('-o, --output <file>', 'Output file path')
57
- .action(async (options) => {
58
- try {
59
- await exportMetrics(options.output);
60
- }
61
- catch (error) {
62
- printError(error.message);
63
- process.exit(1);
64
- }
65
- });
66
- }
67
- // ============================================================
68
- // Collect
69
- // ============================================================
70
- async function collectMetrics(days) {
71
- const projectRoot = await findProjectRoot();
72
- if (!projectRoot) {
73
- throw new Error('Not a TimSquad project');
74
- }
75
- printHeader('Collecting Metrics');
76
- printKeyValue('Period', `Last ${days} days`);
77
- const now = new Date();
78
- const startDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
79
- // Collect all data sources in parallel
80
- const logsDir = path.join(projectRoot, '.timsquad', 'logs');
81
- const ssotDir = path.join(projectRoot, '.timsquad', 'ssot');
82
- const sessionsDir = path.join(projectRoot, '.timsquad', 'logs', 'sessions');
83
- const [logStats, feedbackStats, ssotStats, sessionStats, metaIndexStats] = await Promise.all([
84
- collectLogStats(logsDir, startDate),
85
- collectFeedbackStats(logsDir, startDate),
86
- collectSSOTStats(ssotDir),
87
- collectSessionStats(sessionsDir, startDate),
88
- collectMetaIndexStats(projectRoot),
89
- ]);
90
- const metrics = {
91
- collectedAt: getTimestamp(),
92
- period: {
93
- start: startDate.toISOString().split('T')[0],
94
- end: now.toISOString().split('T')[0],
95
- },
96
- logs: logStats,
97
- feedback: feedbackStats,
98
- ssot: ssotStats,
99
- sessions: sessionStats,
100
- ...(metaIndexStats ? { metaIndex: metaIndexStats } : {}),
101
- };
102
- // Save metrics
103
- const metricsDir = path.join(projectRoot, '.timsquad', 'retrospective', 'metrics');
104
- await fs.ensureDir(metricsDir);
105
- const metricsFile = path.join(metricsDir, `metrics-${getDateString()}.json`);
106
- await fs.writeJson(metricsFile, metrics, { spaces: 2 });
107
- printSuccess('Metrics collected');
108
- console.log(colors.path(`\nSaved to: ${metricsFile}`));
109
- console.log('');
110
- await displayMetrics(metrics);
111
- }
112
- // ============================================================
113
- // Log Statistics
114
- // ============================================================
115
- async function collectLogStats(logsDir, startDate) {
116
- const stats = {
117
- total: 0,
118
- byAgent: {},
119
- byType: {},
120
- decisionRatio: 0,
121
- errorRate: 0,
122
- };
123
- if (!await exists(logsDir))
124
- return stats;
125
- const startDateStr = startDate.toISOString().split('T')[0];
126
- // ── Phase 1: Task JSON 수집 (primary) ──
127
- const tasksDir = path.join(logsDir, 'tasks');
128
- if (await exists(tasksDir)) {
129
- const taskFiles = await listFiles('*.json', tasksDir);
130
- const taskEntries = [];
131
- for (const file of taskFiles) {
132
- try {
133
- const data = await fs.readJson(path.join(tasksDir, file));
134
- // completed_at 기반 날짜 필터
135
- if (data.completed_at) {
136
- const taskDate = data.completed_at?.split('T')[0];
137
- if (taskDate < startDateStr)
138
- continue;
139
- }
140
- taskEntries.push(data);
141
- }
142
- catch {
143
- // 파싱 불가 파일 무시
144
- }
145
- }
146
- if (taskEntries.length > 0) {
147
- const taskStats = {
148
- total: taskEntries.length,
149
- completed: 0,
150
- failed: 0,
151
- successRate: 0,
152
- byAgent: {},
153
- totalFilesChanged: 0,
154
- avgFilesPerTask: 0,
155
- fileActions: {},
156
- withErrors: 0,
157
- errorTypes: {},
158
- withSemantic: 0,
159
- semanticCoverage: 0,
160
- };
161
- for (const task of taskEntries) {
162
- const isSuccess = task.status === 'completed' || task.status === 'success';
163
- if (isSuccess) {
164
- taskStats.completed++;
165
- }
166
- else {
167
- taskStats.failed++;
168
- }
169
- // 에이전트별 카운트
170
- const agent = task.agent || 'unknown';
171
- if (!taskStats.byAgent[agent]) {
172
- taskStats.byAgent[agent] = { total: 0, completed: 0, failed: 0 };
173
- }
174
- taskStats.byAgent[agent].total++;
175
- if (isSuccess) {
176
- taskStats.byAgent[agent].completed++;
177
- }
178
- else {
179
- taskStats.byAgent[agent].failed++;
180
- }
181
- // 기존 byAgent에도 반영
182
- stats.byAgent[agent] = (stats.byAgent[agent] || 0) + 1;
183
- // 파일 변경 집계
184
- const files = task.mechanical?.files || [];
185
- taskStats.totalFilesChanged += files.length;
186
- for (const f of files) {
187
- const action = f.action || 'U';
188
- taskStats.fileActions[action] = (taskStats.fileActions[action] || 0) + 1;
189
- }
190
- // 에러 집계
191
- if (task.error) {
192
- taskStats.withErrors++;
193
- const errorType = task.error.type || 'unknown';
194
- taskStats.errorTypes[errorType] = (taskStats.errorTypes[errorType] || 0) + 1;
195
- }
196
- // semantic 채움 여부
197
- const sem = task.semantic || {};
198
- const hasSemantic = !!(sem.summary ||
199
- (sem.decisions && sem.decisions.length > 0) ||
200
- (sem.issues && sem.issues.length > 0) ||
201
- (sem.techniques && sem.techniques.length > 0));
202
- if (hasSemantic) {
203
- taskStats.withSemantic++;
204
- }
205
- }
206
- // 파생 지표
207
- taskStats.successRate = taskStats.total > 0
208
- ? Math.round((taskStats.completed / taskStats.total) * 100) : 0;
209
- taskStats.avgFilesPerTask = taskStats.total > 0
210
- ? Math.round((taskStats.totalFilesChanged / taskStats.total) * 10) / 10 : 0;
211
- taskStats.semanticCoverage = taskStats.total > 0
212
- ? Math.round((taskStats.withSemantic / taskStats.total) * 100) : 0;
213
- stats.tasks = taskStats;
214
- stats.total += taskEntries.length;
215
- }
216
- }
217
- // ── Phase 2: 마크다운 폴백 (기존 로직 유지) ──
218
- const mdFiles = await listFiles('*.md', logsDir);
219
- for (const file of mdFiles) {
220
- if (file.startsWith('_'))
221
- continue;
222
- const match = file.match(/^(\d{4}-\d{2}-\d{2})-([a-z]+)\.md$/);
223
- if (!match)
224
- continue;
225
- const [, dateStr, agent] = match;
226
- if (dateStr < startDateStr)
227
- continue;
228
- stats.total++;
229
- stats.byAgent[agent] = (stats.byAgent[agent] || 0) + 1;
230
- try {
231
- const content = await readFile(path.join(logsDir, file));
232
- // log.sh 형식: ## [HH:MM:SS] type
233
- const workEntries = (content.match(/## \[[\d:]+\] work/g) || []).length;
234
- const errorEntries = (content.match(/## \[[\d:]+\] error/g) || []).length;
235
- const decisionEntries = (content.match(/## \[[\d:]+\] decision/g) || []).length;
236
- stats.byType['work'] = (stats.byType['work'] || 0) + workEntries;
237
- stats.byType['error'] = (stats.byType['error'] || 0) + errorEntries;
238
- stats.byType['decision'] = (stats.byType['decision'] || 0) + decisionEntries;
239
- }
240
- catch {
241
- // Ignore read errors
242
- }
243
- }
244
- // 파생 지표 계산 (마크다운 기반)
245
- const totalEntries = Object.values(stats.byType).reduce((a, b) => a + b, 0);
246
- if (totalEntries > 0) {
247
- stats.decisionRatio = Math.round(((stats.byType['decision'] || 0) / totalEntries) * 100);
248
- stats.errorRate = Math.round(((stats.byType['error'] || 0) / totalEntries) * 100);
249
- }
250
- return stats;
251
- }
252
- // ============================================================
253
- // Feedback Statistics
254
- // ============================================================
255
- async function collectFeedbackStats(logsDir, startDate) {
256
- const stats = { total: 0, byLevel: {} };
257
- // Structured JSON feedback (우선)
258
- const projectRoot = path.dirname(logsDir.replace(/\/.timsquad\/logs$/, ''));
259
- const structuredDir = path.join(projectRoot, '.timsquad', 'feedback');
260
- if (await exists(structuredDir)) {
261
- const jsonFiles = await listFiles('FB-*.json', structuredDir);
262
- for (const file of jsonFiles) {
263
- try {
264
- const data = await fs.readJson(path.join(structuredDir, file));
265
- if (data.level) {
266
- const level = String(data.level);
267
- stats.byLevel[level] = (stats.byLevel[level] || 0) + 1;
268
- stats.total++;
269
- }
270
- }
271
- catch {
272
- // skip
273
- }
274
- }
275
- }
276
- // Fallback: markdown feedback logs
277
- if (stats.total === 0 && await exists(logsDir)) {
278
- const startDateStr = startDate.toISOString().split('T')[0];
279
- const files = await listFiles('*-feedback.md', logsDir);
280
- for (const file of files) {
281
- const match = file.match(/^(\d{4}-\d{2}-\d{2})-feedback\.md$/);
282
- if (!match)
283
- continue;
284
- const [, dateStr] = match;
285
- if (dateStr < startDateStr)
286
- continue;
287
- try {
288
- const content = await readFile(path.join(logsDir, file));
289
- const level1 = (content.match(/\[Level 1\]/g) || []).length;
290
- const level2 = (content.match(/\[Level 2\]/g) || []).length;
291
- const level3 = (content.match(/\[Level 3\]/g) || []).length;
292
- stats.byLevel['1'] = (stats.byLevel['1'] || 0) + level1;
293
- stats.byLevel['2'] = (stats.byLevel['2'] || 0) + level2;
294
- stats.byLevel['3'] = (stats.byLevel['3'] || 0) + level3;
295
- stats.total += level1 + level2 + level3;
296
- }
297
- catch {
298
- // skip
299
- }
300
- }
301
- }
302
- return stats;
303
- }
304
- // ============================================================
305
- // SSOT Statistics
306
- // ============================================================
307
- async function collectSSOTStats(ssotDir) {
308
- const stats = {
309
- documentsCount: 0,
310
- filledCount: 0,
311
- completionRate: 0,
312
- };
313
- if (!await exists(ssotDir))
314
- return stats;
315
- const files = await listFiles('*.md', ssotDir);
316
- for (const file of files) {
317
- if (file.includes('template'))
318
- continue;
319
- stats.documentsCount++;
320
- try {
321
- const content = await readFile(path.join(ssotDir, file));
322
- const cleanContent = content
323
- .replace(/^#.*$/gm, '')
324
- .replace(/^\s*$/gm, '')
325
- .trim();
326
- if (cleanContent.length > 200) {
327
- stats.filledCount++;
328
- }
329
- }
330
- catch {
331
- // skip
332
- }
333
- }
334
- stats.completionRate = stats.documentsCount > 0
335
- ? Math.round((stats.filledCount / stats.documentsCount) * 100)
336
- : 0;
337
- return stats;
338
- }
339
- // ============================================================
340
- // Meta Index Statistics
341
- // ============================================================
342
- async function collectMetaIndexStats(projectRoot) {
343
- const summaryPath = path.join(projectRoot, '.timsquad', 'state', 'meta-index', 'summary.json');
344
- if (!await exists(summaryPath))
345
- return undefined;
346
- try {
347
- const summary = await fs.readJson(summaryPath);
348
- const result = {
349
- totalFiles: summary.totalFiles || 0,
350
- totalMethods: summary.totalMethods || 0,
351
- healthScore: summary.health?.overall || 0,
352
- freshness: summary.health?.freshness || 0,
353
- semanticCoverage: summary.health?.semanticCoverage || 0,
354
- driftedFiles: summary.alerts?.driftDetected?.length || 0,
355
- alertCount: (summary.alerts?.oversizedFiles?.length || 0) +
356
- (summary.alerts?.missingSemantics?.length || 0) +
357
- (summary.alerts?.driftDetected?.length || 0),
358
- };
359
- // UI Health (있을 때만)
360
- if (summary.uiHealth) {
361
- result.uiComponents = summary.uiHealth.componentCount || 0;
362
- result.uiHealthScore = summary.uiHealth.overall || 0;
363
- result.uiSemanticCoverage = summary.uiHealth.semanticCoverage || 0;
364
- result.uiAccessibilityCoverage = summary.uiHealth.accessibilityCoverage || 0;
365
- }
366
- return result;
367
- }
368
- catch {
369
- return undefined;
370
- }
371
- }
372
- // ============================================================
373
- // Session Statistics (세션 이벤트 기반 품질 지표)
374
- // ============================================================
375
- async function collectSessionStats(sessionsDir, startDate) {
376
- const stats = {
377
- totalSessions: 0,
378
- totalEvents: 0,
379
- totalToolUses: 0,
380
- totalFailures: 0,
381
- toolEfficiency: 0,
382
- subagentCount: 0,
383
- tokens: {
384
- totalInput: 0,
385
- totalOutput: 0,
386
- totalCacheCreate: 0,
387
- totalCacheRead: 0,
388
- cacheHitRate: 0,
389
- avgOutputPerTurn: 0,
390
- maxOutputPerTurn: 0,
391
- },
392
- toolBreakdown: {},
393
- cliAdoption: {
394
- totalBashCommands: 0,
395
- tsqCommands: 0,
396
- adoptionRate: 0,
397
- },
398
- };
399
- if (!await exists(sessionsDir))
400
- return stats;
401
- const files = await listFiles('*.jsonl', sessionsDir);
402
- const startDateStr = startDate.toISOString().split('T')[0];
403
- const allTurnOutputs = [];
404
- for (const file of files) {
405
- // 날짜 필터
406
- const dateStr = file.split('-').slice(0, 3).join('-');
407
- if (dateStr < startDateStr)
408
- continue;
409
- stats.totalSessions++;
410
- try {
411
- const content = await readFile(path.join(sessionsDir, file));
412
- const events = [];
413
- for (const line of content.split('\n')) {
414
- const trimmed = line.trim();
415
- if (!trimmed)
416
- continue;
417
- try {
418
- events.push(JSON.parse(trimmed));
419
- }
420
- catch { /* skip */ }
421
- }
422
- stats.totalEvents += events.length;
423
- for (const ev of events) {
424
- // 도구 사용 통계
425
- if (ev.event === 'PostToolUse') {
426
- stats.totalToolUses++;
427
- if (ev.tool) {
428
- stats.toolBreakdown[ev.tool] = (stats.toolBreakdown[ev.tool] || 0) + 1;
429
- }
430
- // CLI 채택률: Bash 명령 중 tsq 사용 비율
431
- if (ev.tool === 'Bash') {
432
- stats.cliAdoption.totalBashCommands++;
433
- const cmd = ev.detail?.command || '';
434
- if (cmd.match(/^(tsq|npx tsq)\s/)) {
435
- stats.cliAdoption.tsqCommands++;
436
- }
437
- }
438
- }
439
- if (ev.event === 'PostToolUseFailure')
440
- stats.totalFailures++;
441
- if (ev.event === 'SubagentStart')
442
- stats.subagentCount++;
443
- // 토큰 (Stop 이벤트에서 턴별 수집)
444
- if (ev.event === 'Stop' && ev.usage) {
445
- allTurnOutputs.push(ev.usage.output || 0);
446
- }
447
- // 토큰 (SessionEnd에서 세션 합산)
448
- if (ev.event === 'SessionEnd' && ev.total_usage) {
449
- stats.tokens.totalInput += ev.total_usage.total_input || 0;
450
- stats.tokens.totalOutput += ev.total_usage.total_output || 0;
451
- stats.tokens.totalCacheCreate += ev.total_usage.total_cache_create || 0;
452
- stats.tokens.totalCacheRead += ev.total_usage.total_cache_read || 0;
453
- }
454
- }
455
- }
456
- catch {
457
- // skip unreadable files
458
- }
459
- }
460
- // 파생 지표 계산
461
- const totalToolAttempts = stats.totalToolUses + stats.totalFailures;
462
- stats.toolEfficiency = totalToolAttempts > 0
463
- ? Math.round((stats.totalToolUses / totalToolAttempts) * 100) : 0;
464
- const allInput = stats.tokens.totalInput + stats.tokens.totalCacheCreate + stats.tokens.totalCacheRead;
465
- stats.tokens.cacheHitRate = allInput > 0
466
- ? Math.round((stats.tokens.totalCacheRead / allInput) * 100) : 0;
467
- if (allTurnOutputs.length > 0) {
468
- stats.tokens.avgOutputPerTurn = Math.round(allTurnOutputs.reduce((a, b) => a + b, 0) / allTurnOutputs.length);
469
- stats.tokens.maxOutputPerTurn = Math.max(...allTurnOutputs);
470
- }
471
- stats.cliAdoption.adoptionRate = stats.cliAdoption.totalBashCommands > 0
472
- ? Math.round((stats.cliAdoption.tsqCommands / stats.cliAdoption.totalBashCommands) * 100) : 0;
473
- return stats;
474
- }
475
- // ============================================================
476
- // Display
477
- // ============================================================
478
- async function displayMetrics(metrics) {
479
- printKeyValue('Collected at', metrics.collectedAt);
480
- printKeyValue('Period', `${metrics.period.start} ~ ${metrics.period.end}`);
481
- // ── 프로세스 지표 ──
482
- console.log(colors.subheader('\n Process Metrics'));
483
- console.log(colors.dim(' 에이전트 작업 기록 현황. 프로세스 준수도를 나타냄\n'));
484
- printKeyValue(' Log files', String(metrics.logs.total));
485
- if (Object.keys(metrics.logs.byAgent).length > 0) {
486
- console.log(colors.dim(' By Agent:'));
487
- Object.entries(metrics.logs.byAgent)
488
- .sort((a, b) => b[1] - a[1])
489
- .forEach(([agent, count]) => {
490
- console.log(` ${agent.padEnd(12)} ${colors.highlight(String(count))}`);
491
- });
492
- }
493
- if (Object.keys(metrics.logs.byType).length > 0) {
494
- console.log(colors.dim(' By Type:'));
495
- Object.entries(metrics.logs.byType)
496
- .sort((a, b) => b[1] - a[1])
497
- .forEach(([type, count]) => {
498
- console.log(` ${type.padEnd(12)} ${colors.highlight(String(count))}`);
499
- });
500
- }
501
- printKeyValue(' Decision Ratio', `${metrics.logs.decisionRatio}%`);
502
- console.log(colors.dim(' 의사결정 기록 비율. 높을수록 결정 추적 가능'));
503
- printKeyValue(' Error Rate', `${metrics.logs.errorRate}%`);
504
- console.log(colors.dim(' 에러 로그 비율. 낮을수록 안정적'));
505
- // ── 태스크 지표 ──
506
- if (metrics.logs.tasks && metrics.logs.tasks.total > 0) {
507
- const t = metrics.logs.tasks;
508
- console.log(colors.subheader('\n Task Metrics'));
509
- console.log(colors.dim(' 서브에이전트 태스크 실행 결과. 작업 품질과 효율성 추적\n'));
510
- printKeyValue(' Total tasks', String(t.total));
511
- printKeyValue(' Completed', `${t.completed} (${t.successRate}%)`);
512
- if (t.failed > 0) {
513
- printKeyValue(' Failed', String(t.failed));
514
- }
515
- if (Object.keys(t.byAgent).length > 0) {
516
- console.log(colors.dim(' By Agent:'));
517
- Object.entries(t.byAgent)
518
- .sort(([, a], [, b]) => b.total - a.total)
519
- .forEach(([agent, data]) => {
520
- const rate = data.total > 0 ? Math.round((data.completed / data.total) * 100) : 0;
521
- console.log(` ${agent.padEnd(12)} ${colors.highlight(String(data.total))} tasks, ${rate}% success`);
522
- });
523
- }
524
- printKeyValue(' Files changed', String(t.totalFilesChanged));
525
- printKeyValue(' Avg files/task', String(t.avgFilesPerTask));
526
- if (Object.keys(t.fileActions).length > 0) {
527
- const actionLabels = { 'A': 'Added', 'M': 'Modified', 'D': 'Deleted', 'R': 'Renamed' };
528
- console.log(colors.dim(' File actions:'));
529
- Object.entries(t.fileActions)
530
- .sort(([, a], [, b]) => b - a)
531
- .forEach(([action, count]) => {
532
- const label = actionLabels[action] || action;
533
- console.log(` ${(action + '(' + label + ')').padEnd(16)} ${colors.highlight(String(count))}`);
534
- });
535
- }
536
- printKeyValue(' Semantic coverage', `${t.semanticCoverage}%`);
537
- console.log(colors.dim(' semantic 필드 채움 비율. PM이 에이전트 리턴에서 병합'));
538
- if (t.withErrors > 0) {
539
- printKeyValue(' Tasks with errors', String(t.withErrors));
540
- if (Object.keys(t.errorTypes).length > 0) {
541
- console.log(colors.dim(' Error types:'));
542
- Object.entries(t.errorTypes)
543
- .sort(([, a], [, b]) => b - a)
544
- .forEach(([type, count]) => {
545
- console.log(` ${type.padEnd(20)} ${colors.highlight(String(count))}`);
546
- });
547
- }
548
- }
549
- }
550
- // ── 피드백 지표 ──
551
- console.log(colors.subheader('\n Feedback Metrics'));
552
- console.log(colors.dim(' 피드백 레벨별 분포. Level 3이 잦으면 요구사항 정의 개선 필요\n'));
553
- printKeyValue(' Total feedback', String(metrics.feedback.total));
554
- if (Object.keys(metrics.feedback.byLevel).length > 0) {
555
- const levelDesc = {
556
- '1': '구현 수정 - 경미한 코드 수정 (정상적 개발 과정)',
557
- '2': '설계 수정 - SSOT 변경 필요 (빈번하면 초기 설계 검토)',
558
- '3': '기획 수정 - 요구사항 재검토 (잦으면 기획 프로세스 개선)',
559
- };
560
- ['1', '2', '3'].forEach(level => {
561
- const count = metrics.feedback.byLevel[level] || 0;
562
- const bar = count > 0 ? ' ' + '█'.repeat(Math.min(count, 20)) : '';
563
- console.log(` Level ${level} ${colors.highlight(String(count).padStart(3))}${colors.dim(bar)}`);
564
- console.log(colors.dim(` ${levelDesc[level]}`));
565
- });
566
- }
567
- // ── SSOT 지표 ──
568
- console.log(colors.subheader('\n SSOT Health'));
569
- console.log(colors.dim(' 문서 기반 개발 성숙도. 100%에 가까울수록 SSOT 운영 양호\n'));
570
- printKeyValue(' Documents', `${metrics.ssot.filledCount}/${metrics.ssot.documentsCount}`);
571
- printKeyValue(' Completion', `${metrics.ssot.completionRate}%`);
572
- if (metrics.ssot.completionRate < 50) {
573
- console.log(colors.dim(' SSOT 완성률이 낮음. 문서 작성을 우선 진행하세요'));
574
- }
575
- // ── Meta Index 지표 ──
576
- if (metrics.metaIndex) {
577
- const mi = metrics.metaIndex;
578
- console.log(colors.subheader('\n Meta Index Health'));
579
- console.log(colors.dim(' 코드 구조 인덱스 건강도. AST 기반 자동 생성\n'));
580
- printKeyValue(' Files indexed', String(mi.totalFiles));
581
- printKeyValue(' Methods', String(mi.totalMethods));
582
- printKeyValue(' Health Score', `${mi.healthScore}%`);
583
- printKeyValue(' Freshness', `${mi.freshness}%`);
584
- console.log(colors.dim(' 인덱스가 최신인 파일 비율'));
585
- printKeyValue(' Semantic Coverage', `${mi.semanticCoverage}%`);
586
- console.log(colors.dim(' semantic 데이터가 있는 파일 비율'));
587
- if (mi.driftedFiles > 0) {
588
- printKeyValue(' Drifted files', `${mi.driftedFiles}`);
589
- console.log(colors.dim(' 파이프라인 외부에서 변경된 파일. `tsq mi check`로 상세 확인'));
590
- }
591
- if (mi.alertCount > 0) {
592
- printKeyValue(' Alerts', String(mi.alertCount));
593
- }
594
- // UI Components (있을 때만)
595
- if (mi.uiComponents && mi.uiComponents > 0) {
596
- console.log('');
597
- printKeyValue(' UI Components', String(mi.uiComponents));
598
- printKeyValue(' UI Health Score', `${mi.uiHealthScore || 0}%`);
599
- printKeyValue(' UI Semantic', `${mi.uiSemanticCoverage || 0}%`);
600
- console.log(colors.dim(' 디자인 의도가 기록된 컴포넌트 비율'));
601
- printKeyValue(' Accessibility', `${mi.uiAccessibilityCoverage || 0}%`);
602
- console.log(colors.dim(' 접근성 메타가 있는 컴포넌트 비율'));
603
- }
604
- }
605
- // ── 세션 지표 ──
606
- const s = metrics.sessions;
607
- console.log(colors.subheader('\n Session & Token Metrics'));
608
- console.log(colors.dim(' Claude Code 세션 활동. 토큰 효율과 에이전트 정확도 추적\n'));
609
- printKeyValue(' Sessions', String(s.totalSessions));
610
- printKeyValue(' Total events', String(s.totalEvents));
611
- printKeyValue(' Tool uses', String(s.totalToolUses));
612
- printKeyValue(' Failures', String(s.totalFailures));
613
- printKeyValue(' Tool Efficiency', `${s.toolEfficiency}%`);
614
- console.log(colors.dim(' 도구 성공률. 95%+ 정상, 90% 미만이면 에이전트 프롬프트 점검'));
615
- if (s.subagentCount > 0) {
616
- printKeyValue(' Subagents', String(s.subagentCount));
617
- }
618
- // 토큰
619
- if (s.tokens.available === false && s.tokens.totalOutput === 0) {
620
- console.log('');
621
- console.log(colors.dim(' Token Usage: N/A (hook 기반 모드에서 토큰 데이터 미수신)'));
622
- }
623
- else if (s.tokens.totalOutput > 0) {
624
- console.log('');
625
- console.log(colors.dim(' Token Usage:'));
626
- printKeyValue(' Input', formatTokens(s.tokens.totalInput));
627
- printKeyValue(' Output', formatTokens(s.tokens.totalOutput));
628
- printKeyValue(' Cache Create', formatTokens(s.tokens.totalCacheCreate));
629
- printKeyValue(' Cache Read', formatTokens(s.tokens.totalCacheRead));
630
- printKeyValue(' Cache Hit Rate', `${s.tokens.cacheHitRate}%`);
631
- if (s.tokens.cacheHitRate >= 80) {
632
- console.log(colors.dim(' 우수 - 프롬프트 구조 안정, 캐시 효율 높음'));
633
- }
634
- else if (s.tokens.cacheHitRate >= 60) {
635
- console.log(colors.dim(' 보통 - 일부 프롬프트 변경으로 캐시 미스 발생'));
636
- }
637
- else {
638
- console.log(colors.dim(' 주의 - 프롬프트 구조 불안정, 캐시 효율 낮음. CLAUDE.md 검토 필요'));
639
- }
640
- printKeyValue(' Avg Output/Turn', formatTokens(s.tokens.avgOutputPerTurn));
641
- console.log(colors.dim(' 턴당 평균 출력 토큰. 비정상적으로 높으면 응답이 불필요하게 장황'));
642
- printKeyValue(' Max Output/Turn', formatTokens(s.tokens.maxOutputPerTurn));
643
- console.log(colors.dim(' 최대 출력 토큰. 이상치 턴 감지용'));
644
- }
645
- // 도구 분포
646
- if (Object.keys(s.toolBreakdown).length > 0) {
647
- console.log('');
648
- console.log(colors.dim(' Tool Breakdown:'));
649
- const sorted = Object.entries(s.toolBreakdown).sort(([, a], [, b]) => b - a);
650
- for (const [tool, count] of sorted.slice(0, 8)) {
651
- const bar = '█'.repeat(Math.min(Math.round(count / Math.max(1, sorted[0][1]) * 20), 20));
652
- console.log(` ${colors.primary(tool.padEnd(12))} ${colors.dim(bar)} ${count}`);
653
- }
654
- }
655
- // CLI 채택률
656
- if (s.cliAdoption.totalBashCommands > 0) {
657
- console.log('');
658
- printKeyValue(' CLI Adoption', `${s.cliAdoption.adoptionRate}% (${s.cliAdoption.tsqCommands}/${s.cliAdoption.totalBashCommands} Bash commands)`);
659
- console.log(colors.dim(' Bash 명령 중 tsq CLI 사용 비율. 높을수록 프레임워크 정착도 높음'));
660
- }
661
- }
662
- // ============================================================
663
- // Trend (시계열 비교)
664
- // ============================================================
665
- async function showTrend(count) {
666
- const projectRoot = await findProjectRoot();
667
- if (!projectRoot)
668
- throw new Error('Not a TimSquad project');
669
- const metricsDir = path.join(projectRoot, '.timsquad', 'retrospective', 'metrics');
670
- if (!await exists(metricsDir)) {
671
- console.log(colors.dim('No metrics collected yet. Run: tsq metrics collect'));
672
- return;
673
- }
674
- const files = await listFiles('metrics-*.json', metricsDir);
675
- files.sort().reverse();
676
- if (files.length < 2) {
677
- console.log(colors.dim('Need at least 2 collection periods for trend analysis.'));
678
- console.log(colors.dim('Run: tsq metrics collect --days 7'));
679
- return;
680
- }
681
- printHeader('Metrics Trend');
682
- console.log(colors.dim(' 핵심 지표의 시계열 변화. 우측이 최신.\n'));
683
- const periods = [];
684
- for (const file of files.slice(0, count).reverse()) {
685
- const data = await fs.readJson(path.join(metricsDir, file));
686
- periods.push(data);
687
- }
688
- // 헤더
689
- const dates = periods.map(p => p.period.end.slice(5)); // MM-DD
690
- console.log(` ${'Metric'.padEnd(22)} ${dates.map(d => d.padStart(8)).join('')}`);
691
- console.log(colors.dim(` ${'─'.repeat(22 + dates.length * 8)}`));
692
- // SSOT Completion
693
- const ssotValues = periods.map(p => `${p.ssot.completionRate}%`);
694
- console.log(` ${'SSOT Completion'.padEnd(22)} ${ssotValues.map(v => v.padStart(8)).join('')}`);
695
- // Feedback Total
696
- const fbValues = periods.map(p => String(p.feedback.total));
697
- console.log(` ${'Feedback Count'.padEnd(22)} ${fbValues.map(v => v.padStart(8)).join('')}`);
698
- // Decision Ratio
699
- const drValues = periods.map(p => `${p.logs.decisionRatio || 0}%`);
700
- console.log(` ${'Decision Ratio'.padEnd(22)} ${drValues.map(v => v.padStart(8)).join('')}`);
701
- // Error Rate
702
- const erValues = periods.map(p => `${p.logs.errorRate || 0}%`);
703
- console.log(` ${'Error Rate'.padEnd(22)} ${erValues.map(v => v.padStart(8)).join('')}`);
704
- // Task metrics (if available)
705
- if (periods.some(p => p.logs.tasks && p.logs.tasks.total > 0)) {
706
- console.log('');
707
- const tsrValues = periods.map(p => p.logs.tasks ? `${p.logs.tasks.successRate}%` : '-');
708
- console.log(` ${'Task Success Rate'.padEnd(22)} ${tsrValues.map(v => v.padStart(8)).join('')}`);
709
- const tscValues = periods.map(p => p.logs.tasks ? String(p.logs.tasks.total) : '-');
710
- console.log(` ${'Task Count'.padEnd(22)} ${tscValues.map(v => v.padStart(8)).join('')}`);
711
- const semValues = periods.map(p => p.logs.tasks ? `${p.logs.tasks.semanticCoverage}%` : '-');
712
- console.log(` ${'Semantic Coverage'.padEnd(22)} ${semValues.map(v => v.padStart(8)).join('')}`);
713
- }
714
- // Meta Index metrics (if available)
715
- if (periods.some(p => p.metaIndex)) {
716
- console.log('');
717
- const mhValues = periods.map(p => p.metaIndex ? `${p.metaIndex.healthScore}%` : '-');
718
- console.log(` ${'Meta Health'.padEnd(22)} ${mhValues.map(v => v.padStart(8)).join('')}`);
719
- // UI Health trend (있을 때만)
720
- if (periods.some(p => p.metaIndex?.uiComponents && p.metaIndex.uiComponents > 0)) {
721
- const uhValues = periods.map(p => p.metaIndex?.uiHealthScore ? `${p.metaIndex.uiHealthScore}%` : '-');
722
- console.log(` ${'UI Health'.padEnd(22)} ${uhValues.map(v => v.padStart(8)).join('')}`);
723
- }
724
- }
725
- // Session metrics (if available)
726
- if (periods.some(p => p.sessions?.totalSessions > 0)) {
727
- console.log('');
728
- const teValues = periods.map(p => `${p.sessions?.toolEfficiency || 0}%`);
729
- console.log(` ${'Tool Efficiency'.padEnd(22)} ${teValues.map(v => v.padStart(8)).join('')}`);
730
- const chValues = periods.map(p => `${p.sessions?.tokens.cacheHitRate || 0}%`);
731
- console.log(` ${'Cache Hit Rate'.padEnd(22)} ${chValues.map(v => v.padStart(8)).join('')}`);
732
- const aoValues = periods.map(p => formatTokens(p.sessions?.tokens.avgOutputPerTurn || 0));
733
- console.log(` ${'Avg Output/Turn'.padEnd(22)} ${aoValues.map(v => v.padStart(8)).join('')}`);
734
- const caValues = periods.map(p => `${p.sessions?.cliAdoption.adoptionRate || 0}%`);
735
- console.log(` ${'CLI Adoption'.padEnd(22)} ${caValues.map(v => v.padStart(8)).join('')}`);
736
- }
737
- // 변화 분석
738
- if (periods.length >= 2) {
739
- const prev = periods[periods.length - 2];
740
- const curr = periods[periods.length - 1];
741
- console.log(colors.subheader('\n Changes (latest vs previous):'));
742
- const changes = [];
743
- const ssotDelta = curr.ssot.completionRate - prev.ssot.completionRate;
744
- if (ssotDelta !== 0) {
745
- changes.push(` SSOT Completion: ${ssotDelta > 0 ? colors.success(`+${ssotDelta}%`) : colors.error(`${ssotDelta}%`)}`);
746
- }
747
- if (curr.logs.tasks && prev.logs.tasks) {
748
- const taskDelta = curr.logs.tasks.successRate - prev.logs.tasks.successRate;
749
- if (taskDelta !== 0) {
750
- changes.push(` Task Success: ${taskDelta > 0 ? colors.success(`+${taskDelta}%`) : colors.error(`${taskDelta}%`)}`);
751
- }
752
- }
753
- if (curr.metaIndex && prev.metaIndex) {
754
- const metaDelta = curr.metaIndex.healthScore - prev.metaIndex.healthScore;
755
- if (metaDelta !== 0) {
756
- changes.push(` Meta Health: ${metaDelta > 0 ? colors.success(`+${metaDelta}%`) : colors.error(`${metaDelta}%`)}`);
757
- }
758
- }
759
- if (curr.sessions && prev.sessions) {
760
- const cacheDelta = curr.sessions.tokens.cacheHitRate - prev.sessions.tokens.cacheHitRate;
761
- if (cacheDelta !== 0) {
762
- changes.push(` Cache Hit Rate: ${cacheDelta > 0 ? colors.success(`+${cacheDelta}%`) : colors.error(`${cacheDelta}%`)}`);
763
- }
764
- const effDelta = curr.sessions.toolEfficiency - prev.sessions.toolEfficiency;
765
- if (effDelta !== 0) {
766
- changes.push(` Tool Efficiency: ${effDelta > 0 ? colors.success(`+${effDelta}%`) : colors.error(`${effDelta}%`)}`);
767
- }
768
- }
769
- if (changes.length > 0) {
770
- changes.forEach(c => console.log(c));
771
- }
772
- else {
773
- console.log(colors.dim(' No significant changes detected.'));
774
- }
775
- }
776
- }
777
- // ============================================================
778
- // Summary
779
- // ============================================================
780
- async function showMetricsSummary() {
781
- const projectRoot = await findProjectRoot();
782
- if (!projectRoot)
783
- throw new Error('Not a TimSquad project');
784
- printHeader('Metrics Summary');
785
- const metricsDir = path.join(projectRoot, '.timsquad', 'retrospective', 'metrics');
786
- if (!await exists(metricsDir)) {
787
- console.log(colors.dim('No metrics collected yet'));
788
- console.log(colors.dim('\nRun: tsq metrics collect'));
789
- return;
790
- }
791
- const files = await listFiles('metrics-*.json', metricsDir);
792
- files.sort().reverse();
793
- if (files.length === 0) {
794
- console.log(colors.dim('No metrics collected yet'));
795
- console.log(colors.dim('\nRun: tsq metrics collect'));
796
- return;
797
- }
798
- const latestFile = path.join(metricsDir, files[0]);
799
- const metrics = await fs.readJson(latestFile);
800
- await displayMetrics(metrics);
801
- }
802
- // ============================================================
803
- // Export
804
- // ============================================================
805
- async function exportMetrics(outputPath) {
806
- const projectRoot = await findProjectRoot();
807
- if (!projectRoot)
808
- throw new Error('Not a TimSquad project');
809
- const metricsDir = path.join(projectRoot, '.timsquad', 'retrospective', 'metrics');
810
- if (!await exists(metricsDir)) {
811
- throw new Error('No metrics collected yet. Run: tsq metrics collect');
812
- }
813
- const files = await listFiles('metrics-*.json', metricsDir);
814
- if (files.length === 0) {
815
- throw new Error('No metrics collected yet. Run: tsq metrics collect');
816
- }
817
- const allMetrics = [];
818
- for (const file of files.sort()) {
819
- const data = await fs.readJson(path.join(metricsDir, file));
820
- allMetrics.push(data);
821
- }
822
- const output = outputPath || path.join(projectRoot, `timsquad-metrics-export-${getDateString()}.json`);
823
- const exportData = {
824
- exportedAt: getTimestamp(),
825
- projectRoot,
826
- metricsCount: allMetrics.length,
827
- metrics: allMetrics,
828
- };
829
- await fs.writeJson(output, exportData, { spaces: 2 });
830
- printSuccess('Metrics exported');
831
- console.log(colors.path(`\n${output}`));
832
- }
833
- // ============================================================
834
- // Helpers
835
- // ============================================================
836
- function formatTokens(tokens) {
837
- if (tokens < 1000)
838
- return String(tokens);
839
- if (tokens < 1000000)
840
- return `${(tokens / 1000).toFixed(1)}K`;
841
- return `${(tokens / 1000000).toFixed(2)}M`;
842
- }
843
- //# sourceMappingURL=metrics.js.map