harnery 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +494 -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 +32 -0
  316. package/dist/lib/readability/client.d.ts.map +1 -0
  317. package/dist/lib/readability/client.js +119 -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 +564 -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 +156 -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,333 @@
1
+ // Visibility / occlusion check primitive for `harn browse --check-visible`.
2
+ //
3
+ // The bug this exists to catch: a sticky-bottom composer strip painting over
4
+ // a `position: absolute; bottom: 208px` scroll-to-bottom pill, where every
5
+ // other check (element exists, has dimensions, is "in viewport") passes
6
+ // because the pill's bounding rect IS technically inside the visible area;
7
+ // it's just rendered behind another element.
8
+ //
9
+ // Mechanism: get the target's getBoundingClientRect, sample a grid of points
10
+ // inside it, call document.elementFromPoint(x, y) per sample, and count
11
+ // samples where the returned element is the target (or one of its
12
+ // descendants). visibleRatio = visibleSamples / validSamples. Report the
13
+ // dominant occluder for diagnostics.
14
+ /**
15
+ * Build the JS function passed to Playwright's `page.evaluate`. Returns
16
+ * a function reference (not a string) so Playwright serializes args
17
+ * properly. Caller invokes via `page.evaluate(fn, { selectors, sampleGrid })`.
18
+ */
19
+ export function buildVisibilityCheck() {
20
+ return ({ selectors, sampleGrid }) => {
21
+ function findHiddenAncestor(start) {
22
+ let cur = start;
23
+ while (cur) {
24
+ const cs = window.getComputedStyle(cur);
25
+ const tag = cur.tagName.toLowerCase();
26
+ const cls = typeof cur.className === "string" ? cur.className : (cur.getAttribute("class") ?? "");
27
+ const id = cur.id ?? "";
28
+ if (cs.display === "none") {
29
+ return {
30
+ reason: "display-none",
31
+ ancestorTag: tag,
32
+ ancestorClass: cls,
33
+ ancestorId: id,
34
+ propertyValue: "display: none",
35
+ };
36
+ }
37
+ if (cs.visibility === "hidden" || cs.visibility === "collapse") {
38
+ return {
39
+ reason: "visibility-hidden",
40
+ ancestorTag: tag,
41
+ ancestorClass: cls,
42
+ ancestorId: id,
43
+ propertyValue: `visibility: ${cs.visibility}`,
44
+ };
45
+ }
46
+ const op = Number.parseFloat(cs.opacity || "1");
47
+ if (op === 0) {
48
+ // Distinguish opacity:0 alone from opacity:0 + pointer-events:none.
49
+ // The latter is the "hidden-but-keeps-layout" pattern that
50
+ // also makes elementFromPoint skip the element and surface the
51
+ // wrong "occluded" answer.
52
+ const pe = cs.pointerEvents;
53
+ return {
54
+ reason: pe === "none" ? "pointer-events-none-with-opacity-zero" : "opacity-zero",
55
+ ancestorTag: tag,
56
+ ancestorClass: cls,
57
+ ancestorId: id,
58
+ propertyValue: `opacity: 0${pe === "none" ? "; pointer-events: none" : ""}`,
59
+ };
60
+ }
61
+ // contentVisibility is read via the style declaration since it's
62
+ // a property name with hyphens in the standard property list.
63
+ const cv = cs.contentVisibility;
64
+ if (cv === "hidden") {
65
+ return {
66
+ reason: "content-visibility-hidden",
67
+ ancestorTag: tag,
68
+ ancestorClass: cls,
69
+ ancestorId: id,
70
+ propertyValue: "content-visibility: hidden",
71
+ };
72
+ }
73
+ cur = cur.parentElement;
74
+ }
75
+ return null;
76
+ }
77
+ function checkOne(selector) {
78
+ const empty = {
79
+ selector,
80
+ found: false,
81
+ inViewport: false,
82
+ partiallyInViewport: false,
83
+ rect: { x: 0, y: 0, width: 0, height: 0 },
84
+ cssVisible: false,
85
+ hiddenBy: null,
86
+ visibleRatio: 0,
87
+ samples: [],
88
+ occludedBy: null,
89
+ elementOuterHTML: "",
90
+ };
91
+ const el = document.querySelector(selector);
92
+ if (!(el instanceof Element))
93
+ return empty;
94
+ const rect = el.getBoundingClientRect();
95
+ const vw = window.innerWidth;
96
+ const vh = window.innerHeight;
97
+ const inViewport = rect.top >= 0 && rect.bottom <= vh && rect.left >= 0 && rect.right <= vw;
98
+ const partiallyInViewport = !(rect.bottom <= 0 ||
99
+ rect.top >= vh ||
100
+ rect.right <= 0 ||
101
+ rect.left >= vw);
102
+ // CSS-level visibility check FIRST. Element.checkVisibility() is the
103
+ // standard primitive (Chromium 105+, Safari 17.4+, Firefox 125+); we
104
+ // also walk the ancestor chain to identify which property is hiding
105
+ // it. If the element is CSS-hidden, occlusion sampling is irrelevant,
106
+ // so short-circuit with visibleRatio=0 and skip the elementFromPoint
107
+ // calls (which would otherwise surface misleading "occluded by ..."
108
+ // answers when pointer-events:none is in play).
109
+ const checkVis = el
110
+ .checkVisibility;
111
+ const cssVisible = typeof checkVis === "function"
112
+ ? checkVis.call(el, {
113
+ contentVisibilityAuto: true,
114
+ opacityProperty: true,
115
+ visibilityProperty: true,
116
+ })
117
+ : (() => {
118
+ // Fallback for browsers without Element.checkVisibility:
119
+ // detect via the same ancestor walk we use to identify
120
+ // hiddenBy. cssVisible = (no ancestor in the chain hides it).
121
+ return findHiddenAncestor(el) === null;
122
+ })();
123
+ const hiddenBy = cssVisible ? null : findHiddenAncestor(el);
124
+ if (!cssVisible) {
125
+ return {
126
+ selector,
127
+ found: true,
128
+ inViewport,
129
+ partiallyInViewport,
130
+ rect: {
131
+ x: Math.round(rect.x),
132
+ y: Math.round(rect.y),
133
+ width: Math.round(rect.width),
134
+ height: Math.round(rect.height),
135
+ },
136
+ cssVisible: false,
137
+ hiddenBy,
138
+ visibleRatio: 0,
139
+ samples: [],
140
+ occludedBy: null,
141
+ elementOuterHTML: el.outerHTML.slice(0, 500),
142
+ };
143
+ }
144
+ const samples = [];
145
+ let visibleCount = 0;
146
+ let validCount = 0;
147
+ const occluderCounts = {};
148
+ for (let i = 1; i <= sampleGrid; i++) {
149
+ for (let j = 1; j <= sampleGrid; j++) {
150
+ const x = rect.left + (rect.width * i) / (sampleGrid + 1);
151
+ const y = rect.top + (rect.height * j) / (sampleGrid + 1);
152
+ if (x < 0 || x >= vw || y < 0 || y >= vh) {
153
+ samples.push({ x: Math.round(x), y: Math.round(y), status: "outside-viewport" });
154
+ continue;
155
+ }
156
+ validCount++;
157
+ const topEl = document.elementFromPoint(x, y);
158
+ if (!topEl) {
159
+ samples.push({ x: Math.round(x), y: Math.round(y), status: "no-element" });
160
+ continue;
161
+ }
162
+ // Visible if topmost element is the target itself OR one of its
163
+ // descendants (e.g. the pill button contains an SVG icon, so sampling
164
+ // the icon area still counts as the pill being visible).
165
+ const visible = topEl === el || el.contains(topEl);
166
+ if (visible) {
167
+ samples.push({ x: Math.round(x), y: Math.round(y), status: "visible" });
168
+ visibleCount++;
169
+ }
170
+ else {
171
+ const tag = topEl.tagName.toLowerCase();
172
+ const cls = typeof topEl.className === "string"
173
+ ? topEl.className
174
+ : (topEl.getAttribute("class") ?? "");
175
+ const key = `${tag}|${cls}`;
176
+ const existing = occluderCounts[key];
177
+ if (existing) {
178
+ existing.count++;
179
+ }
180
+ else {
181
+ occluderCounts[key] = {
182
+ count: 1,
183
+ firstX: x,
184
+ firstY: y,
185
+ };
186
+ }
187
+ samples.push({
188
+ x: Math.round(x),
189
+ y: Math.round(y),
190
+ status: "occluded",
191
+ occluderTag: tag,
192
+ occluderClass: cls,
193
+ });
194
+ }
195
+ }
196
+ }
197
+ let occludedBy = null;
198
+ const ranked = Object.entries(occluderCounts).sort((a, b) => b[1].count - a[1].count);
199
+ if (ranked.length > 0) {
200
+ const top = ranked[0];
201
+ const [, info] = top;
202
+ const occluderEl = document.elementFromPoint(info.firstX, info.firstY);
203
+ if (occluderEl instanceof Element) {
204
+ const cs = window.getComputedStyle(occluderEl);
205
+ const orect = occluderEl.getBoundingClientRect();
206
+ occludedBy = {
207
+ tagName: occluderEl.tagName.toLowerCase(),
208
+ className: typeof occluderEl.className === "string"
209
+ ? occluderEl.className
210
+ : (occluderEl.getAttribute("class") ?? ""),
211
+ id: occluderEl.id ?? "",
212
+ outerHTML: occluderEl.outerHTML.slice(0, 500),
213
+ computedStyles: {
214
+ position: cs.position,
215
+ zIndex: cs.zIndex,
216
+ backgroundColor: cs.backgroundColor,
217
+ },
218
+ rect: {
219
+ x: Math.round(orect.x),
220
+ y: Math.round(orect.y),
221
+ width: Math.round(orect.width),
222
+ height: Math.round(orect.height),
223
+ },
224
+ };
225
+ }
226
+ }
227
+ return {
228
+ selector,
229
+ found: true,
230
+ inViewport,
231
+ partiallyInViewport,
232
+ rect: {
233
+ x: Math.round(rect.x),
234
+ y: Math.round(rect.y),
235
+ width: Math.round(rect.width),
236
+ height: Math.round(rect.height),
237
+ },
238
+ cssVisible: true,
239
+ hiddenBy: null,
240
+ visibleRatio: validCount > 0 ? visibleCount / validCount : 0,
241
+ samples,
242
+ occludedBy,
243
+ elementOuterHTML: el.outerHTML.slice(0, 500),
244
+ };
245
+ }
246
+ return selectors.map(checkOne);
247
+ };
248
+ }
249
+ /**
250
+ * Build a script that injects overlay rectangles for each visibility result.
251
+ * Green border = target, red border = dominant occluder. Caller injects via
252
+ * `page.evaluate`, takes the screenshot, then clears via
253
+ * `buildClearAnnotationsScript`. Boxes are absolutely positioned at the
254
+ * target/occluder's `getBoundingClientRect()` location, so they survive
255
+ * scroll changes between sample-time and screenshot-time only if nothing
256
+ * has scrolled. The recommended flow is sample → annotate → screenshot →
257
+ * clear without intervening scrolls.
258
+ */
259
+ export function buildAnnotateScript() {
260
+ return ({ results }) => {
261
+ const ROOT_ID = "__bp-check-visible-annotations__";
262
+ document.getElementById(ROOT_ID)?.remove();
263
+ const root = document.createElement("div");
264
+ root.id = ROOT_ID;
265
+ root.style.cssText = "position: fixed; inset: 0; pointer-events: none; z-index: 2147483647;";
266
+ document.body.appendChild(root);
267
+ const drawBox = (rect, color, label) => {
268
+ const box = document.createElement("div");
269
+ box.style.cssText = `
270
+ position: absolute;
271
+ left: ${rect.x}px;
272
+ top: ${rect.y}px;
273
+ width: ${rect.width}px;
274
+ height: ${rect.height}px;
275
+ border: 2px solid ${color};
276
+ box-sizing: border-box;
277
+ background: ${color}1a;
278
+ pointer-events: none;
279
+ `;
280
+ const tag = document.createElement("div");
281
+ tag.textContent = label;
282
+ tag.style.cssText = `
283
+ position: absolute;
284
+ left: 0;
285
+ top: -18px;
286
+ background: ${color};
287
+ color: #fff;
288
+ font: 12px/1.4 -apple-system, system-ui, sans-serif;
289
+ padding: 1px 6px;
290
+ border-radius: 3px 3px 3px 0;
291
+ white-space: nowrap;
292
+ pointer-events: none;
293
+ `;
294
+ box.appendChild(tag);
295
+ root.appendChild(box);
296
+ };
297
+ for (const r of results) {
298
+ if (!r.found)
299
+ continue;
300
+ // Color the target by failure mode:
301
+ // green: cssVisible + visibleRatio>=0.9 (actually visible)
302
+ // red: cssVisible + visibleRatio<0.9 (occluded by sibling)
303
+ // magenta: !cssVisible (CSS-hidden via opacity/display/visibility/...)
304
+ let color;
305
+ let label;
306
+ if (!r.cssVisible) {
307
+ color = "#a855f7"; // tailwind purple-500
308
+ const hb = r.hiddenBy;
309
+ label = hb
310
+ ? `${r.selector} HIDDEN [${hb.reason}] via ${hb.ancestorTag}${hb.ancestorId ? `#${hb.ancestorId}` : ""}`
311
+ : `${r.selector} HIDDEN`;
312
+ }
313
+ else if (r.visibleRatio >= 0.9) {
314
+ color = "#10b981"; // tailwind emerald-500
315
+ label = `${r.selector} ratio=${(r.visibleRatio * 100).toFixed(0)}%`;
316
+ }
317
+ else {
318
+ color = "#ef4444"; // tailwind red-500
319
+ label = `${r.selector} ratio=${(r.visibleRatio * 100).toFixed(0)}%`;
320
+ }
321
+ drawBox(r.rect, color, label);
322
+ if (r.cssVisible && r.occludedBy && r.visibleRatio < 0.9) {
323
+ drawBox(r.occludedBy.rect, "#f59e0b", // amber-500
324
+ `occluder: ${r.occludedBy.tagName}${r.occludedBy.id ? `#${r.occludedBy.id}` : ""}`);
325
+ }
326
+ }
327
+ };
328
+ }
329
+ export function buildClearAnnotationsScript() {
330
+ return () => {
331
+ document.getElementById("__bp-check-visible-annotations__")?.remove();
332
+ };
333
+ }
@@ -0,0 +1,38 @@
1
+ declare const BASELINE_DIR: string;
2
+ export interface SaveBaselineResult {
3
+ name: string;
4
+ path: string;
5
+ bytes: number;
6
+ }
7
+ export interface DiffResult {
8
+ name: string;
9
+ baselinePath: string;
10
+ currentPath: string;
11
+ diffPath: string;
12
+ matched: boolean;
13
+ /** Pixels that differ between baseline and current beyond the threshold. */
14
+ mismatchedPixels: number;
15
+ totalPixels: number;
16
+ /** mismatchedPixels / totalPixels. Lower = more similar. 0 = identical. */
17
+ mismatchRatio: number;
18
+ similarity: number;
19
+ baselineDims: {
20
+ width: number;
21
+ height: number;
22
+ };
23
+ currentDims: {
24
+ width: number;
25
+ height: number;
26
+ };
27
+ /** True when baseline + current have different dimensions (auto-fail). */
28
+ sizeMismatch: boolean;
29
+ }
30
+ export declare function saveBaseline(currentPngPath: string, name: string): SaveBaselineResult;
31
+ export declare function diffAgainstBaseline(currentPngPath: string, name: string, opts?: {
32
+ threshold?: number;
33
+ diffOutputPath?: string;
34
+ }): DiffResult;
35
+ export declare function baselineExists(name: string): boolean;
36
+ export declare function listBaselines(): string[];
37
+ export { BASELINE_DIR };
38
+ //# sourceMappingURL=visual-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-diff.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/visual-diff.ts"],"names":[],"mappings":"AAiBA,QAAA,MAAM,YAAY,QAA8D,CAAC;AAEjF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAC;CACvB;AAWD,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAMrF;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,UAAU,CA+DZ;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpD;AAED,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAUxC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,107 @@
1
+ // Visual-regression primitive for `harn browse --baseline / --diff`. Captures
2
+ // the screenshot under a name + later pixel-diffs against it. Catches the
3
+ // class of regressions where every per-element check (visibility, console
4
+ // errors, network) passes but the rendered UI shifted/lost styling/regressed
5
+ // a hover state: the kind of thing a single human screenshot would have
6
+ // flagged immediately.
7
+ //
8
+ // pixelmatch (with pngjs decoding) is the pixel-diff workhorse: small, no
9
+ // native deps, ships an alpha-blended diff PNG and a mismatched-pixel count
10
+ // in one pass.
11
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
12
+ import { homedir } from "node:os";
13
+ import { dirname, resolve } from "node:path";
14
+ import pixelmatch from "pixelmatch";
15
+ import { PNG } from "pngjs";
16
+ const BASELINE_DIR = resolve(homedir(), ".cache", "harnery", "visual-baselines");
17
+ function baselinePath(name) {
18
+ if (!/^[a-zA-Z0-9_.-]+$/.test(name)) {
19
+ throw new Error(`Invalid baseline name '${name}'. Use alphanumeric + _ . - only (file-system-safe).`);
20
+ }
21
+ return resolve(BASELINE_DIR, `${name}.png`);
22
+ }
23
+ export function saveBaseline(currentPngPath, name) {
24
+ const dest = baselinePath(name);
25
+ mkdirSync(dirname(dest), { recursive: true });
26
+ const bytes = readFileSync(currentPngPath);
27
+ writeFileSync(dest, bytes);
28
+ return { name, path: dest, bytes: bytes.length };
29
+ }
30
+ export function diffAgainstBaseline(currentPngPath, name, opts = {}) {
31
+ const basePath = baselinePath(name);
32
+ if (!existsSync(basePath)) {
33
+ throw new Error(`No baseline named '${name}' at ${basePath}. Save one first with --baseline ${name}.`);
34
+ }
35
+ const baselineBuf = readFileSync(basePath);
36
+ const currentBuf = readFileSync(currentPngPath);
37
+ const baseline = PNG.sync.read(baselineBuf);
38
+ const current = PNG.sync.read(currentBuf);
39
+ const sizeMismatch = baseline.width !== current.width || baseline.height !== current.height;
40
+ const diffPath = opts.diffOutputPath ?? `${currentPngPath.replace(/\.png$/i, "")}-diff.png`;
41
+ mkdirSync(dirname(diffPath), { recursive: true });
42
+ if (sizeMismatch) {
43
+ // Different dimensions: pixelmatch can't compare directly. Write a
44
+ // placeholder diff that's just the current image with a banner; report
45
+ // the size delta in the result so the caller knows what's up.
46
+ writeFileSync(diffPath, currentBuf);
47
+ return {
48
+ name,
49
+ baselinePath: basePath,
50
+ currentPath: currentPngPath,
51
+ diffPath,
52
+ matched: false,
53
+ mismatchedPixels: current.width * current.height,
54
+ totalPixels: current.width * current.height,
55
+ mismatchRatio: 1,
56
+ similarity: 0,
57
+ baselineDims: { width: baseline.width, height: baseline.height },
58
+ currentDims: { width: current.width, height: current.height },
59
+ sizeMismatch: true,
60
+ };
61
+ }
62
+ const { width, height } = baseline;
63
+ const diff = new PNG({ width, height });
64
+ const mismatchedPixels = pixelmatch(baseline.data, current.data, diff.data, width, height, {
65
+ threshold: opts.threshold ?? 0.1, // pixelmatch's per-pixel tolerance (YIQ color delta)
66
+ includeAA: false,
67
+ });
68
+ writeFileSync(diffPath, PNG.sync.write(diff));
69
+ const totalPixels = width * height;
70
+ const mismatchRatio = mismatchedPixels / totalPixels;
71
+ return {
72
+ name,
73
+ baselinePath: basePath,
74
+ currentPath: currentPngPath,
75
+ diffPath,
76
+ matched: mismatchedPixels === 0,
77
+ mismatchedPixels,
78
+ totalPixels,
79
+ mismatchRatio,
80
+ similarity: 1 - mismatchRatio,
81
+ baselineDims: { width, height },
82
+ currentDims: { width: current.width, height: current.height },
83
+ sizeMismatch: false,
84
+ };
85
+ }
86
+ export function baselineExists(name) {
87
+ try {
88
+ return existsSync(baselinePath(name));
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ export function listBaselines() {
95
+ if (!existsSync(BASELINE_DIR))
96
+ return [];
97
+ try {
98
+ return readdirSync(BASELINE_DIR)
99
+ .filter((f) => f.endsWith(".png"))
100
+ .map((f) => f.replace(/\.png$/, ""))
101
+ .sort();
102
+ }
103
+ catch {
104
+ return [];
105
+ }
106
+ }
107
+ export { BASELINE_DIR };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Bash completion generator. Walks a CommandSpec tree and emits a single
3
+ * self-contained bash function `_<bin>` plus the `complete -F _<bin> <bin>`
4
+ * directive that registers it. The bin name is injected by the caller so the
5
+ * same generator serves any host CLI.
6
+ *
7
+ * Generated script architecture:
8
+ * 1. `_<bin>_path()`: walks COMP_WORDS forward, skipping options and option
9
+ * values, returns the current command-path string (e.g., "anthropic cost").
10
+ * 2. `_<bin>_options()` / `_<bin>_subcommands()` / `_<bin>_option_takes_value()` /
11
+ * `_<bin>_option_choices()`: table-lookup functions, generated as big
12
+ * case statements from the spec tree.
13
+ * 3. `_<bin>()`: main entry. Sets COMPREPLY based on whether the cursor is
14
+ * on a subcommand name, option name (--<TAB>), or value.
15
+ * 4. Dynamic value paths shell out to `<bin> __complete <provider> -- "$cur"`.
16
+ *
17
+ * Important escaping rules:
18
+ * - Single-quoted strings in bash don't honor escapes. We replace `'` in
19
+ * descriptions/choices with `'\''` (the standard bash single-quote escape).
20
+ * - We avoid descriptions in bash output because bash COMPREPLY can't render
21
+ * them; descriptions are a zsh/fish feature.
22
+ */
23
+ import type { CommandSpec } from "./walk.js";
24
+ export declare function generateBash(root: CommandSpec, binName: string): string;
25
+ //# sourceMappingURL=bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/lib/completion/bash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,WAAW,CAAC;AAuBzE,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA2FvE"}