harnery 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (445) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -2
  3. package/bin/agent-coord +42 -0
  4. package/bin/agent-hook +44 -0
  5. package/bin/harn +40 -0
  6. package/dist/cli.d.ts +9 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +18 -0
  9. package/dist/commander.d.ts +128 -0
  10. package/dist/commander.d.ts.map +1 -0
  11. package/dist/commander.js +126 -0
  12. package/dist/commands/agents.d.ts +18 -0
  13. package/dist/commands/agents.d.ts.map +1 -0
  14. package/dist/commands/agents.js +3946 -0
  15. package/dist/commands/backup.d.ts +22 -0
  16. package/dist/commands/backup.d.ts.map +1 -0
  17. package/dist/commands/backup.js +262 -0
  18. package/dist/commands/browse-ai.d.ts +4 -0
  19. package/dist/commands/browse-ai.d.ts.map +1 -0
  20. package/dist/commands/browse-ai.js +156 -0
  21. package/dist/commands/browse.d.ts +4 -0
  22. package/dist/commands/browse.d.ts.map +1 -0
  23. package/dist/commands/browse.js +590 -0
  24. package/dist/commands/callers.d.ts +4 -0
  25. package/dist/commands/callers.d.ts.map +1 -0
  26. package/dist/commands/callers.js +276 -0
  27. package/dist/commands/completion.d.ts +17 -0
  28. package/dist/commands/completion.d.ts.map +1 -0
  29. package/dist/commands/completion.js +158 -0
  30. package/dist/commands/config-get.d.ts +4 -0
  31. package/dist/commands/config-get.d.ts.map +1 -0
  32. package/dist/commands/config-get.js +131 -0
  33. package/dist/commands/context.d.ts +11 -0
  34. package/dist/commands/context.d.ts.map +1 -0
  35. package/dist/commands/context.js +185 -0
  36. package/dist/commands/cookies.d.ts +4 -0
  37. package/dist/commands/cookies.d.ts.map +1 -0
  38. package/dist/commands/cookies.js +140 -0
  39. package/dist/commands/docs.d.ts +4 -0
  40. package/dist/commands/docs.d.ts.map +1 -0
  41. package/dist/commands/docs.js +137 -0
  42. package/dist/commands/doctor.d.ts +25 -0
  43. package/dist/commands/doctor.d.ts.map +1 -0
  44. package/dist/commands/doctor.js +200 -0
  45. package/dist/commands/edit-batch.d.ts +18 -0
  46. package/dist/commands/edit-batch.d.ts.map +1 -0
  47. package/dist/commands/edit-batch.js +172 -0
  48. package/dist/commands/eml.d.ts +4 -0
  49. package/dist/commands/eml.d.ts.map +1 -0
  50. package/dist/commands/eml.js +428 -0
  51. package/dist/commands/env.d.ts +4 -0
  52. package/dist/commands/env.d.ts.map +1 -0
  53. package/dist/commands/env.js +201 -0
  54. package/dist/commands/fetch.d.ts +4 -0
  55. package/dist/commands/fetch.d.ts.map +1 -0
  56. package/dist/commands/fetch.js +99 -0
  57. package/dist/commands/file-history.d.ts +4 -0
  58. package/dist/commands/file-history.d.ts.map +1 -0
  59. package/dist/commands/file-history.js +152 -0
  60. package/dist/commands/grep.d.ts +4 -0
  61. package/dist/commands/grep.d.ts.map +1 -0
  62. package/dist/commands/grep.js +317 -0
  63. package/dist/commands/init.d.ts +82 -0
  64. package/dist/commands/init.d.ts.map +1 -0
  65. package/dist/commands/init.js +288 -0
  66. package/dist/commands/outline.d.ts +4 -0
  67. package/dist/commands/outline.d.ts.map +1 -0
  68. package/dist/commands/outline.js +509 -0
  69. package/dist/commands/presence.d.ts +12 -0
  70. package/dist/commands/presence.d.ts.map +1 -0
  71. package/dist/commands/presence.js +123 -0
  72. package/dist/commands/read.d.ts +7 -0
  73. package/dist/commands/read.d.ts.map +1 -0
  74. package/dist/commands/read.js +46 -0
  75. package/dist/commands/scratch.d.ts +4 -0
  76. package/dist/commands/scratch.d.ts.map +1 -0
  77. package/dist/commands/scratch.js +426 -0
  78. package/dist/commands/session.d.ts +4 -0
  79. package/dist/commands/session.d.ts.map +1 -0
  80. package/dist/commands/session.js +162 -0
  81. package/dist/commands/sync.d.ts +24 -0
  82. package/dist/commands/sync.d.ts.map +1 -0
  83. package/dist/commands/sync.js +275 -0
  84. package/dist/commands/toc.d.ts +5 -0
  85. package/dist/commands/toc.d.ts.map +1 -0
  86. package/dist/commands/toc.js +153 -0
  87. package/dist/commands/tokens.d.ts +4 -0
  88. package/dist/commands/tokens.d.ts.map +1 -0
  89. package/dist/commands/tokens.js +48 -0
  90. package/dist/commands/tunnel.d.ts +4 -0
  91. package/dist/commands/tunnel.d.ts.map +1 -0
  92. package/dist/commands/tunnel.js +513 -0
  93. package/dist/commands/uninstall.d.ts +22 -0
  94. package/dist/commands/uninstall.d.ts.map +1 -0
  95. package/dist/commands/uninstall.js +126 -0
  96. package/dist/commands/web.d.ts +4 -0
  97. package/dist/commands/web.d.ts.map +1 -0
  98. package/dist/commands/web.js +165 -0
  99. package/dist/core/agents/canonical-emit.d.ts +27 -0
  100. package/dist/core/agents/canonical-emit.d.ts.map +1 -0
  101. package/dist/core/agents/canonical-emit.js +72 -0
  102. package/dist/core/agents/cli-emit.d.ts +27 -0
  103. package/dist/core/agents/cli-emit.d.ts.map +1 -0
  104. package/dist/core/agents/cli-emit.js +57 -0
  105. package/dist/core/agents/cli.d.ts +10 -0
  106. package/dist/core/agents/cli.d.ts.map +1 -0
  107. package/dist/core/agents/cli.js +757 -0
  108. package/dist/core/agents/codex-replay.d.ts +29 -0
  109. package/dist/core/agents/codex-replay.d.ts.map +1 -0
  110. package/dist/core/agents/codex-replay.js +138 -0
  111. package/dist/core/agents/coord-client.d.ts +98 -0
  112. package/dist/core/agents/coord-client.d.ts.map +1 -0
  113. package/dist/core/agents/coord-client.js +212 -0
  114. package/dist/core/agents/events/consume.d.ts +59 -0
  115. package/dist/core/agents/events/consume.d.ts.map +1 -0
  116. package/dist/core/agents/events/consume.js +147 -0
  117. package/dist/core/agents/events/emit.d.ts +42 -0
  118. package/dist/core/agents/events/emit.d.ts.map +1 -0
  119. package/dist/core/agents/events/emit.js +70 -0
  120. package/dist/core/agents/events/ulid.d.ts +11 -0
  121. package/dist/core/agents/events/ulid.d.ts.map +1 -0
  122. package/dist/core/agents/events/ulid.js +47 -0
  123. package/dist/core/agents/index.d.ts +14 -0
  124. package/dist/core/agents/index.d.ts.map +1 -0
  125. package/dist/core/agents/index.js +13 -0
  126. package/dist/core/agents/paths.d.ts +6 -0
  127. package/dist/core/agents/paths.d.ts.map +1 -0
  128. package/dist/core/agents/paths.js +17 -0
  129. package/dist/core/agents/render/prompt-context.d.ts +43 -0
  130. package/dist/core/agents/render/prompt-context.d.ts.map +1 -0
  131. package/dist/core/agents/render/prompt-context.js +335 -0
  132. package/dist/core/agents/render/session-context.d.ts +39 -0
  133. package/dist/core/agents/render/session-context.d.ts.map +1 -0
  134. package/dist/core/agents/render/session-context.js +283 -0
  135. package/dist/core/agents/rules/claim-conflict.d.ts +35 -0
  136. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -0
  137. package/dist/core/agents/rules/claim-conflict.js +244 -0
  138. package/dist/core/agents/rules/commit-conflict.d.ts +59 -0
  139. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -0
  140. package/dist/core/agents/rules/commit-conflict.js +244 -0
  141. package/dist/core/agents/rules/stop-hook.d.ts +44 -0
  142. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -0
  143. package/dist/core/agents/rules/stop-hook.js +161 -0
  144. package/dist/core/agents/session-events.d.ts +41 -0
  145. package/dist/core/agents/session-events.d.ts.map +1 -0
  146. package/dist/core/agents/session-events.js +205 -0
  147. package/dist/core/agents/state/activity-log.d.ts +18 -0
  148. package/dist/core/agents/state/activity-log.d.ts.map +1 -0
  149. package/dist/core/agents/state/activity-log.js +34 -0
  150. package/dist/core/agents/state/council.d.ts +39 -0
  151. package/dist/core/agents/state/council.d.ts.map +1 -0
  152. package/dist/core/agents/state/council.js +216 -0
  153. package/dist/core/agents/state/heartbeat-projector.d.ts +59 -0
  154. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -0
  155. package/dist/core/agents/state/heartbeat-projector.js +436 -0
  156. package/dist/core/agents/state/heartbeat-writer.d.ts +64 -0
  157. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -0
  158. package/dist/core/agents/state/heartbeat-writer.js +271 -0
  159. package/dist/core/agents/state/names.d.ts +35 -0
  160. package/dist/core/agents/state/names.d.ts.map +1 -0
  161. package/dist/core/agents/state/names.js +376 -0
  162. package/dist/core/agents/state/pidmap.d.ts +11 -0
  163. package/dist/core/agents/state/pidmap.d.ts.map +1 -0
  164. package/dist/core/agents/state/pidmap.js +32 -0
  165. package/dist/core/agents/state/scratch.d.ts +27 -0
  166. package/dist/core/agents/state/scratch.d.ts.map +1 -0
  167. package/dist/core/agents/state/scratch.js +90 -0
  168. package/dist/core/agents/state/shell-mutation.d.ts +17 -0
  169. package/dist/core/agents/state/shell-mutation.d.ts.map +1 -0
  170. package/dist/core/agents/state/shell-mutation.js +41 -0
  171. package/dist/core/agents/state/stale-sweep.d.ts +16 -0
  172. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -0
  173. package/dist/core/agents/state/stale-sweep.js +166 -0
  174. package/dist/core/config.d.ts +29 -0
  175. package/dist/core/config.d.ts.map +1 -0
  176. package/dist/core/config.js +108 -0
  177. package/dist/core/hooks/cli.d.ts +21 -0
  178. package/dist/core/hooks/cli.d.ts.map +1 -0
  179. package/dist/core/hooks/cli.js +1123 -0
  180. package/dist/core/hooks/effects/image-capture.d.ts +43 -0
  181. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -0
  182. package/dist/core/hooks/effects/image-capture.js +288 -0
  183. package/dist/core/hooks/effects/index.d.ts +64 -0
  184. package/dist/core/hooks/effects/index.d.ts.map +1 -0
  185. package/dist/core/hooks/effects/index.js +197 -0
  186. package/dist/core/hooks/events/emit.d.ts +31 -0
  187. package/dist/core/hooks/events/emit.d.ts.map +1 -0
  188. package/dist/core/hooks/events/emit.js +89 -0
  189. package/dist/core/hooks/events/schema.d.ts +235 -0
  190. package/dist/core/hooks/events/schema.d.ts.map +1 -0
  191. package/dist/core/hooks/events/schema.js +12 -0
  192. package/dist/core/hooks/events/ulid.d.ts +10 -0
  193. package/dist/core/hooks/events/ulid.d.ts.map +1 -0
  194. package/dist/core/hooks/events/ulid.js +47 -0
  195. package/dist/core/hooks/harness/detect.d.ts +9 -0
  196. package/dist/core/hooks/harness/detect.d.ts.map +1 -0
  197. package/dist/core/hooks/harness/detect.js +29 -0
  198. package/dist/core/hooks/harness/events.d.ts +45 -0
  199. package/dist/core/hooks/harness/events.d.ts.map +1 -0
  200. package/dist/core/hooks/harness/events.js +71 -0
  201. package/dist/core/hooks/harness/output.d.ts +46 -0
  202. package/dist/core/hooks/harness/output.d.ts.map +1 -0
  203. package/dist/core/hooks/harness/output.js +87 -0
  204. package/dist/core/hooks/harness/parse.d.ts +67 -0
  205. package/dist/core/hooks/harness/parse.d.ts.map +1 -0
  206. package/dist/core/hooks/harness/parse.js +132 -0
  207. package/dist/core/hooks/index.d.ts +8 -0
  208. package/dist/core/hooks/index.d.ts.map +1 -0
  209. package/dist/core/hooks/index.js +7 -0
  210. package/dist/core/hooks/resolve/anchor.d.ts +37 -0
  211. package/dist/core/hooks/resolve/anchor.d.ts.map +1 -0
  212. package/dist/core/hooks/resolve/anchor.js +48 -0
  213. package/dist/core/hooks/resolve/coord-root.d.ts +6 -0
  214. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -0
  215. package/dist/core/hooks/resolve/coord-root.js +27 -0
  216. package/dist/core/hooks/resolve/intent.d.ts +33 -0
  217. package/dist/core/hooks/resolve/intent.d.ts.map +1 -0
  218. package/dist/core/hooks/resolve/intent.js +79 -0
  219. package/dist/core/hooks/resolve/owner.d.ts +42 -0
  220. package/dist/core/hooks/resolve/owner.d.ts.map +1 -0
  221. package/dist/core/hooks/resolve/owner.js +140 -0
  222. package/dist/core/hooks/resolve/transcript.d.ts +26 -0
  223. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -0
  224. package/dist/core/hooks/resolve/transcript.js +73 -0
  225. package/dist/index.d.ts +15 -0
  226. package/dist/index.d.ts.map +1 -0
  227. package/dist/index.js +13 -0
  228. package/dist/lib/agent-browser/client.d.ts +99 -0
  229. package/dist/lib/agent-browser/client.d.ts.map +1 -0
  230. package/dist/lib/agent-browser/client.js +177 -0
  231. package/dist/lib/agent-browser/index.d.ts +2 -0
  232. package/dist/lib/agent-browser/index.d.ts.map +1 -0
  233. package/dist/lib/agent-browser/index.js +1 -0
  234. package/dist/lib/browser/client.d.ts +193 -0
  235. package/dist/lib/browser/client.d.ts.map +1 -0
  236. package/dist/lib/browser/client.js +325 -0
  237. package/dist/lib/browser/dev-overlay.d.ts +23 -0
  238. package/dist/lib/browser/dev-overlay.d.ts.map +1 -0
  239. package/dist/lib/browser/dev-overlay.js +153 -0
  240. package/dist/lib/browser/index.d.ts +5 -0
  241. package/dist/lib/browser/index.d.ts.map +1 -0
  242. package/dist/lib/browser/index.js +2 -0
  243. package/dist/lib/browser/layout.d.ts +79 -0
  244. package/dist/lib/browser/layout.d.ts.map +1 -0
  245. package/dist/lib/browser/layout.js +220 -0
  246. package/dist/lib/browser/visibility.d.ts +86 -0
  247. package/dist/lib/browser/visibility.d.ts.map +1 -0
  248. package/dist/lib/browser/visibility.js +333 -0
  249. package/dist/lib/browser/visual-diff.d.ts +38 -0
  250. package/dist/lib/browser/visual-diff.d.ts.map +1 -0
  251. package/dist/lib/browser/visual-diff.js +107 -0
  252. package/dist/lib/completion/bash.d.ts +25 -0
  253. package/dist/lib/completion/bash.d.ts.map +1 -0
  254. package/dist/lib/completion/bash.js +284 -0
  255. package/dist/lib/completion/fish.d.ts +16 -0
  256. package/dist/lib/completion/fish.d.ts.map +1 -0
  257. package/dist/lib/completion/fish.js +118 -0
  258. package/dist/lib/completion/index.d.ts +5 -0
  259. package/dist/lib/completion/index.d.ts.map +1 -0
  260. package/dist/lib/completion/index.js +4 -0
  261. package/dist/lib/completion/walk.d.ts +68 -0
  262. package/dist/lib/completion/walk.d.ts.map +1 -0
  263. package/dist/lib/completion/walk.js +102 -0
  264. package/dist/lib/completion/zsh.d.ts +13 -0
  265. package/dist/lib/completion/zsh.d.ts.map +1 -0
  266. package/dist/lib/completion/zsh.js +249 -0
  267. package/dist/lib/context/index.d.ts +107 -0
  268. package/dist/lib/context/index.d.ts.map +1 -0
  269. package/dist/lib/context/index.js +275 -0
  270. package/dist/lib/cookies/client.d.ts +131 -0
  271. package/dist/lib/cookies/client.d.ts.map +1 -0
  272. package/dist/lib/cookies/client.js +239 -0
  273. package/dist/lib/cookies/index.d.ts +2 -0
  274. package/dist/lib/cookies/index.d.ts.map +1 -0
  275. package/dist/lib/cookies/index.js +1 -0
  276. package/dist/lib/council/index.d.ts +266 -0
  277. package/dist/lib/council/index.d.ts.map +1 -0
  278. package/dist/lib/council/index.js +674 -0
  279. package/dist/lib/docs-index.d.ts +28 -0
  280. package/dist/lib/docs-index.d.ts.map +1 -0
  281. package/dist/lib/docs-index.js +169 -0
  282. package/dist/lib/docs-lint.d.ts +26 -0
  283. package/dist/lib/docs-lint.d.ts.map +1 -0
  284. package/dist/lib/docs-lint.js +378 -0
  285. package/dist/lib/docs-sweep.d.ts +34 -0
  286. package/dist/lib/docs-sweep.d.ts.map +1 -0
  287. package/dist/lib/docs-sweep.js +304 -0
  288. package/dist/lib/docs.d.ts +27 -0
  289. package/dist/lib/docs.d.ts.map +1 -0
  290. package/dist/lib/docs.js +142 -0
  291. package/dist/lib/env.d.ts +11 -0
  292. package/dist/lib/env.d.ts.map +1 -0
  293. package/dist/lib/env.js +12 -0
  294. package/dist/lib/exec.d.ts +32 -0
  295. package/dist/lib/exec.d.ts.map +1 -0
  296. package/dist/lib/exec.js +54 -0
  297. package/dist/lib/format.d.ts +29 -0
  298. package/dist/lib/format.d.ts.map +1 -0
  299. package/dist/lib/format.js +139 -0
  300. package/dist/lib/http/client.d.ts +56 -0
  301. package/dist/lib/http/client.d.ts.map +1 -0
  302. package/dist/lib/http/client.js +160 -0
  303. package/dist/lib/http/index.d.ts +2 -0
  304. package/dist/lib/http/index.d.ts.map +1 -0
  305. package/dist/lib/http/index.js +1 -0
  306. package/dist/lib/identities/index.d.ts +77 -0
  307. package/dist/lib/identities/index.d.ts.map +1 -0
  308. package/dist/lib/identities/index.js +190 -0
  309. package/dist/lib/machine.d.ts +19 -0
  310. package/dist/lib/machine.d.ts.map +1 -0
  311. package/dist/lib/machine.js +61 -0
  312. package/dist/lib/presence.d.ts +48 -0
  313. package/dist/lib/presence.d.ts.map +1 -0
  314. package/dist/lib/presence.js +123 -0
  315. package/dist/lib/readability/client.d.ts +39 -0
  316. package/dist/lib/readability/client.d.ts.map +1 -0
  317. package/dist/lib/readability/client.js +121 -0
  318. package/dist/lib/readability/index.d.ts +2 -0
  319. package/dist/lib/readability/index.d.ts.map +1 -0
  320. package/dist/lib/readability/index.js +1 -0
  321. package/dist/lib/scratch/index.d.ts +74 -0
  322. package/dist/lib/scratch/index.d.ts.map +1 -0
  323. package/dist/lib/scratch/index.js +393 -0
  324. package/dist/lib/tunnel/gate.d.ts +12 -0
  325. package/dist/lib/tunnel/gate.d.ts.map +1 -0
  326. package/dist/lib/tunnel/gate.js +101 -0
  327. package/dist/lib/tunnel/state.d.ts +34 -0
  328. package/dist/lib/tunnel/state.d.ts.map +1 -0
  329. package/dist/lib/tunnel/state.js +132 -0
  330. package/package.json +160 -8
  331. package/schemas/.gitkeep +0 -0
  332. package/schemas/config.schema.json +109 -0
  333. package/src/cli.ts +22 -0
  334. package/src/commander.ts +242 -0
  335. package/src/commands/.gitkeep +0 -0
  336. package/src/commands/agents.ts +4567 -0
  337. package/src/commands/backup.ts +305 -0
  338. package/src/commands/browse-ai.ts +198 -0
  339. package/src/commands/browse.ts +849 -0
  340. package/src/commands/callers.ts +363 -0
  341. package/src/commands/completion.ts +193 -0
  342. package/src/commands/config-get.ts +161 -0
  343. package/src/commands/context.ts +209 -0
  344. package/src/commands/cookies.ts +198 -0
  345. package/src/commands/docs.ts +174 -0
  346. package/src/commands/doctor.ts +231 -0
  347. package/src/commands/edit-batch.ts +233 -0
  348. package/src/commands/eml.ts +519 -0
  349. package/src/commands/env.ts +254 -0
  350. package/src/commands/fetch.ts +136 -0
  351. package/src/commands/file-history.ts +202 -0
  352. package/src/commands/grep.ts +371 -0
  353. package/src/commands/init.ts +335 -0
  354. package/src/commands/outline.ts +583 -0
  355. package/src/commands/presence.ts +152 -0
  356. package/src/commands/read.ts +64 -0
  357. package/src/commands/scratch.ts +445 -0
  358. package/src/commands/session.ts +187 -0
  359. package/src/commands/sync.ts +306 -0
  360. package/src/commands/toc.ts +218 -0
  361. package/src/commands/tokens.ts +79 -0
  362. package/src/commands/tunnel.ts +633 -0
  363. package/src/commands/uninstall.ts +144 -0
  364. package/src/commands/web.ts +193 -0
  365. package/src/core/agents/canonical-emit.ts +77 -0
  366. package/src/core/agents/cli-emit.ts +64 -0
  367. package/src/core/agents/cli.ts +838 -0
  368. package/src/core/agents/codex-replay.ts +163 -0
  369. package/src/core/agents/coord-client.ts +249 -0
  370. package/src/core/agents/events/consume.ts +196 -0
  371. package/src/core/agents/events/emit.ts +108 -0
  372. package/src/core/agents/events/ulid.ts +51 -0
  373. package/src/core/agents/index.ts +14 -0
  374. package/src/core/agents/paths.ts +16 -0
  375. package/src/core/agents/render/prompt-context.ts +401 -0
  376. package/src/core/agents/render/session-context.ts +341 -0
  377. package/src/core/agents/rules/claim-conflict.ts +282 -0
  378. package/src/core/agents/rules/commit-conflict.ts +303 -0
  379. package/src/core/agents/rules/stop-hook.ts +229 -0
  380. package/src/core/agents/session-events.ts +228 -0
  381. package/src/core/agents/state/activity-log.ts +33 -0
  382. package/src/core/agents/state/council.ts +265 -0
  383. package/src/core/agents/state/heartbeat-projector.ts +488 -0
  384. package/src/core/agents/state/heartbeat-writer.ts +333 -0
  385. package/src/core/agents/state/names.ts +399 -0
  386. package/src/core/agents/state/pidmap.ts +38 -0
  387. package/src/core/agents/state/scratch.ts +121 -0
  388. package/src/core/agents/state/shell-mutation.ts +44 -0
  389. package/src/core/agents/state/stale-sweep.ts +190 -0
  390. package/src/core/config.ts +111 -0
  391. package/src/core/hooks/cli.ts +1247 -0
  392. package/src/core/hooks/effects/image-capture.ts +330 -0
  393. package/src/core/hooks/effects/index.ts +210 -0
  394. package/src/core/hooks/events/emit.ts +120 -0
  395. package/src/core/hooks/events/schema.ts +430 -0
  396. package/src/core/hooks/events/ulid.ts +51 -0
  397. package/src/core/hooks/harness/detect.ts +30 -0
  398. package/src/core/hooks/harness/events.ts +102 -0
  399. package/src/core/hooks/harness/output.ts +100 -0
  400. package/src/core/hooks/harness/parse.ts +180 -0
  401. package/src/core/hooks/index.ts +16 -0
  402. package/src/core/hooks/resolve/anchor.ts +51 -0
  403. package/src/core/hooks/resolve/coord-root.ts +25 -0
  404. package/src/core/hooks/resolve/intent.ts +89 -0
  405. package/src/core/hooks/resolve/owner.ts +140 -0
  406. package/src/core/hooks/resolve/transcript.ts +72 -0
  407. package/src/hooks/.gitkeep +0 -0
  408. package/src/index.ts +15 -0
  409. package/src/lib/agent-browser/client.ts +239 -0
  410. package/src/lib/agent-browser/index.ts +1 -0
  411. package/src/lib/browser/client.ts +449 -0
  412. package/src/lib/browser/dev-overlay.ts +207 -0
  413. package/src/lib/browser/index.ts +24 -0
  414. package/src/lib/browser/layout.ts +288 -0
  415. package/src/lib/browser/visibility.ts +419 -0
  416. package/src/lib/browser/visual-diff.ts +150 -0
  417. package/src/lib/completion/bash.ts +291 -0
  418. package/src/lib/completion/fish.ts +134 -0
  419. package/src/lib/completion/index.ts +10 -0
  420. package/src/lib/completion/walk.ts +184 -0
  421. package/src/lib/completion/zsh.ts +262 -0
  422. package/src/lib/context/index.ts +386 -0
  423. package/src/lib/cookies/client.ts +301 -0
  424. package/src/lib/cookies/index.ts +13 -0
  425. package/src/lib/council/index.ts +803 -0
  426. package/src/lib/docs-index.ts +216 -0
  427. package/src/lib/docs-lint.ts +413 -0
  428. package/src/lib/docs-sweep.ts +348 -0
  429. package/src/lib/docs.ts +199 -0
  430. package/src/lib/env.ts +12 -0
  431. package/src/lib/exec.ts +74 -0
  432. package/src/lib/format.ts +147 -0
  433. package/src/lib/http/client.ts +211 -0
  434. package/src/lib/http/index.ts +1 -0
  435. package/src/lib/identities/index.ts +210 -0
  436. package/src/lib/machine.ts +61 -0
  437. package/src/lib/presence.ts +154 -0
  438. package/src/lib/readability/client.ts +169 -0
  439. package/src/lib/readability/index.ts +5 -0
  440. package/src/lib/readability/turndown-plugin-gfm.d.ts +10 -0
  441. package/src/lib/scratch/index.ts +470 -0
  442. package/src/lib/tunnel/gate.ts +113 -0
  443. package/src/lib/tunnel/state.ts +167 -0
  444. package/src/web/.gitkeep +0 -0
  445. package/index.js +0 -1
@@ -0,0 +1,28 @@
1
+ export declare function initDocsContext(opts: {
2
+ repoRoot: string;
3
+ submodules: readonly string[];
4
+ }): void;
5
+ /**
6
+ * Regenerates index READMEs in docs/audits/ and docs/issues/ directories.
7
+ * Idempotent: safe to run on every commit. Reads the first ~30 lines of
8
+ * each dated file to extract title and (for issues) status.
9
+ *
10
+ * Preserves hand-written preambles. The command updates only the section
11
+ * between `<!-- BEGIN INDEX -->` and `<!-- END INDEX -->` markers. If a
12
+ * README exists without markers, the command refuses to overwrite it and
13
+ * reports it as `needs-markers` so the human can insert them explicitly.
14
+ * New READMEs (no file yet) are created with a minimal default preamble.
15
+ */
16
+ export interface IndexOpts {
17
+ dryRun?: boolean;
18
+ repo?: string;
19
+ }
20
+ export type IndexStatus = "unchanged" | "updated" | "needs-markers" | "created";
21
+ export interface IndexResult {
22
+ path: string;
23
+ status: IndexStatus;
24
+ before: string;
25
+ after: string;
26
+ }
27
+ export declare function runIndex(opts: IndexOpts): Promise<IndexResult[]>;
28
+ //# sourceMappingURL=docs-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-index.d.ts","sourceRoot":"","sources":["../../src/lib/docs-index.ts"],"names":[],"mappings":"AASA,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAG/F;AAcD;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAAC;AAEhF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAsHD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA+CtE"}
@@ -0,0 +1,169 @@
1
+ import { existsSync as __existsSyncForDocs } from "node:fs";
2
+ import { resolve as __resolveForDocs } from "node:path";
3
+ // Module-level docs context, initialized by initDocsContext() before any
4
+ // other function in this file is called. The repo root + submodule list
5
+ // are passed via the context provided to registerDocsCommand.
6
+ let REPO_ROOT = "";
7
+ let SUBMODULES = [];
8
+ export function initDocsContext(opts) {
9
+ REPO_ROOT = opts.repoRoot;
10
+ SUBMODULES = opts.submodules;
11
+ }
12
+ function submodulePath(name) {
13
+ return __resolveForDocs(REPO_ROOT, name);
14
+ }
15
+ function isSubmoduleInitialized(name) {
16
+ return __existsSyncForDocs(__resolveForDocs(REPO_ROOT, name, ".git"));
17
+ }
18
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
19
+ import { join, relative } from "node:path";
20
+ import { resolveBinName } from "../core/config.js";
21
+ const DATED_FILE_PATTERN = /^(\d{4}-\d{2}-\d{2})_([a-z0-9][a-z0-9_-]*)\.md$/i;
22
+ function extractTitle(content, fallbackSlug) {
23
+ const h1Match = content.match(/^#\s+(.+)$/m);
24
+ if (h1Match)
25
+ return h1Match[1].trim();
26
+ // Fallback: slug → Title Case
27
+ return fallbackSlug.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
28
+ }
29
+ function extractStatus(content) {
30
+ const head = content.split("\n").slice(0, 20).join("\n");
31
+ const match = head.match(/\*\*Status:\*\*\s*([a-zA-Z][a-zA-Z-]*)/);
32
+ return match ? match[1].toLowerCase() : undefined;
33
+ }
34
+ function readEntries(dir, includeStatus) {
35
+ if (!existsSync(dir))
36
+ return [];
37
+ const entries = [];
38
+ for (const f of readdirSync(dir)) {
39
+ if (f === "README.md")
40
+ continue;
41
+ const m = f.match(DATED_FILE_PATTERN);
42
+ if (!m)
43
+ continue;
44
+ const [, date, slug] = m;
45
+ let content = "";
46
+ try {
47
+ content = readFileSync(join(dir, f), "utf8");
48
+ }
49
+ catch {
50
+ continue;
51
+ }
52
+ entries.push({
53
+ file: f,
54
+ date: date,
55
+ title: extractTitle(content, slug),
56
+ status: includeStatus ? extractStatus(content) : undefined,
57
+ });
58
+ }
59
+ // Newest first
60
+ entries.sort((a, b) => b.date.localeCompare(a.date));
61
+ return entries;
62
+ }
63
+ function renderAuditsTable(entries) {
64
+ if (entries.length === 0)
65
+ return "_No audits recorded._\n";
66
+ const lines = ["| Date | File | Description |", "|------|------|-------------|"];
67
+ for (const e of entries) {
68
+ lines.push(`| ${e.date} | [${e.file}](${e.file}) | ${e.title} |`);
69
+ }
70
+ return `${lines.join("\n")}\n`;
71
+ }
72
+ function renderIssuesTable(entries) {
73
+ if (entries.length === 0)
74
+ return "_No issues recorded._\n";
75
+ const lines = [
76
+ "| Date | File | Status | Description |",
77
+ "|------|------|--------|-------------|",
78
+ ];
79
+ for (const e of entries) {
80
+ const status = e.status ?? "unknown";
81
+ lines.push(`| ${e.date} | [${e.file}](${e.file}) | ${status} | ${e.title} |`);
82
+ }
83
+ return `${lines.join("\n")}\n`;
84
+ }
85
+ const BEGIN_MARKER = "<!-- BEGIN INDEX -->";
86
+ const END_MARKER = "<!-- END INDEX -->";
87
+ function defaultPreamble(kind) {
88
+ const regen = `The table below is regenerated by \`${resolveBinName()} docs index\`; do not hand-edit it. Add prose above the \`BEGIN INDEX\` marker instead.`;
89
+ return kind === "audits"
90
+ ? [
91
+ "# Audit Documents",
92
+ "",
93
+ "Immutable, date-stamped reports. File names follow `YYYY-MM-DD_<slug>.md`.",
94
+ "",
95
+ regen,
96
+ "",
97
+ ].join("\n")
98
+ : [
99
+ "# Issues",
100
+ "",
101
+ "Date-stamped post-mortems and investigations. File names follow `YYYY-MM-DD_<slug>.md`.",
102
+ "Each file carries a `**Status:**` line (open | resolved | wontfix).",
103
+ "",
104
+ regen,
105
+ "",
106
+ ].join("\n");
107
+ }
108
+ /** Replace ONLY the section between the markers. Never touch content outside them. */
109
+ function spliceBetweenMarkers(existing, body) {
110
+ const beginIdx = existing.indexOf(BEGIN_MARKER);
111
+ const endIdx = existing.indexOf(END_MARKER);
112
+ if (beginIdx < 0 || endIdx < 0 || endIdx < beginIdx) {
113
+ // Caller should have checked hasMarkers() first; return unchanged as a safe fallback.
114
+ return existing;
115
+ }
116
+ const before = existing.slice(0, beginIdx + BEGIN_MARKER.length);
117
+ const after = existing.slice(endIdx);
118
+ return `${before}\n${body}${after}`;
119
+ }
120
+ function hasMarkers(existing) {
121
+ return existing.includes(BEGIN_MARKER) && existing.includes(END_MARKER);
122
+ }
123
+ function buildNewReadme(kind, body) {
124
+ return `${defaultPreamble(kind)}\n${BEGIN_MARKER}\n${body}${END_MARKER}\n`;
125
+ }
126
+ export async function runIndex(opts) {
127
+ const targets = [{ name: "(root)", path: REPO_ROOT }];
128
+ for (const name of SUBMODULES) {
129
+ if (!isSubmoduleInitialized(name))
130
+ continue;
131
+ targets.push({ name, path: submodulePath(name) });
132
+ }
133
+ const filter = opts.repo === "." ? "(root)" : opts.repo;
134
+ const filtered = filter ? targets.filter((t) => t.name === filter) : targets;
135
+ const results = [];
136
+ for (const { name: _name, path } of filtered) {
137
+ for (const kind of ["audits", "issues"]) {
138
+ const dir = join(path, "docs", kind);
139
+ if (!existsSync(dir))
140
+ continue;
141
+ const entries = readEntries(dir, kind === "issues");
142
+ const body = kind === "audits" ? renderAuditsTable(entries) : renderIssuesTable(entries);
143
+ const readmePath = join(dir, "README.md");
144
+ const exists = existsSync(readmePath);
145
+ const before = exists ? readFileSync(readmePath, "utf8") : "";
146
+ const displayPath = relative(REPO_ROOT, readmePath);
147
+ let status;
148
+ let after;
149
+ if (!exists) {
150
+ after = buildNewReadme(kind, body);
151
+ status = "created";
152
+ }
153
+ else if (!hasMarkers(before)) {
154
+ // Hands off: the human-written README has no markers. Don't touch it.
155
+ after = before;
156
+ status = "needs-markers";
157
+ }
158
+ else {
159
+ after = spliceBetweenMarkers(before, body);
160
+ status = before === after ? "unchanged" : "updated";
161
+ }
162
+ results.push({ path: displayPath, status, before, after });
163
+ if (!opts.dryRun && (status === "updated" || status === "created")) {
164
+ writeFileSync(readmePath, after, "utf8");
165
+ }
166
+ }
167
+ }
168
+ return results;
169
+ }
@@ -0,0 +1,26 @@
1
+ export declare function initDocsContext(opts: {
2
+ repoRoot: string;
3
+ submodules: readonly string[];
4
+ extraExcludedPrefixes?: readonly string[];
5
+ }): void;
6
+ /**
7
+ * Documentation linter. Enforces the docs directory-layout + naming contract.
8
+ *
9
+ * Each violation carries a severity: `error` fails the lint, `warning` is
10
+ * informational. `--fast` mode skips content-reading checks so the pre-commit
11
+ * hook stays cheap.
12
+ */
13
+ export type Severity = "error" | "warning";
14
+ export interface Violation {
15
+ severity: Severity;
16
+ repo: string;
17
+ path: string;
18
+ rule: string;
19
+ message: string;
20
+ }
21
+ export interface LintOpts {
22
+ fast?: boolean;
23
+ repo?: string;
24
+ }
25
+ export declare function runLint(opts: LintOpts): Promise<Violation[]>;
26
+ //# sourceMappingURL=docs-lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-lint.d.ts","sourceRoot":"","sources":["../../src/lib/docs-lint.ts"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,qBAAqB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,GAAG,IAAI,CAIP;AAaD;;;;;;GAMG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkVD,wBAAsB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAoBlE"}
@@ -0,0 +1,378 @@
1
+ import { existsSync as __existsSyncForDocs } from "node:fs";
2
+ import { resolve as __resolveForDocs } from "node:path";
3
+ import { sh } from "./exec.js";
4
+ // Module-level docs context, initialized by initDocsContext() before any
5
+ // other function in this file is called. Consumers pass repo metadata
6
+ // + an optional list of extra excluded path prefixes for project-specific
7
+ // directories that shouldn't be subject to doc-lint conventions.
8
+ let REPO_ROOT = "";
9
+ let SUBMODULES = [];
10
+ let EXTRA_EXCLUDED_PREFIXES = [];
11
+ export function initDocsContext(opts) {
12
+ REPO_ROOT = opts.repoRoot;
13
+ SUBMODULES = opts.submodules;
14
+ EXTRA_EXCLUDED_PREFIXES = opts.extraExcludedPrefixes ?? [];
15
+ }
16
+ function submodulePath(name) {
17
+ return __resolveForDocs(REPO_ROOT, name);
18
+ }
19
+ function isSubmoduleInitialized(name) {
20
+ return __existsSyncForDocs(__resolveForDocs(REPO_ROOT, name, ".git"));
21
+ }
22
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
23
+ import { basename, join } from "node:path";
24
+ /** Files allowed at a submodule root level. Includes:
25
+ * - In-repo conventions: README.md, CLAUDE.md, LLM-BRIEFING.md, AGENTS.md
26
+ * - GitHub OSS conventions: CHANGELOG.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md,
27
+ * SECURITY.md, SUPPORT.md, AUTHORS.md, MAINTAINERS.md, PULL_REQUEST_TEMPLATE.md
28
+ * (these are recognized by the GitHub UI, and renaming them breaks the integration)
29
+ */
30
+ const ROOT_FILE_ALLOWLIST = new Set([
31
+ "README.md",
32
+ "CLAUDE.md",
33
+ "LLM-BRIEFING.md",
34
+ "AGENTS.md",
35
+ // GitHub-recognized OSS package files
36
+ "CHANGELOG.md",
37
+ "CONTRIBUTING.md",
38
+ "CODE_OF_CONDUCT.md",
39
+ "SECURITY.md",
40
+ "SUPPORT.md",
41
+ "AUTHORS.md",
42
+ "MAINTAINERS.md",
43
+ "PULL_REQUEST_TEMPLATE.md",
44
+ ]);
45
+ /** Paths that are excluded from markdown discipline even when git-tracked.
46
+ *
47
+ * Covers auto-generated reference dumps and vendored content pages that happen
48
+ * to be checked into git but aren't subject to doc conventions. Paths are
49
+ * relative to the scanned repo root; any file under one of these prefixes is
50
+ * ignored.
51
+ *
52
+ * Note: git-ignored directories (node_modules, .venv, vendor, dbt_packages,
53
+ * target, dist, build) are already excluded because we use `git ls-files`.
54
+ */
55
+ // Built-in exclusions: auto-generated/framework dirs that ship in any
56
+ // project. Consumers extend this via `extraExcludedPrefixes` in
57
+ // initDocsContext for their own project-specific dirs (auto-generated
58
+ // API references, vendored content, etc.).
59
+ const EXCLUDED_PREFIXES = [
60
+ ".agents/", // canonical AI-config sources (skills, subagents, rules, claude-addendum)
61
+ ".claude/", // Claude Code framework files (SKILL.md, agents)
62
+ ".harnery/", // harnery coord/skill state
63
+ ".codex/", // OpenAI Codex framework files (skills/, agents/)
64
+ ".cursor/", // auto-generated Cursor rules
65
+ ];
66
+ /** Filename patterns that should never exist */
67
+ const FORBIDDEN_ROOT_NAMES = new Set([
68
+ "TODO.md",
69
+ "PROJECT.md",
70
+ "VISION.md",
71
+ "NOTES.md",
72
+ "DECISIONS.md", // should be docs/decisions.md
73
+ "CHANGELOG.md", // should be docs/changelogs/YYYY-MM.md
74
+ ]);
75
+ /** YYYY-MM-DD_<slug>.md */
76
+ const DATED_FILE_PATTERN = /^\d{4}-\d{2}-\d{2}_[a-z0-9][a-z0-9_-]*\.md$/i;
77
+ /** YYYY-MM.md for changelogs */
78
+ const CHANGELOG_PATTERN = /^\d{4}-\d{2}\.md$/;
79
+ /** SCREAMING_SNAKE_CASE.md, excluding allowlisted entry files */
80
+ const SCREAMING_SNAKE_PATTERN = /^[A-Z][A-Z0-9_]+\.md$/;
81
+ /** kebab-case.md: lowercase letters, digits, hyphens */
82
+ const KEBAB_CASE_PATTERN = /^[a-z0-9][a-z0-9-]*\.md$/;
83
+ /** Target repos to lint: parent + every initialized submodule */
84
+ function getTargetRepos(opts) {
85
+ const all = [
86
+ { name: "(root)", path: REPO_ROOT, isSubmodule: false },
87
+ ];
88
+ for (const name of SUBMODULES) {
89
+ if (!isSubmoduleInitialized(name))
90
+ continue;
91
+ all.push({ name, path: submodulePath(name), isSubmodule: true });
92
+ }
93
+ if (opts.repo) {
94
+ const filter = opts.repo === "." ? "(root)" : opts.repo;
95
+ return all.filter((r) => r.name === filter);
96
+ }
97
+ return all;
98
+ }
99
+ /** List all tracked .md files in the given repo via `git ls-files`.
100
+ * Returns paths relative to the repo root. Automatically skips node_modules,
101
+ * vendor, .venv, dbt_packages, build/ etc. because they're gitignored.
102
+ */
103
+ async function findMarkdownFiles(root) {
104
+ const result = await sh('git ls-files --cached "**/*.md" "*.md"', { cwd: root });
105
+ if (result.exitCode !== 0 || !result.stdout)
106
+ return [];
107
+ return result.stdout
108
+ .split("\n")
109
+ .filter((f) => f.endsWith(".md"))
110
+ .filter((f) =>
111
+ // Framework dirs are excluded at any depth, not just repo root;
112
+ // in-tree repos (monorepos like harnery) nest .claude/.agents/etc.
113
+ !EXCLUDED_PREFIXES.some((p) => f.startsWith(p) || f.includes(`/${p}`)) &&
114
+ !EXTRA_EXCLUDED_PREFIXES.some((p) => f.startsWith(p) || f.includes(`/${p}`)));
115
+ }
116
+ /** Read first N lines of a file for header inspection */
117
+ function readHead(path, lines = 20) {
118
+ try {
119
+ const content = readFileSync(path, "utf8");
120
+ return content.split("\n").slice(0, lines).join("\n");
121
+ }
122
+ catch {
123
+ return "";
124
+ }
125
+ }
126
+ /** Detect whether a file declares itself an intentional monolith */
127
+ function isDeclaredMonolith(path) {
128
+ const head = readHead(path, 10);
129
+ return /INTENTIONAL-MONOLITH/i.test(head);
130
+ }
131
+ /** Detect whether a file carries a Status line in its opening block */
132
+ function hasStatusHeader(path) {
133
+ const head = readHead(path, 15);
134
+ return /\*\*Status:\*\*/i.test(head);
135
+ }
136
+ // --- Individual checks ---
137
+ /** Entry tier files exist at the repo root */
138
+ function checkEntryTier(repoName, repoPath, isSubmodule) {
139
+ const violations = [];
140
+ // README.md is required for any repo
141
+ if (!existsSync(join(repoPath, "README.md"))) {
142
+ violations.push({
143
+ severity: "error",
144
+ repo: repoName,
145
+ path: join(repoName === "(root)" ? "" : repoName, "README.md"),
146
+ rule: "entry-tier",
147
+ message: "README.md missing at repo root",
148
+ });
149
+ }
150
+ // CLAUDE.md required for submodules (primary LLM context)
151
+ if (isSubmodule && !existsSync(join(repoPath, "CLAUDE.md"))) {
152
+ violations.push({
153
+ severity: "error",
154
+ repo: repoName,
155
+ path: join(repoName, "CLAUDE.md"),
156
+ rule: "entry-tier",
157
+ message: "CLAUDE.md missing: primary LLM context file",
158
+ });
159
+ }
160
+ return violations;
161
+ }
162
+ /** No forbidden root-level files */
163
+ function checkRootAllowlist(repoName, repoPath) {
164
+ const violations = [];
165
+ let entries;
166
+ try {
167
+ entries = readdirSync(repoPath);
168
+ }
169
+ catch {
170
+ return violations;
171
+ }
172
+ for (const entry of entries) {
173
+ if (!entry.endsWith(".md"))
174
+ continue;
175
+ if (ROOT_FILE_ALLOWLIST.has(entry))
176
+ continue;
177
+ const displayPath = join(repoName === "(root)" ? "" : repoName, entry);
178
+ if (FORBIDDEN_ROOT_NAMES.has(entry)) {
179
+ violations.push({
180
+ severity: "error",
181
+ repo: repoName,
182
+ path: displayPath,
183
+ rule: "forbidden-root-file",
184
+ message: `${entry} is not allowed at repo root`,
185
+ });
186
+ }
187
+ else if (SCREAMING_SNAKE_PATTERN.test(entry)) {
188
+ violations.push({
189
+ severity: "error",
190
+ repo: repoName,
191
+ path: displayPath,
192
+ rule: "root-caps-file",
193
+ message: `${entry} is an ad-hoc caps file at repo root: entry tier is reserved for README.md / CLAUDE.md / LLM-BRIEFING.md / AGENTS.md`,
194
+ });
195
+ }
196
+ }
197
+ return violations;
198
+ }
199
+ /** No SCREAMING_SNAKE_CASE filenames anywhere */
200
+ function checkNamingConvention(repoName, _repoPath, files) {
201
+ const violations = [];
202
+ for (const rel of files) {
203
+ const name = basename(rel);
204
+ // Allowlisted names
205
+ if (ROOT_FILE_ALLOWLIST.has(name))
206
+ continue;
207
+ // Dated files (audits/issues)
208
+ if (DATED_FILE_PATTERN.test(name))
209
+ continue;
210
+ // Changelogs
211
+ if (CHANGELOG_PATTERN.test(name))
212
+ continue;
213
+ // decisions.md, runbook.md: explicit
214
+ if (name === "decisions.md" || name === "runbook.md")
215
+ continue;
216
+ // Known-good kebab-case
217
+ if (KEBAB_CASE_PATTERN.test(name))
218
+ continue;
219
+ // README.md inside a subdir is fine
220
+ if (name === "README.md")
221
+ continue;
222
+ // SCREAMING_SNAKE_CASE violations
223
+ if (SCREAMING_SNAKE_PATTERN.test(name)) {
224
+ violations.push({
225
+ severity: "error",
226
+ repo: repoName,
227
+ path: join(repoName === "(root)" ? "" : repoName, rel),
228
+ rule: "screaming-snake-case",
229
+ message: `filename ${name} uses SCREAMING_SNAKE_CASE; rename to kebab-case`,
230
+ });
231
+ continue;
232
+ }
233
+ // Anything else that's not kebab-case is a warning (Title Case, mixed)
234
+ if (!/^[a-z0-9]/.test(name)) {
235
+ violations.push({
236
+ severity: "warning",
237
+ repo: repoName,
238
+ path: join(repoName === "(root)" ? "" : repoName, rel),
239
+ rule: "non-kebab-filename",
240
+ message: `filename ${name} is not kebab-case`,
241
+ });
242
+ }
243
+ }
244
+ return violations;
245
+ }
246
+ /** Files in docs/audits/ and docs/issues/ must match YYYY-MM-DD_<slug>.md */
247
+ function checkDatedDirs(repoName, _repoPath, files) {
248
+ const violations = [];
249
+ const datedDirs = ["docs/audits/", "docs/issues/"];
250
+ for (const rel of files) {
251
+ for (const d of datedDirs) {
252
+ if (!rel.startsWith(d))
253
+ continue;
254
+ const name = basename(rel);
255
+ // README.md is the index file, allowed
256
+ if (name === "README.md")
257
+ continue;
258
+ if (!DATED_FILE_PATTERN.test(name)) {
259
+ violations.push({
260
+ severity: "error",
261
+ repo: repoName,
262
+ path: join(repoName === "(root)" ? "" : repoName, rel),
263
+ rule: "undated-in-dated-dir",
264
+ message: `${d} file must match YYYY-MM-DD_<slug>.md; got ${name}`,
265
+ });
266
+ }
267
+ }
268
+ }
269
+ return violations;
270
+ }
271
+ /** Changelog files must match YYYY-MM.md */
272
+ function checkChangelogNames(repoName, _repoPath, files) {
273
+ const violations = [];
274
+ for (const rel of files) {
275
+ if (!rel.startsWith("docs/changelogs/"))
276
+ continue;
277
+ const name = basename(rel);
278
+ if (name === "README.md")
279
+ continue;
280
+ if (!CHANGELOG_PATTERN.test(name)) {
281
+ violations.push({
282
+ severity: "error",
283
+ repo: repoName,
284
+ path: join(repoName === "(root)" ? "" : repoName, rel),
285
+ rule: "bad-changelog-name",
286
+ message: `changelog must match YYYY-MM.md; got ${name}`,
287
+ });
288
+ }
289
+ }
290
+ return violations;
291
+ }
292
+ /** Plans and issues must carry a Status header (content check, slow) */
293
+ function checkStatusHeaders(repoName, repoPath, files) {
294
+ const violations = [];
295
+ const targetDirs = ["docs/plans/", "docs/issues/"];
296
+ for (const rel of files) {
297
+ const dirMatch = targetDirs.some((d) => rel.startsWith(d));
298
+ if (!dirMatch)
299
+ continue;
300
+ const name = basename(rel);
301
+ if (name === "README.md")
302
+ continue;
303
+ // Skip archive subdir
304
+ if (rel.includes("/archive/"))
305
+ continue;
306
+ const full = join(repoPath, rel);
307
+ if (!hasStatusHeader(full)) {
308
+ const kind = rel.startsWith("docs/plans/") ? "plan" : "issue";
309
+ violations.push({
310
+ severity: "warning",
311
+ repo: repoName,
312
+ path: join(repoName === "(root)" ? "" : repoName, rel),
313
+ rule: "missing-status-header",
314
+ message: `${kind} missing **Status:** line in opening block`,
315
+ });
316
+ }
317
+ }
318
+ return violations;
319
+ }
320
+ /** Intentional monoliths >30KB need a declaration banner */
321
+ function checkMonolithDeclaration(repoName, repoPath, files) {
322
+ const violations = [];
323
+ const SIZE_THRESHOLD = 30 * 1024;
324
+ for (const rel of files) {
325
+ // Only flag top-level docs/ files, not per-repo entry tier (LLM-BRIEFING
326
+ // files are monoliths by convention, no banner needed).
327
+ if (repoName !== "(root)")
328
+ continue;
329
+ if (!rel.startsWith("docs/"))
330
+ continue;
331
+ if (rel.startsWith("docs/plans/"))
332
+ continue;
333
+ if (rel.startsWith("docs/audits/"))
334
+ continue;
335
+ if (rel.startsWith("docs/issues/"))
336
+ continue;
337
+ if (rel.startsWith("docs/changelogs/"))
338
+ continue;
339
+ const full = join(repoPath, rel);
340
+ let size;
341
+ try {
342
+ size = statSync(full).size;
343
+ }
344
+ catch {
345
+ continue;
346
+ }
347
+ if (size < SIZE_THRESHOLD)
348
+ continue;
349
+ if (isDeclaredMonolith(full))
350
+ continue;
351
+ violations.push({
352
+ severity: "warning",
353
+ repo: repoName,
354
+ path: rel,
355
+ rule: "undeclared-monolith",
356
+ message: `${(size / 1024).toFixed(0)} KB file has no INTENTIONAL-MONOLITH banner; add one or split`,
357
+ });
358
+ }
359
+ return violations;
360
+ }
361
+ // --- Runner ---
362
+ export async function runLint(opts) {
363
+ const violations = [];
364
+ const repos = getTargetRepos(opts);
365
+ for (const { name, path, isSubmodule } of repos) {
366
+ violations.push(...checkEntryTier(name, path, isSubmodule));
367
+ violations.push(...checkRootAllowlist(name, path));
368
+ const files = await findMarkdownFiles(path);
369
+ violations.push(...checkNamingConvention(name, path, files));
370
+ violations.push(...checkDatedDirs(name, path, files));
371
+ violations.push(...checkChangelogNames(name, path, files));
372
+ if (!opts.fast) {
373
+ violations.push(...checkStatusHeaders(name, path, files));
374
+ violations.push(...checkMonolithDeclaration(name, path, files));
375
+ }
376
+ }
377
+ return violations;
378
+ }
@@ -0,0 +1,34 @@
1
+ export declare function initDocsContext(opts: {
2
+ repoRoot: string;
3
+ submodules: readonly string[];
4
+ }): void;
5
+ /**
6
+ * Surfaces stalled lifecycle states across the monorepo: plans in-progress
7
+ * too long, open issues gone cold, runbooks that haven't been verified, etc.
8
+ *
9
+ * This is the opposite of `docs --stale`, which flags file-level freshness.
10
+ * Sweep only flags items where the lifecycle state (status header + mtime)
11
+ * suggests attention is needed.
12
+ *
13
+ * Audit files and issue files under `docs/audits/` are explicitly **not**
14
+ * flagged for age; they're immutable records by design.
15
+ */
16
+ export interface SweepOpts {
17
+ repo?: string;
18
+ }
19
+ export interface SweepItem {
20
+ kind: SweepKind;
21
+ repo: string;
22
+ path: string;
23
+ ageDays: number;
24
+ message: string;
25
+ }
26
+ export type SweepKind = "stalled-plan" | "unarchived-shipped" | "open-issue-cold" | "cold-handoff" | "runbook-unverified" | "topic-doc-stale" | "decisions-dormant";
27
+ export declare function runSweep(opts: SweepOpts): Promise<SweepItem[]>;
28
+ /**
29
+ * Cheap parent-repo-only count of `cold-handoff` items, used by `docs lint`
30
+ * to print a one-line nudge without running the full sweep across every
31
+ * submodule (handoffs live under the parent's docs/handoffs/ by convention).
32
+ */
33
+ export declare function countColdHandoffs(): Promise<number>;
34
+ //# sourceMappingURL=docs-sweep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-sweep.d.ts","sourceRoot":"","sources":["../../src/lib/docs-sweep.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAG/F;AAaD;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GACjB,cAAc,GACd,oBAAoB,GACpB,iBAAiB,GACjB,cAAc,GACd,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,CAAC;AAgQxB,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAuBpE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIzD"}