timsquad 2.1.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/README.ko.md +288 -0
  2. package/README.md +170 -763
  3. package/dist/commands/compile.d.ts +3 -0
  4. package/dist/commands/compile.d.ts.map +1 -0
  5. package/dist/commands/compile.js +170 -0
  6. package/dist/commands/compile.js.map +1 -0
  7. package/dist/commands/daemon.d.ts +7 -0
  8. package/dist/commands/daemon.d.ts.map +1 -0
  9. package/dist/commands/daemon.js +229 -0
  10. package/dist/commands/daemon.js.map +1 -0
  11. package/dist/commands/feedback.d.ts +9 -0
  12. package/dist/commands/feedback.d.ts.map +1 -1
  13. package/dist/commands/feedback.js +235 -14
  14. package/dist/commands/feedback.js.map +1 -1
  15. package/dist/commands/full.js +2 -2
  16. package/dist/commands/full.js.map +1 -1
  17. package/dist/commands/init.d.ts.map +1 -1
  18. package/dist/commands/init.js +118 -22
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/commands/knowledge.d.ts +3 -0
  21. package/dist/commands/knowledge.d.ts.map +1 -0
  22. package/dist/commands/knowledge.js +316 -0
  23. package/dist/commands/knowledge.js.map +1 -0
  24. package/dist/commands/log.d.ts +27 -0
  25. package/dist/commands/log.d.ts.map +1 -1
  26. package/dist/commands/log.js +965 -0
  27. package/dist/commands/log.js.map +1 -1
  28. package/dist/commands/meta-index.d.ts +3 -0
  29. package/dist/commands/meta-index.d.ts.map +1 -0
  30. package/dist/commands/meta-index.js +401 -0
  31. package/dist/commands/meta-index.js.map +1 -0
  32. package/dist/commands/metrics.d.ts.map +1 -1
  33. package/dist/commands/metrics.js +239 -4
  34. package/dist/commands/metrics.js.map +1 -1
  35. package/dist/commands/retro.js +154 -6
  36. package/dist/commands/retro.js.map +1 -1
  37. package/dist/commands/skills.d.ts +12 -0
  38. package/dist/commands/skills.d.ts.map +1 -0
  39. package/dist/commands/skills.js +231 -0
  40. package/dist/commands/skills.js.map +1 -0
  41. package/dist/commands/upgrade.d.ts +8 -0
  42. package/dist/commands/upgrade.d.ts.map +1 -0
  43. package/dist/commands/upgrade.js +292 -0
  44. package/dist/commands/upgrade.js.map +1 -0
  45. package/dist/commands/workflow.d.ts +3 -0
  46. package/dist/commands/workflow.d.ts.map +1 -0
  47. package/dist/commands/workflow.js +607 -0
  48. package/dist/commands/workflow.js.map +1 -0
  49. package/dist/daemon/context-writer.d.ts +16 -0
  50. package/dist/daemon/context-writer.d.ts.map +1 -0
  51. package/dist/daemon/context-writer.js +35 -0
  52. package/dist/daemon/context-writer.js.map +1 -0
  53. package/dist/daemon/entry.d.ts +7 -0
  54. package/dist/daemon/entry.d.ts.map +1 -0
  55. package/dist/daemon/entry.js +17 -0
  56. package/dist/daemon/entry.js.map +1 -0
  57. package/dist/daemon/event-queue.d.ts +52 -0
  58. package/dist/daemon/event-queue.d.ts.map +1 -0
  59. package/dist/daemon/event-queue.js +255 -0
  60. package/dist/daemon/event-queue.js.map +1 -0
  61. package/dist/daemon/file-watcher.d.ts +19 -0
  62. package/dist/daemon/file-watcher.d.ts.map +1 -0
  63. package/dist/daemon/file-watcher.js +87 -0
  64. package/dist/daemon/file-watcher.js.map +1 -0
  65. package/dist/daemon/index.d.ts +29 -0
  66. package/dist/daemon/index.d.ts.map +1 -0
  67. package/dist/daemon/index.js +296 -0
  68. package/dist/daemon/index.js.map +1 -0
  69. package/dist/daemon/jsonl-watcher.d.ts +49 -0
  70. package/dist/daemon/jsonl-watcher.d.ts.map +1 -0
  71. package/dist/daemon/jsonl-watcher.js +258 -0
  72. package/dist/daemon/jsonl-watcher.js.map +1 -0
  73. package/dist/daemon/meta-cache.d.ts +63 -0
  74. package/dist/daemon/meta-cache.d.ts.map +1 -0
  75. package/dist/daemon/meta-cache.js +249 -0
  76. package/dist/daemon/meta-cache.js.map +1 -0
  77. package/dist/daemon/session-state.d.ts +19 -0
  78. package/dist/daemon/session-state.d.ts.map +1 -0
  79. package/dist/daemon/session-state.js +132 -0
  80. package/dist/daemon/session-state.js.map +1 -0
  81. package/dist/daemon/shutdown.d.ts +21 -0
  82. package/dist/daemon/shutdown.d.ts.map +1 -0
  83. package/dist/daemon/shutdown.js +164 -0
  84. package/dist/daemon/shutdown.js.map +1 -0
  85. package/dist/index.js +24 -3
  86. package/dist/index.js.map +1 -1
  87. package/dist/lib/agent-composer.d.ts +38 -0
  88. package/dist/lib/agent-composer.d.ts.map +1 -0
  89. package/dist/lib/agent-composer.js +128 -0
  90. package/dist/lib/agent-composer.js.map +1 -0
  91. package/dist/lib/agent-generator.d.ts +22 -0
  92. package/dist/lib/agent-generator.d.ts.map +1 -0
  93. package/dist/lib/agent-generator.js +150 -0
  94. package/dist/lib/agent-generator.js.map +1 -0
  95. package/dist/lib/ast-parser.d.ts +11 -0
  96. package/dist/lib/ast-parser.d.ts.map +1 -0
  97. package/dist/lib/ast-parser.js +282 -0
  98. package/dist/lib/ast-parser.js.map +1 -0
  99. package/dist/lib/compile-rules.d.ts +66 -0
  100. package/dist/lib/compile-rules.d.ts.map +1 -0
  101. package/dist/lib/compile-rules.js +114 -0
  102. package/dist/lib/compile-rules.js.map +1 -0
  103. package/dist/lib/compiler.d.ts +105 -0
  104. package/dist/lib/compiler.d.ts.map +1 -0
  105. package/dist/lib/compiler.js +368 -0
  106. package/dist/lib/compiler.js.map +1 -0
  107. package/dist/lib/config.d.ts +7 -2
  108. package/dist/lib/config.d.ts.map +1 -1
  109. package/dist/lib/config.js +34 -3
  110. package/dist/lib/config.js.map +1 -1
  111. package/dist/lib/meta-index.d.ts +19 -0
  112. package/dist/lib/meta-index.d.ts.map +1 -0
  113. package/dist/lib/meta-index.js +573 -0
  114. package/dist/lib/meta-index.js.map +1 -0
  115. package/dist/lib/project.js +1 -1
  116. package/dist/lib/project.js.map +1 -1
  117. package/dist/lib/skill-generator.d.ts +32 -0
  118. package/dist/lib/skill-generator.d.ts.map +1 -0
  119. package/dist/lib/skill-generator.js +187 -0
  120. package/dist/lib/skill-generator.js.map +1 -0
  121. package/dist/lib/template.d.ts +16 -2
  122. package/dist/lib/template.d.ts.map +1 -1
  123. package/dist/lib/template.js +115 -20
  124. package/dist/lib/template.js.map +1 -1
  125. package/dist/lib/ui-index.d.ts +12 -0
  126. package/dist/lib/ui-index.d.ts.map +1 -0
  127. package/dist/lib/ui-index.js +239 -0
  128. package/dist/lib/ui-index.js.map +1 -0
  129. package/dist/lib/ui-parser.d.ts +12 -0
  130. package/dist/lib/ui-parser.d.ts.map +1 -0
  131. package/dist/lib/ui-parser.js +472 -0
  132. package/dist/lib/ui-parser.js.map +1 -0
  133. package/dist/lib/update-check.d.ts +6 -0
  134. package/dist/lib/update-check.d.ts.map +1 -0
  135. package/dist/lib/update-check.js +121 -0
  136. package/dist/lib/update-check.js.map +1 -0
  137. package/dist/lib/upgrade-backup.d.ts +33 -0
  138. package/dist/lib/upgrade-backup.d.ts.map +1 -0
  139. package/dist/lib/upgrade-backup.js +101 -0
  140. package/dist/lib/upgrade-backup.js.map +1 -0
  141. package/dist/lib/version.d.ts +19 -0
  142. package/dist/lib/version.d.ts.map +1 -0
  143. package/dist/lib/version.js +35 -0
  144. package/dist/lib/version.js.map +1 -0
  145. package/dist/lib/workflow-state.d.ts +48 -0
  146. package/dist/lib/workflow-state.d.ts.map +1 -0
  147. package/dist/lib/workflow-state.js +67 -0
  148. package/dist/lib/workflow-state.js.map +1 -0
  149. package/dist/types/config.d.ts +103 -2
  150. package/dist/types/config.d.ts.map +1 -1
  151. package/dist/types/config.js +184 -9
  152. package/dist/types/config.js.map +1 -1
  153. package/dist/types/feedback.d.ts +7 -0
  154. package/dist/types/feedback.d.ts.map +1 -1
  155. package/dist/types/feedback.js +1 -1
  156. package/dist/types/feedback.js.map +1 -1
  157. package/dist/types/index.d.ts +3 -0
  158. package/dist/types/index.d.ts.map +1 -1
  159. package/dist/types/index.js +3 -0
  160. package/dist/types/index.js.map +1 -1
  161. package/dist/types/meta-index.d.ts +146 -0
  162. package/dist/types/meta-index.d.ts.map +1 -0
  163. package/dist/types/meta-index.js +7 -0
  164. package/dist/types/meta-index.js.map +1 -0
  165. package/dist/types/project.d.ts +19 -3
  166. package/dist/types/project.d.ts.map +1 -1
  167. package/dist/types/project.js +23 -0
  168. package/dist/types/project.js.map +1 -1
  169. package/dist/types/task-log.d.ts +208 -0
  170. package/dist/types/task-log.d.ts.map +1 -0
  171. package/dist/types/task-log.js +6 -0
  172. package/dist/types/task-log.js.map +1 -0
  173. package/dist/types/ui-meta.d.ts +118 -0
  174. package/dist/types/ui-meta.d.ts.map +1 -0
  175. package/dist/types/ui-meta.js +7 -0
  176. package/dist/types/ui-meta.js.map +1 -0
  177. package/package.json +12 -4
  178. package/templates/base/agents/base/tsq-architect.md +68 -0
  179. package/templates/base/agents/base/tsq-dba.md +56 -0
  180. package/templates/base/agents/base/tsq-designer.md +72 -0
  181. package/templates/base/agents/base/tsq-developer.md +67 -0
  182. package/templates/base/agents/base/tsq-qa.md +55 -0
  183. package/templates/base/agents/base/tsq-security.md +65 -0
  184. package/templates/base/agents/overlays/domain/general-web/_common.md +11 -0
  185. package/templates/base/agents/overlays/domain/mobile/_common.md +13 -0
  186. package/templates/base/agents/overlays/platform/claude-code.md +12 -0
  187. package/templates/base/config.template.yaml +213 -0
  188. package/templates/base/knowledge/checklists/accessibility.md +37 -0
  189. package/templates/base/knowledge/checklists/architecture-review.md +28 -0
  190. package/templates/base/knowledge/checklists/database-standards.md +84 -0
  191. package/templates/base/knowledge/checklists/design-reference.md +97 -0
  192. package/templates/base/knowledge/checklists/security.md +50 -0
  193. package/templates/base/knowledge/checklists/ssot-validation.md +19 -0
  194. package/templates/base/knowledge/domains/_template.md +16 -0
  195. package/templates/base/knowledge/platforms/_template.md +16 -0
  196. package/templates/base/knowledge/templates/sequence-report.md +44 -0
  197. package/templates/base/knowledge/templates/task-result.md +105 -0
  198. package/templates/base/skills/_template/SKILL.md +59 -0
  199. package/templates/base/skills/_template/references/_template.md +35 -0
  200. package/templates/base/skills/_template/rules/_sections.md +34 -0
  201. package/templates/base/skills/_template/rules/_template.md +32 -0
  202. package/templates/base/skills/_template/scripts/_template.sh +31 -0
  203. package/templates/base/skills/architecture/SKILL.md +54 -0
  204. package/templates/base/skills/architecture/references/adr-template.md +50 -0
  205. package/templates/base/skills/architecture/references/api-design.md +64 -0
  206. package/templates/base/skills/backend/node/SKILL.md +81 -0
  207. package/templates/base/skills/backend/node/rules/async-patterns.md +81 -0
  208. package/templates/base/skills/backend/node/rules/deployment.md +33 -0
  209. package/templates/base/skills/backend/node/rules/env-config.md +41 -0
  210. package/templates/base/skills/backend/node/rules/error-handling.md +83 -0
  211. package/templates/base/skills/backend/node/rules/hono-app-setup.md +98 -0
  212. package/templates/base/skills/backend/node/rules/jwt-auth.md +76 -0
  213. package/templates/base/skills/backend/node/rules/middleware.md +56 -0
  214. package/templates/base/skills/backend/node/rules/testing.md +82 -0
  215. package/templates/base/skills/coding/SKILL.md +47 -0
  216. package/templates/base/skills/coding/rules/patterns.md +81 -0
  217. package/templates/base/skills/controller/SKILL.md +111 -0
  218. package/templates/base/skills/controller/references/README.md +35 -0
  219. package/templates/base/skills/controller/rules/README.md +18 -0
  220. package/templates/base/skills/database/SKILL.md +98 -0
  221. package/templates/base/skills/database/prisma/SKILL.md +57 -0
  222. package/templates/base/skills/database/prisma/rules/queries.md +133 -0
  223. package/templates/base/skills/database/prisma/rules/schema-design.md +80 -0
  224. package/templates/base/skills/frontend/nextjs/SKILL.md +59 -0
  225. package/templates/base/skills/frontend/nextjs/rules/app-router.md +138 -0
  226. package/templates/base/skills/frontend/react/SKILL.md +86 -0
  227. package/templates/base/skills/frontend/react/rules/_sections.md +88 -0
  228. package/templates/base/skills/frontend/react/rules/anti-patterns.md +67 -0
  229. package/templates/base/skills/frontend/react/rules/async-api-routes.md +38 -0
  230. package/templates/base/skills/frontend/react/rules/async-defer-await.md +80 -0
  231. package/templates/base/skills/frontend/react/rules/async-dependencies.md +36 -0
  232. package/templates/base/skills/frontend/react/rules/async-parallel.md +28 -0
  233. package/templates/base/skills/frontend/react/rules/async-suspense-boundaries.md +99 -0
  234. package/templates/base/skills/frontend/react/rules/bundle-barrel-imports.md +59 -0
  235. package/templates/base/skills/frontend/react/rules/bundle-defer-third-party.md +49 -0
  236. package/templates/base/skills/frontend/react/rules/bundle-dynamic-imports.md +35 -0
  237. package/templates/base/skills/frontend/react/rules/component-conventions.md +74 -0
  238. package/templates/base/skills/frontend/react/rules/js-combine-iterations.md +32 -0
  239. package/templates/base/skills/frontend/react/rules/js-early-exit.md +50 -0
  240. package/templates/base/skills/frontend/react/rules/js-index-maps.md +37 -0
  241. package/templates/base/skills/frontend/react/rules/js-set-map-lookups.md +24 -0
  242. package/templates/base/skills/frontend/react/rules/rendering-conditional-render.md +40 -0
  243. package/templates/base/skills/frontend/react/rules/rendering-content-visibility.md +38 -0
  244. package/templates/base/skills/frontend/react/rules/rendering-hoist-jsx.md +46 -0
  245. package/templates/base/skills/frontend/react/rules/rerender-defer-reads.md +39 -0
  246. package/templates/base/skills/frontend/react/rules/rerender-derived-state.md +29 -0
  247. package/templates/base/skills/frontend/react/rules/rerender-memo.md +44 -0
  248. package/templates/base/skills/frontend/react/rules/rerender-transitions.md +40 -0
  249. package/templates/base/skills/frontend/react/rules/server-after-nonblocking.md +73 -0
  250. package/templates/base/skills/frontend/react/rules/server-cache-react.md +26 -0
  251. package/templates/base/skills/frontend/react/rules/server-parallel-fetching.md +79 -0
  252. package/templates/base/skills/frontend/react/rules/state-location.md +55 -0
  253. package/templates/base/skills/methodology/bdd/SKILL.md +69 -0
  254. package/templates/base/skills/methodology/bdd/rules/gherkin-patterns.md +113 -0
  255. package/templates/base/skills/methodology/ddd/SKILL.md +74 -0
  256. package/templates/base/skills/methodology/ddd/rules/strategic-patterns.md +98 -0
  257. package/templates/base/skills/methodology/debugging/SKILL.md +60 -0
  258. package/templates/base/skills/methodology/debugging/references/root-cause-tracing.md +84 -0
  259. package/templates/base/skills/methodology/tdd/SKILL.md +66 -0
  260. package/templates/base/skills/methodology/tdd/rules/real-world-example.md +88 -0
  261. package/templates/base/skills/methodology/tdd/rules/techniques.md +185 -0
  262. package/templates/base/skills/mobile/dart/SKILL.md +69 -0
  263. package/templates/base/skills/mobile/dart/rules/async-patterns.md +112 -0
  264. package/templates/base/skills/mobile/dart/rules/code-style.md +96 -0
  265. package/templates/base/skills/mobile/dart/rules/null-safety.md +84 -0
  266. package/templates/base/skills/mobile/dart/rules/type-system.md +111 -0
  267. package/templates/base/skills/mobile/flutter/SKILL.md +89 -0
  268. package/templates/base/skills/mobile/flutter/ci-cd/SKILL.md +82 -0
  269. package/templates/base/skills/mobile/flutter/ci-cd/references/ci-cd-pipeline.md +314 -0
  270. package/templates/base/skills/mobile/flutter/ci-cd/rules/code-signing.md +106 -0
  271. package/templates/base/skills/mobile/flutter/ci-cd/rules/codemagic-setup.md +116 -0
  272. package/templates/base/skills/mobile/flutter/ci-cd/rules/fastlane-setup.md +105 -0
  273. package/templates/base/skills/mobile/flutter/ci-cd/rules/github-actions.md +112 -0
  274. package/templates/base/skills/mobile/flutter/ci-cd/rules/store-deployment.md +106 -0
  275. package/templates/base/skills/mobile/flutter/ci-cd/rules/versioning.md +107 -0
  276. package/templates/base/skills/mobile/flutter/i18n/SKILL.md +78 -0
  277. package/templates/base/skills/mobile/flutter/i18n/references/i18n-architecture.md +225 -0
  278. package/templates/base/skills/mobile/flutter/i18n/rules/arb-files.md +182 -0
  279. package/templates/base/skills/mobile/flutter/i18n/rules/locale-switching.md +226 -0
  280. package/templates/base/skills/mobile/flutter/i18n/rules/localization-setup.md +137 -0
  281. package/templates/base/skills/mobile/flutter/i18n/rules/plural-gender.md +159 -0
  282. package/templates/base/skills/mobile/flutter/i18n/rules/text-direction.md +199 -0
  283. package/templates/base/skills/mobile/flutter/monitoring/SKILL.md +81 -0
  284. package/templates/base/skills/mobile/flutter/monitoring/references/monitoring-architecture.md +269 -0
  285. package/templates/base/skills/mobile/flutter/monitoring/rules/analytics.md +227 -0
  286. package/templates/base/skills/mobile/flutter/monitoring/rules/crashlytics-setup.md +195 -0
  287. package/templates/base/skills/mobile/flutter/monitoring/rules/logging.md +258 -0
  288. package/templates/base/skills/mobile/flutter/monitoring/rules/performance-monitoring.md +248 -0
  289. package/templates/base/skills/mobile/flutter/monitoring/rules/sentry-integration.md +249 -0
  290. package/templates/base/skills/mobile/flutter/networking/SKILL.md +88 -0
  291. package/templates/base/skills/mobile/flutter/networking/references/api-client-architecture.md +305 -0
  292. package/templates/base/skills/mobile/flutter/networking/rules/caching.md +212 -0
  293. package/templates/base/skills/mobile/flutter/networking/rules/connectivity.md +213 -0
  294. package/templates/base/skills/mobile/flutter/networking/rules/dio-setup.md +159 -0
  295. package/templates/base/skills/mobile/flutter/networking/rules/error-handling.md +209 -0
  296. package/templates/base/skills/mobile/flutter/networking/rules/interceptors.md +205 -0
  297. package/templates/base/skills/mobile/flutter/networking/rules/retrofit-patterns.md +194 -0
  298. package/templates/base/skills/mobile/flutter/push-notifications/SKILL.md +87 -0
  299. package/templates/base/skills/mobile/flutter/push-notifications/references/notification-architecture.md +340 -0
  300. package/templates/base/skills/mobile/flutter/push-notifications/references/platform-setup.md +286 -0
  301. package/templates/base/skills/mobile/flutter/push-notifications/rules/background-processing.md +308 -0
  302. package/templates/base/skills/mobile/flutter/push-notifications/rules/deep-linking.md +217 -0
  303. package/templates/base/skills/mobile/flutter/push-notifications/rules/fcm-setup.md +164 -0
  304. package/templates/base/skills/mobile/flutter/push-notifications/rules/local-notifications.md +262 -0
  305. package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-handling.md +210 -0
  306. package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-permissions.md +246 -0
  307. package/templates/base/skills/mobile/flutter/push-notifications/rules/rich-notifications.md +320 -0
  308. package/templates/base/skills/mobile/flutter/references/freezed-patterns.md +162 -0
  309. package/templates/base/skills/mobile/flutter/references/project-structure.md +170 -0
  310. package/templates/base/skills/mobile/flutter/rules/animations.md +112 -0
  311. package/templates/base/skills/mobile/flutter/rules/architecture.md +121 -0
  312. package/templates/base/skills/mobile/flutter/rules/navigation-routing.md +117 -0
  313. package/templates/base/skills/mobile/flutter/rules/performance.md +112 -0
  314. package/templates/base/skills/mobile/flutter/rules/platform-adaptive.md +126 -0
  315. package/templates/base/skills/mobile/flutter/rules/state-management.md +110 -0
  316. package/templates/base/skills/mobile/flutter/rules/testing.md +131 -0
  317. package/templates/base/skills/mobile/flutter/rules/widget-conventions.md +122 -0
  318. package/templates/base/skills/mobile/flutter/security/SKILL.md +86 -0
  319. package/templates/base/skills/mobile/flutter/security/references/mobile-security-checklist.md +168 -0
  320. package/templates/base/skills/mobile/flutter/security/rules/api-key-protection.md +206 -0
  321. package/templates/base/skills/mobile/flutter/security/rules/authentication.md +248 -0
  322. package/templates/base/skills/mobile/flutter/security/rules/data-protection.md +271 -0
  323. package/templates/base/skills/mobile/flutter/security/rules/obfuscation.md +213 -0
  324. package/templates/base/skills/mobile/flutter/security/rules/secure-storage.md +171 -0
  325. package/templates/base/skills/mobile/flutter/security/rules/ssl-pinning.md +197 -0
  326. package/templates/base/skills/planning/SKILL.md +58 -0
  327. package/templates/base/skills/planning/references/prd-guide.md +47 -0
  328. package/templates/base/skills/planning/references/requirements-guide.md +46 -0
  329. package/templates/base/skills/prompt-engineering/SKILL.md +103 -0
  330. package/templates/base/skills/retrospective/SKILL.md +102 -0
  331. package/templates/base/skills/security/SKILL.md +55 -0
  332. package/templates/base/skills/security/rules/owasp-examples.md +119 -0
  333. package/templates/base/skills/security/scripts/check-secrets.sh +55 -0
  334. package/templates/base/skills/testing/SKILL.md +63 -0
  335. package/templates/base/skills/testing/references/testing-patterns.md +103 -0
  336. package/templates/base/skills/tsq-protocol/SKILL.md +51 -0
  337. package/templates/base/skills/typescript/SKILL.md +67 -0
  338. package/templates/base/skills/typescript/rules/type-patterns.md +135 -0
  339. package/templates/base/skills/typescript/rules/utility-types.md +76 -0
  340. package/templates/base/skills/ui-design/SKILL.md +70 -0
  341. package/templates/{common → base}/timsquad/feedback/routing-rules.yaml +1 -1
  342. package/templates/{common → base}/timsquad/retrospective/metrics/metrics-schema.json +46 -1
  343. package/templates/platforms/claude-code/CLAUDE.md.template +89 -0
  344. package/templates/platforms/claude-code/rules/adr-rules.md +32 -0
  345. package/templates/platforms/claude-code/rules/feedback-routing.md +18 -0
  346. package/templates/platforms/claude-code/rules/phase-management.md +23 -0
  347. package/templates/platforms/claude-code/rules/reporting-format.md +26 -0
  348. package/templates/platforms/claude-code/rules/sequence-management.md +72 -0
  349. package/templates/platforms/claude-code/rules/workspace-sync.md +33 -0
  350. package/templates/platforms/claude-code/scripts/completion-guard.sh +57 -0
  351. package/templates/platforms/claude-code/scripts/phase-guard.sh +79 -0
  352. package/templates/platforms/claude-code/settings.json +98 -0
  353. package/templates/project-types/api-backend/config.yaml +227 -0
  354. package/templates/project-types/api-backend/process/workflow.xml +214 -0
  355. package/templates/project-types/fintech/config.yaml +151 -0
  356. package/templates/project-types/fintech/process/workflow.xml +316 -0
  357. package/templates/project-types/infra/config.yaml +327 -0
  358. package/templates/project-types/infra/process/workflow.xml +296 -0
  359. package/templates/project-types/mobile-app/config.yaml +123 -0
  360. package/templates/project-types/mobile-app/process/workflow.xml +191 -0
  361. package/templates/project-types/platform/config.yaml +254 -0
  362. package/templates/project-types/platform/process/workflow.xml +254 -0
  363. package/templates/project-types/web-app/config.yaml +198 -0
  364. package/templates/project-types/web-app/process/workflow.xml +210 -0
  365. package/templates/project-types/web-service/config.yaml +136 -0
  366. package/templates/project-types/web-service/process/workflow.xml +184 -0
  367. package/templates/common/CLAUDE.md.template +0 -254
  368. package/templates/common/claude/agents/tsq-dba.md +0 -311
  369. package/templates/common/claude/agents/tsq-designer.md +0 -323
  370. package/templates/common/claude/agents/tsq-developer.md +0 -177
  371. package/templates/common/claude/agents/tsq-planner.md +0 -190
  372. package/templates/common/claude/agents/tsq-prompter.md +0 -356
  373. package/templates/common/claude/agents/tsq-qa.md +0 -168
  374. package/templates/common/claude/agents/tsq-retro.md +0 -193
  375. package/templates/common/claude/agents/tsq-security.md +0 -221
  376. package/templates/common/claude/hooks/auto-metrics.sh +0 -165
  377. package/templates/common/claude/hooks/auto-worklog.sh +0 -245
  378. package/templates/common/claude/hooks/event-logger.sh +0 -208
  379. package/templates/common/claude/settings.json +0 -86
  380. package/templates/common/claude/skills/architecture/SKILL.md +0 -123
  381. package/templates/common/claude/skills/backend/node/SKILL.md +0 -1015
  382. package/templates/common/claude/skills/coding/SKILL.md +0 -171
  383. package/templates/common/claude/skills/database/prisma/SKILL.md +0 -357
  384. package/templates/common/claude/skills/frontend/nextjs/SKILL.md +0 -279
  385. package/templates/common/claude/skills/frontend/react/SKILL.md +0 -1729
  386. package/templates/common/claude/skills/methodology/bdd/SKILL.md +0 -234
  387. package/templates/common/claude/skills/methodology/ddd/SKILL.md +0 -311
  388. package/templates/common/claude/skills/methodology/tdd/SKILL.md +0 -512
  389. package/templates/common/claude/skills/planning/SKILL.md +0 -90
  390. package/templates/common/claude/skills/security/SKILL.md +0 -234
  391. package/templates/common/claude/skills/testing/SKILL.md +0 -146
  392. package/templates/common/claude/skills/typescript/SKILL.md +0 -435
  393. package/templates/common/config.template.yaml +0 -132
  394. /package/templates/{common → base}/timsquad/architectures/clean/ARCHITECTURE.md +0 -0
  395. /package/templates/{common → base}/timsquad/architectures/clean/backend.xml +0 -0
  396. /package/templates/{common → base}/timsquad/architectures/clean/frontend.xml +0 -0
  397. /package/templates/{common → base}/timsquad/architectures/fsd/ARCHITECTURE.md +0 -0
  398. /package/templates/{common → base}/timsquad/architectures/fsd/frontend.xml +0 -0
  399. /package/templates/{common → base}/timsquad/architectures/hexagonal/ARCHITECTURE.md +0 -0
  400. /package/templates/{common → base}/timsquad/architectures/hexagonal/backend.xml +0 -0
  401. /package/templates/{common → base}/timsquad/constraints/competency-framework.xml +0 -0
  402. /package/templates/{common → base}/timsquad/constraints/ssot-schema.xml +0 -0
  403. /package/templates/{common → base}/timsquad/feedback/feedback-router.sh +0 -0
  404. /package/templates/{common → base}/timsquad/generators/data-design.xml +0 -0
  405. /package/templates/{common → base}/timsquad/generators/prd.xml +0 -0
  406. /package/templates/{common → base}/timsquad/generators/requirements.xml +0 -0
  407. /package/templates/{common → base}/timsquad/generators/service-spec.xml +0 -0
  408. /package/templates/{common → base}/timsquad/logs/_example.md +0 -0
  409. /package/templates/{common → base}/timsquad/logs/_template.md +0 -0
  410. /package/templates/{common → base}/timsquad/patterns/cqrs.xml +0 -0
  411. /package/templates/{common → base}/timsquad/patterns/event-sourcing.xml +0 -0
  412. /package/templates/{common → base}/timsquad/patterns/repository.xml +0 -0
  413. /package/templates/{common → base}/timsquad/process/phase-checklist.yaml +0 -0
  414. /package/templates/{common → base}/timsquad/process/state-machine.xml +0 -0
  415. /package/templates/{common → base}/timsquad/process/validation-rules.xml +0 -0
  416. /package/templates/{common → base}/timsquad/process/workflow-base.xml +0 -0
  417. /package/templates/{common → base}/timsquad/retrospective/cycle-report.template.md +0 -0
  418. /package/templates/{common → base}/timsquad/retrospective/patterns/failure-patterns.md +0 -0
  419. /package/templates/{common → base}/timsquad/retrospective/patterns/success-patterns.md +0 -0
  420. /package/templates/{common → base}/timsquad/retrospective/retrospective-config.xml +0 -0
  421. /package/templates/{common → base}/timsquad/retrospective/retrospective-state.xml +0 -0
  422. /package/templates/{common → base}/timsquad/ssot/adr/ADR-000-template.md +0 -0
  423. /package/templates/{common → base}/timsquad/ssot/adr/ADR-001-example.md +0 -0
  424. /package/templates/{common → base}/timsquad/ssot/data-design.template.md +0 -0
  425. /package/templates/{common → base}/timsquad/ssot/deployment-spec.template.md +0 -0
  426. /package/templates/{common → base}/timsquad/ssot/env-config.template.md +0 -0
  427. /package/templates/{common → base}/timsquad/ssot/error-codes.template.md +0 -0
  428. /package/templates/{common → base}/timsquad/ssot/functional-spec.template.md +0 -0
  429. /package/templates/{common → base}/timsquad/ssot/glossary.template.md +0 -0
  430. /package/templates/{common → base}/timsquad/ssot/integration-spec.template.md +0 -0
  431. /package/templates/{common → base}/timsquad/ssot/planning.template.md +0 -0
  432. /package/templates/{common → base}/timsquad/ssot/prd.template.md +0 -0
  433. /package/templates/{common → base}/timsquad/ssot/requirements.template.md +0 -0
  434. /package/templates/{common → base}/timsquad/ssot/security-spec.template.md +0 -0
  435. /package/templates/{common → base}/timsquad/ssot/service-spec.template.md +0 -0
  436. /package/templates/{common → base}/timsquad/ssot/test-spec.template.md +0 -0
  437. /package/templates/{common → base}/timsquad/ssot/ui-ux-spec.template.md +0 -0
  438. /package/templates/{common → base}/timsquad/state/workspace.xml +0 -0
@@ -4,7 +4,9 @@ import { colors, printHeader, printError, printSuccess, printKeyValue } from '..
4
4
  import { findProjectRoot } from '../lib/project.js';
5
5
  import { exists, readFile, writeFile, listFiles } from '../utils/fs.js';
6
6
  import { getDateString, getTimeString, getTimestamp } from '../utils/date.js';
7
+ import { loadWorkflowState } from '../lib/workflow-state.js';
7
8
  const LOG_TYPES = ['work', 'decision', 'error', 'feedback', 'handoff'];
9
+ const LOG_SCHEMA_VERSION = '1.0.0';
8
10
  export function registerLogCommand(program) {
9
11
  const logCmd = program
10
12
  .command('log')
@@ -102,6 +104,173 @@ export function registerLogCommand(program) {
102
104
  process.exit(1);
103
105
  }
104
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
+ });
105
274
  }
106
275
  async function addLog(agent, type, message) {
107
276
  const projectRoot = await findProjectRoot();
@@ -468,4 +637,800 @@ function formatSize(bytes) {
468
637
  return `${(bytes / 1024).toFixed(1)}KB`;
469
638
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
470
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 { execSync } = await import('child_process');
1117
+ execSync(`npx tsq feedback route "${issue.description.replace(/"/g, '\\"')}"`, { 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 unresolved L2/L3 feedback
1176
+ try {
1177
+ const state = await loadWorkflowState(projectRoot);
1178
+ if (state.pending_feedback?.length > 0) {
1179
+ const feedbackDir = path.join(projectRoot, '.timsquad', 'feedback');
1180
+ for (const fbId of state.pending_feedback) {
1181
+ const fbPath = path.join(feedbackDir, `${fbId}.json`);
1182
+ if (await exists(fbPath)) {
1183
+ const fb = await fs.readJson(fbPath);
1184
+ if (!fb.status || fb.status === 'open' || fb.status === 'in_review') {
1185
+ result.can_transition = false;
1186
+ result.blocking_conditions.push(`Unresolved L${fb.level} feedback: ${fbId} (${fb.trigger})`);
1187
+ }
1188
+ }
1189
+ }
1190
+ }
1191
+ }
1192
+ catch { /* workflow state unavailable — skip feedback check */ }
1193
+ return result;
1194
+ }
1195
+ async function createSequenceLog(seqId, options) {
1196
+ const projectRoot = await findProjectRoot();
1197
+ if (!projectRoot)
1198
+ throw new Error('Not a TimSquad project');
1199
+ const entry = await buildSequenceLogData(projectRoot, seqId, options);
1200
+ const seqDir = getSequencesDir(projectRoot);
1201
+ await fs.ensureDir(seqDir);
1202
+ await fs.writeJson(path.join(seqDir, `${seqId}.json`), entry, { spaces: 2 });
1203
+ printSuccess(`Sequence log created: ${seqId}.json`);
1204
+ printKeyValue('Tasks', `${entry.tasks.success}/${entry.tasks.total} success`);
1205
+ printKeyValue('Verdict', entry.verdict.proceed ? 'PROCEED' : 'HOLD');
1206
+ }
1207
+ async function checkSequence(seqId) {
1208
+ const projectRoot = await findProjectRoot();
1209
+ if (!projectRoot)
1210
+ throw new Error('Not a TimSquad project');
1211
+ const taskLogs = await loadSequenceTaskLogs(projectRoot, seqId);
1212
+ printHeader(`Sequence Check: ${seqId}`);
1213
+ printKeyValue('Task Logs Found', String(taskLogs.length));
1214
+ if (taskLogs.length === 0) {
1215
+ console.log(colors.dim(' No task logs found for this sequence'));
1216
+ return;
1217
+ }
1218
+ let withSemantic = 0;
1219
+ for (const { file, data } of taskLogs) {
1220
+ const sem = hasSemantic(data.semantic) ? colors.success('✓ semantic') : colors.warning('○ no semantic');
1221
+ const status = data.status === 'completed' ? '✓' : '✗';
1222
+ console.log(` ${status} ${colors.agent(data.agent || '?')} ${sem} ${colors.dim(file)}`);
1223
+ if (hasSemantic(data.semantic))
1224
+ withSemantic++;
1225
+ }
1226
+ const coverage = Math.round((withSemantic / taskLogs.length) * 100);
1227
+ console.log('');
1228
+ printKeyValue('Semantic Coverage', `${coverage}% (${withSemantic}/${taskLogs.length})`);
1229
+ if (coverage < 100) {
1230
+ console.log(colors.warning('\n ⚠ Run tsq log enrich for tasks missing semantic data'));
1231
+ }
1232
+ }
1233
+ // ============================================================
1234
+ // Step 5: tsq log phase (L3) + Gate
1235
+ // ============================================================
1236
+ async function listPhaseLogs() {
1237
+ const projectRoot = await findProjectRoot();
1238
+ if (!projectRoot)
1239
+ throw new Error('Not a TimSquad project');
1240
+ const phaseDir = getPhasesDir(projectRoot);
1241
+ if (!await exists(phaseDir)) {
1242
+ console.log(colors.dim('No phase logs found'));
1243
+ return;
1244
+ }
1245
+ const files = await listFiles('*.json', phaseDir);
1246
+ if (files.length === 0) {
1247
+ console.log(colors.dim('No phase logs found'));
1248
+ return;
1249
+ }
1250
+ printHeader(`Phase Logs (${files.length})`);
1251
+ for (const file of files.sort()) {
1252
+ try {
1253
+ const data = await fs.readJson(path.join(phaseDir, file));
1254
+ const phaseId = data.trace.phase_id;
1255
+ const status = data.execution.status;
1256
+ const seqs = `${data.sequences.completed}/${data.sequences.total} sequences`;
1257
+ console.log(` ${colors.agent(phaseId)} [${status}] ${seqs}`);
1258
+ }
1259
+ catch {
1260
+ console.log(` ${colors.dim(file)} (unreadable)`);
1261
+ }
1262
+ }
1263
+ }
1264
+ async function viewPhaseLog(phaseId) {
1265
+ const projectRoot = await findProjectRoot();
1266
+ if (!projectRoot)
1267
+ throw new Error('Not a TimSquad project');
1268
+ const filePath = path.join(getPhasesDir(projectRoot), `${phaseId}.json`);
1269
+ if (!await exists(filePath)) {
1270
+ throw new Error(`Phase log not found: ${phaseId}`);
1271
+ }
1272
+ const data = await fs.readJson(filePath);
1273
+ printHeader(`Phase: ${phaseId}`);
1274
+ printKeyValue('Status', data.execution.status);
1275
+ printKeyValue('Duration', `${(data.execution.duration_ms / 1000 / 60).toFixed(1)} min`);
1276
+ printKeyValue('Sessions', String(data.execution.sessions_count));
1277
+ console.log(colors.subheader('\n Sequences'));
1278
+ printKeyValue(' Total', String(data.sequences.total));
1279
+ printKeyValue(' Completed', String(data.sequences.completed));
1280
+ printKeyValue(' Blocked', String(data.sequences.blocked));
1281
+ console.log(` IDs: ${data.sequences.ids.join(', ')}`);
1282
+ console.log(colors.subheader('\n Metrics'));
1283
+ printKeyValue(' Tasks', String(data.aggregate_metrics.total_tasks));
1284
+ printKeyValue(' Success Rate', `${(data.aggregate_metrics.task_success_rate * 100).toFixed(0)}%`);
1285
+ printKeyValue(' Rework Rate', `${(data.aggregate_metrics.task_rework_rate * 100).toFixed(0)}%`);
1286
+ printKeyValue(' Files Changed', String(data.aggregate_metrics.total_files_changed));
1287
+ printKeyValue(' SSOT Conformance', `${(data.aggregate_metrics.ssot_conformance_rate * 100).toFixed(0)}%`);
1288
+ console.log(colors.subheader('\n DORA'));
1289
+ printKeyValue(' Lead Time', `${(data.dora_derived.lead_time_ms / 1000 / 60).toFixed(1)} min`);
1290
+ printKeyValue(' Change Failure Rate', `${(data.dora_derived.change_failure_rate * 100).toFixed(0)}%`);
1291
+ if (data.retrospective.keep.length || data.retrospective.problem.length || data.retrospective.try.length) {
1292
+ console.log(colors.subheader('\n Retrospective'));
1293
+ if (data.retrospective.keep.length) {
1294
+ console.log(' Keep:');
1295
+ data.retrospective.keep.forEach(k => console.log(` + ${k}`));
1296
+ }
1297
+ if (data.retrospective.problem.length) {
1298
+ console.log(' Problem:');
1299
+ data.retrospective.problem.forEach(p => console.log(` - ${p}`));
1300
+ }
1301
+ if (data.retrospective.try.length) {
1302
+ console.log(' Try:');
1303
+ data.retrospective.try.forEach(t => console.log(` → ${t}`));
1304
+ }
1305
+ }
1306
+ }
1307
+ async function createPhaseLog(phaseId, options) {
1308
+ const projectRoot = await findProjectRoot();
1309
+ if (!projectRoot)
1310
+ throw new Error('Not a TimSquad project');
1311
+ const seqIds = options.sequences.split(',').map(s => s.trim());
1312
+ const seqDir = getSequencesDir(projectRoot);
1313
+ const now = getTimestamp();
1314
+ // Load sequence logs
1315
+ const seqLogs = [];
1316
+ let completed = 0, blocked = 0;
1317
+ for (const id of seqIds) {
1318
+ const seqPath = path.join(seqDir, `${id}.json`);
1319
+ if (await exists(seqPath)) {
1320
+ const data = await fs.readJson(seqPath);
1321
+ seqLogs.push(data);
1322
+ if (data.execution.status === 'completed')
1323
+ completed++;
1324
+ else
1325
+ blocked++;
1326
+ }
1327
+ else {
1328
+ blocked++;
1329
+ }
1330
+ }
1331
+ // Aggregate
1332
+ let totalTasks = 0, totalSuccess = 0, totalRework = 0, totalFiles = 0;
1333
+ let totalIssues1 = 0, totalIssues2 = 0, totalIssues3 = 0;
1334
+ const durations = [];
1335
+ for (const seq of seqLogs) {
1336
+ totalTasks += seq.tasks.total;
1337
+ totalSuccess += seq.tasks.success;
1338
+ totalRework += seq.tasks.rework;
1339
+ durations.push(seq.execution.duration_ms);
1340
+ // Count issues from analysis axes
1341
+ for (const axis of Object.values(seq.analysis)) {
1342
+ const r = axis;
1343
+ for (const issue of r.issues) {
1344
+ if (issue.level === 1)
1345
+ totalIssues1++;
1346
+ else if (issue.level === 2)
1347
+ totalIssues2++;
1348
+ else
1349
+ totalIssues3++;
1350
+ }
1351
+ }
1352
+ }
1353
+ // Collect total files from task logs
1354
+ for (const seqId of seqIds) {
1355
+ const taskLogs = await loadSequenceTaskLogs(projectRoot, seqId);
1356
+ for (const { data } of taskLogs) {
1357
+ totalFiles += data.mechanical?.files?.length || 0;
1358
+ }
1359
+ }
1360
+ const timestamps = seqLogs
1361
+ .map(s => [new Date(s.execution.started_at).getTime(), new Date(s.execution.completed_at).getTime()])
1362
+ .flat()
1363
+ .filter(t => t > 0);
1364
+ const leadTime = timestamps.length >= 2 ? Math.max(...timestamps) - Math.min(...timestamps) : 0;
1365
+ const entry = {
1366
+ schema_version: LOG_SCHEMA_VERSION,
1367
+ trace: { phase_id: phaseId },
1368
+ execution: {
1369
+ status: blocked > 0 ? 'aborted' : 'completed',
1370
+ started_at: seqLogs[0]?.execution.started_at || now,
1371
+ completed_at: now,
1372
+ duration_ms: leadTime,
1373
+ sessions_count: seqLogs.length,
1374
+ },
1375
+ sequences: { total: seqIds.length, completed, blocked, ids: seqIds },
1376
+ aggregate_metrics: {
1377
+ total_tasks: totalTasks,
1378
+ task_success_rate: totalTasks > 0 ? totalSuccess / totalTasks : 0,
1379
+ task_rework_rate: totalTasks > 0 ? totalRework / totalTasks : 0,
1380
+ total_files_changed: totalFiles,
1381
+ total_issues: { level_1: totalIssues1, level_2: totalIssues2, level_3: totalIssues3 },
1382
+ ssot_conformance_rate: 0, // Placeholder — from architect reports
1383
+ mean_sequence_duration_ms: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
1384
+ },
1385
+ dora_derived: {
1386
+ lead_time_ms: leadTime,
1387
+ change_failure_rate: totalTasks > 0 ? (totalTasks - totalSuccess) / totalTasks : 0,
1388
+ mean_recovery_time_ms: null,
1389
+ },
1390
+ planning: {
1391
+ original_sequences: seqIds,
1392
+ added_sequences: [],
1393
+ removed_sequences: [],
1394
+ scope_changes: [],
1395
+ plan_adherence_rate: 1,
1396
+ },
1397
+ retrospective: {
1398
+ keep: options.retroKeep ? options.retroKeep.split(',').map(s => s.trim()) : [],
1399
+ problem: options.retroProblem ? options.retroProblem.split(',').map(s => s.trim()) : [],
1400
+ try: options.retroTry ? options.retroTry.split(',').map(s => s.trim()) : [],
1401
+ },
1402
+ knowledge_extracted: [],
1403
+ };
1404
+ const phaseDir = getPhasesDir(projectRoot);
1405
+ await fs.ensureDir(phaseDir);
1406
+ await fs.writeJson(path.join(phaseDir, `${phaseId}.json`), entry, { spaces: 2 });
1407
+ printSuccess(`Phase log created: ${phaseId}.json`);
1408
+ printKeyValue('Sequences', `${completed}/${seqIds.length} completed`);
1409
+ printKeyValue('Tasks', `${totalSuccess}/${totalTasks} success`);
1410
+ }
1411
+ async function checkPhaseGate(phaseId) {
1412
+ const projectRoot = await findProjectRoot();
1413
+ if (!projectRoot)
1414
+ throw new Error('Not a TimSquad project');
1415
+ const result = await buildPhaseGateData(projectRoot, phaseId);
1416
+ printHeader(`Phase Gate: ${phaseId}`);
1417
+ if (result.can_transition) {
1418
+ console.log(colors.success('\n ✓ PASSED — Phase transition allowed'));
1419
+ }
1420
+ else {
1421
+ console.log(colors.error('\n ✗ BLOCKED — Phase transition denied'));
1422
+ if (result.missing_reports.length > 0) {
1423
+ console.log(colors.subheader('\n Missing Reports'));
1424
+ for (const r of result.missing_reports) {
1425
+ console.log(` - ${r}`);
1426
+ }
1427
+ }
1428
+ if (result.blocking_conditions.length > 0) {
1429
+ console.log(colors.subheader('\n Blocking Conditions'));
1430
+ for (const c of result.blocking_conditions) {
1431
+ console.log(` - ${c}`);
1432
+ }
1433
+ }
1434
+ }
1435
+ }
471
1436
  //# sourceMappingURL=log.js.map