@harness-engineering/cli 1.23.0 → 1.23.2

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 (423) hide show
  1. package/dist/agents/commands/codex/harness/add-harness-component/SKILL.md +21 -12
  2. package/dist/agents/commands/codex/harness/cleanup-dead-code/SKILL.md +9 -0
  3. package/dist/agents/commands/codex/harness/detect-doc-drift/SKILL.md +9 -0
  4. package/dist/agents/commands/codex/harness/enforce-architecture/SKILL.md +5 -15
  5. package/dist/agents/commands/codex/harness/harness-architecture-advisor/SKILL.md +5 -15
  6. package/dist/agents/commands/codex/harness/harness-autopilot/SKILL.md +10 -0
  7. package/dist/agents/commands/codex/harness/harness-brainstorming/SKILL.md +9 -0
  8. package/dist/agents/commands/codex/harness/harness-code-review/SKILL.md +5 -15
  9. package/dist/agents/commands/codex/harness/harness-codebase-cleanup/SKILL.md +9 -0
  10. package/dist/agents/commands/codex/harness/harness-debugging/SKILL.md +9 -0
  11. package/dist/agents/commands/codex/harness/harness-dependency-health/SKILL.md +8 -0
  12. package/dist/agents/commands/codex/harness/harness-docs-pipeline/SKILL.md +9 -0
  13. package/dist/agents/commands/codex/harness/harness-execution/SKILL.md +9 -0
  14. package/dist/agents/commands/codex/harness/harness-hotspot-detector/SKILL.md +8 -0
  15. package/dist/agents/commands/codex/harness/harness-impact-analysis/SKILL.md +8 -0
  16. package/dist/agents/commands/codex/harness/harness-integrity/SKILL.md +8 -0
  17. package/dist/agents/commands/codex/harness/harness-onboarding/SKILL.md +18 -10
  18. package/dist/agents/commands/codex/harness/harness-perf/SKILL.md +9 -0
  19. package/dist/agents/commands/codex/harness/harness-planning/SKILL.md +10 -0
  20. package/dist/agents/commands/codex/harness/harness-refactoring/SKILL.md +9 -0
  21. package/dist/agents/commands/codex/harness/harness-release-readiness/SKILL.md +9 -0
  22. package/dist/agents/commands/codex/harness/harness-roadmap/SKILL.md +10 -1
  23. package/dist/agents/commands/codex/harness/harness-security-scan/SKILL.md +5 -15
  24. package/dist/agents/commands/codex/harness/harness-skill-authoring/SKILL.md +20 -1
  25. package/dist/agents/commands/codex/harness/harness-soundness-review/SKILL.md +10 -0
  26. package/dist/agents/commands/codex/harness/harness-supply-chain-audit/SKILL.md +8 -0
  27. package/dist/agents/commands/codex/harness/harness-tdd/SKILL.md +9 -0
  28. package/dist/agents/commands/codex/harness/harness-test-advisor/SKILL.md +8 -0
  29. package/dist/agents/commands/codex/harness/harness-verification/SKILL.md +9 -0
  30. package/dist/agents/commands/codex/harness/harness-verify/SKILL.md +8 -0
  31. package/dist/agents/commands/codex/harness/initialize-harness-project/SKILL.md +22 -13
  32. package/dist/agents/commands/cursor/harness/add-harness-component.mdc +12 -12
  33. package/dist/agents/commands/cursor/harness/harness-onboarding.mdc +10 -10
  34. package/dist/agents/commands/cursor/harness/harness-roadmap.mdc +1 -1
  35. package/dist/agents/commands/cursor/harness/initialize-harness-project.mdc +13 -13
  36. package/dist/agents/skills/claude-code/add-harness-component/SKILL.md +21 -12
  37. package/dist/agents/skills/claude-code/align-documentation/SKILL.md +9 -0
  38. package/dist/agents/skills/claude-code/check-mechanical-constraints/SKILL.md +9 -0
  39. package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +11 -0
  40. package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +9 -0
  41. package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +5 -15
  42. package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +10 -0
  43. package/dist/agents/skills/claude-code/harness-api-design/SKILL.md +5 -15
  44. package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +5 -15
  45. package/dist/agents/skills/claude-code/harness-auth/SKILL.md +5 -15
  46. package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +10 -0
  47. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +9 -0
  48. package/dist/agents/skills/claude-code/harness-caching/SKILL.md +10 -0
  49. package/dist/agents/skills/claude-code/harness-chaos/SKILL.md +10 -0
  50. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +5 -15
  51. package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +11 -0
  52. package/dist/agents/skills/claude-code/harness-compliance/SKILL.md +10 -0
  53. package/dist/agents/skills/claude-code/harness-containerization/SKILL.md +10 -0
  54. package/dist/agents/skills/claude-code/harness-data-pipeline/SKILL.md +10 -0
  55. package/dist/agents/skills/claude-code/harness-data-validation/SKILL.md +10 -0
  56. package/dist/agents/skills/claude-code/harness-database/SKILL.md +5 -15
  57. package/dist/agents/skills/claude-code/harness-debugging/SKILL.md +9 -0
  58. package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +10 -0
  59. package/dist/agents/skills/claude-code/harness-deployment/SKILL.md +5 -15
  60. package/dist/agents/skills/claude-code/harness-design/SKILL.md +10 -0
  61. package/dist/agents/skills/claude-code/harness-design-mobile/SKILL.md +10 -0
  62. package/dist/agents/skills/claude-code/harness-design-system/SKILL.md +10 -0
  63. package/dist/agents/skills/claude-code/harness-design-web/SKILL.md +10 -0
  64. package/dist/agents/skills/claude-code/harness-diagnostics/SKILL.md +9 -0
  65. package/dist/agents/skills/claude-code/harness-docs-pipeline/SKILL.md +11 -0
  66. package/dist/agents/skills/claude-code/harness-dx/SKILL.md +10 -0
  67. package/dist/agents/skills/claude-code/harness-e2e/SKILL.md +9 -0
  68. package/dist/agents/skills/claude-code/harness-event-driven/SKILL.md +10 -0
  69. package/dist/agents/skills/claude-code/harness-execution/SKILL.md +9 -0
  70. package/dist/agents/skills/claude-code/harness-feature-flags/SKILL.md +10 -0
  71. package/dist/agents/skills/claude-code/harness-git-workflow/SKILL.md +10 -0
  72. package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +10 -0
  73. package/dist/agents/skills/claude-code/harness-i18n/SKILL.md +10 -0
  74. package/dist/agents/skills/claude-code/harness-i18n-process/SKILL.md +10 -0
  75. package/dist/agents/skills/claude-code/harness-i18n-workflow/SKILL.md +10 -0
  76. package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +10 -0
  77. package/dist/agents/skills/claude-code/harness-incident-response/SKILL.md +10 -0
  78. package/dist/agents/skills/claude-code/harness-infrastructure-as-code/SKILL.md +10 -0
  79. package/dist/agents/skills/claude-code/harness-integration-test/SKILL.md +9 -0
  80. package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +10 -0
  81. package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +9 -0
  82. package/dist/agents/skills/claude-code/harness-load-testing/SKILL.md +10 -0
  83. package/dist/agents/skills/claude-code/harness-ml-ops/SKILL.md +10 -0
  84. package/dist/agents/skills/claude-code/harness-mobile-patterns/SKILL.md +10 -0
  85. package/dist/agents/skills/claude-code/harness-mutation-test/SKILL.md +9 -0
  86. package/dist/agents/skills/claude-code/harness-observability/SKILL.md +10 -0
  87. package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +18 -10
  88. package/dist/agents/skills/claude-code/harness-parallel-agents/SKILL.md +9 -0
  89. package/dist/agents/skills/claude-code/harness-perf/SKILL.md +11 -0
  90. package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +10 -0
  91. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +10 -0
  92. package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +9 -0
  93. package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +10 -0
  94. package/dist/agents/skills/claude-code/harness-property-test/SKILL.md +10 -0
  95. package/dist/agents/skills/claude-code/harness-refactoring/SKILL.md +9 -0
  96. package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +11 -0
  97. package/dist/agents/skills/claude-code/harness-resilience/SKILL.md +10 -0
  98. package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +10 -1
  99. package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +8 -0
  100. package/dist/agents/skills/claude-code/harness-secrets/SKILL.md +10 -0
  101. package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +10 -0
  102. package/dist/agents/skills/claude-code/harness-security-scan/SKILL.md +5 -15
  103. package/dist/agents/skills/claude-code/harness-skill-authoring/SKILL.md +29 -1
  104. package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +10 -0
  105. package/dist/agents/skills/claude-code/harness-sql-review/SKILL.md +10 -0
  106. package/dist/agents/skills/claude-code/harness-state-management/SKILL.md +10 -0
  107. package/dist/agents/skills/claude-code/harness-supply-chain-audit/SKILL.md +10 -0
  108. package/dist/agents/skills/claude-code/harness-tdd/SKILL.md +9 -0
  109. package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +10 -0
  110. package/dist/agents/skills/claude-code/harness-test-data/SKILL.md +10 -0
  111. package/dist/agents/skills/claude-code/harness-ux-copy/SKILL.md +10 -0
  112. package/dist/agents/skills/claude-code/harness-verification/SKILL.md +9 -0
  113. package/dist/agents/skills/claude-code/harness-verify/SKILL.md +10 -0
  114. package/dist/agents/skills/claude-code/harness-visual-regression/SKILL.md +10 -0
  115. package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +22 -13
  116. package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +9 -0
  117. package/dist/agents/skills/codex/add-harness-component/SKILL.md +21 -12
  118. package/dist/agents/skills/codex/align-documentation/SKILL.md +9 -0
  119. package/dist/agents/skills/codex/check-mechanical-constraints/SKILL.md +9 -0
  120. package/dist/agents/skills/codex/cleanup-dead-code/SKILL.md +11 -0
  121. package/dist/agents/skills/codex/detect-doc-drift/SKILL.md +9 -0
  122. package/dist/agents/skills/codex/enforce-architecture/SKILL.md +5 -15
  123. package/dist/agents/skills/codex/harness-accessibility/SKILL.md +10 -0
  124. package/dist/agents/skills/codex/harness-api-design/SKILL.md +5 -15
  125. package/dist/agents/skills/codex/harness-architecture-advisor/SKILL.md +5 -15
  126. package/dist/agents/skills/codex/harness-auth/SKILL.md +5 -15
  127. package/dist/agents/skills/codex/harness-autopilot/SKILL.md +10 -0
  128. package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +9 -0
  129. package/dist/agents/skills/codex/harness-caching/SKILL.md +10 -0
  130. package/dist/agents/skills/codex/harness-chaos/SKILL.md +10 -0
  131. package/dist/agents/skills/codex/harness-code-review/SKILL.md +5 -15
  132. package/dist/agents/skills/codex/harness-codebase-cleanup/SKILL.md +11 -0
  133. package/dist/agents/skills/codex/harness-compliance/SKILL.md +10 -0
  134. package/dist/agents/skills/codex/harness-containerization/SKILL.md +10 -0
  135. package/dist/agents/skills/codex/harness-data-pipeline/SKILL.md +10 -0
  136. package/dist/agents/skills/codex/harness-data-validation/SKILL.md +10 -0
  137. package/dist/agents/skills/codex/harness-database/SKILL.md +5 -15
  138. package/dist/agents/skills/codex/harness-debugging/SKILL.md +9 -0
  139. package/dist/agents/skills/codex/harness-dependency-health/SKILL.md +10 -0
  140. package/dist/agents/skills/codex/harness-deployment/SKILL.md +5 -15
  141. package/dist/agents/skills/codex/harness-design/SKILL.md +10 -0
  142. package/dist/agents/skills/codex/harness-design-mobile/SKILL.md +10 -0
  143. package/dist/agents/skills/codex/harness-design-system/SKILL.md +10 -0
  144. package/dist/agents/skills/codex/harness-design-web/SKILL.md +10 -0
  145. package/dist/agents/skills/codex/harness-diagnostics/SKILL.md +9 -0
  146. package/dist/agents/skills/codex/harness-docs-pipeline/SKILL.md +11 -0
  147. package/dist/agents/skills/codex/harness-dx/SKILL.md +10 -0
  148. package/dist/agents/skills/codex/harness-e2e/SKILL.md +9 -0
  149. package/dist/agents/skills/codex/harness-event-driven/SKILL.md +10 -0
  150. package/dist/agents/skills/codex/harness-execution/SKILL.md +9 -0
  151. package/dist/agents/skills/codex/harness-feature-flags/SKILL.md +10 -0
  152. package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +10 -0
  153. package/dist/agents/skills/codex/harness-hotspot-detector/SKILL.md +10 -0
  154. package/dist/agents/skills/codex/harness-i18n/SKILL.md +10 -0
  155. package/dist/agents/skills/codex/harness-i18n-process/SKILL.md +10 -0
  156. package/dist/agents/skills/codex/harness-i18n-workflow/SKILL.md +10 -0
  157. package/dist/agents/skills/codex/harness-impact-analysis/SKILL.md +10 -0
  158. package/dist/agents/skills/codex/harness-incident-response/SKILL.md +10 -0
  159. package/dist/agents/skills/codex/harness-infrastructure-as-code/SKILL.md +10 -0
  160. package/dist/agents/skills/codex/harness-integration-test/SKILL.md +9 -0
  161. package/dist/agents/skills/codex/harness-integrity/SKILL.md +10 -0
  162. package/dist/agents/skills/codex/harness-knowledge-mapper/SKILL.md +9 -0
  163. package/dist/agents/skills/codex/harness-load-testing/SKILL.md +10 -0
  164. package/dist/agents/skills/codex/harness-ml-ops/SKILL.md +10 -0
  165. package/dist/agents/skills/codex/harness-mobile-patterns/SKILL.md +10 -0
  166. package/dist/agents/skills/codex/harness-mutation-test/SKILL.md +9 -0
  167. package/dist/agents/skills/codex/harness-observability/SKILL.md +10 -0
  168. package/dist/agents/skills/codex/harness-onboarding/SKILL.md +18 -10
  169. package/dist/agents/skills/codex/harness-parallel-agents/SKILL.md +9 -0
  170. package/dist/agents/skills/codex/harness-perf/SKILL.md +11 -0
  171. package/dist/agents/skills/codex/harness-perf-tdd/SKILL.md +10 -0
  172. package/dist/agents/skills/codex/harness-planning/SKILL.md +10 -0
  173. package/dist/agents/skills/codex/harness-pre-commit-review/SKILL.md +9 -0
  174. package/dist/agents/skills/codex/harness-product-spec/SKILL.md +10 -0
  175. package/dist/agents/skills/codex/harness-property-test/SKILL.md +10 -0
  176. package/dist/agents/skills/codex/harness-refactoring/SKILL.md +9 -0
  177. package/dist/agents/skills/codex/harness-release-readiness/SKILL.md +11 -0
  178. package/dist/agents/skills/codex/harness-resilience/SKILL.md +10 -0
  179. package/dist/agents/skills/codex/harness-roadmap/SKILL.md +10 -1
  180. package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +8 -0
  181. package/dist/agents/skills/codex/harness-secrets/SKILL.md +10 -0
  182. package/dist/agents/skills/codex/harness-security-review/SKILL.md +10 -0
  183. package/dist/agents/skills/codex/harness-security-scan/SKILL.md +5 -15
  184. package/dist/agents/skills/codex/harness-skill-authoring/SKILL.md +29 -1
  185. package/dist/agents/skills/codex/harness-soundness-review/SKILL.md +10 -0
  186. package/dist/agents/skills/codex/harness-sql-review/SKILL.md +10 -0
  187. package/dist/agents/skills/codex/harness-state-management/SKILL.md +10 -0
  188. package/dist/agents/skills/codex/harness-supply-chain-audit/SKILL.md +10 -0
  189. package/dist/agents/skills/codex/harness-tdd/SKILL.md +9 -0
  190. package/dist/agents/skills/codex/harness-test-advisor/SKILL.md +10 -0
  191. package/dist/agents/skills/codex/harness-test-data/SKILL.md +10 -0
  192. package/dist/agents/skills/codex/harness-ux-copy/SKILL.md +10 -0
  193. package/dist/agents/skills/codex/harness-verification/SKILL.md +9 -0
  194. package/dist/agents/skills/codex/harness-verify/SKILL.md +10 -0
  195. package/dist/agents/skills/codex/harness-visual-regression/SKILL.md +10 -0
  196. package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +22 -13
  197. package/dist/agents/skills/codex/validate-context-engineering/SKILL.md +9 -0
  198. package/dist/agents/skills/cursor/add-harness-component/SKILL.md +21 -12
  199. package/dist/agents/skills/cursor/align-documentation/SKILL.md +9 -0
  200. package/dist/agents/skills/cursor/check-mechanical-constraints/SKILL.md +9 -0
  201. package/dist/agents/skills/cursor/cleanup-dead-code/SKILL.md +11 -0
  202. package/dist/agents/skills/cursor/detect-doc-drift/SKILL.md +9 -0
  203. package/dist/agents/skills/cursor/enforce-architecture/SKILL.md +5 -15
  204. package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +10 -0
  205. package/dist/agents/skills/cursor/harness-api-design/SKILL.md +5 -15
  206. package/dist/agents/skills/cursor/harness-architecture-advisor/SKILL.md +5 -15
  207. package/dist/agents/skills/cursor/harness-auth/SKILL.md +5 -15
  208. package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +10 -0
  209. package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +9 -0
  210. package/dist/agents/skills/cursor/harness-caching/SKILL.md +10 -0
  211. package/dist/agents/skills/cursor/harness-chaos/SKILL.md +10 -0
  212. package/dist/agents/skills/cursor/harness-code-review/SKILL.md +5 -15
  213. package/dist/agents/skills/cursor/harness-codebase-cleanup/SKILL.md +11 -0
  214. package/dist/agents/skills/cursor/harness-compliance/SKILL.md +10 -0
  215. package/dist/agents/skills/cursor/harness-containerization/SKILL.md +10 -0
  216. package/dist/agents/skills/cursor/harness-data-pipeline/SKILL.md +10 -0
  217. package/dist/agents/skills/cursor/harness-data-validation/SKILL.md +10 -0
  218. package/dist/agents/skills/cursor/harness-database/SKILL.md +5 -15
  219. package/dist/agents/skills/cursor/harness-debugging/SKILL.md +9 -0
  220. package/dist/agents/skills/cursor/harness-dependency-health/SKILL.md +10 -0
  221. package/dist/agents/skills/cursor/harness-deployment/SKILL.md +5 -15
  222. package/dist/agents/skills/cursor/harness-design/SKILL.md +10 -0
  223. package/dist/agents/skills/cursor/harness-design-mobile/SKILL.md +10 -0
  224. package/dist/agents/skills/cursor/harness-design-system/SKILL.md +10 -0
  225. package/dist/agents/skills/cursor/harness-design-web/SKILL.md +10 -0
  226. package/dist/agents/skills/cursor/harness-diagnostics/SKILL.md +9 -0
  227. package/dist/agents/skills/cursor/harness-docs-pipeline/SKILL.md +11 -0
  228. package/dist/agents/skills/cursor/harness-dx/SKILL.md +10 -0
  229. package/dist/agents/skills/cursor/harness-e2e/SKILL.md +9 -0
  230. package/dist/agents/skills/cursor/harness-event-driven/SKILL.md +10 -0
  231. package/dist/agents/skills/cursor/harness-execution/SKILL.md +9 -0
  232. package/dist/agents/skills/cursor/harness-feature-flags/SKILL.md +10 -0
  233. package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +10 -0
  234. package/dist/agents/skills/cursor/harness-hotspot-detector/SKILL.md +10 -0
  235. package/dist/agents/skills/cursor/harness-i18n/SKILL.md +10 -0
  236. package/dist/agents/skills/cursor/harness-i18n-process/SKILL.md +10 -0
  237. package/dist/agents/skills/cursor/harness-i18n-workflow/SKILL.md +10 -0
  238. package/dist/agents/skills/cursor/harness-impact-analysis/SKILL.md +10 -0
  239. package/dist/agents/skills/cursor/harness-incident-response/SKILL.md +10 -0
  240. package/dist/agents/skills/cursor/harness-infrastructure-as-code/SKILL.md +10 -0
  241. package/dist/agents/skills/cursor/harness-integration-test/SKILL.md +9 -0
  242. package/dist/agents/skills/cursor/harness-integrity/SKILL.md +10 -0
  243. package/dist/agents/skills/cursor/harness-knowledge-mapper/SKILL.md +9 -0
  244. package/dist/agents/skills/cursor/harness-load-testing/SKILL.md +10 -0
  245. package/dist/agents/skills/cursor/harness-ml-ops/SKILL.md +10 -0
  246. package/dist/agents/skills/cursor/harness-mobile-patterns/SKILL.md +10 -0
  247. package/dist/agents/skills/cursor/harness-mutation-test/SKILL.md +9 -0
  248. package/dist/agents/skills/cursor/harness-observability/SKILL.md +10 -0
  249. package/dist/agents/skills/cursor/harness-onboarding/SKILL.md +18 -10
  250. package/dist/agents/skills/cursor/harness-parallel-agents/SKILL.md +9 -0
  251. package/dist/agents/skills/cursor/harness-perf/SKILL.md +11 -0
  252. package/dist/agents/skills/cursor/harness-perf-tdd/SKILL.md +10 -0
  253. package/dist/agents/skills/cursor/harness-planning/SKILL.md +10 -0
  254. package/dist/agents/skills/cursor/harness-pre-commit-review/SKILL.md +9 -0
  255. package/dist/agents/skills/cursor/harness-product-spec/SKILL.md +10 -0
  256. package/dist/agents/skills/cursor/harness-property-test/SKILL.md +10 -0
  257. package/dist/agents/skills/cursor/harness-refactoring/SKILL.md +9 -0
  258. package/dist/agents/skills/cursor/harness-release-readiness/SKILL.md +11 -0
  259. package/dist/agents/skills/cursor/harness-resilience/SKILL.md +10 -0
  260. package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +10 -1
  261. package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +8 -0
  262. package/dist/agents/skills/cursor/harness-secrets/SKILL.md +10 -0
  263. package/dist/agents/skills/cursor/harness-security-review/SKILL.md +10 -0
  264. package/dist/agents/skills/cursor/harness-security-scan/SKILL.md +5 -15
  265. package/dist/agents/skills/cursor/harness-skill-authoring/SKILL.md +29 -1
  266. package/dist/agents/skills/cursor/harness-soundness-review/SKILL.md +10 -0
  267. package/dist/agents/skills/cursor/harness-sql-review/SKILL.md +10 -0
  268. package/dist/agents/skills/cursor/harness-state-management/SKILL.md +10 -0
  269. package/dist/agents/skills/cursor/harness-supply-chain-audit/SKILL.md +10 -0
  270. package/dist/agents/skills/cursor/harness-tdd/SKILL.md +9 -0
  271. package/dist/agents/skills/cursor/harness-test-advisor/SKILL.md +10 -0
  272. package/dist/agents/skills/cursor/harness-test-data/SKILL.md +10 -0
  273. package/dist/agents/skills/cursor/harness-ux-copy/SKILL.md +10 -0
  274. package/dist/agents/skills/cursor/harness-verification/SKILL.md +9 -0
  275. package/dist/agents/skills/cursor/harness-verify/SKILL.md +10 -0
  276. package/dist/agents/skills/cursor/harness-visual-regression/SKILL.md +10 -0
  277. package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +22 -13
  278. package/dist/agents/skills/cursor/validate-context-engineering/SKILL.md +9 -0
  279. package/dist/agents/skills/gemini-cli/add-harness-component/SKILL.md +21 -12
  280. package/dist/agents/skills/gemini-cli/align-documentation/SKILL.md +9 -0
  281. package/dist/agents/skills/gemini-cli/check-mechanical-constraints/SKILL.md +9 -0
  282. package/dist/agents/skills/gemini-cli/cleanup-dead-code/SKILL.md +11 -0
  283. package/dist/agents/skills/gemini-cli/detect-doc-drift/SKILL.md +9 -0
  284. package/dist/agents/skills/gemini-cli/enforce-architecture/SKILL.md +5 -15
  285. package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +10 -0
  286. package/dist/agents/skills/gemini-cli/harness-api-design/SKILL.md +5 -15
  287. package/dist/agents/skills/gemini-cli/harness-architecture-advisor/SKILL.md +5 -15
  288. package/dist/agents/skills/gemini-cli/harness-auth/SKILL.md +5 -15
  289. package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +10 -0
  290. package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +9 -0
  291. package/dist/agents/skills/gemini-cli/harness-caching/SKILL.md +10 -0
  292. package/dist/agents/skills/gemini-cli/harness-chaos/SKILL.md +10 -0
  293. package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +5 -15
  294. package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +11 -0
  295. package/dist/agents/skills/gemini-cli/harness-compliance/SKILL.md +10 -0
  296. package/dist/agents/skills/gemini-cli/harness-containerization/SKILL.md +10 -0
  297. package/dist/agents/skills/gemini-cli/harness-data-pipeline/SKILL.md +10 -0
  298. package/dist/agents/skills/gemini-cli/harness-data-validation/SKILL.md +10 -0
  299. package/dist/agents/skills/gemini-cli/harness-database/SKILL.md +5 -15
  300. package/dist/agents/skills/gemini-cli/harness-debugging/SKILL.md +9 -0
  301. package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +10 -0
  302. package/dist/agents/skills/gemini-cli/harness-deployment/SKILL.md +5 -15
  303. package/dist/agents/skills/gemini-cli/harness-design/SKILL.md +10 -0
  304. package/dist/agents/skills/gemini-cli/harness-design-mobile/SKILL.md +10 -0
  305. package/dist/agents/skills/gemini-cli/harness-design-system/SKILL.md +10 -0
  306. package/dist/agents/skills/gemini-cli/harness-design-web/SKILL.md +10 -0
  307. package/dist/agents/skills/gemini-cli/harness-diagnostics/SKILL.md +9 -0
  308. package/dist/agents/skills/gemini-cli/harness-docs-pipeline/SKILL.md +11 -0
  309. package/dist/agents/skills/gemini-cli/harness-dx/SKILL.md +10 -0
  310. package/dist/agents/skills/gemini-cli/harness-e2e/SKILL.md +9 -0
  311. package/dist/agents/skills/gemini-cli/harness-event-driven/SKILL.md +10 -0
  312. package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +9 -0
  313. package/dist/agents/skills/gemini-cli/harness-feature-flags/SKILL.md +10 -0
  314. package/dist/agents/skills/gemini-cli/harness-git-workflow/SKILL.md +10 -0
  315. package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +10 -0
  316. package/dist/agents/skills/gemini-cli/harness-i18n/SKILL.md +10 -0
  317. package/dist/agents/skills/gemini-cli/harness-i18n-process/SKILL.md +10 -0
  318. package/dist/agents/skills/gemini-cli/harness-i18n-workflow/SKILL.md +10 -0
  319. package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +10 -0
  320. package/dist/agents/skills/gemini-cli/harness-incident-response/SKILL.md +10 -0
  321. package/dist/agents/skills/gemini-cli/harness-infrastructure-as-code/SKILL.md +10 -0
  322. package/dist/agents/skills/gemini-cli/harness-integration-test/SKILL.md +9 -0
  323. package/dist/agents/skills/gemini-cli/harness-integrity/SKILL.md +10 -0
  324. package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +9 -0
  325. package/dist/agents/skills/gemini-cli/harness-load-testing/SKILL.md +10 -0
  326. package/dist/agents/skills/gemini-cli/harness-ml-ops/SKILL.md +10 -0
  327. package/dist/agents/skills/gemini-cli/harness-mobile-patterns/SKILL.md +10 -0
  328. package/dist/agents/skills/gemini-cli/harness-mutation-test/SKILL.md +9 -0
  329. package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +10 -0
  330. package/dist/agents/skills/gemini-cli/harness-onboarding/SKILL.md +18 -10
  331. package/dist/agents/skills/gemini-cli/harness-parallel-agents/SKILL.md +9 -0
  332. package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +11 -0
  333. package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +10 -0
  334. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +10 -0
  335. package/dist/agents/skills/gemini-cli/harness-pre-commit-review/SKILL.md +9 -0
  336. package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +10 -0
  337. package/dist/agents/skills/gemini-cli/harness-property-test/SKILL.md +10 -0
  338. package/dist/agents/skills/gemini-cli/harness-refactoring/SKILL.md +9 -0
  339. package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +11 -0
  340. package/dist/agents/skills/gemini-cli/harness-resilience/SKILL.md +10 -0
  341. package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +10 -1
  342. package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +8 -0
  343. package/dist/agents/skills/gemini-cli/harness-secrets/SKILL.md +10 -0
  344. package/dist/agents/skills/gemini-cli/harness-security-review/SKILL.md +10 -0
  345. package/dist/agents/skills/gemini-cli/harness-security-scan/SKILL.md +5 -15
  346. package/dist/agents/skills/gemini-cli/harness-skill-authoring/SKILL.md +29 -1
  347. package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +10 -0
  348. package/dist/agents/skills/gemini-cli/harness-sql-review/SKILL.md +10 -0
  349. package/dist/agents/skills/gemini-cli/harness-state-management/SKILL.md +10 -0
  350. package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/SKILL.md +10 -0
  351. package/dist/agents/skills/gemini-cli/harness-tdd/SKILL.md +9 -0
  352. package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +10 -0
  353. package/dist/agents/skills/gemini-cli/harness-test-data/SKILL.md +10 -0
  354. package/dist/agents/skills/gemini-cli/harness-ux-copy/SKILL.md +10 -0
  355. package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +9 -0
  356. package/dist/agents/skills/gemini-cli/harness-verify/SKILL.md +10 -0
  357. package/dist/agents/skills/gemini-cli/harness-visual-regression/SKILL.md +10 -0
  358. package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +22 -13
  359. package/dist/agents/skills/gemini-cli/validate-context-engineering/SKILL.md +9 -0
  360. package/dist/agents-md-HCCCO5PK.js +9 -0
  361. package/dist/{architecture-EDSBAGR4.js → architecture-S2H624W7.js} +5 -5
  362. package/dist/{assess-project-CEDY4JU3.js → assess-project-XSGK44S5.js} +1 -1
  363. package/dist/bin/harness-mcp.js +18 -18
  364. package/dist/bin/harness.js +124 -35
  365. package/dist/{check-phase-gate-N3DTKFCZ.js → check-phase-gate-UGBJ237T.js} +5 -5
  366. package/dist/{chunk-AIBAYANF.js → chunk-2DHX6TAP.js} +4 -4
  367. package/dist/{chunk-ENA4O4WD.js → chunk-2GT3HO2T.js} +3 -3
  368. package/dist/{chunk-TJ6NLLAY.js → chunk-2YA4XRI3.js} +5 -5
  369. package/dist/{chunk-GZKSBLQL.js → chunk-35EQ5UEI.js} +1 -1
  370. package/dist/{chunk-T5QWCVGK.js → chunk-4FHBPA3E.js} +11 -3
  371. package/dist/{chunk-ERS5EVUZ.js → chunk-5LMZA5LZ.js} +10 -10
  372. package/dist/{chunk-SM22U22L.js → chunk-BK52Z6DR.js} +869 -419
  373. package/dist/{chunk-5SWE24IG.js → chunk-CLD4KL7O.js} +342 -72
  374. package/dist/{chunk-OD3S2NHN.js → chunk-E2GTL3YS.js} +1 -1
  375. package/dist/{chunk-YLN34N65.js → chunk-FP53DDB5.js} +1 -1
  376. package/dist/{chunk-TLDCCPUZ.js → chunk-I47JLISV.js} +1 -1
  377. package/dist/{chunk-AKVG4MMZ.js → chunk-KC5CTCEL.js} +9 -9
  378. package/dist/{chunk-26AUZBV4.js → chunk-KTL3PHNQ.js} +6445 -6222
  379. package/dist/{chunk-DBSOCI3G.js → chunk-KV4M6Y5J.js} +1 -1
  380. package/dist/{chunk-FIAPHX37.js → chunk-LM5Z2WCA.js} +1 -1
  381. package/dist/{chunk-SD3SQOZ2.js → chunk-LOUH2LIC.js} +1 -1
  382. package/dist/{chunk-QUKH6QCJ.js → chunk-MHOO7NLG.js} +11 -11
  383. package/dist/{chunk-HT4VPPB4.js → chunk-MZAHE4DK.js} +12 -12
  384. package/dist/{chunk-A4AI3H3R.js → chunk-NKL53UBL.js} +6 -6
  385. package/dist/{chunk-GJRUIXUK.js → chunk-PGF44T2D.js} +6 -6
  386. package/dist/{chunk-H7Y5CKTM.js → chunk-Q3XYV5UC.js} +1 -1
  387. package/dist/{chunk-TD6MQUV2.js → chunk-S5ZXT3TZ.js} +1 -1
  388. package/dist/{chunk-6KWBH4EO.js → chunk-UGD37ECK.js} +5 -5
  389. package/dist/{chunk-XDAIFVGC.js → chunk-V27WDRYV.js} +603 -525
  390. package/dist/{chunk-YQ6KC6TE.js → chunk-YDRB55Q4.js} +1 -1
  391. package/dist/{chunk-2LAEDVOC.js → chunk-ZRYDYDB2.js} +6 -6
  392. package/dist/{chunk-LIWGCYON.js → chunk-ZYJJUPNE.js} +1 -1
  393. package/dist/ci-workflow-I3V7FZNV.js +9 -0
  394. package/dist/{create-skill-U3XCFRZN.js → create-skill-AO25CJFM.js} +2 -2
  395. package/dist/{dist-USY2C5JL.js → dist-666AAZQ6.js} +1 -1
  396. package/dist/{dist-DZ63LLUD.js → dist-KQSTRP36.js} +1 -1
  397. package/dist/{dist-YIKUBJLQ.js → dist-MKWF5CXR.js} +7 -3
  398. package/dist/{dist-OEXTQQZC.js → dist-WU3TVNNG.js} +7 -1
  399. package/dist/{docs-F5G7NAFF.js → docs-R7UVQBMQ.js} +5 -5
  400. package/dist/engine-JGI3MWAC.js +9 -0
  401. package/dist/{entropy-A5Q2USYX.js → entropy-IDHIG7HS.js} +4 -4
  402. package/dist/{feedback-2EU25RIW.js → feedback-JZETY4UR.js} +1 -1
  403. package/dist/{generate-agent-definitions-HNJHO5YQ.js → generate-agent-definitions-D7B25YTM.js} +6 -6
  404. package/dist/{graph-loader-XULF5QF7.js → graph-loader-BJULJYGG.js} +1 -1
  405. package/dist/index.d.ts +20 -16
  406. package/dist/index.js +54 -54
  407. package/dist/loader-E4KNTOP2.js +11 -0
  408. package/dist/mcp-67I2DBNM.js +37 -0
  409. package/dist/{performance-YAY2A6A6.js → performance-744OSR6P.js} +5 -5
  410. package/dist/{review-pipeline-YD4WI3JM.js → review-pipeline-HIO7HBW4.js} +1 -1
  411. package/dist/runtime-JXQ26U4Z.js +10 -0
  412. package/dist/{security-IBSUKMVD.js → security-GDKHVFUC.js} +1 -1
  413. package/dist/{validate-NHXWKMCR.js → validate-2IUR3OWX.js} +5 -5
  414. package/dist/validate-cross-check-AM4T6P2K.js +9 -0
  415. package/package.json +5 -5
  416. package/dist/agents-md-GLKJSGKT.js +0 -9
  417. package/dist/ci-workflow-LE3QF4FP.js +0 -9
  418. package/dist/engine-LX5RVGXN.js +0 -9
  419. package/dist/loader-GWIEW4HM.js +0 -11
  420. package/dist/mcp-ID3LR6JB.js +0 -37
  421. package/dist/runtime-UJ4YO4CA.js +0 -10
  422. package/dist/validate-cross-check-R3GV2MLM.js +0 -9
  423. package/dist/{chunk-CJDVBBPB.js → chunk-3ISINLYT.js} +1 -1
@@ -2,11 +2,11 @@ import {
2
2
  Err,
3
3
  Ok,
4
4
  SESSION_SECTION_NAMES
5
- } from "./chunk-ERS5EVUZ.js";
5
+ } from "./chunk-5LMZA5LZ.js";
6
6
  import {
7
7
  GraphStore,
8
8
  queryTraceability
9
- } from "./chunk-5SWE24IG.js";
9
+ } from "./chunk-CLD4KL7O.js";
10
10
 
11
11
  // ../core/dist/chunk-BQUWXBGR.mjs
12
12
  import { z } from "zod";
@@ -139,17 +139,17 @@ function resolveFileToLayer(file, layers) {
139
139
  }
140
140
  var accessAsync = promisify(access);
141
141
  var readFileAsync = promisify(readFile);
142
- async function fileExists(path28) {
142
+ async function fileExists(path31) {
143
143
  try {
144
- await accessAsync(path28, constants.F_OK);
144
+ await accessAsync(path31, constants.F_OK);
145
145
  return true;
146
146
  } catch {
147
147
  return false;
148
148
  }
149
149
  }
150
- async function readFileContent(path28) {
150
+ async function readFileContent(path31) {
151
151
  try {
152
- const content = await readFileAsync(path28, "utf-8");
152
+ const content = await readFileAsync(path31, "utf-8");
153
153
  return Ok(content);
154
154
  } catch (error) {
155
155
  return Err(error);
@@ -1850,49 +1850,56 @@ import * as fs12 from "fs";
1850
1850
  import * as path9 from "path";
1851
1851
  import * as fs13 from "fs";
1852
1852
  import * as path10 from "path";
1853
+ import * as crypto2 from "crypto";
1853
1854
  import * as fs14 from "fs";
1854
1855
  import * as path11 from "path";
1855
- import { execSync as execSync2 } from "child_process";
1856
1856
  import * as fs15 from "fs";
1857
1857
  import * as path12 from "path";
1858
1858
  import * as fs16 from "fs";
1859
1859
  import * as path13 from "path";
1860
1860
  import * as fs17 from "fs";
1861
1861
  import * as path14 from "path";
1862
+ import { execSync as execSync2 } from "child_process";
1862
1863
  import * as fs18 from "fs";
1863
1864
  import * as path15 from "path";
1864
- import { z as z7 } from "zod";
1865
- import * as fs20 from "fs/promises";
1866
- import { minimatch as minimatch4 } from "minimatch";
1867
- import { z as z8 } from "zod";
1868
1865
  import * as fs19 from "fs";
1869
1866
  import * as path16 from "path";
1870
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync12, unlinkSync, mkdirSync as mkdirSync12, readdirSync as readdirSync3 } from "fs";
1871
- import { join as join242, dirname as dirname9 } from "path";
1867
+ import * as fs20 from "fs";
1872
1868
  import * as path17 from "path";
1869
+ import * as fs21 from "fs";
1873
1870
  import * as path18 from "path";
1871
+ import { z as z7 } from "zod";
1872
+ import * as fs23 from "fs/promises";
1873
+ import { minimatch as minimatch4 } from "minimatch";
1874
+ import { z as z8 } from "zod";
1875
+ import * as fs22 from "fs";
1874
1876
  import * as path19 from "path";
1877
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, unlinkSync, mkdirSync as mkdirSync13, readdirSync as readdirSync3 } from "fs";
1878
+ import { join as join272, dirname as dirname9 } from "path";
1875
1879
  import * as path20 from "path";
1876
- import * as fs21 from "fs";
1877
1880
  import * as path21 from "path";
1878
- import * as fs22 from "fs";
1879
- import { z as z9 } from "zod";
1880
- import * as fs23 from "fs/promises";
1881
1881
  import * as path22 from "path";
1882
- import * as fs24 from "fs/promises";
1883
1882
  import * as path23 from "path";
1884
- import * as ejs from "ejs";
1885
- import * as fs25 from "fs";
1883
+ import * as fs24 from "fs";
1886
1884
  import * as path24 from "path";
1887
- import * as os from "os";
1888
- import { spawn } from "child_process";
1889
- import Parser from "web-tree-sitter";
1885
+ import * as fs25 from "fs";
1886
+ import { z as z9 } from "zod";
1890
1887
  import * as fs26 from "fs/promises";
1891
1888
  import * as path25 from "path";
1892
- import * as fs27 from "fs";
1889
+ import * as fs27 from "fs/promises";
1893
1890
  import * as path26 from "path";
1891
+ import * as ejs from "ejs";
1894
1892
  import * as fs28 from "fs";
1895
1893
  import * as path27 from "path";
1894
+ import * as os from "os";
1895
+ import { spawn } from "child_process";
1896
+ import Parser from "web-tree-sitter";
1897
+ import * as fs29 from "fs/promises";
1898
+ import * as path28 from "path";
1899
+ import * as fs30 from "fs";
1900
+ import * as path29 from "path";
1901
+ import * as fs31 from "fs";
1902
+ import * as path30 from "path";
1896
1903
  import * as os2 from "os";
1897
1904
  async function validateFileStructure(projectPath, conventions) {
1898
1905
  const missing = [];
@@ -1929,15 +1936,15 @@ function validateConfig(data, schema) {
1929
1936
  let message = "Configuration validation failed";
1930
1937
  const suggestions = [];
1931
1938
  if (firstError) {
1932
- const path28 = firstError.path.join(".");
1933
- const pathDisplay = path28 ? ` at "${path28}"` : "";
1939
+ const path31 = firstError.path.join(".");
1940
+ const pathDisplay = path31 ? ` at "${path31}"` : "";
1934
1941
  if (firstError.code === "invalid_type") {
1935
1942
  const received = firstError.received;
1936
1943
  const expected = firstError.expected;
1937
1944
  if (received === "undefined") {
1938
1945
  code = "MISSING_FIELD";
1939
1946
  message = `Missing required field${pathDisplay}: ${firstError.message}`;
1940
- suggestions.push(`Field "${path28}" is required and must be of type "${expected}"`);
1947
+ suggestions.push(`Field "${path31}" is required and must be of type "${expected}"`);
1941
1948
  } else {
1942
1949
  code = "INVALID_TYPE";
1943
1950
  message = `Invalid type${pathDisplay}: ${firstError.message}`;
@@ -2146,27 +2153,27 @@ function extractSections(content) {
2146
2153
  }
2147
2154
  return sections.map((section) => buildAgentMapSection(section, lines));
2148
2155
  }
2149
- function isExternalLink(path28) {
2150
- return path28.startsWith("http://") || path28.startsWith("https://") || path28.startsWith("#") || path28.startsWith("mailto:");
2156
+ function isExternalLink(path31) {
2157
+ return path31.startsWith("http://") || path31.startsWith("https://") || path31.startsWith("#") || path31.startsWith("mailto:");
2151
2158
  }
2152
2159
  function resolveLinkPath(linkPath, baseDir) {
2153
2160
  return linkPath.startsWith(".") ? join4(baseDir, linkPath) : linkPath;
2154
2161
  }
2155
- async function validateAgentsMap(path28 = "./AGENTS.md") {
2156
- const contentResult = await readFileContent(path28);
2162
+ async function validateAgentsMap(path31 = "./AGENTS.md") {
2163
+ const contentResult = await readFileContent(path31);
2157
2164
  if (!contentResult.ok) {
2158
2165
  return Err(
2159
2166
  createError(
2160
2167
  "PARSE_ERROR",
2161
2168
  `Failed to read AGENTS.md: ${contentResult.error.message}`,
2162
- { path: path28 },
2169
+ { path: path31 },
2163
2170
  ["Ensure the file exists", "Check file permissions"]
2164
2171
  )
2165
2172
  );
2166
2173
  }
2167
2174
  const content = contentResult.value;
2168
2175
  const sections = extractSections(content);
2169
- const baseDir = dirname4(path28);
2176
+ const baseDir = dirname4(path31);
2170
2177
  const sectionTitles = sections.map((s) => s.title);
2171
2178
  const missingSections = REQUIRED_SECTIONS.filter(
2172
2179
  (required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
@@ -2300,8 +2307,8 @@ async function checkDocCoverage(domain, options = {}) {
2300
2307
  );
2301
2308
  }
2302
2309
  }
2303
- function suggestFix(path28, existingFiles) {
2304
- const targetName = basename2(path28).toLowerCase();
2310
+ function suggestFix(path31, existingFiles) {
2311
+ const targetName = basename2(path31).toLowerCase();
2305
2312
  const similar = existingFiles.find((file) => {
2306
2313
  const fileName = basename2(file).toLowerCase();
2307
2314
  return fileName.includes(targetName) || targetName.includes(fileName);
@@ -2309,7 +2316,7 @@ function suggestFix(path28, existingFiles) {
2309
2316
  if (similar) {
2310
2317
  return `Did you mean "${similar}"?`;
2311
2318
  }
2312
- return `Create the file "${path28}" or remove the link`;
2319
+ return `Create the file "${path31}" or remove the link`;
2313
2320
  }
2314
2321
  async function validateKnowledgeMap(rootDir = process.cwd()) {
2315
2322
  const agentsPath = join22(rootDir, "AGENTS.md");
@@ -2652,8 +2659,8 @@ function createBoundaryValidator(schema, name) {
2652
2659
  return Ok(result.data);
2653
2660
  }
2654
2661
  const suggestions = result.error.issues.map((issue) => {
2655
- const path28 = issue.path.join(".");
2656
- return path28 ? `${path28}: ${issue.message}` : issue.message;
2662
+ const path31 = issue.path.join(".");
2663
+ return path31 ? `${path31}: ${issue.message}` : issue.message;
2657
2664
  });
2658
2665
  return Err(
2659
2666
  createError(
@@ -3261,11 +3268,11 @@ function processExportListSpecifiers(exportDecl, exports) {
3261
3268
  var TypeScriptParser = class {
3262
3269
  name = "typescript";
3263
3270
  extensions = [".ts", ".tsx", ".mts", ".cts"];
3264
- async parseFile(path28) {
3265
- const contentResult = await readFileContent(path28);
3271
+ async parseFile(path31) {
3272
+ const contentResult = await readFileContent(path31);
3266
3273
  if (!contentResult.ok) {
3267
3274
  return Err(
3268
- createParseError("NOT_FOUND", `File not found: ${path28}`, { path: path28 }, [
3275
+ createParseError("NOT_FOUND", `File not found: ${path31}`, { path: path31 }, [
3269
3276
  "Check that the file exists",
3270
3277
  "Verify the path is correct"
3271
3278
  ])
@@ -3275,7 +3282,7 @@ var TypeScriptParser = class {
3275
3282
  const ast = parse(contentResult.value, {
3276
3283
  loc: true,
3277
3284
  range: true,
3278
- jsx: path28.endsWith(".tsx"),
3285
+ jsx: path31.endsWith(".tsx"),
3279
3286
  errorOnUnknownASTType: false
3280
3287
  });
3281
3288
  return Ok({
@@ -3286,7 +3293,7 @@ var TypeScriptParser = class {
3286
3293
  } catch (e) {
3287
3294
  const error = e;
3288
3295
  return Err(
3289
- createParseError("SYNTAX_ERROR", `Failed to parse ${path28}: ${error.message}`, { path: path28 }, [
3296
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path31}: ${error.message}`, { path: path31 }, [
3290
3297
  "Check for syntax errors in the file",
3291
3298
  "Ensure valid TypeScript syntax"
3292
3299
  ])
@@ -3467,22 +3474,22 @@ function extractInlineRefs(content) {
3467
3474
  }
3468
3475
  return refs;
3469
3476
  }
3470
- async function parseDocumentationFile(path28) {
3471
- const contentResult = await readFileContent(path28);
3477
+ async function parseDocumentationFile(path31) {
3478
+ const contentResult = await readFileContent(path31);
3472
3479
  if (!contentResult.ok) {
3473
3480
  return Err(
3474
3481
  createEntropyError(
3475
3482
  "PARSE_ERROR",
3476
- `Failed to read documentation file: ${path28}`,
3477
- { file: path28 },
3483
+ `Failed to read documentation file: ${path31}`,
3484
+ { file: path31 },
3478
3485
  ["Check that the file exists"]
3479
3486
  )
3480
3487
  );
3481
3488
  }
3482
3489
  const content = contentResult.value;
3483
- const type = path28.endsWith(".md") ? "markdown" : "text";
3490
+ const type = path31.endsWith(".md") ? "markdown" : "text";
3484
3491
  return Ok({
3485
- path: path28,
3492
+ path: path31,
3486
3493
  type,
3487
3494
  content,
3488
3495
  codeBlocks: extractCodeBlocks(content),
@@ -6918,8 +6925,7 @@ function parseListField(fieldMap, ...keys) {
6918
6925
  if (raw === EM_DASH || raw === "none") return [];
6919
6926
  return raw.split(",").map((s) => s.trim());
6920
6927
  }
6921
- function parseFeatureFields(name, body) {
6922
- const fieldMap = extractFieldMap(body);
6928
+ function validateStatus(name, fieldMap) {
6923
6929
  const statusRaw = fieldMap.get("Status");
6924
6930
  if (!statusRaw || !VALID_STATUSES.has(statusRaw)) {
6925
6931
  return Err(
@@ -6928,12 +6934,10 @@ function parseFeatureFields(name, body) {
6928
6934
  )
6929
6935
  );
6930
6936
  }
6931
- const specRaw = fieldMap.get("Spec") ?? EM_DASH;
6932
- const plans = parseListField(fieldMap, "Plans", "Plan");
6933
- const blockedBy = parseListField(fieldMap, "Blocked by", "Blockers");
6934
- const assigneeRaw = fieldMap.get("Assignee") ?? EM_DASH;
6937
+ return Ok(statusRaw);
6938
+ }
6939
+ function validatePriority(name, fieldMap) {
6935
6940
  const priorityRaw = fieldMap.get("Priority") ?? EM_DASH;
6936
- const externalIdRaw = fieldMap.get("External-ID") ?? EM_DASH;
6937
6941
  if (priorityRaw !== EM_DASH && !VALID_PRIORITIES.has(priorityRaw)) {
6938
6942
  return Err(
6939
6943
  new Error(
@@ -6941,16 +6945,28 @@ function parseFeatureFields(name, body) {
6941
6945
  )
6942
6946
  );
6943
6947
  }
6948
+ return Ok(priorityRaw === EM_DASH ? null : priorityRaw);
6949
+ }
6950
+ function optionalField(fieldMap, key) {
6951
+ const raw = fieldMap.get(key) ?? EM_DASH;
6952
+ return raw === EM_DASH ? null : raw;
6953
+ }
6954
+ function parseFeatureFields(name, body) {
6955
+ const fieldMap = extractFieldMap(body);
6956
+ const statusResult = validateStatus(name, fieldMap);
6957
+ if (!statusResult.ok) return statusResult;
6958
+ const priorityResult = validatePriority(name, fieldMap);
6959
+ if (!priorityResult.ok) return priorityResult;
6944
6960
  return Ok({
6945
6961
  name,
6946
- status: statusRaw,
6947
- spec: specRaw === EM_DASH ? null : specRaw,
6948
- plans,
6949
- blockedBy,
6962
+ status: statusResult.value,
6963
+ spec: optionalField(fieldMap, "Spec"),
6964
+ plans: parseListField(fieldMap, "Plans", "Plan"),
6965
+ blockedBy: parseListField(fieldMap, "Blocked by", "Blockers"),
6950
6966
  summary: fieldMap.get("Summary") ?? "",
6951
- assignee: assigneeRaw === EM_DASH ? null : assigneeRaw,
6952
- priority: priorityRaw === EM_DASH ? null : priorityRaw,
6953
- externalId: externalIdRaw === EM_DASH ? null : externalIdRaw
6967
+ assignee: optionalField(fieldMap, "Assignee"),
6968
+ priority: priorityResult.value,
6969
+ externalId: optionalField(fieldMap, "External-ID")
6954
6970
  });
6955
6971
  }
6956
6972
  function parseAssignmentHistory(body) {
@@ -7014,82 +7030,16 @@ var PredictionEngine = class {
7014
7030
  const firstDate = new Date(snapshots[0].capturedAt).getTime();
7015
7031
  const lastSnapshot = snapshots[snapshots.length - 1];
7016
7032
  const currentT = (new Date(lastSnapshot.capturedAt).getTime() - firstDate) / (7 * 24 * 60 * 60 * 1e3);
7017
- const baselines = {};
7018
- for (const category of ALL_CATEGORIES2) {
7019
- const threshold = thresholds[category];
7020
- const shouldProcess = categoriesToProcess.includes(category);
7021
- if (!shouldProcess) {
7022
- baselines[category] = this.zeroForecast(category, threshold);
7023
- continue;
7024
- }
7025
- const timeSeries = this.extractTimeSeries(snapshots, category, firstDate);
7026
- baselines[category] = this.forecastCategory(
7027
- category,
7028
- timeSeries,
7029
- currentT,
7030
- threshold,
7031
- opts.horizon
7032
- );
7033
- }
7033
+ const baselines = this.computeBaselines(
7034
+ categoriesToProcess,
7035
+ thresholds,
7036
+ snapshots,
7037
+ firstDate,
7038
+ currentT,
7039
+ opts.horizon
7040
+ );
7034
7041
  const specImpacts = this.computeSpecImpacts(opts);
7035
- const categories = {};
7036
- for (const category of ALL_CATEGORIES2) {
7037
- const baseline = baselines[category];
7038
- const threshold = thresholds[category];
7039
- if (!specImpacts || specImpacts.length === 0) {
7040
- categories[category] = {
7041
- baseline,
7042
- adjusted: baseline,
7043
- contributingFeatures: []
7044
- };
7045
- continue;
7046
- }
7047
- let totalDelta = 0;
7048
- const contributing = [];
7049
- for (const impact of specImpacts) {
7050
- const delta = impact.deltas?.[category] ?? 0;
7051
- if (delta !== 0) {
7052
- totalDelta += delta;
7053
- contributing.push({
7054
- name: impact.featureName,
7055
- specPath: impact.specPath,
7056
- delta
7057
- });
7058
- }
7059
- }
7060
- if (totalDelta === 0) {
7061
- categories[category] = {
7062
- baseline,
7063
- adjusted: baseline,
7064
- contributingFeatures: []
7065
- };
7066
- continue;
7067
- }
7068
- const adjusted = {
7069
- ...baseline,
7070
- projectedValue4w: baseline.projectedValue4w + totalDelta,
7071
- projectedValue8w: baseline.projectedValue8w + totalDelta,
7072
- projectedValue12w: baseline.projectedValue12w + totalDelta
7073
- };
7074
- const adjustedFit = {
7075
- slope: baseline.regression.slope,
7076
- intercept: baseline.regression.intercept + totalDelta,
7077
- rSquared: baseline.regression.rSquared,
7078
- dataPoints: baseline.regression.dataPoints
7079
- };
7080
- adjusted.thresholdCrossingWeeks = weeksUntilThreshold(adjustedFit, currentT, threshold);
7081
- adjusted.regression = {
7082
- slope: adjustedFit.slope,
7083
- intercept: adjustedFit.intercept,
7084
- rSquared: adjustedFit.rSquared,
7085
- dataPoints: adjustedFit.dataPoints
7086
- };
7087
- categories[category] = {
7088
- baseline,
7089
- adjusted,
7090
- contributingFeatures: contributing
7091
- };
7092
- }
7042
+ const categories = this.computeAdjustedForecasts(baselines, thresholds, specImpacts, currentT);
7093
7043
  const warnings = this.generateWarnings(
7094
7044
  categories,
7095
7045
  opts.horizon
@@ -7131,6 +7081,76 @@ var PredictionEngine = class {
7131
7081
  }
7132
7082
  return base;
7133
7083
  }
7084
+ computeBaselines(categoriesToProcess, thresholds, snapshots, firstDate, currentT, horizon) {
7085
+ const baselines = {};
7086
+ for (const category of ALL_CATEGORIES2) {
7087
+ const threshold = thresholds[category];
7088
+ if (!categoriesToProcess.includes(category)) {
7089
+ baselines[category] = this.zeroForecast(category, threshold);
7090
+ continue;
7091
+ }
7092
+ const timeSeries = this.extractTimeSeries(snapshots, category, firstDate);
7093
+ baselines[category] = this.forecastCategory(
7094
+ category,
7095
+ timeSeries,
7096
+ currentT,
7097
+ threshold,
7098
+ horizon
7099
+ );
7100
+ }
7101
+ return baselines;
7102
+ }
7103
+ computeAdjustedForecasts(baselines, thresholds, specImpacts, currentT) {
7104
+ const categories = {};
7105
+ for (const category of ALL_CATEGORIES2) {
7106
+ const baseline = baselines[category];
7107
+ categories[category] = this.adjustForecastForCategory(
7108
+ category,
7109
+ baseline,
7110
+ thresholds[category],
7111
+ specImpacts,
7112
+ currentT
7113
+ );
7114
+ }
7115
+ return categories;
7116
+ }
7117
+ adjustForecastForCategory(category, baseline, threshold, specImpacts, currentT) {
7118
+ if (!specImpacts || specImpacts.length === 0) {
7119
+ return { baseline, adjusted: baseline, contributingFeatures: [] };
7120
+ }
7121
+ let totalDelta = 0;
7122
+ const contributing = [];
7123
+ for (const impact of specImpacts) {
7124
+ const delta = impact.deltas?.[category] ?? 0;
7125
+ if (delta !== 0) {
7126
+ totalDelta += delta;
7127
+ contributing.push({ name: impact.featureName, specPath: impact.specPath, delta });
7128
+ }
7129
+ }
7130
+ if (totalDelta === 0) {
7131
+ return { baseline, adjusted: baseline, contributingFeatures: [] };
7132
+ }
7133
+ const adjusted = {
7134
+ ...baseline,
7135
+ projectedValue4w: baseline.projectedValue4w + totalDelta,
7136
+ projectedValue8w: baseline.projectedValue8w + totalDelta,
7137
+ projectedValue12w: baseline.projectedValue12w + totalDelta
7138
+ };
7139
+ const adjustedFit = {
7140
+ slope: baseline.regression.slope,
7141
+ intercept: baseline.regression.intercept + totalDelta,
7142
+ rSquared: baseline.regression.rSquared,
7143
+ dataPoints: baseline.regression.dataPoints
7144
+ };
7145
+ adjusted.thresholdCrossingWeeks = weeksUntilThreshold(adjustedFit, currentT, threshold);
7146
+ adjusted.regression = {
7147
+ slope: adjustedFit.slope,
7148
+ intercept: adjustedFit.intercept,
7149
+ rSquared: adjustedFit.rSquared,
7150
+ dataPoints: adjustedFit.dataPoints
7151
+ };
7152
+ return { baseline, adjusted, contributingFeatures: contributing };
7153
+ }
7134
7154
  /**
7135
7155
  * Extract time series for a single category from snapshots.
7136
7156
  * Returns array of { t (weeks from first), value } sorted oldest first.
@@ -7926,6 +7946,25 @@ function parseFrontmatter2(line) {
7926
7946
  const tags = match[2] ? match[2].split(",").filter(Boolean) : [];
7927
7947
  return { hash, tags };
7928
7948
  }
7949
+ function parseDateFromEntry(entry) {
7950
+ const match = entry.match(/(\d{4}-\d{2}-\d{2})/);
7951
+ return match ? match[1] ?? null : null;
7952
+ }
7953
+ function extractIndexEntry(entry) {
7954
+ const lines = entry.split("\n");
7955
+ const summary = lines[0] ?? entry;
7956
+ const tags = [];
7957
+ const skillMatch = entry.match(/\[skill:([^\]]+)\]/);
7958
+ if (skillMatch?.[1]) tags.push(skillMatch[1]);
7959
+ const outcomeMatch = entry.match(/\[outcome:([^\]]+)\]/);
7960
+ if (outcomeMatch?.[1]) tags.push(outcomeMatch[1]);
7961
+ return {
7962
+ hash: computeEntryHash(entry),
7963
+ tags,
7964
+ summary,
7965
+ fullText: entry
7966
+ };
7967
+ }
7929
7968
  function computeEntryHash(text) {
7930
7969
  return crypto.createHash("sha256").update(text).digest("hex").slice(0, 8);
7931
7970
  }
@@ -7960,8 +7999,8 @@ function saveContentHashes(stateDir, index) {
7960
7999
  const hashesPath = path8.join(stateDir, CONTENT_HASHES_FILE);
7961
8000
  fs11.writeFileSync(hashesPath, JSON.stringify(index, null, 2) + "\n");
7962
8001
  }
7963
- function rebuildContentHashes(stateDir) {
7964
- const learningsPath = path8.join(stateDir, LEARNINGS_FILE);
8002
+ function rebuildContentHashes(stateDir, learningsFile) {
8003
+ const learningsPath = path8.join(stateDir, learningsFile);
7965
8004
  if (!fs11.existsSync(learningsPath)) return {};
7966
8005
  const content = fs11.readFileSync(learningsPath, "utf-8");
7967
8006
  const lines = content.split("\n");
@@ -7982,43 +8021,116 @@ function rebuildContentHashes(stateDir) {
7982
8021
  saveContentHashes(stateDir, index);
7983
8022
  return index;
7984
8023
  }
7985
- function extractIndexEntry(entry) {
7986
- const lines = entry.split("\n");
7987
- const summary = lines[0] ?? entry;
7988
- const tags = [];
7989
- const skillMatch = entry.match(/\[skill:([^\]]+)\]/);
7990
- if (skillMatch?.[1]) tags.push(skillMatch[1]);
7991
- const outcomeMatch = entry.match(/\[outcome:([^\]]+)\]/);
7992
- if (outcomeMatch?.[1]) tags.push(outcomeMatch[1]);
7993
- return {
7994
- hash: computeEntryHash(entry),
7995
- tags,
7996
- summary,
7997
- fullText: entry
7998
- };
8024
+ function analyzeLearningPatterns(entries) {
8025
+ const tagGroups = /* @__PURE__ */ new Map();
8026
+ for (const entry of entries) {
8027
+ const tagMatches = entry.matchAll(/\[(skill:[^\]]+)\]|\[(outcome:[^\]]+)\]/g);
8028
+ for (const match of tagMatches) {
8029
+ const tag = match[1] ?? match[2];
8030
+ if (tag) {
8031
+ const group = tagGroups.get(tag) ?? [];
8032
+ group.push(entry);
8033
+ tagGroups.set(tag, group);
8034
+ }
8035
+ }
8036
+ }
8037
+ const patterns = [];
8038
+ for (const [tag, groupEntries] of tagGroups) {
8039
+ if (groupEntries.length >= 3) {
8040
+ patterns.push({ tag, count: groupEntries.length, entries: groupEntries });
8041
+ }
8042
+ }
8043
+ return patterns.sort((a, b) => b.count - a.count);
8044
+ }
8045
+ function estimateTokens(text) {
8046
+ return Math.ceil(text.length / 4);
8047
+ }
8048
+ function scoreRelevance(entry, intent) {
8049
+ if (!intent || intent.trim() === "") return 0;
8050
+ const intentWords = intent.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
8051
+ if (intentWords.length === 0) return 0;
8052
+ const entryLower = entry.toLowerCase();
8053
+ const matches = intentWords.filter((word) => entryLower.includes(word));
8054
+ return matches.length / intentWords.length;
7999
8055
  }
8000
8056
  var learningsCacheMap = /* @__PURE__ */ new Map();
8001
8057
  function clearLearningsCache() {
8002
8058
  learningsCacheMap.clear();
8003
8059
  }
8060
+ function invalidateLearningsCacheEntry(key) {
8061
+ learningsCacheMap.delete(key);
8062
+ }
8063
+ async function loadRelevantLearnings(projectPath, skillName, stream, session) {
8064
+ try {
8065
+ const dirResult = await getStateDir(projectPath, stream, session);
8066
+ if (!dirResult.ok) return dirResult;
8067
+ const stateDir = dirResult.value;
8068
+ const learningsPath = path9.join(stateDir, LEARNINGS_FILE);
8069
+ if (!fs12.existsSync(learningsPath)) {
8070
+ return Ok([]);
8071
+ }
8072
+ const stats = fs12.statSync(learningsPath);
8073
+ const cacheKey = learningsPath;
8074
+ const cached = learningsCacheMap.get(cacheKey);
8075
+ let entries;
8076
+ if (cached && cached.mtimeMs === stats.mtimeMs) {
8077
+ entries = cached.entries;
8078
+ } else {
8079
+ const content = fs12.readFileSync(learningsPath, "utf-8");
8080
+ const lines = content.split("\n");
8081
+ entries = [];
8082
+ let currentBlock = [];
8083
+ for (const line of lines) {
8084
+ if (line.startsWith("# ")) continue;
8085
+ if (/^<!--\s+hash:[a-f0-9]+/.test(line)) continue;
8086
+ const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
8087
+ const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
8088
+ if (isDatedBullet || isHeading) {
8089
+ if (currentBlock.length > 0) {
8090
+ entries.push(currentBlock.join("\n"));
8091
+ }
8092
+ currentBlock = [line];
8093
+ } else if (line.trim() !== "" && currentBlock.length > 0) {
8094
+ currentBlock.push(line);
8095
+ }
8096
+ }
8097
+ if (currentBlock.length > 0) {
8098
+ entries.push(currentBlock.join("\n"));
8099
+ }
8100
+ learningsCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
8101
+ evictIfNeeded(learningsCacheMap);
8102
+ }
8103
+ if (!skillName) {
8104
+ return Ok(entries);
8105
+ }
8106
+ const filtered = entries.filter((entry) => entry.includes(`[skill:${skillName}]`));
8107
+ return Ok(filtered);
8108
+ } catch (error) {
8109
+ return Err(
8110
+ new Error(
8111
+ `Failed to load learnings: ${error instanceof Error ? error.message : String(error)}`
8112
+ )
8113
+ );
8114
+ }
8115
+ }
8004
8116
  async function appendLearning(projectPath, learning, skillName, outcome, stream, session) {
8005
8117
  try {
8006
8118
  const dirResult = await getStateDir(projectPath, stream, session);
8007
8119
  if (!dirResult.ok) return dirResult;
8008
8120
  const stateDir = dirResult.value;
8009
- const learningsPath = path8.join(stateDir, LEARNINGS_FILE);
8010
- fs11.mkdirSync(stateDir, { recursive: true });
8121
+ const learningsPath = path10.join(stateDir, LEARNINGS_FILE);
8122
+ fs13.mkdirSync(stateDir, { recursive: true });
8011
8123
  const normalizedContent = normalizeLearningContent(learning);
8012
8124
  const contentHash = computeContentHash(normalizedContent);
8013
- const hashesPath = path8.join(stateDir, CONTENT_HASHES_FILE);
8125
+ const hashesPath = path10.join(stateDir, CONTENT_HASHES_FILE);
8014
8126
  let contentHashes;
8015
- if (fs11.existsSync(hashesPath)) {
8127
+ if (fs13.existsSync(hashesPath)) {
8016
8128
  contentHashes = loadContentHashes(stateDir);
8017
- if (Object.keys(contentHashes).length === 0 && fs11.existsSync(learningsPath)) {
8018
- contentHashes = rebuildContentHashes(stateDir);
8129
+ if (Object.keys(contentHashes).length === 0 && fs13.existsSync(learningsPath)) {
8130
+ contentHashes = rebuildContentHashes(stateDir, LEARNINGS_FILE);
8019
8131
  }
8020
- } else if (fs11.existsSync(learningsPath)) {
8021
- contentHashes = rebuildContentHashes(stateDir);
8132
+ } else if (fs13.existsSync(learningsPath)) {
8133
+ contentHashes = rebuildContentHashes(stateDir, LEARNINGS_FILE);
8022
8134
  } else {
8023
8135
  contentHashes = {};
8024
8136
  }
@@ -8037,7 +8149,7 @@ async function appendLearning(projectPath, learning, skillName, outcome, stream,
8037
8149
  } else {
8038
8150
  bulletLine = `- **${timestamp}:** ${learning}`;
8039
8151
  }
8040
- const hash = crypto.createHash("sha256").update(bulletLine).digest("hex").slice(0, 8);
8152
+ const hash = crypto2.createHash("sha256").update(bulletLine).digest("hex").slice(0, 8);
8041
8153
  const tagsStr = fmTags.length > 0 ? ` tags:${fmTags.join(",")}` : "";
8042
8154
  const frontmatter = `<!-- hash:${hash}${tagsStr} -->`;
8043
8155
  const entry = `
@@ -8045,19 +8157,19 @@ ${frontmatter}
8045
8157
  ${bulletLine}
8046
8158
  `;
8047
8159
  let existingLineCount;
8048
- if (!fs11.existsSync(learningsPath)) {
8049
- fs11.writeFileSync(learningsPath, `# Learnings
8160
+ if (!fs13.existsSync(learningsPath)) {
8161
+ fs13.writeFileSync(learningsPath, `# Learnings
8050
8162
  ${entry}`);
8051
8163
  existingLineCount = 1;
8052
8164
  } else {
8053
- const existingContent = fs11.readFileSync(learningsPath, "utf-8");
8165
+ const existingContent = fs13.readFileSync(learningsPath, "utf-8");
8054
8166
  existingLineCount = existingContent.split("\n").length;
8055
- fs11.appendFileSync(learningsPath, entry);
8167
+ fs13.appendFileSync(learningsPath, entry);
8056
8168
  }
8057
8169
  const bulletLine_lineNum = existingLineCount + 2;
8058
8170
  contentHashes[contentHash] = { date: timestamp ?? "", line: bulletLine_lineNum };
8059
8171
  saveContentHashes(stateDir, contentHashes);
8060
- learningsCacheMap.delete(learningsPath);
8172
+ invalidateLearningsCacheEntry(learningsPath);
8061
8173
  return Ok(void 0);
8062
8174
  } catch (error) {
8063
8175
  return Err(
@@ -8067,42 +8179,6 @@ ${entry}`);
8067
8179
  );
8068
8180
  }
8069
8181
  }
8070
- function estimateTokens(text) {
8071
- return Math.ceil(text.length / 4);
8072
- }
8073
- function scoreRelevance(entry, intent) {
8074
- if (!intent || intent.trim() === "") return 0;
8075
- const intentWords = intent.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
8076
- if (intentWords.length === 0) return 0;
8077
- const entryLower = entry.toLowerCase();
8078
- const matches = intentWords.filter((word) => entryLower.includes(word));
8079
- return matches.length / intentWords.length;
8080
- }
8081
- function parseDateFromEntry(entry) {
8082
- const match = entry.match(/(\d{4}-\d{2}-\d{2})/);
8083
- return match ? match[1] ?? null : null;
8084
- }
8085
- function analyzeLearningPatterns(entries) {
8086
- const tagGroups = /* @__PURE__ */ new Map();
8087
- for (const entry of entries) {
8088
- const tagMatches = entry.matchAll(/\[(skill:[^\]]+)\]|\[(outcome:[^\]]+)\]/g);
8089
- for (const match of tagMatches) {
8090
- const tag = match[1] ?? match[2];
8091
- if (tag) {
8092
- const group = tagGroups.get(tag) ?? [];
8093
- group.push(entry);
8094
- tagGroups.set(tag, group);
8095
- }
8096
- }
8097
- }
8098
- const patterns = [];
8099
- for (const [tag, groupEntries] of tagGroups) {
8100
- if (groupEntries.length >= 3) {
8101
- patterns.push({ tag, count: groupEntries.length, entries: groupEntries });
8102
- }
8103
- }
8104
- return patterns.sort((a, b) => b.count - a.count);
8105
- }
8106
8182
  async function loadBudgetedLearnings(projectPath, options) {
8107
8183
  const { intent, tokenBudget = 1e3, skill, session, stream, depth = "summary" } = options;
8108
8184
  if (depth === "index") {
@@ -8166,11 +8242,11 @@ async function loadIndexEntries(projectPath, skillName, stream, session) {
8166
8242
  const dirResult = await getStateDir(projectPath, stream, session);
8167
8243
  if (!dirResult.ok) return dirResult;
8168
8244
  const stateDir = dirResult.value;
8169
- const learningsPath = path8.join(stateDir, LEARNINGS_FILE);
8170
- if (!fs11.existsSync(learningsPath)) {
8245
+ const learningsPath = path10.join(stateDir, LEARNINGS_FILE);
8246
+ if (!fs13.existsSync(learningsPath)) {
8171
8247
  return Ok([]);
8172
8248
  }
8173
- const content = fs11.readFileSync(learningsPath, "utf-8");
8249
+ const content = fs13.readFileSync(learningsPath, "utf-8");
8174
8250
  const lines = content.split("\n");
8175
8251
  const indexEntries = [];
8176
8252
  let pendingFrontmatter = null;
@@ -8223,74 +8299,21 @@ async function loadIndexEntries(projectPath, skillName, stream, session) {
8223
8299
  );
8224
8300
  }
8225
8301
  }
8226
- async function loadRelevantLearnings(projectPath, skillName, stream, session) {
8227
- try {
8228
- const dirResult = await getStateDir(projectPath, stream, session);
8229
- if (!dirResult.ok) return dirResult;
8230
- const stateDir = dirResult.value;
8231
- const learningsPath = path8.join(stateDir, LEARNINGS_FILE);
8232
- if (!fs11.existsSync(learningsPath)) {
8233
- return Ok([]);
8234
- }
8235
- const stats = fs11.statSync(learningsPath);
8236
- const cacheKey = learningsPath;
8237
- const cached = learningsCacheMap.get(cacheKey);
8238
- let entries;
8239
- if (cached && cached.mtimeMs === stats.mtimeMs) {
8240
- entries = cached.entries;
8241
- } else {
8242
- const content = fs11.readFileSync(learningsPath, "utf-8");
8243
- const lines = content.split("\n");
8244
- entries = [];
8245
- let currentBlock = [];
8246
- for (const line of lines) {
8247
- if (line.startsWith("# ")) continue;
8248
- if (/^<!--\s+hash:[a-f0-9]+/.test(line)) continue;
8249
- const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
8250
- const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
8251
- if (isDatedBullet || isHeading) {
8252
- if (currentBlock.length > 0) {
8253
- entries.push(currentBlock.join("\n"));
8254
- }
8255
- currentBlock = [line];
8256
- } else if (line.trim() !== "" && currentBlock.length > 0) {
8257
- currentBlock.push(line);
8258
- }
8259
- }
8260
- if (currentBlock.length > 0) {
8261
- entries.push(currentBlock.join("\n"));
8262
- }
8263
- learningsCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
8264
- evictIfNeeded(learningsCacheMap);
8265
- }
8266
- if (!skillName) {
8267
- return Ok(entries);
8268
- }
8269
- const filtered = entries.filter((entry) => entry.includes(`[skill:${skillName}]`));
8270
- return Ok(filtered);
8271
- } catch (error) {
8272
- return Err(
8273
- new Error(
8274
- `Failed to load learnings: ${error instanceof Error ? error.message : String(error)}`
8275
- )
8276
- );
8277
- }
8278
- }
8279
8302
  async function archiveLearnings(projectPath, entries, stream) {
8280
8303
  try {
8281
8304
  const dirResult = await getStateDir(projectPath, stream);
8282
8305
  if (!dirResult.ok) return dirResult;
8283
8306
  const stateDir = dirResult.value;
8284
- const archiveDir = path8.join(stateDir, "learnings-archive");
8285
- fs11.mkdirSync(archiveDir, { recursive: true });
8307
+ const archiveDir = path11.join(stateDir, "learnings-archive");
8308
+ fs14.mkdirSync(archiveDir, { recursive: true });
8286
8309
  const now = /* @__PURE__ */ new Date();
8287
8310
  const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
8288
- const archivePath = path8.join(archiveDir, `${yearMonth}.md`);
8311
+ const archivePath = path11.join(archiveDir, `${yearMonth}.md`);
8289
8312
  const archiveContent = entries.join("\n\n") + "\n";
8290
- if (fs11.existsSync(archivePath)) {
8291
- fs11.appendFileSync(archivePath, "\n" + archiveContent);
8313
+ if (fs14.existsSync(archivePath)) {
8314
+ fs14.appendFileSync(archivePath, "\n" + archiveContent);
8292
8315
  } else {
8293
- fs11.writeFileSync(archivePath, `# Learnings Archive
8316
+ fs14.writeFileSync(archivePath, `# Learnings Archive
8294
8317
 
8295
8318
  ${archiveContent}`);
8296
8319
  }
@@ -8308,8 +8331,8 @@ async function pruneLearnings(projectPath, stream) {
8308
8331
  const dirResult = await getStateDir(projectPath, stream);
8309
8332
  if (!dirResult.ok) return dirResult;
8310
8333
  const stateDir = dirResult.value;
8311
- const learningsPath = path8.join(stateDir, LEARNINGS_FILE);
8312
- if (!fs11.existsSync(learningsPath)) {
8334
+ const learningsPath = path11.join(stateDir, LEARNINGS_FILE);
8335
+ if (!fs14.existsSync(learningsPath)) {
8313
8336
  return Ok({ kept: 0, archived: 0, patterns: [] });
8314
8337
  }
8315
8338
  const loadResult = await loadRelevantLearnings(projectPath, void 0, stream);
@@ -8340,8 +8363,8 @@ async function pruneLearnings(projectPath, stream) {
8340
8363
  if (!archiveResult.ok) return archiveResult;
8341
8364
  }
8342
8365
  const newContent = "# Learnings\n\n" + toKeep.join("\n\n") + "\n";
8343
- fs11.writeFileSync(learningsPath, newContent);
8344
- learningsCacheMap.delete(learningsPath);
8366
+ fs14.writeFileSync(learningsPath, newContent);
8367
+ invalidateLearningsCacheEntry(learningsPath);
8345
8368
  return Ok({
8346
8369
  kept: toKeep.length,
8347
8370
  archived: toArchive.length,
@@ -8385,21 +8408,21 @@ async function promoteSessionLearnings(projectPath, sessionSlug, stream) {
8385
8408
  const dirResult = await getStateDir(projectPath, stream);
8386
8409
  if (!dirResult.ok) return dirResult;
8387
8410
  const stateDir = dirResult.value;
8388
- const globalPath = path8.join(stateDir, LEARNINGS_FILE);
8389
- const existingGlobal = fs11.existsSync(globalPath) ? fs11.readFileSync(globalPath, "utf-8") : "";
8411
+ const globalPath = path11.join(stateDir, LEARNINGS_FILE);
8412
+ const existingGlobal = fs14.existsSync(globalPath) ? fs14.readFileSync(globalPath, "utf-8") : "";
8390
8413
  const newEntries = toPromote.filter((entry) => !existingGlobal.includes(entry.trim()));
8391
8414
  if (newEntries.length === 0) {
8392
8415
  return Ok({ promoted: 0, skipped: skipped + toPromote.length });
8393
8416
  }
8394
8417
  const promotedContent = newEntries.join("\n\n") + "\n";
8395
8418
  if (!existingGlobal) {
8396
- fs11.writeFileSync(globalPath, `# Learnings
8419
+ fs14.writeFileSync(globalPath, `# Learnings
8397
8420
 
8398
8421
  ${promotedContent}`);
8399
8422
  } else {
8400
- fs11.appendFileSync(globalPath, "\n\n" + promotedContent);
8423
+ fs14.appendFileSync(globalPath, "\n\n" + promotedContent);
8401
8424
  }
8402
- learningsCacheMap.delete(globalPath);
8425
+ invalidateLearningsCacheEntry(globalPath);
8403
8426
  return Ok({
8404
8427
  promoted: newEntries.length,
8405
8428
  skipped: skipped + (toPromote.length - newEntries.length)
@@ -8427,17 +8450,17 @@ async function appendFailure(projectPath, description, skillName, type, stream,
8427
8450
  const dirResult = await getStateDir(projectPath, stream, session);
8428
8451
  if (!dirResult.ok) return dirResult;
8429
8452
  const stateDir = dirResult.value;
8430
- const failuresPath = path9.join(stateDir, FAILURES_FILE);
8431
- fs12.mkdirSync(stateDir, { recursive: true });
8453
+ const failuresPath = path12.join(stateDir, FAILURES_FILE);
8454
+ fs15.mkdirSync(stateDir, { recursive: true });
8432
8455
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
8433
8456
  const entry = `
8434
8457
  - **${timestamp} [skill:${skillName}] [type:${type}]:** ${description}
8435
8458
  `;
8436
- if (!fs12.existsSync(failuresPath)) {
8437
- fs12.writeFileSync(failuresPath, `# Failures
8459
+ if (!fs15.existsSync(failuresPath)) {
8460
+ fs15.writeFileSync(failuresPath, `# Failures
8438
8461
  ${entry}`);
8439
8462
  } else {
8440
- fs12.appendFileSync(failuresPath, entry);
8463
+ fs15.appendFileSync(failuresPath, entry);
8441
8464
  }
8442
8465
  failuresCacheMap.delete(failuresPath);
8443
8466
  return Ok(void 0);
@@ -8454,17 +8477,17 @@ async function loadFailures(projectPath, stream, session) {
8454
8477
  const dirResult = await getStateDir(projectPath, stream, session);
8455
8478
  if (!dirResult.ok) return dirResult;
8456
8479
  const stateDir = dirResult.value;
8457
- const failuresPath = path9.join(stateDir, FAILURES_FILE);
8458
- if (!fs12.existsSync(failuresPath)) {
8480
+ const failuresPath = path12.join(stateDir, FAILURES_FILE);
8481
+ if (!fs15.existsSync(failuresPath)) {
8459
8482
  return Ok([]);
8460
8483
  }
8461
- const stats = fs12.statSync(failuresPath);
8484
+ const stats = fs15.statSync(failuresPath);
8462
8485
  const cacheKey = failuresPath;
8463
8486
  const cached = failuresCacheMap.get(cacheKey);
8464
8487
  if (cached && cached.mtimeMs === stats.mtimeMs) {
8465
8488
  return Ok(cached.entries);
8466
8489
  }
8467
- const content = fs12.readFileSync(failuresPath, "utf-8");
8490
+ const content = fs15.readFileSync(failuresPath, "utf-8");
8468
8491
  const entries = [];
8469
8492
  for (const line of content.split("\n")) {
8470
8493
  const match = line.match(FAILURE_LINE_REGEX);
@@ -8493,20 +8516,20 @@ async function archiveFailures(projectPath, stream, session) {
8493
8516
  const dirResult = await getStateDir(projectPath, stream, session);
8494
8517
  if (!dirResult.ok) return dirResult;
8495
8518
  const stateDir = dirResult.value;
8496
- const failuresPath = path9.join(stateDir, FAILURES_FILE);
8497
- if (!fs12.existsSync(failuresPath)) {
8519
+ const failuresPath = path12.join(stateDir, FAILURES_FILE);
8520
+ if (!fs15.existsSync(failuresPath)) {
8498
8521
  return Ok(void 0);
8499
8522
  }
8500
- const archiveDir = path9.join(stateDir, "archive");
8501
- fs12.mkdirSync(archiveDir, { recursive: true });
8523
+ const archiveDir = path12.join(stateDir, "archive");
8524
+ fs15.mkdirSync(archiveDir, { recursive: true });
8502
8525
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
8503
8526
  let archiveName = `failures-${date}.md`;
8504
8527
  let counter = 2;
8505
- while (fs12.existsSync(path9.join(archiveDir, archiveName))) {
8528
+ while (fs15.existsSync(path12.join(archiveDir, archiveName))) {
8506
8529
  archiveName = `failures-${date}-${counter}.md`;
8507
8530
  counter++;
8508
8531
  }
8509
- fs12.renameSync(failuresPath, path9.join(archiveDir, archiveName));
8532
+ fs15.renameSync(failuresPath, path12.join(archiveDir, archiveName));
8510
8533
  failuresCacheMap.delete(failuresPath);
8511
8534
  return Ok(void 0);
8512
8535
  } catch (error) {
@@ -8522,9 +8545,9 @@ async function saveHandoff(projectPath, handoff, stream, session) {
8522
8545
  const dirResult = await getStateDir(projectPath, stream, session);
8523
8546
  if (!dirResult.ok) return dirResult;
8524
8547
  const stateDir = dirResult.value;
8525
- const handoffPath = path10.join(stateDir, HANDOFF_FILE);
8526
- fs13.mkdirSync(stateDir, { recursive: true });
8527
- fs13.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2));
8548
+ const handoffPath = path13.join(stateDir, HANDOFF_FILE);
8549
+ fs16.mkdirSync(stateDir, { recursive: true });
8550
+ fs16.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2));
8528
8551
  return Ok(void 0);
8529
8552
  } catch (error) {
8530
8553
  return Err(
@@ -8537,11 +8560,11 @@ async function loadHandoff(projectPath, stream, session) {
8537
8560
  const dirResult = await getStateDir(projectPath, stream, session);
8538
8561
  if (!dirResult.ok) return dirResult;
8539
8562
  const stateDir = dirResult.value;
8540
- const handoffPath = path10.join(stateDir, HANDOFF_FILE);
8541
- if (!fs13.existsSync(handoffPath)) {
8563
+ const handoffPath = path13.join(stateDir, HANDOFF_FILE);
8564
+ if (!fs16.existsSync(handoffPath)) {
8542
8565
  return Ok(null);
8543
8566
  }
8544
- const raw = fs13.readFileSync(handoffPath, "utf-8");
8567
+ const raw = fs16.readFileSync(handoffPath, "utf-8");
8545
8568
  const parsed = JSON.parse(raw);
8546
8569
  const result = HandoffSchema.safeParse(parsed);
8547
8570
  if (!result.success) {
@@ -8556,28 +8579,28 @@ async function loadHandoff(projectPath, stream, session) {
8556
8579
  }
8557
8580
  var SAFE_GATE_COMMAND = /^(?:npm|pnpm|yarn)\s+(?:test|run\s+[\w.-]+|run-script\s+[\w.-]+)$|^go\s+(?:test|build|vet|fmt)\s+[\w./ -]+$|^(?:python|python3)\s+-m\s+[\w.-]+$|^make\s+[\w.-]+$|^cargo\s+(?:test|build|check|clippy)(?:\s+[\w./ -]+)?$|^(?:gradle|mvn)\s+[\w:.-]+$/;
8558
8581
  function loadChecksFromConfig(gateConfigPath) {
8559
- if (!fs14.existsSync(gateConfigPath)) return [];
8560
- const raw = JSON.parse(fs14.readFileSync(gateConfigPath, "utf-8"));
8582
+ if (!fs17.existsSync(gateConfigPath)) return [];
8583
+ const raw = JSON.parse(fs17.readFileSync(gateConfigPath, "utf-8"));
8561
8584
  const config = GateConfigSchema.safeParse(raw);
8562
8585
  if (config.success && config.data.checks) return config.data.checks;
8563
8586
  return [];
8564
8587
  }
8565
8588
  function discoverChecksFromProject(projectPath) {
8566
8589
  const checks = [];
8567
- const packageJsonPath = path11.join(projectPath, "package.json");
8568
- if (fs14.existsSync(packageJsonPath)) {
8569
- const pkg = JSON.parse(fs14.readFileSync(packageJsonPath, "utf-8"));
8590
+ const packageJsonPath = path14.join(projectPath, "package.json");
8591
+ if (fs17.existsSync(packageJsonPath)) {
8592
+ const pkg = JSON.parse(fs17.readFileSync(packageJsonPath, "utf-8"));
8570
8593
  const scripts = pkg.scripts || {};
8571
8594
  if (scripts.test) checks.push({ name: "test", command: "npm test" });
8572
8595
  if (scripts.lint) checks.push({ name: "lint", command: "npm run lint" });
8573
8596
  if (scripts.typecheck) checks.push({ name: "typecheck", command: "npm run typecheck" });
8574
8597
  if (scripts.build) checks.push({ name: "build", command: "npm run build" });
8575
8598
  }
8576
- if (fs14.existsSync(path11.join(projectPath, "go.mod"))) {
8599
+ if (fs17.existsSync(path14.join(projectPath, "go.mod"))) {
8577
8600
  checks.push({ name: "test", command: "go test ./..." });
8578
8601
  checks.push({ name: "build", command: "go build ./..." });
8579
8602
  }
8580
- if (fs14.existsSync(path11.join(projectPath, "pyproject.toml")) || fs14.existsSync(path11.join(projectPath, "setup.py"))) {
8603
+ if (fs17.existsSync(path14.join(projectPath, "pyproject.toml")) || fs17.existsSync(path14.join(projectPath, "setup.py"))) {
8581
8604
  checks.push({ name: "test", command: "python -m pytest" });
8582
8605
  }
8583
8606
  return checks;
@@ -8617,8 +8640,8 @@ function executeCheck(check, projectPath) {
8617
8640
  }
8618
8641
  }
8619
8642
  async function runMechanicalGate(projectPath) {
8620
- const harnessDir = path11.join(projectPath, HARNESS_DIR);
8621
- const gateConfigPath = path11.join(harnessDir, GATE_CONFIG_FILE);
8643
+ const harnessDir = path14.join(projectPath, HARNESS_DIR);
8644
+ const gateConfigPath = path14.join(harnessDir, GATE_CONFIG_FILE);
8622
8645
  try {
8623
8646
  let checks = loadChecksFromConfig(gateConfigPath);
8624
8647
  if (checks.length === 0) {
@@ -8674,9 +8697,9 @@ function writeSessionSummary(projectPath, sessionSlug, data) {
8674
8697
  const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
8675
8698
  if (!dirResult.ok) return dirResult;
8676
8699
  const sessionDir = dirResult.value;
8677
- const summaryPath = path12.join(sessionDir, SUMMARY_FILE);
8700
+ const summaryPath = path15.join(sessionDir, SUMMARY_FILE);
8678
8701
  const content = formatSummary(data);
8679
- fs15.writeFileSync(summaryPath, content);
8702
+ fs18.writeFileSync(summaryPath, content);
8680
8703
  const description = deriveIndexDescription(data);
8681
8704
  updateSessionIndex(projectPath, sessionSlug, description);
8682
8705
  return Ok(void 0);
@@ -8693,11 +8716,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
8693
8716
  const dirResult = resolveSessionDir(projectPath, sessionSlug);
8694
8717
  if (!dirResult.ok) return dirResult;
8695
8718
  const sessionDir = dirResult.value;
8696
- const summaryPath = path12.join(sessionDir, SUMMARY_FILE);
8697
- if (!fs15.existsSync(summaryPath)) {
8719
+ const summaryPath = path15.join(sessionDir, SUMMARY_FILE);
8720
+ if (!fs18.existsSync(summaryPath)) {
8698
8721
  return Ok(null);
8699
8722
  }
8700
- const content = fs15.readFileSync(summaryPath, "utf-8");
8723
+ const content = fs18.readFileSync(summaryPath, "utf-8");
8701
8724
  return Ok(content);
8702
8725
  } catch (error) {
8703
8726
  return Err(
@@ -8709,11 +8732,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
8709
8732
  }
8710
8733
  function listActiveSessions(projectPath) {
8711
8734
  try {
8712
- const indexPath2 = path12.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
8713
- if (!fs15.existsSync(indexPath2)) {
8735
+ const indexPath2 = path15.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
8736
+ if (!fs18.existsSync(indexPath2)) {
8714
8737
  return Ok(null);
8715
8738
  }
8716
- const content = fs15.readFileSync(indexPath2, "utf-8");
8739
+ const content = fs18.readFileSync(indexPath2, "utf-8");
8717
8740
  return Ok(content);
8718
8741
  } catch (error) {
8719
8742
  return Err(
@@ -8734,12 +8757,12 @@ async function loadSessionState(projectPath, sessionSlug) {
8734
8757
  const dirResult = resolveSessionDir(projectPath, sessionSlug);
8735
8758
  if (!dirResult.ok) return dirResult;
8736
8759
  const sessionDir = dirResult.value;
8737
- const filePath = path13.join(sessionDir, SESSION_STATE_FILE);
8738
- if (!fs16.existsSync(filePath)) {
8760
+ const filePath = path16.join(sessionDir, SESSION_STATE_FILE);
8761
+ if (!fs19.existsSync(filePath)) {
8739
8762
  return Ok(emptySections());
8740
8763
  }
8741
8764
  try {
8742
- const raw = fs16.readFileSync(filePath, "utf-8");
8765
+ const raw = fs19.readFileSync(filePath, "utf-8");
8743
8766
  const parsed = JSON.parse(raw);
8744
8767
  const sections = emptySections();
8745
8768
  for (const name of SESSION_SECTION_NAMES) {
@@ -8760,9 +8783,9 @@ async function saveSessionState(projectPath, sessionSlug, sections) {
8760
8783
  const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
8761
8784
  if (!dirResult.ok) return dirResult;
8762
8785
  const sessionDir = dirResult.value;
8763
- const filePath = path13.join(sessionDir, SESSION_STATE_FILE);
8786
+ const filePath = path16.join(sessionDir, SESSION_STATE_FILE);
8764
8787
  try {
8765
- fs16.writeFileSync(filePath, JSON.stringify(sections, null, 2));
8788
+ fs19.writeFileSync(filePath, JSON.stringify(sections, null, 2));
8766
8789
  return Ok(void 0);
8767
8790
  } catch (error) {
8768
8791
  return Err(
@@ -8818,26 +8841,26 @@ async function archiveSession(projectPath, sessionSlug) {
8818
8841
  const dirResult = resolveSessionDir(projectPath, sessionSlug);
8819
8842
  if (!dirResult.ok) return dirResult;
8820
8843
  const sessionDir = dirResult.value;
8821
- if (!fs17.existsSync(sessionDir)) {
8844
+ if (!fs20.existsSync(sessionDir)) {
8822
8845
  return Err(new Error(`Session '${sessionSlug}' not found at ${sessionDir}`));
8823
8846
  }
8824
- const archiveBase = path14.join(projectPath, HARNESS_DIR, ARCHIVE_DIR, "sessions");
8847
+ const archiveBase = path17.join(projectPath, HARNESS_DIR, ARCHIVE_DIR, "sessions");
8825
8848
  try {
8826
- fs17.mkdirSync(archiveBase, { recursive: true });
8849
+ fs20.mkdirSync(archiveBase, { recursive: true });
8827
8850
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
8828
8851
  let archiveName = `${sessionSlug}-${date}`;
8829
8852
  let counter = 1;
8830
- while (fs17.existsSync(path14.join(archiveBase, archiveName))) {
8853
+ while (fs20.existsSync(path17.join(archiveBase, archiveName))) {
8831
8854
  archiveName = `${sessionSlug}-${date}-${counter}`;
8832
8855
  counter++;
8833
8856
  }
8834
- const dest = path14.join(archiveBase, archiveName);
8857
+ const dest = path17.join(archiveBase, archiveName);
8835
8858
  try {
8836
- fs17.renameSync(sessionDir, dest);
8859
+ fs20.renameSync(sessionDir, dest);
8837
8860
  } catch (renameErr) {
8838
8861
  if (renameErr instanceof Error && "code" in renameErr && renameErr.code === "EXDEV") {
8839
- fs17.cpSync(sessionDir, dest, { recursive: true });
8840
- fs17.rmSync(sessionDir, { recursive: true });
8862
+ fs20.cpSync(sessionDir, dest, { recursive: true });
8863
+ fs20.rmSync(sessionDir, { recursive: true });
8841
8864
  } else {
8842
8865
  throw renameErr;
8843
8866
  }
@@ -8870,8 +8893,8 @@ function loadKnownHashes(eventsPath) {
8870
8893
  const cached = knownHashesCache.get(eventsPath);
8871
8894
  if (cached) return cached;
8872
8895
  const hashes = /* @__PURE__ */ new Set();
8873
- if (fs18.existsSync(eventsPath)) {
8874
- const content = fs18.readFileSync(eventsPath, "utf-8");
8896
+ if (fs21.existsSync(eventsPath)) {
8897
+ const content = fs21.readFileSync(eventsPath, "utf-8");
8875
8898
  const lines = content.split("\n").filter((line) => line.trim() !== "");
8876
8899
  for (const line of lines) {
8877
8900
  try {
@@ -8894,8 +8917,8 @@ async function emitEvent(projectPath, event, options) {
8894
8917
  const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
8895
8918
  if (!dirResult.ok) return dirResult;
8896
8919
  const stateDir = dirResult.value;
8897
- const eventsPath = path15.join(stateDir, EVENTS_FILE);
8898
- fs18.mkdirSync(stateDir, { recursive: true });
8920
+ const eventsPath = path18.join(stateDir, EVENTS_FILE);
8921
+ fs21.mkdirSync(stateDir, { recursive: true });
8899
8922
  const contentHash = computeEventHash(event, options?.session);
8900
8923
  const knownHashes = loadKnownHashes(eventsPath);
8901
8924
  if (knownHashes.has(contentHash)) {
@@ -8909,7 +8932,7 @@ async function emitEvent(projectPath, event, options) {
8909
8932
  if (options?.session) {
8910
8933
  fullEvent.session = options.session;
8911
8934
  }
8912
- fs18.appendFileSync(eventsPath, JSON.stringify(fullEvent) + "\n");
8935
+ fs21.appendFileSync(eventsPath, JSON.stringify(fullEvent) + "\n");
8913
8936
  knownHashes.add(contentHash);
8914
8937
  return Ok({ written: true });
8915
8938
  } catch (error) {
@@ -8923,11 +8946,11 @@ async function loadEvents(projectPath, options) {
8923
8946
  const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
8924
8947
  if (!dirResult.ok) return dirResult;
8925
8948
  const stateDir = dirResult.value;
8926
- const eventsPath = path15.join(stateDir, EVENTS_FILE);
8927
- if (!fs18.existsSync(eventsPath)) {
8949
+ const eventsPath = path18.join(stateDir, EVENTS_FILE);
8950
+ if (!fs21.existsSync(eventsPath)) {
8928
8951
  return Ok([]);
8929
8952
  }
8930
- const content = fs18.readFileSync(eventsPath, "utf-8");
8953
+ const content = fs21.readFileSync(eventsPath, "utf-8");
8931
8954
  const lines = content.split("\n").filter((line) => line.trim() !== "");
8932
8955
  const events = [];
8933
8956
  for (const line of lines) {
@@ -9212,11 +9235,11 @@ function resolveRuleSeverity(ruleId, defaultSeverity, overrides, strict) {
9212
9235
  }
9213
9236
  function detectStack(projectRoot) {
9214
9237
  const stacks = [];
9215
- const pkgJsonPath = path16.join(projectRoot, "package.json");
9216
- if (fs19.existsSync(pkgJsonPath)) {
9238
+ const pkgJsonPath = path19.join(projectRoot, "package.json");
9239
+ if (fs22.existsSync(pkgJsonPath)) {
9217
9240
  stacks.push("node");
9218
9241
  try {
9219
- const pkgJson = JSON.parse(fs19.readFileSync(pkgJsonPath, "utf-8"));
9242
+ const pkgJson = JSON.parse(fs22.readFileSync(pkgJsonPath, "utf-8"));
9220
9243
  const allDeps = {
9221
9244
  ...pkgJson.dependencies,
9222
9245
  ...pkgJson.devDependencies
@@ -9231,13 +9254,13 @@ function detectStack(projectRoot) {
9231
9254
  } catch {
9232
9255
  }
9233
9256
  }
9234
- const goModPath = path16.join(projectRoot, "go.mod");
9235
- if (fs19.existsSync(goModPath)) {
9257
+ const goModPath = path19.join(projectRoot, "go.mod");
9258
+ if (fs22.existsSync(goModPath)) {
9236
9259
  stacks.push("go");
9237
9260
  }
9238
- const requirementsPath = path16.join(projectRoot, "requirements.txt");
9239
- const pyprojectPath = path16.join(projectRoot, "pyproject.toml");
9240
- if (fs19.existsSync(requirementsPath) || fs19.existsSync(pyprojectPath)) {
9261
+ const requirementsPath = path19.join(projectRoot, "requirements.txt");
9262
+ const pyprojectPath = path19.join(projectRoot, "pyproject.toml");
9263
+ if (fs22.existsSync(requirementsPath) || fs22.existsSync(pyprojectPath)) {
9241
9264
  stacks.push("python");
9242
9265
  }
9243
9266
  return stacks;
@@ -10036,7 +10059,7 @@ var SecurityScanner = class {
10036
10059
  }
10037
10060
  async scanFile(filePath) {
10038
10061
  if (!this.config.enabled) return [];
10039
- const content = await fs20.readFile(filePath, "utf-8");
10062
+ const content = await fs23.readFile(filePath, "utf-8");
10040
10063
  return this.scanContentForFile(content, filePath, 1);
10041
10064
  }
10042
10065
  scanContentForFile(content, filePath, startLine = 1) {
@@ -10363,13 +10386,13 @@ var TAINT_DURATION_MS = 30 * 60 * 1e3;
10363
10386
  var DEFAULT_SESSION_ID = "default";
10364
10387
  function getTaintFilePath(projectRoot, sessionId) {
10365
10388
  const id = sessionId || DEFAULT_SESSION_ID;
10366
- return join242(projectRoot, ".harness", `session-taint-${id}.json`);
10389
+ return join272(projectRoot, ".harness", `session-taint-${id}.json`);
10367
10390
  }
10368
10391
  function readTaint(projectRoot, sessionId) {
10369
10392
  const filePath = getTaintFilePath(projectRoot, sessionId);
10370
10393
  let content;
10371
10394
  try {
10372
- content = readFileSync17(filePath, "utf8");
10395
+ content = readFileSync20(filePath, "utf8");
10373
10396
  } catch {
10374
10397
  return null;
10375
10398
  }
@@ -10414,7 +10437,7 @@ function writeTaint(projectRoot, sessionId, reason, findings, source) {
10414
10437
  const filePath = getTaintFilePath(projectRoot, id);
10415
10438
  const now = (/* @__PURE__ */ new Date()).toISOString();
10416
10439
  const dir = dirname9(filePath);
10417
- mkdirSync12(dir, { recursive: true });
10440
+ mkdirSync13(dir, { recursive: true });
10418
10441
  const existing = readTaint(projectRoot, id);
10419
10442
  const maxSeverity = findings.some((f) => f.severity === "high") ? "high" : "medium";
10420
10443
  const taintFindings = findings.map((f) => ({
@@ -10432,7 +10455,7 @@ function writeTaint(projectRoot, sessionId, reason, findings, source) {
10432
10455
  severity: existing?.severity === "high" || maxSeverity === "high" ? "high" : "medium",
10433
10456
  findings: [...existing?.findings || [], ...taintFindings]
10434
10457
  };
10435
- writeFileSync12(filePath, JSON.stringify(state, null, 2) + "\n");
10458
+ writeFileSync14(filePath, JSON.stringify(state, null, 2) + "\n");
10436
10459
  return state;
10437
10460
  }
10438
10461
  function clearTaint(projectRoot, sessionId) {
@@ -10445,14 +10468,14 @@ function clearTaint(projectRoot, sessionId) {
10445
10468
  return 0;
10446
10469
  }
10447
10470
  }
10448
- const harnessDir = join242(projectRoot, ".harness");
10471
+ const harnessDir = join272(projectRoot, ".harness");
10449
10472
  let count = 0;
10450
10473
  try {
10451
10474
  const files = readdirSync3(harnessDir);
10452
10475
  for (const file of files) {
10453
10476
  if (file.startsWith("session-taint-") && file.endsWith(".json")) {
10454
10477
  try {
10455
- unlinkSync(join242(harnessDir, file));
10478
+ unlinkSync(join272(harnessDir, file));
10456
10479
  count++;
10457
10480
  } catch {
10458
10481
  }
@@ -10463,7 +10486,7 @@ function clearTaint(projectRoot, sessionId) {
10463
10486
  return count;
10464
10487
  }
10465
10488
  function listTaintedSessions(projectRoot) {
10466
- const harnessDir = join242(projectRoot, ".harness");
10489
+ const harnessDir = join272(projectRoot, ".harness");
10467
10490
  const sessions = [];
10468
10491
  try {
10469
10492
  const files = readdirSync3(harnessDir);
@@ -10542,7 +10565,7 @@ var ALL_CHECKS = [
10542
10565
  ];
10543
10566
  async function runValidateCheck(projectRoot, config) {
10544
10567
  const issues = [];
10545
- const agentsPath = path17.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10568
+ const agentsPath = path20.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10546
10569
  const result = await validateAgentsMap(agentsPath);
10547
10570
  if (!result.ok) {
10548
10571
  issues.push({ severity: "error", message: result.error.message });
@@ -10599,7 +10622,7 @@ async function runDepsCheck(projectRoot, config) {
10599
10622
  }
10600
10623
  async function runDocsCheck(projectRoot, config) {
10601
10624
  const issues = [];
10602
- const docsDir = path17.join(projectRoot, config.docsDir ?? "docs");
10625
+ const docsDir = path20.join(projectRoot, config.docsDir ?? "docs");
10603
10626
  const entropyConfig = config.entropy || {};
10604
10627
  const result = await checkDocCoverage("project", {
10605
10628
  docsDir,
@@ -10784,7 +10807,7 @@ async function runTraceabilityCheck(projectRoot, config) {
10784
10807
  const issues = [];
10785
10808
  const traceConfig = config.traceability || {};
10786
10809
  if (traceConfig.enabled === false) return issues;
10787
- const graphDir = path17.join(projectRoot, ".harness", "graph");
10810
+ const graphDir = path20.join(projectRoot, ".harness", "graph");
10788
10811
  const store = new GraphStore();
10789
10812
  const loaded = await store.load(graphDir);
10790
10813
  if (!loaded) {
@@ -10922,7 +10945,7 @@ async function runMechanicalChecks(options) {
10922
10945
  };
10923
10946
  if (!skip.includes("validate")) {
10924
10947
  try {
10925
- const agentsPath = path18.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10948
+ const agentsPath = path21.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10926
10949
  const result = await validateAgentsMap(agentsPath);
10927
10950
  if (!result.ok) {
10928
10951
  statuses.validate = "fail";
@@ -10959,7 +10982,7 @@ async function runMechanicalChecks(options) {
10959
10982
  statuses.validate = "fail";
10960
10983
  findings.push({
10961
10984
  tool: "validate",
10962
- file: path18.join(projectRoot, "AGENTS.md"),
10985
+ file: path21.join(projectRoot, "AGENTS.md"),
10963
10986
  message: err instanceof Error ? err.message : String(err),
10964
10987
  severity: "error"
10965
10988
  });
@@ -11023,7 +11046,7 @@ async function runMechanicalChecks(options) {
11023
11046
  (async () => {
11024
11047
  const localFindings = [];
11025
11048
  try {
11026
- const docsDir = path18.join(projectRoot, config.docsDir ?? "docs");
11049
+ const docsDir = path21.join(projectRoot, config.docsDir ?? "docs");
11027
11050
  const result = await checkDocCoverage("project", { docsDir });
11028
11051
  if (!result.ok) {
11029
11052
  statuses["check-docs"] = "warn";
@@ -11050,7 +11073,7 @@ async function runMechanicalChecks(options) {
11050
11073
  statuses["check-docs"] = "warn";
11051
11074
  localFindings.push({
11052
11075
  tool: "check-docs",
11053
- file: path18.join(projectRoot, "docs"),
11076
+ file: path21.join(projectRoot, "docs"),
11054
11077
  message: err instanceof Error ? err.message : String(err),
11055
11078
  severity: "warning"
11056
11079
  });
@@ -11199,18 +11222,18 @@ function computeContextBudget(diffLines) {
11199
11222
  return diffLines;
11200
11223
  }
11201
11224
  function isWithinProject(absPath, projectRoot) {
11202
- const resolvedRoot = path19.resolve(projectRoot) + path19.sep;
11203
- const resolvedPath = path19.resolve(absPath);
11204
- return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path19.resolve(projectRoot);
11225
+ const resolvedRoot = path22.resolve(projectRoot) + path22.sep;
11226
+ const resolvedPath = path22.resolve(absPath);
11227
+ return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path22.resolve(projectRoot);
11205
11228
  }
11206
11229
  async function readContextFile(projectRoot, filePath, reason) {
11207
- const absPath = path19.isAbsolute(filePath) ? filePath : path19.join(projectRoot, filePath);
11230
+ const absPath = path22.isAbsolute(filePath) ? filePath : path22.join(projectRoot, filePath);
11208
11231
  if (!isWithinProject(absPath, projectRoot)) return null;
11209
11232
  const result = await readFileContent(absPath);
11210
11233
  if (!result.ok) return null;
11211
11234
  const content = result.value;
11212
11235
  const lines = content.split("\n").length;
11213
- const relPath = path19.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
11236
+ const relPath = path22.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
11214
11237
  return { path: relPath, content, reason, lines };
11215
11238
  }
11216
11239
  function extractImportSources2(content) {
@@ -11225,18 +11248,18 @@ function extractImportSources2(content) {
11225
11248
  }
11226
11249
  async function resolveImportPath2(projectRoot, fromFile, importSource) {
11227
11250
  if (!importSource.startsWith(".")) return null;
11228
- const fromDir = path19.dirname(path19.join(projectRoot, fromFile));
11229
- const basePath = path19.resolve(fromDir, importSource);
11251
+ const fromDir = path22.dirname(path22.join(projectRoot, fromFile));
11252
+ const basePath = path22.resolve(fromDir, importSource);
11230
11253
  if (!isWithinProject(basePath, projectRoot)) return null;
11231
11254
  const relBase = relativePosix(projectRoot, basePath);
11232
11255
  const candidates = [
11233
11256
  relBase + ".ts",
11234
11257
  relBase + ".tsx",
11235
11258
  relBase + ".mts",
11236
- path19.join(relBase, "index.ts")
11259
+ path22.join(relBase, "index.ts")
11237
11260
  ];
11238
11261
  for (const candidate of candidates) {
11239
- const absCandidate = path19.join(projectRoot, candidate);
11262
+ const absCandidate = path22.join(projectRoot, candidate);
11240
11263
  if (await fileExists(absCandidate)) {
11241
11264
  return candidate;
11242
11265
  }
@@ -11244,7 +11267,7 @@ async function resolveImportPath2(projectRoot, fromFile, importSource) {
11244
11267
  return null;
11245
11268
  }
11246
11269
  async function findTestFiles(projectRoot, sourceFile) {
11247
- const baseName = path19.basename(sourceFile, path19.extname(sourceFile));
11270
+ const baseName = path22.basename(sourceFile, path22.extname(sourceFile));
11248
11271
  const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
11249
11272
  const results = await findFiles(pattern, projectRoot);
11250
11273
  return results.map((f) => relativePosix(projectRoot, f));
@@ -12057,7 +12080,7 @@ function normalizePath(filePath, projectRoot) {
12057
12080
  let normalized = filePath;
12058
12081
  normalized = normalized.replace(/\\/g, "/");
12059
12082
  const normalizedRoot = projectRoot.replace(/\\/g, "/");
12060
- if (path20.isAbsolute(normalized)) {
12083
+ if (path23.isAbsolute(normalized)) {
12061
12084
  const root = normalizedRoot.endsWith("/") ? normalizedRoot : normalizedRoot + "/";
12062
12085
  if (normalized.startsWith(root)) {
12063
12086
  normalized = normalized.slice(root.length);
@@ -12082,12 +12105,12 @@ function followImportChain(fromFile, fileContents, maxDepth = 2) {
12082
12105
  while ((match = importRegex.exec(content)) !== null) {
12083
12106
  const importPath = match[1];
12084
12107
  if (!importPath.startsWith(".")) continue;
12085
- const dir = path20.dirname(current.file);
12086
- let resolved = path20.join(dir, importPath).replace(/\\/g, "/");
12108
+ const dir = path23.dirname(current.file);
12109
+ let resolved = path23.join(dir, importPath).replace(/\\/g, "/");
12087
12110
  if (!resolved.match(/\.(ts|tsx|js|jsx)$/)) {
12088
12111
  resolved += ".ts";
12089
12112
  }
12090
- resolved = path20.normalize(resolved).replace(/\\/g, "/");
12113
+ resolved = path23.normalize(resolved).replace(/\\/g, "/");
12091
12114
  if (!visited.has(resolved) && current.depth + 1 <= maxDepth) {
12092
12115
  queue.push({ file: resolved, depth: current.depth + 1 });
12093
12116
  }
@@ -12104,7 +12127,7 @@ async function validateFindings(options) {
12104
12127
  if (exclusionSet.isExcluded(normalizedFile, finding.lineRange) || exclusionSet.isExcluded(finding.file, finding.lineRange)) {
12105
12128
  continue;
12106
12129
  }
12107
- const absoluteFile = path20.isAbsolute(finding.file) ? finding.file : path20.join(projectRoot, finding.file).replace(/\\/g, "/");
12130
+ const absoluteFile = path23.isAbsolute(finding.file) ? finding.file : path23.join(projectRoot, finding.file).replace(/\\/g, "/");
12108
12131
  if (exclusionSet.isExcluded(absoluteFile, finding.lineRange)) {
12109
12132
  continue;
12110
12133
  }
@@ -12791,10 +12814,10 @@ function inferStatus(feature, projectPath, allFeatures) {
12791
12814
  const featuresWithPlans = allFeatures.filter((f) => f.plans.length > 0);
12792
12815
  const useRootState = featuresWithPlans.length <= 1;
12793
12816
  if (useRootState) {
12794
- const rootStatePath = path21.join(projectPath, ".harness", "state.json");
12795
- if (fs21.existsSync(rootStatePath)) {
12817
+ const rootStatePath = path24.join(projectPath, ".harness", "state.json");
12818
+ if (fs24.existsSync(rootStatePath)) {
12796
12819
  try {
12797
- const raw = fs21.readFileSync(rootStatePath, "utf-8");
12820
+ const raw = fs24.readFileSync(rootStatePath, "utf-8");
12798
12821
  const state = JSON.parse(raw);
12799
12822
  if (state.progress) {
12800
12823
  for (const status of Object.values(state.progress)) {
@@ -12805,16 +12828,16 @@ function inferStatus(feature, projectPath, allFeatures) {
12805
12828
  }
12806
12829
  }
12807
12830
  }
12808
- const sessionsDir = path21.join(projectPath, ".harness", "sessions");
12809
- if (fs21.existsSync(sessionsDir)) {
12831
+ const sessionsDir = path24.join(projectPath, ".harness", "sessions");
12832
+ if (fs24.existsSync(sessionsDir)) {
12810
12833
  try {
12811
- const sessionDirs = fs21.readdirSync(sessionsDir, { withFileTypes: true });
12834
+ const sessionDirs = fs24.readdirSync(sessionsDir, { withFileTypes: true });
12812
12835
  for (const entry of sessionDirs) {
12813
12836
  if (!entry.isDirectory()) continue;
12814
- const autopilotPath = path21.join(sessionsDir, entry.name, "autopilot-state.json");
12815
- if (!fs21.existsSync(autopilotPath)) continue;
12837
+ const autopilotPath = path24.join(sessionsDir, entry.name, "autopilot-state.json");
12838
+ if (!fs24.existsSync(autopilotPath)) continue;
12816
12839
  try {
12817
- const raw = fs21.readFileSync(autopilotPath, "utf-8");
12840
+ const raw = fs24.readFileSync(autopilotPath, "utf-8");
12818
12841
  const autopilot = JSON.parse(raw);
12819
12842
  if (!autopilot.phases) continue;
12820
12843
  const linkedPhases = autopilot.phases.filter(
@@ -13135,6 +13158,7 @@ var GitHubIssuesSyncAdapter = class {
13135
13158
  const data = await response.json();
13136
13159
  return Ok({
13137
13160
  externalId,
13161
+ title: data.title,
13138
13162
  status: data.state,
13139
13163
  labels: data.labels.map((l) => l.name),
13140
13164
  assignee: data.assignee ? `@${data.assignee.login}` : null
@@ -13169,6 +13193,7 @@ var GitHubIssuesSyncAdapter = class {
13169
13193
  for (const issue of issues) {
13170
13194
  tickets.push({
13171
13195
  externalId: buildExternalId(this.owner, this.repo, issue.number),
13196
+ title: issue.title,
13172
13197
  status: issue.state,
13173
13198
  labels: issue.labels.map((l) => l.name),
13174
13199
  assignee: issue.assignee ? `@${issue.assignee.login}` : null
@@ -13210,43 +13235,61 @@ var GitHubIssuesSyncAdapter = class {
13210
13235
  function emptySyncResult() {
13211
13236
  return { created: [], updated: [], assignmentChanges: [], errors: [] };
13212
13237
  }
13213
- async function syncToExternal(roadmap, adapter, _config) {
13214
- const result = emptySyncResult();
13215
- let defaultAssignee = null;
13216
- const userResult = await adapter.getAuthenticatedUser();
13217
- if (userResult.ok) {
13218
- defaultAssignee = userResult.value;
13238
+ function buildDedupIndex(tickets, config) {
13239
+ const index = /* @__PURE__ */ new Map();
13240
+ if (!tickets) return index;
13241
+ const configLabels = new Set((config.labels ?? []).map((l) => l.toLowerCase()));
13242
+ for (const ticket of tickets) {
13243
+ const hasConfigLabels = configLabels.size === 0 || ticket.labels.some((l) => configLabels.has(l.toLowerCase()));
13244
+ if (!hasConfigLabels) continue;
13245
+ const key = ticket.title.toLowerCase();
13246
+ const prev = index.get(key);
13247
+ if (!prev || prev.status === "closed" && ticket.status === "open") {
13248
+ index.set(key, ticket);
13249
+ }
13250
+ }
13251
+ return index;
13252
+ }
13253
+ async function resolveExternalId(feature, milestone, adapter, dedupIndex, result) {
13254
+ if (feature.externalId) return true;
13255
+ const existing = dedupIndex.get(feature.name.toLowerCase());
13256
+ if (existing) {
13257
+ feature.externalId = existing.externalId;
13258
+ return true;
13259
+ }
13260
+ const createResult = await adapter.createTicket(feature, milestone);
13261
+ if (createResult.ok) {
13262
+ feature.externalId = createResult.value.externalId;
13263
+ result.created.push(createResult.value);
13264
+ } else {
13265
+ result.errors.push({ featureOrId: feature.name, error: createResult.error });
13219
13266
  }
13267
+ return false;
13268
+ }
13269
+ async function syncToExternal(roadmap, adapter, config, prefetchedTickets) {
13270
+ const result = emptySyncResult();
13271
+ const dedupIndex = buildDedupIndex(prefetchedTickets, config);
13220
13272
  for (const milestone of roadmap.milestones) {
13221
13273
  for (const feature of milestone.features) {
13222
- if (!feature.assignee && defaultAssignee) {
13223
- feature.assignee = defaultAssignee;
13224
- }
13225
- if (!feature.externalId) {
13226
- const createResult = await adapter.createTicket(feature, milestone.name);
13227
- if (createResult.ok) {
13228
- feature.externalId = createResult.value.externalId;
13229
- result.created.push(createResult.value);
13230
- } else {
13231
- result.errors.push({ featureOrId: feature.name, error: createResult.error });
13232
- }
13274
+ const shouldUpdate = await resolveExternalId(
13275
+ feature,
13276
+ milestone.name,
13277
+ adapter,
13278
+ dedupIndex,
13279
+ result
13280
+ );
13281
+ if (!shouldUpdate) continue;
13282
+ const updateResult = await adapter.updateTicket(feature.externalId, feature, milestone.name);
13283
+ if (updateResult.ok) {
13284
+ result.updated.push(feature.externalId);
13233
13285
  } else {
13234
- const updateResult = await adapter.updateTicket(
13235
- feature.externalId,
13236
- feature,
13237
- milestone.name
13238
- );
13239
- if (updateResult.ok) {
13240
- result.updated.push(feature.externalId);
13241
- } else {
13242
- result.errors.push({ featureOrId: feature.externalId, error: updateResult.error });
13243
- }
13286
+ result.errors.push({ featureOrId: feature.externalId, error: updateResult.error });
13244
13287
  }
13245
13288
  }
13246
13289
  }
13247
13290
  return result;
13248
13291
  }
13249
- async function syncFromExternal(roadmap, adapter, config, options) {
13292
+ async function syncFromExternal(roadmap, adapter, config, options, prefetchedTickets) {
13250
13293
  const result = emptySyncResult();
13251
13294
  const forceSync = options?.forceSync ?? false;
13252
13295
  const featureByExternalId = /* @__PURE__ */ new Map();
@@ -13258,12 +13301,18 @@ async function syncFromExternal(roadmap, adapter, config, options) {
13258
13301
  }
13259
13302
  }
13260
13303
  if (featureByExternalId.size === 0) return result;
13261
- const fetchResult = await adapter.fetchAllTickets();
13262
- if (!fetchResult.ok) {
13263
- result.errors.push({ featureOrId: "*", error: fetchResult.error });
13264
- return result;
13304
+ let tickets;
13305
+ if (prefetchedTickets) {
13306
+ tickets = prefetchedTickets;
13307
+ } else {
13308
+ const fetchResult = await adapter.fetchAllTickets();
13309
+ if (!fetchResult.ok) {
13310
+ result.errors.push({ featureOrId: "*", error: fetchResult.error });
13311
+ return result;
13312
+ }
13313
+ tickets = fetchResult.value;
13265
13314
  }
13266
- for (const ticketState of fetchResult.value) {
13315
+ for (const ticketState of tickets) {
13267
13316
  const feature = featureByExternalId.get(ticketState.externalId);
13268
13317
  if (!feature) continue;
13269
13318
  if (ticketState.assignee !== feature.assignee) {
@@ -13280,6 +13329,9 @@ async function syncFromExternal(roadmap, adapter, config, options) {
13280
13329
  if (!forceSync && isRegression(feature.status, newStatus)) {
13281
13330
  continue;
13282
13331
  }
13332
+ if (!forceSync && feature.status === "blocked" && newStatus === "planned") {
13333
+ continue;
13334
+ }
13283
13335
  feature.status = newStatus;
13284
13336
  }
13285
13337
  }
@@ -13294,7 +13346,7 @@ async function fullSync(roadmapPath, adapter, config, options) {
13294
13346
  });
13295
13347
  await previousSync;
13296
13348
  try {
13297
- const raw = fs22.readFileSync(roadmapPath, "utf-8");
13349
+ const raw = fs25.readFileSync(roadmapPath, "utf-8");
13298
13350
  const parseResult = parseRoadmap(raw);
13299
13351
  if (!parseResult.ok) {
13300
13352
  return {
@@ -13303,9 +13355,11 @@ async function fullSync(roadmapPath, adapter, config, options) {
13303
13355
  };
13304
13356
  }
13305
13357
  const roadmap = parseResult.value;
13306
- const pushResult = await syncToExternal(roadmap, adapter, config);
13307
- const pullResult = await syncFromExternal(roadmap, adapter, config, options);
13308
- fs22.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
13358
+ const fetchResult = await adapter.fetchAllTickets();
13359
+ const tickets = fetchResult.ok ? fetchResult.value : void 0;
13360
+ const pushResult = await syncToExternal(roadmap, adapter, config, tickets);
13361
+ const pullResult = await syncFromExternal(roadmap, adapter, config, options, tickets);
13362
+ fs25.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
13309
13363
  return {
13310
13364
  created: pushResult.created,
13311
13365
  updated: pushResult.updated,
@@ -13463,10 +13517,10 @@ var ProjectScanner = class {
13463
13517
  }
13464
13518
  rootDir;
13465
13519
  async scan() {
13466
- let projectName = path22.basename(this.rootDir);
13520
+ let projectName = path25.basename(this.rootDir);
13467
13521
  try {
13468
- const pkgPath = path22.join(this.rootDir, "package.json");
13469
- const pkgRaw = await fs23.readFile(pkgPath, "utf-8");
13522
+ const pkgPath = path25.join(this.rootDir, "package.json");
13523
+ const pkgRaw = await fs26.readFile(pkgPath, "utf-8");
13470
13524
  const pkg = JSON.parse(pkgRaw);
13471
13525
  if (pkg.name) projectName = pkg.name;
13472
13526
  } catch {
@@ -13579,13 +13633,13 @@ var BlueprintGenerator = class {
13579
13633
  styles: STYLES,
13580
13634
  scripts: SCRIPTS
13581
13635
  });
13582
- await fs24.mkdir(options.outputDir, { recursive: true });
13583
- await fs24.writeFile(path23.join(options.outputDir, "index.html"), html);
13636
+ await fs27.mkdir(options.outputDir, { recursive: true });
13637
+ await fs27.writeFile(path26.join(options.outputDir, "index.html"), html);
13584
13638
  }
13585
13639
  };
13586
13640
  function getStatePath() {
13587
13641
  const home = process.env["HOME"] || os.homedir();
13588
- return path24.join(home, ".harness", "update-check.json");
13642
+ return path27.join(home, ".harness", "update-check.json");
13589
13643
  }
13590
13644
  function isUpdateCheckEnabled(configInterval) {
13591
13645
  if (process.env["HARNESS_NO_UPDATE_CHECK"] === "1") return false;
@@ -13598,7 +13652,7 @@ function shouldRunCheck(state, intervalMs) {
13598
13652
  }
13599
13653
  function readCheckState() {
13600
13654
  try {
13601
- const raw = fs25.readFileSync(getStatePath(), "utf-8");
13655
+ const raw = fs28.readFileSync(getStatePath(), "utf-8");
13602
13656
  const parsed = JSON.parse(raw);
13603
13657
  if (typeof parsed === "object" && parsed !== null && "lastCheckTime" in parsed && typeof parsed.lastCheckTime === "number" && "currentVersion" in parsed && typeof parsed.currentVersion === "string") {
13604
13658
  const state = parsed;
@@ -13615,7 +13669,7 @@ function readCheckState() {
13615
13669
  }
13616
13670
  function spawnBackgroundCheck(currentVersion) {
13617
13671
  const statePath = getStatePath();
13618
- const stateDir = path24.dirname(statePath);
13672
+ const stateDir = path27.dirname(statePath);
13619
13673
  const script = `
13620
13674
  const { execSync } = require('child_process');
13621
13675
  const fs = require('fs');
@@ -13699,9 +13753,9 @@ async function resolveWasmPath(grammarName) {
13699
13753
  const { createRequire } = await import("module");
13700
13754
  const require2 = createRequire(import.meta.url ?? __filename);
13701
13755
  const pkgPath = require2.resolve("tree-sitter-wasms/package.json");
13702
- const path28 = await import("path");
13703
- const pkgDir = path28.dirname(pkgPath);
13704
- return path28.join(pkgDir, "out", `${grammarName}.wasm`);
13756
+ const path31 = await import("path");
13757
+ const pkgDir = path31.dirname(pkgPath);
13758
+ return path31.join(pkgDir, "out", `${grammarName}.wasm`);
13705
13759
  }
13706
13760
  async function loadLanguage(lang) {
13707
13761
  const grammarName = GRAMMAR_MAP[lang];
@@ -14143,14 +14197,14 @@ var LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/mai
14143
14197
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
14144
14198
  var STALENESS_WARNING_DAYS = 7;
14145
14199
  function getCachePath(projectRoot) {
14146
- return path25.join(projectRoot, ".harness", "cache", "pricing.json");
14200
+ return path28.join(projectRoot, ".harness", "cache", "pricing.json");
14147
14201
  }
14148
14202
  function getStalenessMarkerPath(projectRoot) {
14149
- return path25.join(projectRoot, ".harness", "cache", "staleness-marker.json");
14203
+ return path28.join(projectRoot, ".harness", "cache", "staleness-marker.json");
14150
14204
  }
14151
14205
  async function readDiskCache(projectRoot) {
14152
14206
  try {
14153
- const raw = await fs26.readFile(getCachePath(projectRoot), "utf-8");
14207
+ const raw = await fs29.readFile(getCachePath(projectRoot), "utf-8");
14154
14208
  return JSON.parse(raw);
14155
14209
  } catch {
14156
14210
  return null;
@@ -14158,8 +14212,8 @@ async function readDiskCache(projectRoot) {
14158
14212
  }
14159
14213
  async function writeDiskCache(projectRoot, data) {
14160
14214
  const cachePath = getCachePath(projectRoot);
14161
- await fs26.mkdir(path25.dirname(cachePath), { recursive: true });
14162
- await fs26.writeFile(cachePath, JSON.stringify(data, null, 2));
14215
+ await fs29.mkdir(path28.dirname(cachePath), { recursive: true });
14216
+ await fs29.writeFile(cachePath, JSON.stringify(data, null, 2));
14163
14217
  }
14164
14218
  async function fetchFromNetwork() {
14165
14219
  try {
@@ -14186,7 +14240,7 @@ function loadFallbackDataset() {
14186
14240
  async function checkAndWarnStaleness(projectRoot) {
14187
14241
  const markerPath = getStalenessMarkerPath(projectRoot);
14188
14242
  try {
14189
- const raw = await fs26.readFile(markerPath, "utf-8");
14243
+ const raw = await fs29.readFile(markerPath, "utf-8");
14190
14244
  const marker = JSON.parse(raw);
14191
14245
  const firstUse = new Date(marker.firstFallbackUse).getTime();
14192
14246
  const now = Date.now();
@@ -14198,8 +14252,8 @@ async function checkAndWarnStaleness(projectRoot) {
14198
14252
  }
14199
14253
  } catch {
14200
14254
  try {
14201
- await fs26.mkdir(path25.dirname(markerPath), { recursive: true });
14202
- await fs26.writeFile(
14255
+ await fs29.mkdir(path28.dirname(markerPath), { recursive: true });
14256
+ await fs29.writeFile(
14203
14257
  markerPath,
14204
14258
  JSON.stringify({ firstFallbackUse: (/* @__PURE__ */ new Date()).toISOString() })
14205
14259
  );
@@ -14209,7 +14263,7 @@ async function checkAndWarnStaleness(projectRoot) {
14209
14263
  }
14210
14264
  async function clearStalenessMarker(projectRoot) {
14211
14265
  try {
14212
- await fs26.unlink(getStalenessMarkerPath(projectRoot));
14266
+ await fs29.unlink(getStalenessMarkerPath(projectRoot));
14213
14267
  } catch {
14214
14268
  }
14215
14269
  }
@@ -14251,8 +14305,7 @@ function calculateCost(record, dataset) {
14251
14305
  }
14252
14306
  return Math.round(costUSD * MICRODOLLARS_PER_DOLLAR);
14253
14307
  }
14254
- function aggregateBySession(records) {
14255
- if (records.length === 0) return [];
14308
+ function bucketRecordsBySession(records) {
14256
14309
  const sessionMap = /* @__PURE__ */ new Map();
14257
14310
  for (const record of records) {
14258
14311
  const tagged = record;
@@ -14268,58 +14321,104 @@ function aggregateBySession(records) {
14268
14321
  }
14269
14322
  bucket.allRecords.push(tagged);
14270
14323
  }
14324
+ return sessionMap;
14325
+ }
14326
+ function accumulateCost(running, recordCost) {
14327
+ if (recordCost != null && running != null) {
14328
+ return running + recordCost;
14329
+ }
14330
+ if (recordCost == null) {
14331
+ return null;
14332
+ }
14333
+ return running;
14334
+ }
14335
+ function sumRecordTokens(tokenSource) {
14336
+ const tokens = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
14337
+ let cacheCreation;
14338
+ let cacheRead;
14339
+ let costMicroUSD = 0;
14340
+ let model;
14341
+ for (const r of tokenSource) {
14342
+ tokens.inputTokens += r.tokens.inputTokens;
14343
+ tokens.outputTokens += r.tokens.outputTokens;
14344
+ tokens.totalTokens += r.tokens.totalTokens;
14345
+ if (r.cacheCreationTokens != null) {
14346
+ cacheCreation = (cacheCreation ?? 0) + r.cacheCreationTokens;
14347
+ }
14348
+ if (r.cacheReadTokens != null) {
14349
+ cacheRead = (cacheRead ?? 0) + r.cacheReadTokens;
14350
+ }
14351
+ costMicroUSD = accumulateCost(costMicroUSD, r.costMicroUSD);
14352
+ if (!model && r.model) {
14353
+ model = r.model;
14354
+ }
14355
+ }
14356
+ return { tokens, cacheCreation, cacheRead, costMicroUSD, model };
14357
+ }
14358
+ function findModel(records) {
14359
+ for (const r of records) {
14360
+ if (r.model) return r.model;
14361
+ }
14362
+ return void 0;
14363
+ }
14364
+ function determineSource(hasHarness, hasCC) {
14365
+ if (hasHarness && hasCC) return "merged";
14366
+ if (hasCC) return "claude-code";
14367
+ return "harness";
14368
+ }
14369
+ function applyOptionalFields(session, totals, model) {
14370
+ if (model) session.model = model;
14371
+ if (totals.cacheCreation != null) session.cacheCreationTokens = totals.cacheCreation;
14372
+ if (totals.cacheRead != null) session.cacheReadTokens = totals.cacheRead;
14373
+ }
14374
+ function buildSessionUsage(sessionId, bucket) {
14375
+ const hasHarness = bucket.harnessRecords.length > 0;
14376
+ const hasCC = bucket.ccRecords.length > 0;
14377
+ const tokenSource = hasHarness ? bucket.harnessRecords : bucket.ccRecords;
14378
+ const totals = sumRecordTokens(tokenSource);
14379
+ const model = totals.model ?? (hasCC ? findModel(bucket.ccRecords) : void 0);
14380
+ const timestamps = bucket.allRecords.map((r) => r.timestamp).sort();
14381
+ const session = {
14382
+ sessionId,
14383
+ firstTimestamp: timestamps[0] ?? "",
14384
+ lastTimestamp: timestamps[timestamps.length - 1] ?? "",
14385
+ tokens: totals.tokens,
14386
+ costMicroUSD: totals.costMicroUSD,
14387
+ source: determineSource(hasHarness, hasCC)
14388
+ };
14389
+ applyOptionalFields(session, totals, model);
14390
+ return session;
14391
+ }
14392
+ function accumulateIntoDayBucket(day, record) {
14393
+ day.sessions.add(record.sessionId);
14394
+ day.tokens.inputTokens += record.tokens.inputTokens;
14395
+ day.tokens.outputTokens += record.tokens.outputTokens;
14396
+ day.tokens.totalTokens += record.tokens.totalTokens;
14397
+ if (record.cacheCreationTokens != null) {
14398
+ day.cacheCreation = (day.cacheCreation ?? 0) + record.cacheCreationTokens;
14399
+ }
14400
+ if (record.cacheReadTokens != null) {
14401
+ day.cacheRead = (day.cacheRead ?? 0) + record.cacheReadTokens;
14402
+ }
14403
+ day.costMicroUSD = accumulateCost(day.costMicroUSD, record.costMicroUSD);
14404
+ if (record.model) {
14405
+ day.models.add(record.model);
14406
+ }
14407
+ }
14408
+ function createDayBucket() {
14409
+ return {
14410
+ sessions: /* @__PURE__ */ new Set(),
14411
+ tokens: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
14412
+ costMicroUSD: 0,
14413
+ models: /* @__PURE__ */ new Set()
14414
+ };
14415
+ }
14416
+ function aggregateBySession(records) {
14417
+ if (records.length === 0) return [];
14418
+ const sessionMap = bucketRecordsBySession(records);
14271
14419
  const results = [];
14272
14420
  for (const [sessionId, bucket] of sessionMap) {
14273
- const hasHarness = bucket.harnessRecords.length > 0;
14274
- const hasCC = bucket.ccRecords.length > 0;
14275
- const isMerged = hasHarness && hasCC;
14276
- const tokenSource = hasHarness ? bucket.harnessRecords : bucket.ccRecords;
14277
- const tokens = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
14278
- let cacheCreation;
14279
- let cacheRead;
14280
- let costMicroUSD = 0;
14281
- let model;
14282
- for (const r of tokenSource) {
14283
- tokens.inputTokens += r.tokens.inputTokens;
14284
- tokens.outputTokens += r.tokens.outputTokens;
14285
- tokens.totalTokens += r.tokens.totalTokens;
14286
- if (r.cacheCreationTokens != null) {
14287
- cacheCreation = (cacheCreation ?? 0) + r.cacheCreationTokens;
14288
- }
14289
- if (r.cacheReadTokens != null) {
14290
- cacheRead = (cacheRead ?? 0) + r.cacheReadTokens;
14291
- }
14292
- if (r.costMicroUSD != null && costMicroUSD != null) {
14293
- costMicroUSD += r.costMicroUSD;
14294
- } else if (r.costMicroUSD == null) {
14295
- costMicroUSD = null;
14296
- }
14297
- if (!model && r.model) {
14298
- model = r.model;
14299
- }
14300
- }
14301
- if (!model && hasCC) {
14302
- for (const r of bucket.ccRecords) {
14303
- if (r.model) {
14304
- model = r.model;
14305
- break;
14306
- }
14307
- }
14308
- }
14309
- const timestamps = bucket.allRecords.map((r) => r.timestamp).sort();
14310
- const source = isMerged ? "merged" : hasCC ? "claude-code" : "harness";
14311
- const session = {
14312
- sessionId,
14313
- firstTimestamp: timestamps[0] ?? "",
14314
- lastTimestamp: timestamps[timestamps.length - 1] ?? "",
14315
- tokens,
14316
- costMicroUSD,
14317
- source
14318
- };
14319
- if (model) session.model = model;
14320
- if (cacheCreation != null) session.cacheCreationTokens = cacheCreation;
14321
- if (cacheRead != null) session.cacheReadTokens = cacheRead;
14322
- results.push(session);
14421
+ results.push(buildSessionUsage(sessionId, bucket));
14323
14422
  }
14324
14423
  results.sort((a, b) => b.firstTimestamp.localeCompare(a.firstTimestamp));
14325
14424
  return results;
@@ -14330,32 +14429,9 @@ function aggregateByDay(records) {
14330
14429
  for (const record of records) {
14331
14430
  const date = record.timestamp.slice(0, 10);
14332
14431
  if (!dayMap.has(date)) {
14333
- dayMap.set(date, {
14334
- sessions: /* @__PURE__ */ new Set(),
14335
- tokens: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
14336
- costMicroUSD: 0,
14337
- models: /* @__PURE__ */ new Set()
14338
- });
14339
- }
14340
- const day = dayMap.get(date);
14341
- day.sessions.add(record.sessionId);
14342
- day.tokens.inputTokens += record.tokens.inputTokens;
14343
- day.tokens.outputTokens += record.tokens.outputTokens;
14344
- day.tokens.totalTokens += record.tokens.totalTokens;
14345
- if (record.cacheCreationTokens != null) {
14346
- day.cacheCreation = (day.cacheCreation ?? 0) + record.cacheCreationTokens;
14347
- }
14348
- if (record.cacheReadTokens != null) {
14349
- day.cacheRead = (day.cacheRead ?? 0) + record.cacheReadTokens;
14350
- }
14351
- if (record.costMicroUSD != null && day.costMicroUSD != null) {
14352
- day.costMicroUSD += record.costMicroUSD;
14353
- } else if (record.costMicroUSD == null) {
14354
- day.costMicroUSD = null;
14355
- }
14356
- if (record.model) {
14357
- day.models.add(record.model);
14432
+ dayMap.set(date, createDayBucket());
14358
14433
  }
14434
+ accumulateIntoDayBucket(dayMap.get(date), record);
14359
14435
  }
14360
14436
  const results = [];
14361
14437
  for (const [date, day] of dayMap) {
@@ -14411,10 +14487,10 @@ function parseLine(line, lineNumber) {
14411
14487
  return record;
14412
14488
  }
14413
14489
  function readCostRecords(projectRoot) {
14414
- const costsFile = path26.join(projectRoot, ".harness", "metrics", "costs.jsonl");
14490
+ const costsFile = path29.join(projectRoot, ".harness", "metrics", "costs.jsonl");
14415
14491
  let raw;
14416
14492
  try {
14417
- raw = fs27.readFileSync(costsFile, "utf-8");
14493
+ raw = fs30.readFileSync(costsFile, "utf-8");
14418
14494
  } catch {
14419
14495
  return [];
14420
14496
  }
@@ -14461,7 +14537,7 @@ function parseCCLine(line, filePath, lineNumber) {
14461
14537
  entry = JSON.parse(line);
14462
14538
  } catch {
14463
14539
  console.warn(
14464
- `[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path27.basename(filePath)}`
14540
+ `[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path30.basename(filePath)}`
14465
14541
  );
14466
14542
  return null;
14467
14543
  }
@@ -14475,7 +14551,7 @@ function parseCCLine(line, filePath, lineNumber) {
14475
14551
  function readCCFile(filePath) {
14476
14552
  let raw;
14477
14553
  try {
14478
- raw = fs28.readFileSync(filePath, "utf-8");
14554
+ raw = fs31.readFileSync(filePath, "utf-8");
14479
14555
  } catch {
14480
14556
  return [];
14481
14557
  }
@@ -14497,10 +14573,10 @@ function readCCFile(filePath) {
14497
14573
  }
14498
14574
  function parseCCRecords() {
14499
14575
  const homeDir = process.env.HOME ?? os2.homedir();
14500
- const projectsDir = path27.join(homeDir, ".claude", "projects");
14576
+ const projectsDir = path30.join(homeDir, ".claude", "projects");
14501
14577
  let projectDirs;
14502
14578
  try {
14503
- projectDirs = fs28.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path27.join(projectsDir, d.name));
14579
+ projectDirs = fs31.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path30.join(projectsDir, d.name));
14504
14580
  } catch {
14505
14581
  return [];
14506
14582
  }
@@ -14508,7 +14584,7 @@ function parseCCRecords() {
14508
14584
  for (const dir of projectDirs) {
14509
14585
  let files;
14510
14586
  try {
14511
- files = fs28.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path27.join(dir, f));
14587
+ files = fs31.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path30.join(dir, f));
14512
14588
  } catch {
14513
14589
  continue;
14514
14590
  }
@@ -14688,14 +14764,16 @@ export {
14688
14764
  loadState,
14689
14765
  saveState,
14690
14766
  parseFrontmatter2,
14767
+ parseDateFromEntry,
14691
14768
  extractIndexEntry,
14769
+ normalizeLearningContent,
14770
+ computeContentHash,
14771
+ analyzeLearningPatterns,
14692
14772
  clearLearningsCache,
14773
+ loadRelevantLearnings,
14693
14774
  appendLearning,
14694
- parseDateFromEntry,
14695
- analyzeLearningPatterns,
14696
14775
  loadBudgetedLearnings,
14697
14776
  loadIndexEntries,
14698
- loadRelevantLearnings,
14699
14777
  archiveLearnings,
14700
14778
  pruneLearnings,
14701
14779
  promoteSessionLearnings,