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,1468 +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, writeFile, listFiles } from '../utils/fs.js';
6
- import { getDateString, getTimeString, getTimestamp } from '../utils/date.js';
7
- import { loadWorkflowState } from '../lib/workflow-state.js';
8
- const LOG_TYPES = ['work', 'decision', 'error', 'feedback', 'handoff'];
9
- const LOG_SCHEMA_VERSION = '1.0.0';
10
- export function registerLogCommand(program) {
11
- const logCmd = program
12
- .command('log')
13
- .description('Manage work logs');
14
- // tsq log add <agent> <type> [message]
15
- logCmd
16
- .command('add <agent> <type> [message]')
17
- .description('Add a log entry')
18
- .action(async (agent, type, message) => {
19
- try {
20
- await addLog(agent, type, message);
21
- }
22
- catch (error) {
23
- printError(error.message);
24
- process.exit(1);
25
- }
26
- });
27
- // tsq log list [agent]
28
- logCmd
29
- .command('list [agent]')
30
- .description('List log files')
31
- .action(async (agent) => {
32
- try {
33
- await listLogs(agent);
34
- }
35
- catch (error) {
36
- printError(error.message);
37
- process.exit(1);
38
- }
39
- });
40
- // tsq log view <file>
41
- logCmd
42
- .command('view <file>')
43
- .description('View a log file')
44
- .action(async (file) => {
45
- try {
46
- await viewLog(file);
47
- }
48
- catch (error) {
49
- printError(error.message);
50
- process.exit(1);
51
- }
52
- });
53
- // tsq log today [agent]
54
- logCmd
55
- .command('today [agent]')
56
- .description('Show today\'s logs')
57
- .action(async (agent) => {
58
- try {
59
- await showTodayLogs(agent);
60
- }
61
- catch (error) {
62
- printError(error.message);
63
- process.exit(1);
64
- }
65
- });
66
- // tsq log search <keyword>
67
- logCmd
68
- .command('search <keyword>')
69
- .description('Search logs')
70
- .action(async (keyword) => {
71
- try {
72
- await searchLogs(keyword);
73
- }
74
- catch (error) {
75
- printError(error.message);
76
- process.exit(1);
77
- }
78
- });
79
- // tsq log summary [date]
80
- logCmd
81
- .command('summary [date]')
82
- .description('Generate daily summary')
83
- .action(async (date) => {
84
- try {
85
- await generateSummary(date);
86
- }
87
- catch (error) {
88
- printError(error.message);
89
- process.exit(1);
90
- }
91
- });
92
- // tsq log compact
93
- logCmd
94
- .command('compact')
95
- .description('Compress old logs (session JSONL → summary, merge old md)')
96
- .option('--days <n>', 'Keep logs newer than N days', '7')
97
- .option('--dry-run', 'Show what would be compacted without changes')
98
- .action(async (options) => {
99
- try {
100
- await compactLogs(parseInt(options.days, 10), !!options.dryRun);
101
- }
102
- catch (error) {
103
- printError(error.message);
104
- process.exit(1);
105
- }
106
- });
107
- // ── tsq log enrich <agent> ──
108
- logCmd
109
- .command('enrich <agent>')
110
- .description('Enrich latest task log with semantic data')
111
- .requiredOption('--json <data>', 'Semantic data as JSON string')
112
- .action(async (agent, options) => {
113
- try {
114
- await enrichTaskLog(agent, options.json);
115
- }
116
- catch (error) {
117
- printError(error.message);
118
- process.exit(1);
119
- }
120
- });
121
- // ── tsq log task <subcommand> ──
122
- const taskCmd = logCmd
123
- .command('task')
124
- .description('L1 Task log management');
125
- taskCmd
126
- .command('list')
127
- .description('List task logs')
128
- .option('--agent <name>', 'Filter by agent')
129
- .action(async (options) => {
130
- try {
131
- await listTaskLogs(options.agent);
132
- }
133
- catch (error) {
134
- printError(error.message);
135
- process.exit(1);
136
- }
137
- });
138
- taskCmd
139
- .command('view <file>')
140
- .description('View a task log')
141
- .action(async (file) => {
142
- try {
143
- await viewTaskLog(file);
144
- }
145
- catch (error) {
146
- printError(error.message);
147
- process.exit(1);
148
- }
149
- });
150
- taskCmd
151
- .command('stats')
152
- .description('Task log statistics')
153
- .action(async () => {
154
- try {
155
- await showTaskStats();
156
- }
157
- catch (error) {
158
- printError(error.message);
159
- process.exit(1);
160
- }
161
- });
162
- // ── tsq log sequence <subcommand> ──
163
- const seqCmd = logCmd
164
- .command('sequence')
165
- .description('L2 Sequence log management');
166
- seqCmd
167
- .command('list')
168
- .description('List sequence logs')
169
- .action(async () => {
170
- try {
171
- await listSequenceLogs();
172
- }
173
- catch (error) {
174
- printError(error.message);
175
- process.exit(1);
176
- }
177
- });
178
- seqCmd
179
- .command('view <seq-id>')
180
- .description('View a sequence log')
181
- .action(async (seqId) => {
182
- try {
183
- await viewSequenceLog(seqId);
184
- }
185
- catch (error) {
186
- printError(error.message);
187
- process.exit(1);
188
- }
189
- });
190
- seqCmd
191
- .command('create <seq-id>')
192
- .description('Create sequence log from task logs')
193
- .requiredOption('--phase <id>', 'Phase ID')
194
- .requiredOption('--report <path>', 'Architect report path')
195
- .option('--verdict <v>', 'proceed or hold', 'proceed')
196
- .option('--conditions <c>', 'Comma-separated conditions')
197
- .action(async (seqId, options) => {
198
- try {
199
- await createSequenceLog(seqId, options);
200
- }
201
- catch (error) {
202
- printError(error.message);
203
- process.exit(1);
204
- }
205
- });
206
- seqCmd
207
- .command('check <seq-id>')
208
- .description('Check task log completeness for a sequence')
209
- .action(async (seqId) => {
210
- try {
211
- await checkSequence(seqId);
212
- }
213
- catch (error) {
214
- printError(error.message);
215
- process.exit(1);
216
- }
217
- });
218
- // ── tsq log phase <subcommand> ──
219
- const phaseCmd = logCmd
220
- .command('phase')
221
- .description('L3 Phase log management');
222
- phaseCmd
223
- .command('list')
224
- .description('List phase logs')
225
- .action(async () => {
226
- try {
227
- await listPhaseLogs();
228
- }
229
- catch (error) {
230
- printError(error.message);
231
- process.exit(1);
232
- }
233
- });
234
- phaseCmd
235
- .command('view <phase-id>')
236
- .description('View a phase log')
237
- .action(async (phaseId) => {
238
- try {
239
- await viewPhaseLog(phaseId);
240
- }
241
- catch (error) {
242
- printError(error.message);
243
- process.exit(1);
244
- }
245
- });
246
- phaseCmd
247
- .command('create <phase-id>')
248
- .description('Create phase log')
249
- .requiredOption('--sequences <ids>', 'Comma-separated sequence IDs')
250
- .option('--retro-keep <items>', 'Retrospective: keep (comma-separated)')
251
- .option('--retro-problem <items>', 'Retrospective: problems (comma-separated)')
252
- .option('--retro-try <items>', 'Retrospective: try (comma-separated)')
253
- .action(async (phaseId, options) => {
254
- try {
255
- await createPhaseLog(phaseId, options);
256
- }
257
- catch (error) {
258
- printError(error.message);
259
- process.exit(1);
260
- }
261
- });
262
- phaseCmd
263
- .command('gate <phase-id>')
264
- .description('Check phase transition gate')
265
- .action(async (phaseId) => {
266
- try {
267
- await checkPhaseGate(phaseId);
268
- }
269
- catch (error) {
270
- printError(error.message);
271
- process.exit(1);
272
- }
273
- });
274
- }
275
- async function addLog(agent, type, message) {
276
- const projectRoot = await findProjectRoot();
277
- if (!projectRoot) {
278
- throw new Error('Not a TimSquad project');
279
- }
280
- if (!LOG_TYPES.includes(type)) {
281
- throw new Error(`Invalid log type. Use: ${LOG_TYPES.join(', ')}`);
282
- }
283
- // Read message from stdin if not provided
284
- let logMessage = message;
285
- if (!logMessage) {
286
- // Check if stdin has data
287
- if (!process.stdin.isTTY) {
288
- logMessage = await readFromStdin();
289
- }
290
- if (!logMessage) {
291
- throw new Error('Message is required');
292
- }
293
- }
294
- const date = getDateString();
295
- const time = getTimeString();
296
- const logDir = path.join(projectRoot, '.timsquad', 'logs');
297
- const logFile = path.join(logDir, `${date}-${agent}.md`);
298
- // Create or append to log file
299
- let content = '';
300
- if (await exists(logFile)) {
301
- content = await readFile(logFile);
302
- }
303
- else {
304
- content = `# ${agent} Log - ${date}\n\n`;
305
- }
306
- // Add entry
307
- const typeIcon = getTypeIcon(type);
308
- content += `## ${time} [${type}] ${typeIcon}\n\n${logMessage}\n\n---\n\n`;
309
- await writeFile(logFile, content);
310
- printSuccess(`Log added: ${date}-${agent}.md`);
311
- }
312
- async function listLogs(agent) {
313
- const projectRoot = await findProjectRoot();
314
- if (!projectRoot) {
315
- throw new Error('Not a TimSquad project');
316
- }
317
- const logDir = path.join(projectRoot, '.timsquad', 'logs');
318
- const pattern = agent ? `*-${agent}.md` : '*.md';
319
- const files = await listFiles(pattern, logDir);
320
- // Filter out templates
321
- const logFiles = files.filter(f => !f.startsWith('_'));
322
- if (logFiles.length === 0) {
323
- console.log(colors.dim('No logs found'));
324
- return;
325
- }
326
- printHeader('Log Files');
327
- logFiles.sort().reverse().forEach(file => {
328
- console.log(` ${colors.path(file)}`);
329
- });
330
- }
331
- async function viewLog(file) {
332
- const projectRoot = await findProjectRoot();
333
- if (!projectRoot) {
334
- throw new Error('Not a TimSquad project');
335
- }
336
- const logFile = path.join(projectRoot, '.timsquad', 'logs', file);
337
- if (!await exists(logFile)) {
338
- throw new Error(`Log file not found: ${file}`);
339
- }
340
- const content = await readFile(logFile);
341
- console.log(content);
342
- }
343
- async function showTodayLogs(agent) {
344
- const projectRoot = await findProjectRoot();
345
- if (!projectRoot) {
346
- throw new Error('Not a TimSquad project');
347
- }
348
- const date = getDateString();
349
- const logDir = path.join(projectRoot, '.timsquad', 'logs');
350
- const pattern = agent ? `${date}-${agent}.md` : `${date}-*.md`;
351
- const files = await listFiles(pattern, logDir);
352
- if (files.length === 0) {
353
- console.log(colors.dim('No logs for today'));
354
- return;
355
- }
356
- printHeader(`Today's Logs (${date})`);
357
- for (const file of files) {
358
- const content = await readFile(path.join(logDir, file));
359
- console.log(colors.subheader(file));
360
- console.log(content);
361
- console.log('');
362
- }
363
- }
364
- async function searchLogs(keyword) {
365
- const projectRoot = await findProjectRoot();
366
- if (!projectRoot) {
367
- throw new Error('Not a TimSquad project');
368
- }
369
- const logDir = path.join(projectRoot, '.timsquad', 'logs');
370
- const files = await listFiles('*.md', logDir);
371
- const logFiles = files.filter(f => !f.startsWith('_'));
372
- let found = 0;
373
- const lowerKeyword = keyword.toLowerCase();
374
- for (const file of logFiles) {
375
- const content = await readFile(path.join(logDir, file));
376
- const lines = content.split('\n');
377
- lines.forEach((line, index) => {
378
- if (line.toLowerCase().includes(lowerKeyword)) {
379
- if (found === 0) {
380
- printHeader(`Search Results: "${keyword}"`);
381
- }
382
- console.log(`${colors.path(file)}:${index + 1}`);
383
- console.log(` ${highlightKeyword(line, keyword)}`);
384
- found++;
385
- }
386
- });
387
- }
388
- if (found === 0) {
389
- console.log(colors.dim(`No results for "${keyword}"`));
390
- }
391
- else {
392
- console.log(colors.dim(`\nFound ${found} matches`));
393
- }
394
- }
395
- async function generateSummary(date) {
396
- const projectRoot = await findProjectRoot();
397
- if (!projectRoot) {
398
- throw new Error('Not a TimSquad project');
399
- }
400
- const targetDate = date || getDateString();
401
- const logDir = path.join(projectRoot, '.timsquad', 'logs');
402
- const files = await listFiles(`${targetDate}-*.md`, logDir);
403
- if (files.length === 0) {
404
- console.log(colors.dim(`No logs for ${targetDate}`));
405
- return;
406
- }
407
- printHeader(`Summary for ${targetDate}`);
408
- const stats = {};
409
- for (const file of files) {
410
- const agent = file.replace(`${targetDate}-`, '').replace('.md', '');
411
- const content = await readFile(path.join(logDir, file));
412
- stats[agent] = { work: 0, decision: 0, error: 0, feedback: 0, handoff: 0 };
413
- LOG_TYPES.forEach(type => {
414
- const regex = new RegExp(`\\[${type}\\]`, 'gi');
415
- const matches = content.match(regex);
416
- stats[agent][type] = matches ? matches.length : 0;
417
- });
418
- }
419
- // Display stats
420
- Object.entries(stats).forEach(([agent, counts]) => {
421
- console.log(colors.agent(`\n ${agent}:`));
422
- Object.entries(counts).forEach(([type, count]) => {
423
- if (count > 0) {
424
- console.log(` ${type}: ${count}`);
425
- }
426
- });
427
- });
428
- console.log('');
429
- }
430
- function getTypeIcon(type) {
431
- const icons = {
432
- work: '📝',
433
- decision: '🎯',
434
- error: '❌',
435
- feedback: '💬',
436
- handoff: '🤝',
437
- };
438
- return icons[type] || '';
439
- }
440
- function highlightKeyword(text, keyword) {
441
- const regex = new RegExp(`(${keyword})`, 'gi');
442
- return text.replace(regex, colors.highlight('$1'));
443
- }
444
- async function readFromStdin() {
445
- return new Promise((resolve) => {
446
- let data = '';
447
- process.stdin.on('data', chunk => {
448
- data += chunk;
449
- });
450
- process.stdin.on('end', () => {
451
- resolve(data.trim());
452
- });
453
- setTimeout(() => resolve(''), 100);
454
- });
455
- }
456
- async function compactLogs(days, dryRun) {
457
- const projectRoot = await findProjectRoot();
458
- if (!projectRoot) {
459
- throw new Error('Not a TimSquad project');
460
- }
461
- printHeader('Log Compact');
462
- printKeyValue('Keep newer than', `${days} days`);
463
- if (dryRun) {
464
- console.log(colors.warning('DRY RUN - no files will be modified\n'));
465
- }
466
- const cutoffDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
467
- const cutoffStr = cutoffDate.toISOString().split('T')[0];
468
- let jsonlCompacted = 0;
469
- let mdMerged = 0;
470
- let bytesFreed = 0;
471
- // ── 1. 세션 JSONL 압축 ──
472
- const sessionsDir = path.join(projectRoot, '.timsquad', 'logs', 'sessions');
473
- if (await exists(sessionsDir)) {
474
- const jsonlFiles = await listFiles('*.jsonl', sessionsDir);
475
- const oldJsonl = jsonlFiles.filter(f => {
476
- const dateStr = f.split('-').slice(0, 3).join('-');
477
- return dateStr < cutoffStr;
478
- });
479
- if (oldJsonl.length > 0) {
480
- console.log(colors.subheader(`\n Session JSONL: ${oldJsonl.length} files to compact`));
481
- const summaries = [];
482
- for (const file of oldJsonl) {
483
- const filePath = path.join(sessionsDir, file);
484
- const stat = await fs.stat(filePath);
485
- bytesFreed += stat.size;
486
- try {
487
- const content = await readFile(filePath);
488
- const lines = content.split('\n').filter(l => l.trim());
489
- let toolUses = 0;
490
- let failures = 0;
491
- let subagents = 0;
492
- let tokenInput = 0;
493
- let tokenOutput = 0;
494
- let cacheCreate = 0;
495
- let cacheRead = 0;
496
- for (const line of lines) {
497
- try {
498
- const ev = JSON.parse(line);
499
- if (ev.event === 'PostToolUse')
500
- toolUses++;
501
- if (ev.event === 'PostToolUseFailure')
502
- failures++;
503
- if (ev.event === 'SubagentStart')
504
- subagents++;
505
- if (ev.event === 'SessionEnd' && ev.total_usage) {
506
- tokenInput += ev.total_usage.total_input || 0;
507
- tokenOutput += ev.total_usage.total_output || 0;
508
- cacheCreate += ev.total_usage.total_cache_create || 0;
509
- cacheRead += ev.total_usage.total_cache_read || 0;
510
- }
511
- }
512
- catch { /* skip */ }
513
- }
514
- const dateStr = file.split('-').slice(0, 3).join('-');
515
- const sessionId = file.replace(/\.jsonl$/, '').split('-').slice(3).join('-');
516
- summaries.push({
517
- file,
518
- date: dateStr,
519
- session: sessionId,
520
- events: lines.length,
521
- toolUses,
522
- failures,
523
- subagents,
524
- tokens: { input: tokenInput, output: tokenOutput, cacheCreate, cacheRead },
525
- });
526
- if (!dryRun) {
527
- await fs.remove(filePath);
528
- }
529
- jsonlCompacted++;
530
- console.log(colors.dim(` ${dryRun ? '[dry-run] ' : ''}${file} (${lines.length} events, ${formatSize(stat.size)})`));
531
- }
532
- catch {
533
- // skip unreadable files
534
- }
535
- }
536
- // 압축 요약 저장
537
- if (!dryRun && summaries.length > 0) {
538
- const archiveDir = path.join(sessionsDir, 'archive');
539
- await fs.ensureDir(archiveDir);
540
- const monthGroups = {};
541
- for (const s of summaries) {
542
- const month = s.date.slice(0, 7); // YYYY-MM
543
- if (!monthGroups[month])
544
- monthGroups[month] = [];
545
- monthGroups[month].push(s);
546
- }
547
- for (const [month, group] of Object.entries(monthGroups)) {
548
- const archivePath = path.join(archiveDir, `${month}-summary.json`);
549
- let existing = [];
550
- if (await exists(archivePath)) {
551
- try {
552
- const data = await fs.readJson(archivePath);
553
- existing = data.sessions || [];
554
- }
555
- catch { /* start fresh */ }
556
- }
557
- await fs.writeJson(archivePath, {
558
- compactedAt: getTimestamp(),
559
- month,
560
- sessions: [...existing, ...group],
561
- totals: {
562
- sessions: existing.length + group.length,
563
- events: [...existing, ...group].reduce((a, s) => a + s.events, 0),
564
- toolUses: [...existing, ...group].reduce((a, s) => a + s.toolUses, 0),
565
- failures: [...existing, ...group].reduce((a, s) => a + s.failures, 0),
566
- },
567
- }, { spaces: 2 });
568
- }
569
- }
570
- }
571
- }
572
- // ── 2. 작업 로그 MD 병합 ──
573
- const logsDir = path.join(projectRoot, '.timsquad', 'logs');
574
- if (await exists(logsDir)) {
575
- const mdFiles = await listFiles('????-??-??-*.md', logsDir);
576
- const oldMd = mdFiles.filter(f => {
577
- const match = f.match(/^(\d{4}-\d{2}-\d{2})-/);
578
- return match && match[1] < cutoffStr;
579
- });
580
- if (oldMd.length > 0) {
581
- console.log(colors.subheader(`\n Work Logs MD: ${oldMd.length} files to merge`));
582
- // 월별 그룹핑
583
- const monthGroups = {};
584
- for (const file of oldMd) {
585
- const month = file.slice(0, 7);
586
- if (!monthGroups[month])
587
- monthGroups[month] = [];
588
- monthGroups[month].push(file);
589
- }
590
- for (const [month, files] of Object.entries(monthGroups)) {
591
- const mergedPath = path.join(logsDir, `${month}-archive.md`);
592
- let mergedContent = '';
593
- if (await exists(mergedPath)) {
594
- mergedContent = await readFile(mergedPath);
595
- }
596
- else {
597
- mergedContent = `# Archive - ${month}\n\n> ${files.length} log files merged by tsq log compact\n\n---\n`;
598
- }
599
- for (const file of files.sort()) {
600
- const filePath = path.join(logsDir, file);
601
- const stat = await fs.stat(filePath);
602
- bytesFreed += stat.size;
603
- try {
604
- const content = await readFile(filePath);
605
- mergedContent += `\n\n<!-- ${file} -->\n${content}`;
606
- if (!dryRun) {
607
- await fs.remove(filePath);
608
- }
609
- mdMerged++;
610
- console.log(colors.dim(` ${dryRun ? '[dry-run] ' : ''}${file} → ${month}-archive.md`));
611
- }
612
- catch { /* skip */ }
613
- }
614
- if (!dryRun) {
615
- await writeFile(mergedPath, mergedContent);
616
- }
617
- }
618
- }
619
- }
620
- // ── 결과 ──
621
- console.log('');
622
- if (jsonlCompacted + mdMerged === 0) {
623
- console.log(colors.dim('No files older than threshold. Nothing to compact.'));
624
- }
625
- else {
626
- printSuccess(`Compacted: ${jsonlCompacted} JSONL + ${mdMerged} MD files`);
627
- printKeyValue('Space freed', `~${formatSize(bytesFreed)}`);
628
- if (dryRun) {
629
- console.log(colors.dim('\nRun without --dry-run to apply changes.'));
630
- }
631
- }
632
- }
633
- function formatSize(bytes) {
634
- if (bytes < 1024)
635
- return `${bytes}B`;
636
- if (bytes < 1024 * 1024)
637
- return `${(bytes / 1024).toFixed(1)}KB`;
638
- return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
639
- }
640
- // ============================================================
641
- // Task Log Helpers
642
- // ============================================================
643
- export function getTasksDir(projectRoot) {
644
- return path.join(projectRoot, '.timsquad', 'logs', 'tasks');
645
- }
646
- export function getSequencesDir(projectRoot) {
647
- return path.join(projectRoot, '.timsquad', 'logs', 'sequences');
648
- }
649
- export function getPhasesDir(projectRoot) {
650
- return path.join(projectRoot, '.timsquad', 'logs', 'phases');
651
- }
652
- async function findLatestTaskLog(projectRoot, agent) {
653
- const tasksDir = getTasksDir(projectRoot);
654
- if (!await exists(tasksDir))
655
- return null;
656
- // Flat structure: *-{agent}.json
657
- const flatFiles = await listFiles(`*-${agent}.json`, tasksDir);
658
- // Nested structure: look inside subdirectories
659
- const nestedFiles = [];
660
- try {
661
- const entries = await fs.readdir(tasksDir, { withFileTypes: true });
662
- for (const entry of entries) {
663
- if (entry.isDirectory()) {
664
- const subFiles = await listFiles(`*-${agent}.json`, path.join(tasksDir, entry.name));
665
- nestedFiles.push(...subFiles.map(f => path.join(entry.name, f)));
666
- }
667
- }
668
- }
669
- catch { /* no subdirectories */ }
670
- const allFiles = [...flatFiles, ...nestedFiles].sort().reverse();
671
- return allFiles.length > 0 ? allFiles[0] : null;
672
- }
673
- export async function loadAllTaskLogs(projectRoot, agent) {
674
- const tasksDir = getTasksDir(projectRoot);
675
- if (!await exists(tasksDir))
676
- return [];
677
- const pattern = agent ? `*-${agent}.json` : '*.json';
678
- const files = await listFiles(pattern, tasksDir);
679
- const results = [];
680
- for (const file of files) {
681
- try {
682
- const data = await fs.readJson(path.join(tasksDir, file));
683
- results.push({ file, data });
684
- }
685
- catch { /* skip malformed */ }
686
- }
687
- return results.sort((a, b) => a.file.localeCompare(b.file));
688
- }
689
- function mergeSemantic(existing, incoming) {
690
- return {
691
- summary: incoming.summary ?? existing.summary,
692
- techniques: incoming.techniques ?? existing.techniques,
693
- ssot_refs: incoming.ssot_refs ?? existing.ssot_refs,
694
- decisions: incoming.decisions ?? existing.decisions,
695
- issues: incoming.issues ?? existing.issues,
696
- };
697
- }
698
- export function hasSemantic(sem) {
699
- if (!sem)
700
- return false;
701
- return !!(sem.summary || sem.techniques?.length || sem.ssot_refs?.length ||
702
- sem.decisions?.length || sem.issues?.length);
703
- }
704
- // ============================================================
705
- // Step 2: tsq log enrich
706
- // ============================================================
707
- async function enrichTaskLog(agent, jsonData) {
708
- const projectRoot = await findProjectRoot();
709
- if (!projectRoot)
710
- throw new Error('Not a TimSquad project');
711
- const latestFile = await findLatestTaskLog(projectRoot, agent);
712
- if (!latestFile) {
713
- throw new Error(`No task log found for agent: ${agent}`);
714
- }
715
- const filePath = path.join(getTasksDir(projectRoot), latestFile);
716
- let incoming;
717
- try {
718
- incoming = JSON.parse(jsonData);
719
- }
720
- catch {
721
- throw new Error('Invalid JSON data');
722
- }
723
- const taskLog = await fs.readJson(filePath);
724
- taskLog.semantic = mergeSemantic(taskLog.semantic || {}, incoming);
725
- await fs.writeJson(filePath, taskLog, { spaces: 2 });
726
- printSuccess(`Enriched: ${latestFile}`);
727
- if (taskLog.semantic.summary) {
728
- printKeyValue('Summary', taskLog.semantic.summary);
729
- }
730
- if (taskLog.semantic.techniques?.length) {
731
- printKeyValue('Techniques', taskLog.semantic.techniques.map(t => t.name).join(', '));
732
- }
733
- // Auto-feedback: L2/L3 이슈 → 자동 피드백 라우팅
734
- await autoFeedbackFromIssues(projectRoot, taskLog.semantic);
735
- }
736
- // ============================================================
737
- // Step 3: tsq log task (L1 views)
738
- // ============================================================
739
- async function listTaskLogs(agent) {
740
- const projectRoot = await findProjectRoot();
741
- if (!projectRoot)
742
- throw new Error('Not a TimSquad project');
743
- const logs = await loadAllTaskLogs(projectRoot, agent);
744
- if (logs.length === 0) {
745
- console.log(colors.dim('No task logs found'));
746
- return;
747
- }
748
- printHeader(`Task Logs (${logs.length})`);
749
- for (const { file, data } of logs.reverse()) {
750
- const sem = hasSemantic(data.semantic) ? '✓' : '○';
751
- const status = data.status === 'completed' ? colors.success('✓') : colors.error('✗');
752
- const agentName = colors.agent(data.agent || '?');
753
- const date = file.slice(0, 10);
754
- console.log(` ${status} ${sem} ${colors.dim(date)} ${agentName} ${colors.dim(file)}`);
755
- if (data.semantic?.summary) {
756
- console.log(` ${colors.dim(data.semantic.summary.slice(0, 80))}`);
757
- }
758
- }
759
- }
760
- async function viewTaskLog(file) {
761
- const projectRoot = await findProjectRoot();
762
- if (!projectRoot)
763
- throw new Error('Not a TimSquad project');
764
- const filePath = path.join(getTasksDir(projectRoot), file);
765
- if (!await exists(filePath)) {
766
- throw new Error(`Task log not found: ${file}`);
767
- }
768
- const data = await fs.readJson(filePath);
769
- printHeader(`Task Log: ${file}`);
770
- // Basic info
771
- printKeyValue('Agent', data.agent);
772
- printKeyValue('Status', data.status);
773
- printKeyValue('Completed', data.completed_at || 'N/A');
774
- if (data.duration_ms)
775
- printKeyValue('Duration', `${(data.duration_ms / 1000).toFixed(1)}s`);
776
- // Mechanical
777
- console.log(colors.subheader('\n Mechanical'));
778
- if (data.mechanical?.files?.length) {
779
- for (const f of data.mechanical.files) {
780
- console.log(` ${f.action}: ${colors.path(f.path)}`);
781
- }
782
- }
783
- else {
784
- console.log(colors.dim(' (no file changes)'));
785
- }
786
- // Semantic
787
- console.log(colors.subheader('\n Semantic'));
788
- if (hasSemantic(data.semantic)) {
789
- if (data.semantic.summary)
790
- printKeyValue(' Summary', data.semantic.summary);
791
- if (data.semantic.techniques?.length) {
792
- console.log(' Techniques:');
793
- for (const t of data.semantic.techniques) {
794
- console.log(` - ${t.name}: ${colors.dim(t.reason)}`);
795
- }
796
- }
797
- if (data.semantic.ssot_refs?.length) {
798
- console.log(' SSOT Refs:');
799
- for (const r of data.semantic.ssot_refs) {
800
- const icon = r.status === 'aligned' ? '✓' : r.status === 'misaligned' ? '✗' : '~';
801
- console.log(` ${icon} ${r.doc} → ${r.section} (${r.status})`);
802
- }
803
- }
804
- if (data.semantic.decisions?.length) {
805
- console.log(' Decisions:');
806
- for (const d of data.semantic.decisions) {
807
- console.log(` - ${d.decision}`);
808
- console.log(` ${colors.dim(d.rationale)}`);
809
- }
810
- }
811
- if (data.semantic.issues?.length) {
812
- console.log(' Issues:');
813
- for (const i of data.semantic.issues) {
814
- console.log(` L${i.level}: ${i.description}`);
815
- }
816
- }
817
- }
818
- else {
819
- console.log(colors.dim(' (empty — run tsq log enrich to populate)'));
820
- }
821
- }
822
- async function showTaskStats() {
823
- const projectRoot = await findProjectRoot();
824
- if (!projectRoot)
825
- throw new Error('Not a TimSquad project');
826
- const logs = await loadAllTaskLogs(projectRoot);
827
- if (logs.length === 0) {
828
- console.log(colors.dim('No task logs found'));
829
- return;
830
- }
831
- const stats = {
832
- total: logs.length,
833
- completed: 0, failed: 0, successRate: 0,
834
- byAgent: {},
835
- totalFilesChanged: 0, avgFilesPerTask: 0, fileActions: {},
836
- withErrors: 0, errorTypes: {},
837
- withSemantic: 0, semanticCoverage: 0,
838
- };
839
- for (const { data } of logs) {
840
- // Status
841
- if (data.status === 'completed' || data.status === 'success')
842
- stats.completed++;
843
- else
844
- stats.failed++;
845
- // By agent
846
- const a = data.agent || 'unknown';
847
- if (!stats.byAgent[a])
848
- stats.byAgent[a] = { total: 0, completed: 0, failed: 0 };
849
- stats.byAgent[a].total++;
850
- if (data.status === 'completed' || data.status === 'success')
851
- stats.byAgent[a].completed++;
852
- else
853
- stats.byAgent[a].failed++;
854
- // Files
855
- const files = data.mechanical?.files || [];
856
- stats.totalFilesChanged += files.length;
857
- for (const f of files) {
858
- stats.fileActions[f.action] = (stats.fileActions[f.action] || 0) + 1;
859
- }
860
- // Errors
861
- if (data.error) {
862
- stats.withErrors++;
863
- const t = data.error.type || 'unknown';
864
- stats.errorTypes[t] = (stats.errorTypes[t] || 0) + 1;
865
- }
866
- // Semantic
867
- if (hasSemantic(data.semantic))
868
- stats.withSemantic++;
869
- }
870
- stats.successRate = Math.round((stats.completed / stats.total) * 100);
871
- stats.avgFilesPerTask = Math.round((stats.totalFilesChanged / stats.total) * 10) / 10;
872
- stats.semanticCoverage = Math.round((stats.withSemantic / stats.total) * 100);
873
- printHeader('Task Log Statistics');
874
- printKeyValue('Total Tasks', String(stats.total));
875
- printKeyValue('Success Rate', `${stats.successRate}% (${stats.completed}/${stats.total})`);
876
- printKeyValue('Semantic Coverage', `${stats.semanticCoverage}% (${stats.withSemantic}/${stats.total})`);
877
- printKeyValue('Files Changed', `${stats.totalFilesChanged} (avg ${stats.avgFilesPerTask}/task)`);
878
- if (Object.keys(stats.byAgent).length > 1) {
879
- console.log(colors.subheader('\n By Agent'));
880
- for (const [agent, s] of Object.entries(stats.byAgent)) {
881
- const rate = Math.round((s.completed / s.total) * 100);
882
- console.log(` ${colors.agent(agent)}: ${s.total} tasks, ${rate}% success`);
883
- }
884
- }
885
- if (stats.withErrors > 0) {
886
- console.log(colors.subheader('\n Errors'));
887
- printKeyValue(' Tasks with errors', String(stats.withErrors));
888
- for (const [type, count] of Object.entries(stats.errorTypes)) {
889
- console.log(` ${type}: ${count}`);
890
- }
891
- }
892
- }
893
- // ============================================================
894
- // Step 4: tsq log sequence (L2)
895
- // ============================================================
896
- export async function loadSequenceTaskLogs(projectRoot, seqId) {
897
- const tasksDir = getTasksDir(projectRoot);
898
- if (!await exists(tasksDir))
899
- return [];
900
- const results = [];
901
- // 1. Check nested directory: tasks/{SEQ-ID}/*.json
902
- const seqDir = path.join(tasksDir, seqId);
903
- if (await exists(seqDir)) {
904
- const files = await listFiles('*.json', seqDir);
905
- for (const file of files) {
906
- try {
907
- const data = await fs.readJson(path.join(seqDir, file));
908
- results.push({ file: path.join(seqId, file), data });
909
- }
910
- catch { /* skip */ }
911
- }
912
- }
913
- // 2. Check flat files with trace.sequence_id matching
914
- const flatFiles = await listFiles('*.json', tasksDir);
915
- for (const file of flatFiles) {
916
- try {
917
- const data = await fs.readJson(path.join(tasksDir, file));
918
- if (data.trace?.sequence_id === seqId) {
919
- // Avoid duplicates from nested
920
- if (!results.some(r => r.file === file)) {
921
- results.push({ file, data });
922
- }
923
- }
924
- }
925
- catch { /* skip */ }
926
- }
927
- return results.sort((a, b) => a.file.localeCompare(b.file));
928
- }
929
- function aggregateSequenceStats(taskLogs) {
930
- let success = 0, failure = 0, error = 0, rework = 0;
931
- const durations = [];
932
- for (const { file, data } of taskLogs) {
933
- const s = data.status;
934
- if (s === 'completed' || s === 'success')
935
- success++;
936
- else if (s === 'failure')
937
- failure++;
938
- else if (s === 'error')
939
- error++;
940
- if (data.duration_ms)
941
- durations.push(data.duration_ms);
942
- // Simple rework detection: same agent + file overlap with earlier task
943
- const changedFiles = new Set(data.mechanical?.files?.map(f => f.path) || []);
944
- for (const other of taskLogs) {
945
- if (other.file === file)
946
- continue;
947
- if (other.data.agent === data.agent && other.file < file) {
948
- const otherFiles = other.data.mechanical?.files?.map(f => f.path) || [];
949
- if (otherFiles.some(f => changedFiles.has(f))) {
950
- rework++;
951
- break;
952
- }
953
- }
954
- }
955
- }
956
- const total = taskLogs.length;
957
- return {
958
- total, success, failure, error, rework,
959
- first_pass_success_rate: total > 0 ? Math.round(((success) / total) * 100) / 100 : 0,
960
- final_success_rate: total > 0 ? Math.round(((success) / total) * 100) / 100 : 0,
961
- durations,
962
- };
963
- }
964
- export function makeAxisPlaceholder() {
965
- return { verdict: 'n/a', details: 'See architect report', issues: [] };
966
- }
967
- async function listSequenceLogs() {
968
- const projectRoot = await findProjectRoot();
969
- if (!projectRoot)
970
- throw new Error('Not a TimSquad project');
971
- const seqDir = getSequencesDir(projectRoot);
972
- if (!await exists(seqDir)) {
973
- console.log(colors.dim('No sequence logs found'));
974
- return;
975
- }
976
- const files = await listFiles('*.json', seqDir);
977
- if (files.length === 0) {
978
- console.log(colors.dim('No sequence logs found'));
979
- return;
980
- }
981
- printHeader(`Sequence Logs (${files.length})`);
982
- for (const file of files.sort()) {
983
- try {
984
- const data = await fs.readJson(path.join(seqDir, file));
985
- const seqId = data.trace.sequence_id;
986
- const status = data.execution.status;
987
- const verdict = data.verdict.proceed ? colors.success('PROCEED') : colors.error('HOLD');
988
- const tasks = `${data.tasks.success}/${data.tasks.total} tasks`;
989
- console.log(` ${verdict} ${colors.agent(seqId)} [${status}] ${tasks} ${colors.dim(data.trace.phase_id)}`);
990
- }
991
- catch {
992
- console.log(` ${colors.dim(file)} (unreadable)`);
993
- }
994
- }
995
- }
996
- async function viewSequenceLog(seqId) {
997
- const projectRoot = await findProjectRoot();
998
- if (!projectRoot)
999
- throw new Error('Not a TimSquad project');
1000
- const filePath = path.join(getSequencesDir(projectRoot), `${seqId}.json`);
1001
- if (!await exists(filePath)) {
1002
- throw new Error(`Sequence log not found: ${seqId}`);
1003
- }
1004
- const data = await fs.readJson(filePath);
1005
- printHeader(`Sequence: ${seqId}`);
1006
- printKeyValue('Phase', data.trace.phase_id);
1007
- printKeyValue('Status', data.execution.status);
1008
- printKeyValue('Duration', `${(data.execution.duration_ms / 1000).toFixed(1)}s`);
1009
- printKeyValue('Verdict', data.verdict.proceed ? 'PROCEED' : 'HOLD');
1010
- console.log(colors.subheader('\n Tasks'));
1011
- printKeyValue(' Total', String(data.tasks.total));
1012
- printKeyValue(' Success', String(data.tasks.success));
1013
- printKeyValue(' Failure', String(data.tasks.failure));
1014
- printKeyValue(' Rework', String(data.tasks.rework));
1015
- printKeyValue(' Success Rate', `${(data.tasks.final_success_rate * 100).toFixed(0)}%`);
1016
- console.log(colors.subheader('\n Analysis'));
1017
- for (const [axis, result] of Object.entries(data.analysis)) {
1018
- const r = result;
1019
- const icon = r.verdict === 'pass' ? '✓' : r.verdict === 'fail' ? '✗' : r.verdict === 'warn' ? '!' : '–';
1020
- console.log(` ${icon} ${axis}: ${r.verdict} — ${colors.dim(r.details)}`);
1021
- }
1022
- console.log(colors.subheader('\n DORA'));
1023
- printKeyValue(' Change Failure Rate', `${(data.dora_derived.change_failure_rate * 100).toFixed(0)}%`);
1024
- printKeyValue(' Rework Rate', `${(data.dora_derived.rework_rate * 100).toFixed(0)}%`);
1025
- printKeyValue(' Mean Task Duration', `${(data.dora_derived.mean_task_duration_ms / 1000).toFixed(1)}s`);
1026
- if (data.verdict.conditions.length > 0) {
1027
- console.log(colors.subheader('\n Conditions'));
1028
- for (const c of data.verdict.conditions) {
1029
- console.log(` - ${c}`);
1030
- }
1031
- }
1032
- printKeyValue('\n Report', data.verdict.report_path);
1033
- }
1034
- /**
1035
- * Core: build SequenceLogEntry data (no I/O side effects except reading task logs)
1036
- */
1037
- export async function buildSequenceLogData(projectRoot, seqId, options) {
1038
- const taskLogs = await loadSequenceTaskLogs(projectRoot, seqId);
1039
- if (taskLogs.length === 0) {
1040
- const tasksDir = getTasksDir(projectRoot);
1041
- if (await exists(tasksDir)) {
1042
- const allFiles = await listFiles('*.json', tasksDir);
1043
- for (const file of allFiles) {
1044
- if (file.toLowerCase().includes(seqId.toLowerCase())) {
1045
- try {
1046
- const data = await fs.readJson(path.join(tasksDir, file));
1047
- taskLogs.push({ file, data });
1048
- }
1049
- catch { /* skip */ }
1050
- }
1051
- }
1052
- }
1053
- }
1054
- const stats = aggregateSequenceStats(taskLogs);
1055
- const now = getTimestamp();
1056
- const timestamps = taskLogs
1057
- .map(t => t.data.completed_at ? new Date(t.data.completed_at).getTime() : 0)
1058
- .filter(t => t > 0);
1059
- const startedAt = taskLogs[0]?.data.started_at || taskLogs[0]?.data.completed_at || now;
1060
- const duration = timestamps.length >= 2
1061
- ? Math.max(...timestamps) - Math.min(...timestamps)
1062
- : 0;
1063
- const meanDuration = stats.durations.length > 0
1064
- ? stats.durations.reduce((a, b) => a + b, 0) / stats.durations.length
1065
- : 0;
1066
- return {
1067
- schema_version: LOG_SCHEMA_VERSION,
1068
- trace: { phase_id: options.phase, sequence_id: seqId },
1069
- execution: {
1070
- status: stats.failure > 0 ? 'partial' : 'completed',
1071
- started_at: startedAt,
1072
- completed_at: now,
1073
- duration_ms: duration,
1074
- },
1075
- tasks: {
1076
- total: stats.total,
1077
- success: stats.success,
1078
- failure: stats.failure,
1079
- error: stats.error,
1080
- rework: stats.rework,
1081
- first_pass_success_rate: stats.first_pass_success_rate,
1082
- final_success_rate: stats.final_success_rate,
1083
- },
1084
- analysis: {
1085
- axis_1_consistency: makeAxisPlaceholder(),
1086
- axis_2_ssot_conformance: makeAxisPlaceholder(),
1087
- axis_3_cross_sequence: { ...makeAxisPlaceholder(), prev_sequence: null },
1088
- },
1089
- dora_derived: {
1090
- change_failure_rate: stats.total > 0 ? stats.failure / stats.total : 0,
1091
- rework_rate: stats.total > 0 ? stats.rework / stats.total : 0,
1092
- mean_task_duration_ms: meanDuration,
1093
- recovery_time_ms: null,
1094
- },
1095
- verdict: {
1096
- proceed: options.verdict !== 'hold',
1097
- conditions: options.conditions ? options.conditions.split(',').map(c => c.trim()) : [],
1098
- report_path: options.report,
1099
- },
1100
- };
1101
- }
1102
- /**
1103
- * Auto-feedback: L2/L3 이슈가 enrich로 들어오면 자동 피드백 라우팅
1104
- */
1105
- async function autoFeedbackFromIssues(projectRoot, semantic) {
1106
- const issues = semantic.issues || [];
1107
- const l2l3Issues = issues.filter(i => i.level >= 2);
1108
- if (l2l3Issues.length === 0)
1109
- return;
1110
- try {
1111
- const state = await loadWorkflowState(projectRoot);
1112
- if (!state.automation.feedback)
1113
- return;
1114
- for (const issue of l2l3Issues) {
1115
- try {
1116
- const { execFileSync } = await import('child_process');
1117
- execFileSync('npx', ['tsq', 'feedback', 'route', issue.description], { cwd: projectRoot, timeout: 10000, stdio: 'ignore' });
1118
- }
1119
- catch { /* 피드백 라우팅 실패 무시 */ }
1120
- }
1121
- }
1122
- catch { /* 자동 피드백 실패 무시 */ }
1123
- }
1124
- /**
1125
- * Core: build PhaseGateResult (no I/O side effects except reading sequence logs)
1126
- */
1127
- export async function buildPhaseGateData(projectRoot, phaseId) {
1128
- const seqDir = getSequencesDir(projectRoot);
1129
- const result = {
1130
- phase_id: phaseId,
1131
- can_transition: true,
1132
- missing_sequences: [],
1133
- missing_reports: [],
1134
- blocking_conditions: [],
1135
- };
1136
- if (!await exists(seqDir)) {
1137
- result.can_transition = false;
1138
- result.blocking_conditions.push('No sequence logs directory');
1139
- return result;
1140
- }
1141
- const files = await listFiles('*.json', seqDir);
1142
- const phaseSeqs = [];
1143
- for (const file of files) {
1144
- try {
1145
- const data = await fs.readJson(path.join(seqDir, file));
1146
- if (data.trace.phase_id === phaseId) {
1147
- phaseSeqs.push(data);
1148
- }
1149
- }
1150
- catch { /* skip */ }
1151
- }
1152
- if (phaseSeqs.length === 0) {
1153
- result.can_transition = false;
1154
- result.blocking_conditions.push('No sequence logs found for this phase');
1155
- return result;
1156
- }
1157
- for (const seq of phaseSeqs) {
1158
- if (!seq.verdict.proceed) {
1159
- result.can_transition = false;
1160
- result.blocking_conditions.push(`${seq.trace.sequence_id}: verdict is HOLD`);
1161
- }
1162
- if (seq.verdict.report_path) {
1163
- const reportPath = path.resolve(projectRoot, seq.verdict.report_path);
1164
- if (!await exists(reportPath)) {
1165
- result.can_transition = false;
1166
- result.missing_reports.push(seq.verdict.report_path);
1167
- }
1168
- }
1169
- if (seq.verdict.conditions.length > 0) {
1170
- for (const c of seq.verdict.conditions) {
1171
- result.blocking_conditions.push(`${seq.trace.sequence_id}: condition "${c}"`);
1172
- }
1173
- }
1174
- }
1175
- // Check E2E test gate (only if test:e2e script exists)
1176
- try {
1177
- const pkgPath = path.join(projectRoot, 'package.json');
1178
- if (await exists(pkgPath)) {
1179
- const pkg = await fs.readJson(pkgPath);
1180
- if (pkg.scripts?.['test:e2e']) {
1181
- const e2eMarker = path.join(projectRoot, '.e2e-passed');
1182
- if (await exists(e2eMarker)) {
1183
- const markerContent = await fs.readFile(e2eMarker, 'utf-8');
1184
- try {
1185
- const marker = JSON.parse(markerContent);
1186
- if (marker.exit_code != null && marker.exit_code !== 0) {
1187
- result.can_transition = false;
1188
- result.blocking_conditions.push(`E2E tests failed (exit_code=${marker.exit_code})`);
1189
- }
1190
- else if (marker.expires_at && new Date(marker.expires_at) < new Date()) {
1191
- result.can_transition = false;
1192
- result.blocking_conditions.push('E2E marker expired — re-run E2E tests');
1193
- }
1194
- }
1195
- catch {
1196
- // bare touch fallback — file exists means passed
1197
- }
1198
- }
1199
- else {
1200
- result.can_transition = false;
1201
- result.blocking_conditions.push('E2E tests not passed (missing .e2e-passed marker)');
1202
- }
1203
- }
1204
- }
1205
- }
1206
- catch { /* package.json read failure — skip E2E gate */ }
1207
- // Check unresolved L2/L3 feedback
1208
- try {
1209
- const state = await loadWorkflowState(projectRoot);
1210
- if (state.pending_feedback?.length > 0) {
1211
- const feedbackDir = path.join(projectRoot, '.timsquad', 'feedback');
1212
- for (const fbId of state.pending_feedback) {
1213
- const fbPath = path.join(feedbackDir, `${fbId}.json`);
1214
- if (await exists(fbPath)) {
1215
- const fb = await fs.readJson(fbPath);
1216
- if (!fb.status || fb.status === 'open' || fb.status === 'in_review') {
1217
- result.can_transition = false;
1218
- result.blocking_conditions.push(`Unresolved L${fb.level} feedback: ${fbId} (${fb.trigger})`);
1219
- }
1220
- }
1221
- }
1222
- }
1223
- }
1224
- catch { /* workflow state unavailable — skip feedback check */ }
1225
- return result;
1226
- }
1227
- async function createSequenceLog(seqId, options) {
1228
- const projectRoot = await findProjectRoot();
1229
- if (!projectRoot)
1230
- throw new Error('Not a TimSquad project');
1231
- const entry = await buildSequenceLogData(projectRoot, seqId, options);
1232
- const seqDir = getSequencesDir(projectRoot);
1233
- await fs.ensureDir(seqDir);
1234
- await fs.writeJson(path.join(seqDir, `${seqId}.json`), entry, { spaces: 2 });
1235
- printSuccess(`Sequence log created: ${seqId}.json`);
1236
- printKeyValue('Tasks', `${entry.tasks.success}/${entry.tasks.total} success`);
1237
- printKeyValue('Verdict', entry.verdict.proceed ? 'PROCEED' : 'HOLD');
1238
- }
1239
- async function checkSequence(seqId) {
1240
- const projectRoot = await findProjectRoot();
1241
- if (!projectRoot)
1242
- throw new Error('Not a TimSquad project');
1243
- const taskLogs = await loadSequenceTaskLogs(projectRoot, seqId);
1244
- printHeader(`Sequence Check: ${seqId}`);
1245
- printKeyValue('Task Logs Found', String(taskLogs.length));
1246
- if (taskLogs.length === 0) {
1247
- console.log(colors.dim(' No task logs found for this sequence'));
1248
- return;
1249
- }
1250
- let withSemantic = 0;
1251
- for (const { file, data } of taskLogs) {
1252
- const sem = hasSemantic(data.semantic) ? colors.success('✓ semantic') : colors.warning('○ no semantic');
1253
- const status = data.status === 'completed' ? '✓' : '✗';
1254
- console.log(` ${status} ${colors.agent(data.agent || '?')} ${sem} ${colors.dim(file)}`);
1255
- if (hasSemantic(data.semantic))
1256
- withSemantic++;
1257
- }
1258
- const coverage = Math.round((withSemantic / taskLogs.length) * 100);
1259
- console.log('');
1260
- printKeyValue('Semantic Coverage', `${coverage}% (${withSemantic}/${taskLogs.length})`);
1261
- if (coverage < 100) {
1262
- console.log(colors.warning('\n ⚠ Run tsq log enrich for tasks missing semantic data'));
1263
- }
1264
- }
1265
- // ============================================================
1266
- // Step 5: tsq log phase (L3) + Gate
1267
- // ============================================================
1268
- async function listPhaseLogs() {
1269
- const projectRoot = await findProjectRoot();
1270
- if (!projectRoot)
1271
- throw new Error('Not a TimSquad project');
1272
- const phaseDir = getPhasesDir(projectRoot);
1273
- if (!await exists(phaseDir)) {
1274
- console.log(colors.dim('No phase logs found'));
1275
- return;
1276
- }
1277
- const files = await listFiles('*.json', phaseDir);
1278
- if (files.length === 0) {
1279
- console.log(colors.dim('No phase logs found'));
1280
- return;
1281
- }
1282
- printHeader(`Phase Logs (${files.length})`);
1283
- for (const file of files.sort()) {
1284
- try {
1285
- const data = await fs.readJson(path.join(phaseDir, file));
1286
- const phaseId = data.trace.phase_id;
1287
- const status = data.execution.status;
1288
- const seqs = `${data.sequences.completed}/${data.sequences.total} sequences`;
1289
- console.log(` ${colors.agent(phaseId)} [${status}] ${seqs}`);
1290
- }
1291
- catch {
1292
- console.log(` ${colors.dim(file)} (unreadable)`);
1293
- }
1294
- }
1295
- }
1296
- async function viewPhaseLog(phaseId) {
1297
- const projectRoot = await findProjectRoot();
1298
- if (!projectRoot)
1299
- throw new Error('Not a TimSquad project');
1300
- const filePath = path.join(getPhasesDir(projectRoot), `${phaseId}.json`);
1301
- if (!await exists(filePath)) {
1302
- throw new Error(`Phase log not found: ${phaseId}`);
1303
- }
1304
- const data = await fs.readJson(filePath);
1305
- printHeader(`Phase: ${phaseId}`);
1306
- printKeyValue('Status', data.execution.status);
1307
- printKeyValue('Duration', `${(data.execution.duration_ms / 1000 / 60).toFixed(1)} min`);
1308
- printKeyValue('Sessions', String(data.execution.sessions_count));
1309
- console.log(colors.subheader('\n Sequences'));
1310
- printKeyValue(' Total', String(data.sequences.total));
1311
- printKeyValue(' Completed', String(data.sequences.completed));
1312
- printKeyValue(' Blocked', String(data.sequences.blocked));
1313
- console.log(` IDs: ${data.sequences.ids.join(', ')}`);
1314
- console.log(colors.subheader('\n Metrics'));
1315
- printKeyValue(' Tasks', String(data.aggregate_metrics.total_tasks));
1316
- printKeyValue(' Success Rate', `${(data.aggregate_metrics.task_success_rate * 100).toFixed(0)}%`);
1317
- printKeyValue(' Rework Rate', `${(data.aggregate_metrics.task_rework_rate * 100).toFixed(0)}%`);
1318
- printKeyValue(' Files Changed', String(data.aggregate_metrics.total_files_changed));
1319
- printKeyValue(' SSOT Conformance', `${(data.aggregate_metrics.ssot_conformance_rate * 100).toFixed(0)}%`);
1320
- console.log(colors.subheader('\n DORA'));
1321
- printKeyValue(' Lead Time', `${(data.dora_derived.lead_time_ms / 1000 / 60).toFixed(1)} min`);
1322
- printKeyValue(' Change Failure Rate', `${(data.dora_derived.change_failure_rate * 100).toFixed(0)}%`);
1323
- if (data.retrospective.keep.length || data.retrospective.problem.length || data.retrospective.try.length) {
1324
- console.log(colors.subheader('\n Retrospective'));
1325
- if (data.retrospective.keep.length) {
1326
- console.log(' Keep:');
1327
- data.retrospective.keep.forEach(k => console.log(` + ${k}`));
1328
- }
1329
- if (data.retrospective.problem.length) {
1330
- console.log(' Problem:');
1331
- data.retrospective.problem.forEach(p => console.log(` - ${p}`));
1332
- }
1333
- if (data.retrospective.try.length) {
1334
- console.log(' Try:');
1335
- data.retrospective.try.forEach(t => console.log(` → ${t}`));
1336
- }
1337
- }
1338
- }
1339
- async function createPhaseLog(phaseId, options) {
1340
- const projectRoot = await findProjectRoot();
1341
- if (!projectRoot)
1342
- throw new Error('Not a TimSquad project');
1343
- const seqIds = options.sequences.split(',').map(s => s.trim());
1344
- const seqDir = getSequencesDir(projectRoot);
1345
- const now = getTimestamp();
1346
- // Load sequence logs
1347
- const seqLogs = [];
1348
- let completed = 0, blocked = 0;
1349
- for (const id of seqIds) {
1350
- const seqPath = path.join(seqDir, `${id}.json`);
1351
- if (await exists(seqPath)) {
1352
- const data = await fs.readJson(seqPath);
1353
- seqLogs.push(data);
1354
- if (data.execution.status === 'completed')
1355
- completed++;
1356
- else
1357
- blocked++;
1358
- }
1359
- else {
1360
- blocked++;
1361
- }
1362
- }
1363
- // Aggregate
1364
- let totalTasks = 0, totalSuccess = 0, totalRework = 0, totalFiles = 0;
1365
- let totalIssues1 = 0, totalIssues2 = 0, totalIssues3 = 0;
1366
- const durations = [];
1367
- for (const seq of seqLogs) {
1368
- totalTasks += seq.tasks.total;
1369
- totalSuccess += seq.tasks.success;
1370
- totalRework += seq.tasks.rework;
1371
- durations.push(seq.execution.duration_ms);
1372
- // Count issues from analysis axes
1373
- for (const axis of Object.values(seq.analysis)) {
1374
- const r = axis;
1375
- for (const issue of r.issues) {
1376
- if (issue.level === 1)
1377
- totalIssues1++;
1378
- else if (issue.level === 2)
1379
- totalIssues2++;
1380
- else
1381
- totalIssues3++;
1382
- }
1383
- }
1384
- }
1385
- // Collect total files from task logs
1386
- for (const seqId of seqIds) {
1387
- const taskLogs = await loadSequenceTaskLogs(projectRoot, seqId);
1388
- for (const { data } of taskLogs) {
1389
- totalFiles += data.mechanical?.files?.length || 0;
1390
- }
1391
- }
1392
- const timestamps = seqLogs
1393
- .map(s => [new Date(s.execution.started_at).getTime(), new Date(s.execution.completed_at).getTime()])
1394
- .flat()
1395
- .filter(t => t > 0);
1396
- const leadTime = timestamps.length >= 2 ? Math.max(...timestamps) - Math.min(...timestamps) : 0;
1397
- const entry = {
1398
- schema_version: LOG_SCHEMA_VERSION,
1399
- trace: { phase_id: phaseId },
1400
- execution: {
1401
- status: blocked > 0 ? 'aborted' : 'completed',
1402
- started_at: seqLogs[0]?.execution.started_at || now,
1403
- completed_at: now,
1404
- duration_ms: leadTime,
1405
- sessions_count: seqLogs.length,
1406
- },
1407
- sequences: { total: seqIds.length, completed, blocked, ids: seqIds },
1408
- aggregate_metrics: {
1409
- total_tasks: totalTasks,
1410
- task_success_rate: totalTasks > 0 ? totalSuccess / totalTasks : 0,
1411
- task_rework_rate: totalTasks > 0 ? totalRework / totalTasks : 0,
1412
- total_files_changed: totalFiles,
1413
- total_issues: { level_1: totalIssues1, level_2: totalIssues2, level_3: totalIssues3 },
1414
- ssot_conformance_rate: 0, // Placeholder — from architect reports
1415
- mean_sequence_duration_ms: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
1416
- },
1417
- dora_derived: {
1418
- lead_time_ms: leadTime,
1419
- change_failure_rate: totalTasks > 0 ? (totalTasks - totalSuccess) / totalTasks : 0,
1420
- mean_recovery_time_ms: null,
1421
- },
1422
- planning: {
1423
- original_sequences: seqIds,
1424
- added_sequences: [],
1425
- removed_sequences: [],
1426
- scope_changes: [],
1427
- plan_adherence_rate: 1,
1428
- },
1429
- retrospective: {
1430
- keep: options.retroKeep ? options.retroKeep.split(',').map(s => s.trim()) : [],
1431
- problem: options.retroProblem ? options.retroProblem.split(',').map(s => s.trim()) : [],
1432
- try: options.retroTry ? options.retroTry.split(',').map(s => s.trim()) : [],
1433
- },
1434
- knowledge_extracted: [],
1435
- };
1436
- const phaseDir = getPhasesDir(projectRoot);
1437
- await fs.ensureDir(phaseDir);
1438
- await fs.writeJson(path.join(phaseDir, `${phaseId}.json`), entry, { spaces: 2 });
1439
- printSuccess(`Phase log created: ${phaseId}.json`);
1440
- printKeyValue('Sequences', `${completed}/${seqIds.length} completed`);
1441
- printKeyValue('Tasks', `${totalSuccess}/${totalTasks} success`);
1442
- }
1443
- async function checkPhaseGate(phaseId) {
1444
- const projectRoot = await findProjectRoot();
1445
- if (!projectRoot)
1446
- throw new Error('Not a TimSquad project');
1447
- const result = await buildPhaseGateData(projectRoot, phaseId);
1448
- printHeader(`Phase Gate: ${phaseId}`);
1449
- if (result.can_transition) {
1450
- console.log(colors.success('\n ✓ PASSED — Phase transition allowed'));
1451
- }
1452
- else {
1453
- console.log(colors.error('\n ✗ BLOCKED — Phase transition denied'));
1454
- if (result.missing_reports.length > 0) {
1455
- console.log(colors.subheader('\n Missing Reports'));
1456
- for (const r of result.missing_reports) {
1457
- console.log(` - ${r}`);
1458
- }
1459
- }
1460
- if (result.blocking_conditions.length > 0) {
1461
- console.log(colors.subheader('\n Blocking Conditions'));
1462
- for (const c of result.blocking_conditions) {
1463
- console.log(` - ${c}`);
1464
- }
1465
- }
1466
- }
1467
- }
1468
- //# sourceMappingURL=log.js.map