crewly 1.8.9 → 1.8.12

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 (245) hide show
  1. package/config/constants.d.ts.map +1 -0
  2. package/config/index.d.ts.map +1 -0
  3. package/config/roles/_common/memory-instructions.md +6 -5
  4. package/config/roles/_common/wiki-instructions.md +49 -0
  5. package/config/roles/architect/prompt.md +2 -2
  6. package/config/roles/backend-developer/prompt.md +2 -2
  7. package/config/roles/designer/prompt.md +2 -2
  8. package/config/roles/developer/prompt.md +2 -2
  9. package/config/roles/frontend-developer/prompt.md +2 -2
  10. package/config/roles/fullstack-dev/prompt.md +2 -2
  11. package/config/roles/generalist/prompt.md +2 -2
  12. package/config/roles/ops/prompt.md +2 -2
  13. package/config/roles/orchestrator/prompt.md +135 -11
  14. package/config/roles/product-manager/prompt.md +2 -2
  15. package/config/roles/qa/prompt.md +2 -2
  16. package/config/roles/qa-engineer/prompt.md +2 -2
  17. package/config/roles/researcher/prompt.md +15 -6
  18. package/config/roles/sales/prompt.md +2 -2
  19. package/config/roles/support/prompt.md +2 -2
  20. package/config/roles/team-leader/prompt.md +17 -2
  21. package/config/roles/tpm/prompt.md +2 -2
  22. package/config/roles/ux-designer/prompt.md +2 -2
  23. package/config/skills/orchestrator/wiki-cleanup/SKILL.md +89 -0
  24. package/config/skills/orchestrator/wiki-cleanup/execute.sh +139 -0
  25. package/config/skills/orchestrator/wiki-lint/SKILL.md +75 -0
  26. package/config/skills/orchestrator/wiki-lint/execute.sh +66 -0
  27. package/config/skills/orchestrator/wiki-migrate/SKILL.md +103 -0
  28. package/config/skills/orchestrator/wiki-migrate/execute.sh +82 -0
  29. package/config/skills/orchestrator/wiki-process-queue/SKILL.md +9 -1
  30. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +169 -0
  31. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -0
  32. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +1779 -0
  33. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -0
  34. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +18 -0
  35. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
  36. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +63 -0
  37. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  38. package/dist/backend/backend/src/controllers/task-pool/task-pool.routes.d.ts.map +1 -1
  39. package/dist/backend/backend/src/controllers/task-pool/task-pool.routes.js +5 -1
  40. package/dist/backend/backend/src/controllers/task-pool/task-pool.routes.js.map +1 -1
  41. package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +109 -0
  42. package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -1
  43. package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +419 -4
  44. package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -1
  45. package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -1
  46. package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +11 -1
  47. package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -1
  48. package/dist/backend/backend/src/index.d.ts.map +1 -1
  49. package/dist/backend/backend/src/index.js +78 -3
  50. package/dist/backend/backend/src/index.js.map +1 -1
  51. package/dist/backend/backend/src/index.js.orc-bak-20260529 +3130 -0
  52. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +513 -0
  53. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -0
  54. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +1568 -0
  55. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -0
  56. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts +86 -0
  57. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js +147 -0
  59. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js.map +1 -0
  60. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.d.ts +68 -0
  61. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.d.ts.map +1 -0
  62. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.js +131 -0
  63. package/dist/backend/backend/src/services/agent/crewly-agent/api-client.js.map +1 -0
  64. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.d.ts +130 -0
  65. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.js +263 -0
  67. package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.js.map +1 -0
  68. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts +74 -0
  69. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts.map +1 -0
  70. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js +140 -0
  71. package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js.map +1 -0
  72. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts +29 -0
  73. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts.map +1 -0
  74. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js +279 -0
  75. package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js.map +1 -0
  76. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +340 -0
  77. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +1 -0
  78. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +1176 -0
  79. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +1 -0
  80. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts +79 -0
  81. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts.map +1 -0
  82. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js +145 -0
  83. package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js.map +1 -0
  84. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.d.ts +79 -0
  85. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.d.ts.map +1 -0
  86. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.js +218 -0
  87. package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.js.map +1 -0
  88. package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts +16 -0
  89. package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts.map +1 -0
  90. package/dist/backend/backend/src/services/agent/crewly-agent/index.js +16 -0
  91. package/dist/backend/backend/src/services/agent/crewly-agent/index.js.map +1 -0
  92. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts +135 -0
  93. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts.map +1 -0
  94. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js +185 -0
  95. package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js.map +1 -0
  96. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +141 -0
  97. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -0
  98. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +310 -0
  99. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -0
  100. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.d.ts +91 -0
  101. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.d.ts.map +1 -0
  102. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.js +143 -0
  103. package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.js.map +1 -0
  104. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.d.ts +103 -0
  105. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.d.ts.map +1 -0
  106. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.js +256 -0
  107. package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.js.map +1 -0
  108. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +143 -0
  109. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +1 -0
  110. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +264 -0
  111. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +1 -0
  112. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.d.ts +13 -0
  113. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.d.ts.map +1 -0
  114. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js +91 -0
  115. package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js.map +1 -0
  116. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts +135 -0
  117. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts.map +1 -0
  118. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js +1937 -0
  119. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js.map +1 -0
  120. package/dist/backend/backend/src/services/ai/prompt-builder.service.js +1 -1
  121. package/dist/backend/backend/src/services/autonomous/auto-assign.service.d.ts +429 -0
  122. package/dist/backend/backend/src/services/autonomous/auto-assign.service.d.ts.map +1 -0
  123. package/dist/backend/backend/src/services/autonomous/auto-assign.service.js +852 -0
  124. package/dist/backend/backend/src/services/autonomous/auto-assign.service.js.map +1 -0
  125. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +171 -0
  126. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -0
  127. package/dist/backend/backend/src/services/project/task-tracking.service.js +725 -0
  128. package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -0
  129. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
  130. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +50 -0
  131. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
  132. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +19 -0
  133. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  134. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +45 -0
  135. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  136. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts.map +1 -1
  137. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js +34 -1
  138. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
  139. package/dist/backend/backend/src/services/v3/project-task-watcher.service.d.ts +118 -0
  140. package/dist/backend/backend/src/services/v3/project-task-watcher.service.d.ts.map +1 -0
  141. package/dist/backend/backend/src/services/v3/project-task-watcher.service.js +326 -0
  142. package/dist/backend/backend/src/services/v3/project-task-watcher.service.js.map +1 -0
  143. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.d.ts +72 -0
  144. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.d.ts.map +1 -0
  145. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.js +186 -0
  146. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.js.map +1 -0
  147. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts +27 -4
  148. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts.map +1 -1
  149. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js +133 -10
  150. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js.map +1 -1
  151. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts +18 -1
  152. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -1
  153. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +15 -4
  154. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -1
  155. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +74 -0
  156. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +1 -0
  157. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +154 -0
  158. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +1 -0
  159. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.d.ts +160 -0
  160. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.d.ts.map +1 -0
  161. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js +399 -0
  162. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js.map +1 -0
  163. package/dist/backend/backend/src/services/wiki/wiki-lint.service.d.ts +182 -0
  164. package/dist/backend/backend/src/services/wiki/wiki-lint.service.d.ts.map +1 -0
  165. package/dist/backend/backend/src/services/wiki/wiki-lint.service.js +505 -0
  166. package/dist/backend/backend/src/services/wiki/wiki-lint.service.js.map +1 -0
  167. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts +232 -0
  168. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -0
  169. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +1416 -0
  170. package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -0
  171. package/dist/backend/backend/src/services/wiki/wiki-recent.service.d.ts +51 -0
  172. package/dist/backend/backend/src/services/wiki/wiki-recent.service.d.ts.map +1 -0
  173. package/dist/backend/backend/src/services/wiki/wiki-recent.service.js +102 -0
  174. package/dist/backend/backend/src/services/wiki/wiki-recent.service.js.map +1 -0
  175. package/dist/backend/backend/src/services/wiki/wiki-reflect-trigger.service.d.ts +104 -0
  176. package/dist/backend/backend/src/services/wiki/wiki-reflect-trigger.service.d.ts.map +1 -0
  177. package/dist/backend/backend/src/services/wiki/wiki-reflect-trigger.service.js +229 -0
  178. package/dist/backend/backend/src/services/wiki/wiki-reflect-trigger.service.js.map +1 -0
  179. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +90 -0
  180. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -0
  181. package/dist/backend/backend/src/services/wiki/wiki-search.service.js +190 -0
  182. package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -0
  183. package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts +164 -0
  184. package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts.map +1 -0
  185. package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js +675 -0
  186. package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js.map +1 -0
  187. package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
  188. package/dist/backend/backend/src/services/workflow/cron-task.service.js +65 -0
  189. package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
  190. package/dist/backend/backend/src/types/auto-assign.types.d.ts +271 -0
  191. package/dist/backend/backend/src/types/auto-assign.types.d.ts.map +1 -0
  192. package/dist/backend/backend/src/types/auto-assign.types.js +136 -0
  193. package/dist/backend/backend/src/types/auto-assign.types.js.map +1 -0
  194. package/dist/backend/backend/src/types/cron-task.types.d.ts +16 -1
  195. package/dist/backend/backend/src/types/cron-task.types.d.ts.map +1 -1
  196. package/dist/backend/backend/src/utils/esm-require.utils.d.ts +111 -0
  197. package/dist/backend/backend/src/utils/esm-require.utils.d.ts.map +1 -0
  198. package/dist/backend/backend/src/utils/esm-require.utils.js +124 -0
  199. package/dist/backend/backend/src/utils/esm-require.utils.js.map +1 -0
  200. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +220 -0
  201. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -0
  202. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js +37 -0
  203. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -0
  204. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.d.ts +56 -0
  205. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.d.ts.map +1 -0
  206. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.js +91 -0
  207. package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.js.map +1 -0
  208. package/dist/cli/backend/src/services/knowledge/learnings-index.service.d.ts +159 -0
  209. package/dist/cli/backend/src/services/knowledge/learnings-index.service.d.ts.map +1 -0
  210. package/dist/cli/backend/src/services/knowledge/learnings-index.service.js +304 -0
  211. package/dist/cli/backend/src/services/knowledge/learnings-index.service.js.map +1 -0
  212. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.d.ts +115 -0
  213. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.d.ts.map +1 -0
  214. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.js +215 -0
  215. package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.js.map +1 -0
  216. package/dist/cli/backend/src/services/memory/embedding-provider.d.ts +78 -0
  217. package/dist/cli/backend/src/services/memory/embedding-provider.d.ts.map +1 -0
  218. package/dist/cli/backend/src/services/memory/embedding-provider.js +179 -0
  219. package/dist/cli/backend/src/services/memory/embedding-provider.js.map +1 -0
  220. package/dist/cli/backend/src/services/memory/vector-store.service.d.ts +331 -0
  221. package/dist/cli/backend/src/services/memory/vector-store.service.d.ts.map +1 -0
  222. package/dist/cli/backend/src/services/memory/vector-store.service.js +814 -0
  223. package/dist/cli/backend/src/services/memory/vector-store.service.js.map +1 -0
  224. package/dist/cli/backend/src/services/project/task-tracking.service.d.ts +171 -0
  225. package/dist/cli/backend/src/services/project/task-tracking.service.d.ts.map +1 -0
  226. package/dist/cli/backend/src/services/project/task-tracking.service.js +725 -0
  227. package/dist/cli/backend/src/services/project/task-tracking.service.js.map +1 -0
  228. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +19 -0
  229. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  230. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +45 -0
  231. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  232. package/dist/cli/backend/src/types/auto-assign.types.d.ts +271 -0
  233. package/dist/cli/backend/src/types/auto-assign.types.d.ts.map +1 -0
  234. package/dist/cli/backend/src/types/auto-assign.types.js +136 -0
  235. package/dist/cli/backend/src/types/auto-assign.types.js.map +1 -0
  236. package/dist/cli/cli/src/index.js +0 -0
  237. package/frontend/dist/assets/{index-db3f5041.css → index-068bb4f6.css} +10 -1
  238. package/frontend/dist/assets/index-c24ceb15.js +4960 -0
  239. package/frontend/dist/index.html +2 -2
  240. package/package.json +1 -1
  241. package/config/skills/agent/core/query-knowledge/SKILL.md +0 -87
  242. package/config/skills/agent/core/query-knowledge/execute.sh +0 -30
  243. package/config/skills/orchestrator/query-knowledge/SKILL.md +0 -75
  244. package/config/skills/orchestrator/query-knowledge/execute.sh +0 -30
  245. package/frontend/dist/assets/index-cc115bb4.js +0 -4926
@@ -0,0 +1,399 @@
1
+ /**
2
+ * WikiCleanupService — detect + remove low-quality pages from a wiki vault.
3
+ *
4
+ * Origin: the 2026-05-27 migration dumped every agent's `memory.json`
5
+ * roleKnowledge entries as their own wiki page (~3,277 pages across 6
6
+ * project vaults). Many are stream-of-consciousness daily memory rather
7
+ * than team-level patterns. Symptom: each project vault has 500+ pages
8
+ * under `patterns/`, most low-quality (confidence < 0.5, verbatim memory
9
+ * dump shape). Karpathy's wiki spec says "frequently-read distilled
10
+ * knowledge" — 500 stream-of-consciousness pages violates that.
11
+ *
12
+ * Detection is **rule-based + mechanical** (OSS does this). The actual
13
+ * keep/delete decision can be deferred to an agent via the bridge —
14
+ * this service exposes both `scan(rules)` (mechanical candidate list)
15
+ * and `apply(pages)` (executes the explicit page list provided).
16
+ *
17
+ * Design rules (mirror WikiMigrateService):
18
+ * - Default DRY-RUN. Caller must pass `{ apply: true }` to delete.
19
+ * - Idempotent + reversible. Every deleted page body + frontmatter is
20
+ * archived to `<vault>/.wiki-cleanup-archive.json` BEFORE the file
21
+ * is removed. Re-running with the same input is a no-op.
22
+ * - Migrate manifest is updated so the SAME source entry is not
23
+ * re-imported by the next `wiki-migrate --apply` (would defeat the
24
+ * cleanup).
25
+ * - LEGACY FILES (`memory.json`, `.crewly/knowledge/*`) are NEVER
26
+ * touched. The cleanup ONLY removes pages from the wiki vault.
27
+ * - Frozen folders (`memory/`, `sop/`, `sop-overrides/`, `okr/`,
28
+ * `decisions/manual/`) are never scanned.
29
+ *
30
+ * @module services/wiki/wiki-cleanup.service
31
+ */
32
+ import * as fs from 'fs/promises';
33
+ import * as path from 'path';
34
+ import { existsSync } from 'fs';
35
+ import { LoggerService } from '../core/logger.service.js';
36
+ import { atomicWriteJson, safeReadJson, ensureDir } from '../../utils/file-io.utils.js';
37
+ // ---------------------------------------------------------------------------
38
+ // Constants
39
+ // ---------------------------------------------------------------------------
40
+ export const WIKI_CLEANUP_ARCHIVE_FILENAME = '.wiki-cleanup-archive.json';
41
+ export const WIKI_CLEANUP_ARCHIVE_VERSION = 1;
42
+ /** Folders we never scan — managed by OSS code path, not LLM-editable. */
43
+ const FROZEN_FOLDERS = new Set([
44
+ 'memory',
45
+ 'sop',
46
+ 'sop-overrides',
47
+ 'okr',
48
+ ]);
49
+ /** Folder under the vault where llm-curated pages live. */
50
+ const LLM_CURATED_DIR = 'llm-curated';
51
+ /** Hard cap on candidates returned per scan — defensive (prevents OOM on a
52
+ * corrupted vault with 100k+ files). */
53
+ const SCAN_HARD_CAP = 5_000;
54
+ // ---------------------------------------------------------------------------
55
+ // Service
56
+ // ---------------------------------------------------------------------------
57
+ export class WikiCleanupService {
58
+ static instance = null;
59
+ logger;
60
+ constructor() {
61
+ this.logger = LoggerService.getInstance().createComponentLogger('WikiCleanup');
62
+ }
63
+ static getInstance() {
64
+ if (!this.instance)
65
+ this.instance = new WikiCleanupService();
66
+ return this.instance;
67
+ }
68
+ /** Test-only reset. */
69
+ static resetInstance() {
70
+ this.instance = null;
71
+ }
72
+ /**
73
+ * Walk the vault's `llm-curated/` tree, parse frontmatter, return all
74
+ * pages matching at least one cleanup rule. Pure read — no writes.
75
+ */
76
+ async scan(input) {
77
+ const validation = this.validateVault(input.vaultPath);
78
+ if (!validation.ok)
79
+ return validation;
80
+ const rules = {
81
+ minConfidence: input.rules?.minConfidence ?? 0.5,
82
+ dropAgentMemoryDumps: input.rules?.dropAgentMemoryDumps ?? true,
83
+ maxPerAgent: input.rules?.maxPerAgent ?? 0,
84
+ };
85
+ const llmCuratedRoot = path.join(input.vaultPath, LLM_CURATED_DIR);
86
+ const allPages = [];
87
+ let truncated = false;
88
+ if (existsSync(llmCuratedRoot)) {
89
+ truncated = await this.walkPages(llmCuratedRoot, input.vaultPath, allPages, SCAN_HARD_CAP);
90
+ }
91
+ const flagged = new Map();
92
+ const summary = { lowConfidence: 0, agentMemoryDump: 0, perAgentCapped: 0 };
93
+ for (const page of allPages) {
94
+ const fm = page.frontmatter;
95
+ const reasons = [];
96
+ const conf = parseConfidence(fm['confidence']);
97
+ if (conf !== null && conf < rules.minConfidence) {
98
+ reasons.push(`confidence ${conf} < ${rules.minConfidence}`);
99
+ summary.lowConfidence++;
100
+ }
101
+ const migratedFrom = typeof fm['migrated_from'] === 'string' ? fm['migrated_from'] : null;
102
+ if (rules.dropAgentMemoryDumps && migratedFrom?.startsWith('agent/') && migratedFrom.endsWith('/memory.json')) {
103
+ reasons.push('migrated from agent memory.json');
104
+ summary.agentMemoryDump++;
105
+ }
106
+ if (reasons.length > 0) {
107
+ flagged.set(page.relPath, {
108
+ reasons,
109
+ meta: {
110
+ confidence: conf,
111
+ originalAuthor: typeof fm['original_author'] === 'string' ? fm['original_author'] : null,
112
+ originalDate: typeof fm['original_date'] === 'string' ? fm['original_date'] : null,
113
+ },
114
+ });
115
+ }
116
+ }
117
+ // Second pass — per-agent cap. Only considers pages NOT already flagged
118
+ // by other rules (so a low-confidence page doesn't take a "cap slot").
119
+ if (rules.maxPerAgent > 0) {
120
+ const byAuthor = new Map();
121
+ for (const page of allPages) {
122
+ if (flagged.has(page.relPath))
123
+ continue;
124
+ const fm = page.frontmatter;
125
+ const author = typeof fm['original_author'] === 'string' ? fm['original_author'] : null;
126
+ if (!author)
127
+ continue;
128
+ const conf = parseConfidence(fm['confidence']) ?? 0;
129
+ const date = typeof fm['original_date'] === 'string' ? fm['original_date'] : '';
130
+ const arr = byAuthor.get(author) ?? [];
131
+ arr.push({ relPath: page.relPath, confidence: conf, date });
132
+ byAuthor.set(author, arr);
133
+ }
134
+ for (const [author, arr] of byAuthor) {
135
+ if (arr.length <= rules.maxPerAgent)
136
+ continue;
137
+ // Keep top-N by confidence desc, then date desc.
138
+ arr.sort((a, b) => (b.confidence - a.confidence) || b.date.localeCompare(a.date));
139
+ for (const overflow of arr.slice(rules.maxPerAgent)) {
140
+ const existing = flagged.get(overflow.relPath);
141
+ if (existing) {
142
+ existing.reasons.push(`per-agent cap (${author}: keep ${rules.maxPerAgent})`);
143
+ }
144
+ else {
145
+ flagged.set(overflow.relPath, {
146
+ reasons: [`per-agent cap (${author}: keep ${rules.maxPerAgent})`],
147
+ meta: { confidence: overflow.confidence, originalAuthor: author, originalDate: overflow.date },
148
+ });
149
+ }
150
+ summary.perAgentCapped++;
151
+ }
152
+ }
153
+ }
154
+ const candidates = [];
155
+ for (const page of allPages) {
156
+ const flag = flagged.get(page.relPath);
157
+ if (!flag)
158
+ continue;
159
+ const fm = page.frontmatter;
160
+ candidates.push({
161
+ relPath: page.relPath,
162
+ reasons: flag.reasons,
163
+ confidence: flag.meta.confidence,
164
+ originalAuthor: flag.meta.originalAuthor,
165
+ migratedFrom: typeof fm['migrated_from'] === 'string' ? fm['migrated_from'] : null,
166
+ originalId: typeof fm['original_id'] === 'string' ? fm['original_id'] : null,
167
+ bytes: page.bytes,
168
+ });
169
+ if (candidates.length >= SCAN_HARD_CAP) {
170
+ truncated = true;
171
+ break;
172
+ }
173
+ }
174
+ this.logger.info('Wiki cleanup scan complete', {
175
+ vaultPath: input.vaultPath,
176
+ scannedCount: allPages.length,
177
+ candidateCount: candidates.length,
178
+ truncated,
179
+ summary,
180
+ });
181
+ return {
182
+ ok: true,
183
+ vaultPath: input.vaultPath,
184
+ candidates,
185
+ scannedCount: allPages.length,
186
+ truncated,
187
+ summary,
188
+ };
189
+ }
190
+ /**
191
+ * Delete the listed pages from the vault, archive each one (body +
192
+ * frontmatter) to `.wiki-cleanup-archive.json`, and invalidate the
193
+ * corresponding entry in the migrate manifest so the same source can't
194
+ * resurrect the page on the next `wiki-migrate --apply`.
195
+ */
196
+ async apply(input) {
197
+ const validation = this.validateVault(input.vaultPath);
198
+ if (!validation.ok)
199
+ return validation;
200
+ if (!Array.isArray(input.pages) || input.pages.length === 0) {
201
+ return { ok: false, reason: 'invalid_input', message: 'pages must be a non-empty array' };
202
+ }
203
+ const archivePath = path.join(input.vaultPath, WIKI_CLEANUP_ARCHIVE_FILENAME);
204
+ const archive = await safeReadJson(archivePath, { version: WIKI_CLEANUP_ARCHIVE_VERSION, entries: [] }, this.logger);
205
+ if (archive.version !== WIKI_CLEANUP_ARCHIVE_VERSION) {
206
+ // Migrate-style: don't trust an unknown version, just start fresh.
207
+ archive.version = WIKI_CLEANUP_ARCHIVE_VERSION;
208
+ archive.entries = [];
209
+ }
210
+ const deleted = [];
211
+ const skipped = [];
212
+ for (const relPath of input.pages) {
213
+ const safe = this.normalizeRelPath(relPath);
214
+ if (!safe) {
215
+ skipped.push({ relPath, reason: 'outside_vault' });
216
+ continue;
217
+ }
218
+ // Defence: even if the caller passes a frozen-folder path, refuse.
219
+ // The top-level segment is the folder name (`memory/secret.md` →
220
+ // `memory`); pages directly under the vault root are never frozen.
221
+ const segments = safe.split('/');
222
+ if (segments.length >= 2 && FROZEN_FOLDERS.has(segments[0])) {
223
+ skipped.push({ relPath, reason: 'frozen' });
224
+ continue;
225
+ }
226
+ const abs = path.join(input.vaultPath, safe);
227
+ if (!existsSync(abs)) {
228
+ skipped.push({ relPath, reason: 'not_found' });
229
+ continue;
230
+ }
231
+ // Read + parse before delete so we can archive shape.
232
+ const raw = await fs.readFile(abs, 'utf8');
233
+ const { frontmatter, body } = parseFrontmatter(raw);
234
+ archive.entries.push({
235
+ relPath: safe,
236
+ archivedAt: new Date().toISOString(),
237
+ reasons: ['apply-list'],
238
+ body,
239
+ frontmatter,
240
+ });
241
+ await fs.unlink(abs);
242
+ deleted.push(safe);
243
+ }
244
+ // Persist archive — the rollback source of truth.
245
+ //
246
+ // **Manifest is deliberately NOT modified** (2026-05-28 fix). Earlier
247
+ // versions removed the matching entries from `.migration-state.json`
248
+ // on the theory "now nothing pins the page in place." That was
249
+ // exactly backwards: the migrate manifest is what makes
250
+ // `wiki-migrate --apply` IDEMPOTENT. With the entry present + hash
251
+ // match, migrate sees "already migrated" → skips. With the entry
252
+ // removed, migrate sees "new content" → re-imports → the
253
+ // just-deleted page reappears on the next bridge tick. Symptom seen
254
+ // 2026-05-28 ~05:30: 20 pages deleted, then 20 re-imported by the
255
+ // next migrate tick, candidate count never dropped. The page on
256
+ // disk is gone; that is sufficient. Manifest stays intact.
257
+ await ensureDir(input.vaultPath);
258
+ await atomicWriteJson(archivePath, archive);
259
+ this.logger.info('Wiki cleanup apply complete', {
260
+ vaultPath: input.vaultPath,
261
+ requested: input.pages.length,
262
+ deleted: deleted.length,
263
+ skipped: skipped.length,
264
+ archivePath,
265
+ });
266
+ return {
267
+ ok: true,
268
+ vaultPath: input.vaultPath,
269
+ deleted,
270
+ skipped,
271
+ archivePath,
272
+ manifestEntriesInvalidated: 0,
273
+ };
274
+ }
275
+ // -------------------------------------------------------------------------
276
+ // Internals
277
+ // -------------------------------------------------------------------------
278
+ validateVault(vaultPath) {
279
+ if (!vaultPath || !path.isAbsolute(vaultPath)) {
280
+ return { ok: false, reason: 'invalid_input', message: 'vaultPath must be an absolute path' };
281
+ }
282
+ if (!existsSync(vaultPath)) {
283
+ return { ok: false, reason: 'vault_missing', message: `vault not found: ${vaultPath}` };
284
+ }
285
+ return { ok: true };
286
+ }
287
+ /**
288
+ * Best-effort safe-rel normalisation. Returns null if the path would
289
+ * resolve outside the vault (`..` traversal etc).
290
+ */
291
+ normalizeRelPath(rel) {
292
+ const normalised = path.posix.normalize(rel.replace(/\\/g, '/'));
293
+ if (normalised.startsWith('..') || path.isAbsolute(normalised))
294
+ return null;
295
+ return normalised;
296
+ }
297
+ /**
298
+ * Walk the vault tree, parsing frontmatter on each `.md` file. Skips
299
+ * frozen folders + non-md files. Returns true if the scan was truncated
300
+ * by the hard cap.
301
+ */
302
+ async walkPages(dir, vaultPath, accumulator, cap) {
303
+ let entries;
304
+ try {
305
+ entries = await fs.readdir(dir, { withFileTypes: true });
306
+ }
307
+ catch {
308
+ return false;
309
+ }
310
+ for (const entry of entries) {
311
+ if (accumulator.length >= cap)
312
+ return true;
313
+ // Skip frozen folders only at the vault-root level (`llm-curated/`
314
+ // sits next to them, so we never recurse INTO sibling frozen dirs
315
+ // — but defence-in-depth this check covers anyone who calls
316
+ // `walkPages` with the vault root directly).
317
+ if (entry.isDirectory()) {
318
+ const relParent = path.relative(vaultPath, path.join(dir, entry.name));
319
+ const topLevel = relParent.split(path.sep)[0];
320
+ if (FROZEN_FOLDERS.has(topLevel))
321
+ continue;
322
+ const truncated = await this.walkPages(path.join(dir, entry.name), vaultPath, accumulator, cap);
323
+ if (truncated)
324
+ return true;
325
+ continue;
326
+ }
327
+ if (!entry.isFile() || !entry.name.endsWith('.md'))
328
+ continue;
329
+ const abs = path.join(dir, entry.name);
330
+ try {
331
+ const stat = await fs.stat(abs);
332
+ const raw = await fs.readFile(abs, 'utf8');
333
+ const { frontmatter } = parseFrontmatter(raw);
334
+ accumulator.push({
335
+ relPath: path.relative(vaultPath, abs).split(path.sep).join('/'),
336
+ frontmatter,
337
+ bytes: stat.size,
338
+ });
339
+ }
340
+ catch (err) {
341
+ this.logger.debug('walkPages: skipping unreadable file', {
342
+ path: abs,
343
+ error: err instanceof Error ? err.message : String(err),
344
+ });
345
+ }
346
+ }
347
+ return false;
348
+ }
349
+ }
350
+ // ---------------------------------------------------------------------------
351
+ // Helpers (module-private, exported for tests)
352
+ // ---------------------------------------------------------------------------
353
+ /**
354
+ * Parse `confidence` from frontmatter into a number, or null if absent /
355
+ * unparseable. Accepts both numeric (`0.3`) and string (`"0.3"`) shapes
356
+ * because YAML quoting is inconsistent across older migrated pages.
357
+ */
358
+ export function parseConfidence(raw) {
359
+ if (typeof raw === 'number' && Number.isFinite(raw))
360
+ return raw;
361
+ if (typeof raw === 'string') {
362
+ const parsed = parseFloat(raw);
363
+ if (Number.isFinite(parsed))
364
+ return parsed;
365
+ }
366
+ return null;
367
+ }
368
+ /**
369
+ * Minimal YAML frontmatter parser. Handles the shapes our migrate service
370
+ * emits — `key: value` lines, with optional quotes around values. NOT a
371
+ * general YAML parser. Returns `{}` when no frontmatter is present.
372
+ */
373
+ export function parseFrontmatter(raw) {
374
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
375
+ if (!match)
376
+ return { frontmatter: {}, body: raw };
377
+ const fm = {};
378
+ for (const line of match[1].split('\n')) {
379
+ const lineMatch = line.match(/^([A-Za-z_][A-Za-z0-9_]*):\s*(.*)$/);
380
+ if (!lineMatch)
381
+ continue;
382
+ let value = lineMatch[2].trim();
383
+ // Strip wrapping quotes.
384
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
385
+ value = value.slice(1, -1);
386
+ }
387
+ // Coerce a few common scalar shapes.
388
+ if (value === 'true')
389
+ fm[lineMatch[1]] = true;
390
+ else if (value === 'false')
391
+ fm[lineMatch[1]] = false;
392
+ else if (/^-?\d+(\.\d+)?$/.test(value))
393
+ fm[lineMatch[1]] = parseFloat(value);
394
+ else
395
+ fm[lineMatch[1]] = value;
396
+ }
397
+ return { frontmatter: fm, body: match[2] };
398
+ }
399
+ //# sourceMappingURL=wiki-cleanup.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-cleanup.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-cleanup.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * WikiLintService — deterministic validation pass over a vault.
3
+ *
4
+ * Per v2.1 spec §3, the third Phase 1 skill (alongside `wiki-ingest` and
5
+ * `wiki-query`). Unlike `wiki-bookkeep` (vault HEALTH metrics — counts,
6
+ * recent activity, duplicate clusters), lint focuses on CORRECTNESS:
7
+ *
8
+ * - **frozenPathRespected** — no markdown content in folders flagged
9
+ * `frozen: true` in SCHEMA.md (other than the SCHEMA.md itself /
10
+ * legitimate frozen content). Lint refuses to alter frozen paths.
11
+ * - **missingEntities** — `[[wikilinks]]` that don't resolve to any
12
+ * page in the vault. Either the target was renamed, deleted, or the
13
+ * wikilink was made up. The lint flags them; the agent decides.
14
+ * - **orphanPages** — pages with zero incoming wikilinks, excluding
15
+ * seed pages (log.md, index.md, README*). These are candidates for
16
+ * either deletion or new linking.
17
+ * - **staleClaims** — files un-touched for `staleDays` (default 90).
18
+ * - **restructureProposals** — heuristics for llm-curated/ only: large
19
+ * un-indexed folders, near-duplicate filenames.
20
+ *
21
+ * The service never writes. The agent's LLM reads the report and decides
22
+ * whether to ingest a consolidation, archive stale pages, etc.
23
+ *
24
+ * @module services/wiki/wiki-lint.service
25
+ */
26
+ /** Default age threshold (days) for marking a page stale. */
27
+ export declare const WIKI_LINT_DEFAULT_STALE_DAYS = 90;
28
+ /** Folder size threshold above which lint proposes an `index.md` rollup. */
29
+ export declare const WIKI_LINT_ROLLUP_THRESHOLD = 20;
30
+ /** Max number of pages walked per lint pass. */
31
+ export declare const WIKI_LINT_MAX_PAGES = 1000;
32
+ /** Cap per category to keep the payload bounded. */
33
+ export declare const WIKI_LINT_MAX_ROWS_PER_SECTION = 50;
34
+ /** Pages with these basenames never count as "orphans". */
35
+ export declare const WIKI_LINT_SEED_BASENAMES: Set<string>;
36
+ /**
37
+ * A `[[wikilink]]` target is "concept-shaped" (vs a dangling typo) when
38
+ * it appears at least this many times across the vault. Below this, the
39
+ * unresolved target is just noise; at or above this, the concept is
40
+ * load-bearing and deserves its own page.
41
+ */
42
+ export declare const WIKI_LINT_MISSING_CONCEPT_THRESHOLD = 3;
43
+ export interface WikiLintInput {
44
+ vaultPath: string;
45
+ staleDays?: number;
46
+ }
47
+ export interface WikiLintFrozenViolation {
48
+ /** Relative path of the offending file. */
49
+ path: string;
50
+ /** The frozen folder it lives in. */
51
+ frozenFolder: string;
52
+ }
53
+ export interface WikiLintMissingEntity {
54
+ /** Page that contains the dangling wikilink. */
55
+ sourcePath: string;
56
+ /** The unresolved wikilink target. */
57
+ target: string;
58
+ /** Line number in the source page (1-based). */
59
+ lineNumber: number;
60
+ }
61
+ export interface WikiLintRestructureProposal {
62
+ /** Plain-English description of the proposal, e.g. "folder X has 31 pages without an index.md — propose llm-curated/X/index.md". */
63
+ description: string;
64
+ /** Optional related path (folder or page). */
65
+ path?: string;
66
+ }
67
+ /**
68
+ * A wikilink target that appears repeatedly across the vault but has no
69
+ * dedicated page. Karpathy's lint contract names this explicitly:
70
+ * *"important concepts mentioned but lacking their own page."* Different
71
+ * from `missingEntities` (which is one-off dangling refs / typos):
72
+ * `missingConcepts` is **frequency-weighted** signal that the team keeps
73
+ * mentioning a thing → write a page for it.
74
+ */
75
+ export interface WikiLintMissingConcept {
76
+ /** The wikilink target referenced (e.g. `verify-output`). */
77
+ target: string;
78
+ /** How many distinct wikilink occurrences resolved to nothing. */
79
+ referenceCount: number;
80
+ /** Sample sources (capped) that reference this concept. */
81
+ sources: string[];
82
+ }
83
+ export interface WikiLintReport {
84
+ vault: {
85
+ scope: string;
86
+ id: string;
87
+ path: string;
88
+ };
89
+ generatedAt: string;
90
+ staleDays: number;
91
+ frozenPathRespected: boolean;
92
+ frozenViolations: WikiLintFrozenViolation[];
93
+ missingEntities: WikiLintMissingEntity[];
94
+ /** New 2026-05-26: frequency-weighted "missing concept" signals. */
95
+ missingConcepts: WikiLintMissingConcept[];
96
+ orphanPages: string[];
97
+ staleClaims: string[];
98
+ restructureProposals: WikiLintRestructureProposal[];
99
+ truncated: boolean;
100
+ }
101
+ export type WikiLintOutcome = {
102
+ ok: true;
103
+ report: WikiLintReport;
104
+ } | {
105
+ ok: false;
106
+ reason: 'vault_missing' | 'schema_missing' | 'invalid_input';
107
+ message: string;
108
+ };
109
+ /**
110
+ * Singleton lint service. Stateless — pattern mirrors the other wiki
111
+ * services so the controller wiring is uniform.
112
+ */
113
+ export declare class WikiLintService {
114
+ private static instance;
115
+ private readonly logger;
116
+ private readonly schemaLoader;
117
+ private constructor();
118
+ static getInstance(): WikiLintService;
119
+ static resetInstance(): void;
120
+ /**
121
+ * Generate a lint report for the given vault.
122
+ */
123
+ generate(input: WikiLintInput): Promise<WikiLintOutcome>;
124
+ /**
125
+ * Recursive walk collecting `.md` files. Honors `WIKI_LINT_MAX_PAGES`.
126
+ */
127
+ private collectFiles;
128
+ /**
129
+ * Find `.md` files that live inside any frozen folder. SCHEMA.md and
130
+ * legitimate sibling files inside frozen dirs (e.g. `sop/<role>.md`)
131
+ * are excluded — frozen folders ARE allowed to contain content; what's
132
+ * NOT allowed is `wiki-ingest` writing INTO them. That's a runtime
133
+ * check elsewhere. Lint surfaces files only when they look like they
134
+ * were created by ingest patterns (timestamp-prefixed slugs).
135
+ */
136
+ private detectFrozenViolations;
137
+ /**
138
+ * One read pass per file: pulls `[[wikilink]]` references, builds the
139
+ * inverse "incoming" map for orphan detection, and emits missing-entity
140
+ * rows for any link that resolves to nothing.
141
+ */
142
+ private scanWikilinks;
143
+ /**
144
+ * A page is an orphan when no other page wikilinks to it AND it is
145
+ * not a seed page (log.md / index.md / README.md / SCHEMA.md).
146
+ */
147
+ private detectOrphans;
148
+ /**
149
+ * Find load-bearing concepts referenced repeatedly across the vault
150
+ * but lacking a dedicated page. Karpathy's lint contract names this:
151
+ * *"important concepts mentioned but lacking their own page."*
152
+ *
153
+ * Frequency-filtered (`WIKI_LINT_MISSING_CONCEPT_THRESHOLD`, default 3)
154
+ * so we ignore typos and inline-code-style `[[X]]` brackets that aren't
155
+ * meant as wikilinks. Distinct from `missingEntities`, which flags every
156
+ * dangling ref individually.
157
+ *
158
+ * Results sort by referenceCount desc — highest-leverage concepts first.
159
+ */
160
+ private detectMissingConcepts;
161
+ /**
162
+ * Files whose content is older than `staleDays`.
163
+ *
164
+ * Migrated pages may have an `original_date` frontmatter field
165
+ * (e.g. the legacy decision was made 2026-02-01 but we wrote the
166
+ * markdown TODAY). Stale detection should respect the original date
167
+ * when present — otherwise every freshly-migrated old page would look
168
+ * "new" by mtime alone. Falls back to mtime when frontmatter is absent.
169
+ */
170
+ private detectStale;
171
+ /**
172
+ * Heuristic restructure proposals — only for `llm-curated/` since
173
+ * frozen folders cannot be restructured.
174
+ *
175
+ * (1) A subfolder with > WIKI_LINT_ROLLUP_THRESHOLD pages and NO `index.md`
176
+ * gets an "add an index.md rollup" proposal.
177
+ * (2) Near-duplicate filename prefixes (e.g. `pricing-v1.md`, `pricing-v2.md`)
178
+ * get a "consider merging" proposal.
179
+ */
180
+ private proposeRestructures;
181
+ }
182
+ //# sourceMappingURL=wiki-lint.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-lint.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-lint.service.ts"],"names":[],"mappings":"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"}