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,46 @@
1
+ import { readFileSync, writeFileSync } from "node:fs";
2
+ import { resolveBinName } from "../core/config.js";
3
+ import { htmlToMarkdown } from "../lib/readability/index.js";
4
+ // Module-scoped emit assigned by registerReadCommand. Same pattern as cookies.ts:
5
+ // the runRead helper closes over this so the .action callback stays concise.
6
+ let emit;
7
+ /**
8
+ * `harn read`: extract clean readable markdown from HTML.
9
+ */
10
+ export function registerReadCommand(program, emitParam) {
11
+ emit = emitParam;
12
+ program
13
+ .command("read [html-file]")
14
+ .description(`Extract clean readable markdown from HTML. Reads from file or stdin (use '-'). Pair with \`${resolveBinName()} fetch\` or \`${resolveBinName()} browse\` for scrape-to-markdown.`)
15
+ .option("-o, --output <file>", "Write markdown to file instead of stdout")
16
+ .option("--url <url>", "Base URL: used to resolve relative links")
17
+ .option("--selector <css>", "Use this CSS selector instead of Readability (fallback when extraction misses content)")
18
+ .option("--raw", "Output cleaned HTML instead of markdown (debugging)")
19
+ .option("--max-chars <n>", "Truncate output to N characters (0 = disable)", "100000")
20
+ .action(async (htmlFile, opts) => {
21
+ try {
22
+ await runRead(htmlFile, opts);
23
+ }
24
+ catch (err) {
25
+ const msg = err instanceof Error ? err.message : String(err);
26
+ emit.error({ code: "read_error", message: msg });
27
+ process.exit(1);
28
+ }
29
+ });
30
+ }
31
+ async function runRead(htmlFile, opts) {
32
+ const input = htmlFile && htmlFile !== "-" ? readFileSync(htmlFile, "utf-8") : readFileSync(0, "utf-8");
33
+ const result = await htmlToMarkdown(input, {
34
+ url: opts.url,
35
+ selector: opts.selector,
36
+ raw: opts.raw,
37
+ maxChars: Number.parseInt(opts.maxChars, 10),
38
+ });
39
+ if (opts.output) {
40
+ writeFileSync(opts.output, result.output);
41
+ emit.file(opts.output, { chars: result.output.length });
42
+ }
43
+ else {
44
+ emit.text(result.output);
45
+ }
46
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext } from "../commander.js";
3
+ export declare function registerScratchCommand(program: Command, emitParam: EmitContext): void;
4
+ //# sourceMappingURL=scratch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scratch.d.ts","sourceRoot":"","sources":["../../src/commands/scratch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA6BnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,GAAG,IAAI,CA2RrF"}
@@ -0,0 +1,426 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync, unlinkSync, watch } from "node:fs";
2
+ import { resolve as resolvePath } from "node:path";
3
+ import { emitCanonical, normalizeHarness, readHeartbeat } from "../core/agents/index.js";
4
+ import { resolveBinName } from "../core/config.js";
5
+ import { appendEntry, archiveScratch, currentOwnerOrThrow, lintScratch, listArchives, loadScratch, parseScratch, pruneArchives, resolveOwnerByName, SCRATCH_CATEGORIES, scratchDir, scratchPath, sweepOrphanScratchpads, } from "../lib/scratch/index.js";
6
+ /**
7
+ * `harn scratch`: per-agent markdown journal at `.harnery/scratch/<instance_id>.md`.
8
+ * Used both for self-notes (surviving compaction) and peer coordination (other
9
+ * agents pull-read it on demand). SessionEnd hook archives; SessionStart
10
+ * janitor surfaces the most-recent archive as a recovery cue.
11
+ */
12
+ let emit;
13
+ export function registerScratchCommand(program, emitParam) {
14
+ emit = emitParam;
15
+ const root = program
16
+ .command("scratch")
17
+ .description("Per-agent markdown journal: append-only timestamped entries. " +
18
+ "Survives in-session compaction, archived at session end, pruned after 7 days.");
19
+ // ── add ───────────────────────────────────────────────────────────────
20
+ root
21
+ .command("add <category> <text...>")
22
+ .description(`Append an entry to my scratchpad. Category: ${SCRATCH_CATEGORIES.join(" | ")}`)
23
+ .action((category, text) => {
24
+ const cat = validateCategory(category);
25
+ const body = text.join(" ");
26
+ if (!body.trim()) {
27
+ emit.error({ code: "empty_body", message: "scratch add: body is empty" });
28
+ process.exit(1);
29
+ }
30
+ try {
31
+ const owner = currentOwnerOrThrow();
32
+ const doc = appendEntry(owner, cat, body);
33
+ const hb = readHeartbeat(owner);
34
+ emitCanonical({
35
+ type: "state.scratch_append",
36
+ owner,
37
+ session: hb?.session_id ?? owner,
38
+ harness: normalizeHarness(hb?.platform),
39
+ data: {
40
+ category: cat,
41
+ body_summary: body.length > 1000 ? `${body.slice(0, 997)}...` : body,
42
+ },
43
+ });
44
+ emit.data({
45
+ instance_id: owner,
46
+ name: doc.header.name,
47
+ category: cat,
48
+ entries: doc.entries.length,
49
+ bytes: doc.bytes,
50
+ path: doc.path,
51
+ });
52
+ }
53
+ catch (err) {
54
+ emit.error({ code: "add_failed", message: err.message });
55
+ process.exit(1);
56
+ }
57
+ });
58
+ // ── read ──────────────────────────────────────────────────────────────
59
+ root
60
+ .command("read")
61
+ .description("Render a scratchpad to stdout. No --name: my own. With --name: a peer's.")
62
+ .option("--name <name>", "Read the named peer's scratchpad (case-insensitive)")
63
+ .option("--owner <id>", "Read by instance_id directly")
64
+ .option("--archive <basename>", "Read an archive file (e.g. <owner>-<ts>.md)")
65
+ .option("--limit <n>", "Cap entries rendered (newest first)", "50")
66
+ .action((opts) => {
67
+ try {
68
+ runRead(opts);
69
+ }
70
+ catch (err) {
71
+ emit.error({ code: "read_failed", message: err.message });
72
+ process.exit(1);
73
+ }
74
+ });
75
+ // ── list ──────────────────────────────────────────────────────────────
76
+ root
77
+ .command("list")
78
+ .description("Summarize all active scratchpads + archive count")
79
+ .option("--archives", "List archive files instead of active scratchpads")
80
+ .action((opts) => {
81
+ try {
82
+ if (opts.archives) {
83
+ const items = listArchives().map((a) => {
84
+ const doc = parseSafe(a.path);
85
+ const lastEntry = doc?.entries[0];
86
+ const ageMin = Math.floor((Date.now() - a.mtimeMs) / 60000);
87
+ return {
88
+ basename: a.basename,
89
+ name: doc?.header.name ?? "unknown",
90
+ entries: doc?.entries.length ?? 0,
91
+ bytes: a.bytes,
92
+ archived_min_ago: ageMin,
93
+ last_category: lastEntry?.category ?? null,
94
+ last_ts: lastEntry?.ts_display ?? null,
95
+ };
96
+ });
97
+ emit.data({ rows: items });
98
+ return;
99
+ }
100
+ const dir = scratchDir();
101
+ const rows = [];
102
+ for (const f of readdirSync(dir)) {
103
+ if (!f.endsWith(".md"))
104
+ continue;
105
+ const instanceId = f.replace(/\.md$/, "");
106
+ const doc = loadScratch(instanceId);
107
+ if (!doc)
108
+ continue;
109
+ rows.push({
110
+ instance_id: instanceId,
111
+ name: doc.header.name,
112
+ entries: doc.entries.length,
113
+ bytes: doc.bytes,
114
+ last_category: doc.entries[0]?.category ?? null,
115
+ last_ts: doc.entries[0]?.ts_display ?? null,
116
+ });
117
+ }
118
+ rows.sort((a, b) => (b.last_ts ?? "").localeCompare(a.last_ts ?? ""));
119
+ emit.data({ rows });
120
+ }
121
+ catch (err) {
122
+ emit.error({ code: "list_failed", message: err.message });
123
+ process.exit(1);
124
+ }
125
+ });
126
+ // ── tail ──────────────────────────────────────────────────────────────
127
+ root
128
+ .command("tail")
129
+ .description("Follow my scratchpad (or a peer's) for new entries.")
130
+ .option("--name <name>", "Tail the named peer's scratchpad")
131
+ .option("--owner <id>", "Tail by instance_id directly")
132
+ .action(async (opts) => {
133
+ try {
134
+ const owner = resolveTargetOwner(opts);
135
+ const path = scratchPath(owner);
136
+ if (!existsSync(path)) {
137
+ emit.error({ code: "no_scratchpad", message: `no scratchpad at ${path} yet` });
138
+ process.exit(1);
139
+ }
140
+ process.stderr.write(`tailing ${path}\n`); // lint-ok-emission: tail banner, immediate stderr flush before streaming
141
+ let lastSize = statSync(path).size;
142
+ // Print initial render
143
+ process.stdout.write(`${renderScratch(loadScratch(owner), 10)}\n`); // lint-ok-emission: streaming tail body
144
+ const w = watch(path, { persistent: true }, () => {
145
+ try {
146
+ const curr = statSync(path).size;
147
+ if (curr === lastSize)
148
+ return;
149
+ lastSize = curr;
150
+ const doc = loadScratch(owner);
151
+ if (!doc)
152
+ return;
153
+ const newest = doc.entries[0];
154
+ if (!newest)
155
+ return;
156
+ const line = `\n## ${newest.ts_display} · ${newest.category}\n${newest.body}\n`;
157
+ process.stdout.write(line); // lint-ok-emission: streaming tail, per-line stdout flush, no envelope wrap
158
+ }
159
+ catch {
160
+ // ignore transient
161
+ }
162
+ });
163
+ await new Promise((resolveP) => {
164
+ const stop = () => {
165
+ w.close();
166
+ resolveP();
167
+ };
168
+ process.on("SIGINT", stop);
169
+ process.on("SIGTERM", stop);
170
+ });
171
+ }
172
+ catch (err) {
173
+ emit.error({ code: "tail_failed", message: err.message });
174
+ process.exit(1);
175
+ }
176
+ });
177
+ // ── clear ─────────────────────────────────────────────────────────────
178
+ root
179
+ .command("clear")
180
+ .description("Delete my scratchpad (rare; mainly for testing)")
181
+ .option("--yes", "Confirm deletion")
182
+ .action((opts) => {
183
+ if (!opts.yes) {
184
+ emit.error({ code: "needs_yes", message: "pass --yes to confirm" });
185
+ process.exit(1);
186
+ }
187
+ try {
188
+ const owner = currentOwnerOrThrow();
189
+ const path = scratchPath(owner);
190
+ if (existsSync(path)) {
191
+ unlinkSync(path);
192
+ emit.data({ cleared: true, path });
193
+ }
194
+ else {
195
+ emit.data({ cleared: false, path, reason: "did not exist" });
196
+ }
197
+ }
198
+ catch (err) {
199
+ emit.error({ code: "clear_failed", message: err.message });
200
+ process.exit(1);
201
+ }
202
+ });
203
+ // ── lint ──────────────────────────────────────────────────────────────
204
+ root
205
+ .command("lint")
206
+ .description("Validate scratchpad format + size")
207
+ .option("--all", "Lint every scratchpad in .harnery/scratch/")
208
+ .option("--owner <id>", "Lint a specific owner's scratchpad")
209
+ .action((opts) => {
210
+ try {
211
+ runLint(opts);
212
+ }
213
+ catch (err) {
214
+ emit.error({ code: "lint_failed", message: err.message });
215
+ process.exit(1);
216
+ }
217
+ });
218
+ // ── archive (manual / hook helper) ────────────────────────────────────
219
+ root
220
+ .command("archive")
221
+ .description("Archive my scratchpad now (idempotent; fired by SessionEnd hook)")
222
+ .option("--owner <id>", "Archive a specific owner's scratchpad")
223
+ .action((opts) => {
224
+ try {
225
+ const owner = opts.owner ?? currentOwnerOrThrow();
226
+ const dest = archiveScratch(owner);
227
+ emit.data({ instance_id: owner, archived: !!dest, path: dest });
228
+ }
229
+ catch (err) {
230
+ emit.error({ code: "archive_failed", message: err.message });
231
+ process.exit(1);
232
+ }
233
+ });
234
+ // ── recovery-cue (SessionStart hook helper) ───────────────────────────
235
+ root
236
+ .command("recovery-cue")
237
+ .description("Emit a one-line recovery hint to stdout when a recent archive exists. " +
238
+ "Used by SessionStart hook to surface 'previous session was doing X'. " +
239
+ "Stays silent when no relevant archive (no noise on fresh sessions).")
240
+ .option("--max-age-hours <n>", "Only surface archives newer than this", "24")
241
+ .action((opts) => {
242
+ try {
243
+ const maxHours = Number.parseInt(opts.maxAgeHours, 10);
244
+ const archives = listArchives();
245
+ if (archives.length === 0)
246
+ return;
247
+ const newest = archives[0];
248
+ const ageHours = (Date.now() - newest.mtimeMs) / 3600_000;
249
+ if (ageHours > maxHours)
250
+ return;
251
+ const doc = parseSafe(newest.path);
252
+ if (!doc || doc.entries.length === 0)
253
+ return;
254
+ const last = doc.entries[0];
255
+ const ageMin = Math.floor((Date.now() - newest.mtimeMs) / 60_000);
256
+ const ageStr = ageMin < 60 ? `${ageMin}m` : `${Math.floor(ageMin / 60)}h ${ageMin % 60}m`;
257
+ const bodyOneLine = last.body.replace(/\s+/g, " ").trim();
258
+ const bodyTrunc = bodyOneLine.length > 100 ? `${bodyOneLine.slice(0, 99)}…` : bodyOneLine;
259
+ const cue = `Recent scratchpad archive (${ageStr} ago): agent-${doc.header.name}: ` +
260
+ `last entry [${last.category}] "${bodyTrunc}". ` +
261
+ `Read full: \`${resolveBinName()} scratch read --archive ${newest.basename}\`.`;
262
+ process.stdout.write(`${cue}\n`); // lint-ok-emission: bash hook reads stdout to compose SessionStart additionalContext
263
+ }
264
+ catch (_err) {
265
+ // Recovery cue is best-effort; never fail the SessionStart hook.
266
+ }
267
+ });
268
+ // ── janitor (SessionStart hook) ───────────────────────────────────────
269
+ root
270
+ .command("janitor")
271
+ .description("Prune old archives + sweep orphan scratchpads (heartbeat gone). Fired by SessionStart hook.")
272
+ .option("--days <n>", "Archive retention in days", "7")
273
+ .option("--quiet", "Suppress stdout output")
274
+ .action((opts) => {
275
+ try {
276
+ const days = Number.parseInt(opts.days, 10);
277
+ const swept = sweepOrphanScratchpads();
278
+ const pruned = pruneArchives(days);
279
+ if (!opts.quiet) {
280
+ emit.data({
281
+ archives_pruned: pruned,
282
+ orphans_swept: swept.length,
283
+ orphans: swept,
284
+ });
285
+ }
286
+ }
287
+ catch (err) {
288
+ emit.error({ code: "janitor_failed", message: err.message });
289
+ process.exit(1);
290
+ }
291
+ });
292
+ }
293
+ // ─── runRead ──────────────────────────────────────────────────────────────
294
+ function runRead(opts) {
295
+ const limit = Number.parseInt(opts.limit, 10);
296
+ if (opts.archive) {
297
+ const dir = scratchDir();
298
+ const path = resolvePath(dir, "archived", opts.archive);
299
+ if (!existsSync(path)) {
300
+ emit.error({ code: "no_archive", message: `archive not found: ${opts.archive}` });
301
+ process.exit(1);
302
+ }
303
+ const content = readFileSync(path, "utf8");
304
+ process.stdout.write(content); // lint-ok-emission: archive render, file content is already the rendered form
305
+ return;
306
+ }
307
+ const owner = resolveTargetOwner(opts);
308
+ const doc = loadScratch(owner);
309
+ if (!doc) {
310
+ emit.error({
311
+ code: "no_scratchpad",
312
+ message: `no scratchpad for owner=${owner.slice(0, 8)}… (file not created yet)`,
313
+ });
314
+ process.exit(1);
315
+ }
316
+ const hb = readHeartbeat(owner);
317
+ const staleBanner = renderStaleBannerIfNeeded(hb?.last_heartbeat);
318
+ process.stdout.write(`${staleBanner + renderScratch(doc, limit)}\n`); // lint-ok-emission: pretty render, multi-line markdown for direct TTY/pipe consumption
319
+ }
320
+ function runLint(opts) {
321
+ const dir = scratchDir();
322
+ const files = [];
323
+ if (opts.owner) {
324
+ files.push(scratchPath(opts.owner));
325
+ }
326
+ else if (opts.all) {
327
+ for (const f of readdirSync(dir)) {
328
+ if (f.endsWith(".md"))
329
+ files.push(resolvePath(dir, f));
330
+ }
331
+ }
332
+ else {
333
+ const owner = currentOwnerOrThrow();
334
+ files.push(scratchPath(owner));
335
+ }
336
+ let totalIssues = 0;
337
+ const reports = [];
338
+ for (const path of files) {
339
+ if (!existsSync(path)) {
340
+ reports.push({ path, issues: [{ line: 0, message: "(file does not exist)" }] });
341
+ continue;
342
+ }
343
+ const content = readFileSync(path, "utf8");
344
+ const issues = lintScratch(content);
345
+ if (issues.length > 0)
346
+ totalIssues += issues.length;
347
+ reports.push({ path, issues });
348
+ }
349
+ emit.data({ files: reports.length, total_issues: totalIssues, reports });
350
+ if (totalIssues > 0)
351
+ process.exit(1);
352
+ }
353
+ // ─── Helpers ──────────────────────────────────────────────────────────────
354
+ function validateCategory(c) {
355
+ if (!SCRATCH_CATEGORIES.includes(c)) {
356
+ emit.error({
357
+ code: "bad_category",
358
+ message: `category must be one of: ${SCRATCH_CATEGORIES.join(", ")}`,
359
+ });
360
+ process.exit(1);
361
+ }
362
+ return c;
363
+ }
364
+ function resolveTargetOwner(opts) {
365
+ if (opts.owner)
366
+ return opts.owner;
367
+ if (opts.name) {
368
+ const id = resolveOwnerByName(opts.name);
369
+ if (!id) {
370
+ emit.error({
371
+ code: "no_match",
372
+ message: `no live agent named "${opts.name}". Try \`${resolveBinName()} agents list\`.`,
373
+ });
374
+ process.exit(1);
375
+ }
376
+ return id;
377
+ }
378
+ return currentOwnerOrThrow();
379
+ }
380
+ function renderScratch(doc, limit) {
381
+ const lines = [];
382
+ lines.push(`# Scratchpad: agent-${doc.header.name}`);
383
+ if (doc.header.session_id)
384
+ lines.push(`session_id: ${doc.header.session_id}`);
385
+ if (doc.header.machine)
386
+ lines.push(`machine: ${doc.header.machine}`);
387
+ if (doc.header.started)
388
+ lines.push(`started: ${doc.header.started}`);
389
+ if (doc.header.last_updated)
390
+ lines.push(`last_updated: ${doc.header.last_updated}`);
391
+ lines.push("\n---\n");
392
+ for (const entry of doc.entries.slice(0, limit)) {
393
+ lines.push(`## ${entry.ts_display} · ${entry.category}`);
394
+ if (entry.body)
395
+ lines.push(entry.body);
396
+ lines.push("");
397
+ }
398
+ if (doc.entries.length > limit) {
399
+ lines.push(`(+${doc.entries.length - limit} older entries; raise --limit to see them)`);
400
+ }
401
+ return lines.join("\n").trimEnd();
402
+ }
403
+ const FRESHNESS_SECS = 600;
404
+ function renderStaleBannerIfNeeded(lastHeartbeat) {
405
+ if (!lastHeartbeat)
406
+ return "";
407
+ const ts = Date.parse(lastHeartbeat);
408
+ if (!Number.isFinite(ts))
409
+ return "";
410
+ const ageSec = Math.floor((Date.now() - ts) / 1000);
411
+ if (ageSec < FRESHNESS_SECS)
412
+ return "";
413
+ const m = Math.floor(ageSec / 60);
414
+ return `[STALE: heartbeat ${m}m old, agent may be dead]\n\n`;
415
+ }
416
+ function parseSafe(path) {
417
+ try {
418
+ if (!existsSync(path))
419
+ return null;
420
+ const content = readFileSync(path, "utf8");
421
+ return parseScratch(path, content);
422
+ }
423
+ catch {
424
+ return null;
425
+ }
426
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext } from "../commander.js";
3
+ export declare function registerSessionCommand(program: Command, emitParam: EmitContext): void;
4
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/commands/session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAsCnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,GAAG,IAAI,CAsDrF"}
@@ -0,0 +1,162 @@
1
+ import { spawn } from "node:child_process";
2
+ import { resolveOwner, selfDisplayName } from "../core/agents/index.js";
3
+ import { clampField, newCmdId, readLastIntent, writeSessionEvent, } from "../core/agents/session-events.js";
4
+ import { resolveBinName } from "../core/config.js";
5
+ /** Strip the `agent-` prefix so structured event `agent` field matches heartbeat.name. */
6
+ function bareAgentName() {
7
+ const full = selfDisplayName();
8
+ return full.startsWith("agent-") ? full.slice(6) : full;
9
+ }
10
+ function selfOwnerId() {
11
+ return resolveOwner() ?? undefined;
12
+ }
13
+ /**
14
+ * `harn session`: run a command (or narrate) and emit canonical coordination
15
+ * events for follow-along.
16
+ *
17
+ * Follow-along happens through the canonical `.harnery/events.ndjson` stream +
18
+ * the `/live` web viewer (or `harn agents watch`): `harn session -- <cmd>` runs
19
+ * the command, forwards its output to the terminal verbatim, and emits canonical
20
+ * `command.start/output/end`; `harn session log` emits a canonical `narration`
21
+ * event. The file-management subcommands (`tail`/`clear`/`trim`/`path`) are
22
+ * retired no-op stubs; `trim` is a silent no-op so a SessionStart hook that
23
+ * calls it keeps working.
24
+ *
25
+ * Usage:
26
+ * harn session "<intent>" -- <cmd> [args...] run command, emit command.* events
27
+ * harn session log "<message>" emit a narration event
28
+ */
29
+ let emit;
30
+ export function registerSessionCommand(program, emitParam) {
31
+ emit = emitParam;
32
+ const session = program
33
+ .command("session")
34
+ .description("Run a command (or narrate) and emit canonical coordination events");
35
+ // Narration-only entry → canonical narration event.
36
+ session
37
+ .command("log <message...>")
38
+ .description("Emit a narration event (no command run)")
39
+ .action((messageParts) => {
40
+ const message = messageParts.join(" ");
41
+ writeSessionEvent("narration", bareAgentName(), {
42
+ instance_id: selfOwnerId(),
43
+ message: clampField(message),
44
+ });
45
+ emit.text(`⋯ ${message}\n`);
46
+ });
47
+ // Retired file-management subcommands, kept as graceful no-op stubs so
48
+ // existing callers (hooks, muscle memory) don't error. `trim` is the one a
49
+ // hook invokes, so it must exit 0 silently.
50
+ session
51
+ .command("trim")
52
+ .description("(retired): no-op kept for hook compatibility")
53
+ .option("-y, --yes", "(ignored)")
54
+ .option("--max-entries <n>", "(ignored)")
55
+ .option("--max-bytes <size>", "(ignored)")
56
+ .allowUnknownOption()
57
+ .allowExcessArguments()
58
+ .action(() => {
59
+ /* silent no-op, exit 0 */
60
+ });
61
+ for (const name of ["tail", "clear", "path"]) {
62
+ session
63
+ .command(name)
64
+ .description(`(retired): watch /live or '${resolveBinName()} agents watch'`)
65
+ .allowUnknownOption()
66
+ .action(() => {
67
+ emit.text(`Retired. Live activity flows to .harnery/events.ndjson; watch the /live web viewer or run '${resolveBinName()} agents watch'.\n`);
68
+ });
69
+ }
70
+ // Default form: harn session "<intent>" -- <cmd> [args]
71
+ session
72
+ .argument("<intent>", "One-line description of what this action is for")
73
+ .argument("<cmd...>", "The command to run (prefix with -- if it has its own flags)")
74
+ .allowUnknownOption()
75
+ .action((intent, cmd) => {
76
+ runLogged(intent, cmd);
77
+ });
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // Core
81
+ // ---------------------------------------------------------------------------
82
+ /**
83
+ * Strip ONLY carriage-return redraw noise (progress bars like `docker pull`'s
84
+ * sticky line) from a chunk before splitting into event lines. Terminal
85
+ * forwarding keeps the raw bytes; this only cleans the canonical event copy.
86
+ */
87
+ function stripCRNoise(text) {
88
+ return text.replace(/[^\n]*\r(?!\n)/g, "");
89
+ }
90
+ function runLogged(intent, cmdArg) {
91
+ // Strip a leading `--` separator if commander left one in.
92
+ const cmd = cmdArg[0] === "--" ? cmdArg.slice(1) : cmdArg;
93
+ if (cmd.length === 0) {
94
+ emit.error({ code: "usage", message: "Usage: harn session <intent> -- <cmd> [args...]" });
95
+ process.exit(2);
96
+ }
97
+ const cmdLine = cmd.map(quoteArg).join(" ");
98
+ const agent = bareAgentName();
99
+ const instanceId = selfOwnerId();
100
+ const cmdId = newCmdId();
101
+ // Intent precedence: explicit arg wins; else the PreToolUse-stamped intent
102
+ // file; else the command line itself.
103
+ const resolvedIntent = intent && intent.trim().length > 0 ? intent : (readLastIntent(instanceId) ?? cmdLine);
104
+ writeSessionEvent("command_start", agent, {
105
+ instance_id: instanceId,
106
+ cmd_id: cmdId,
107
+ intent: clampField(resolvedIntent),
108
+ cmd: clampField(cmdLine),
109
+ });
110
+ const start = Date.now();
111
+ const child = spawn(cmd[0], cmd.slice(1), {
112
+ stdio: ["inherit", "pipe", "pipe"],
113
+ env: process.env,
114
+ });
115
+ child.stdout?.on("data", (chunk) => {
116
+ process.stdout.write(chunk); // lint-ok-emission: harn session forwards child stdout verbatim; this IS the command's primary purpose
117
+ for (const line of stripCRNoise(chunk.toString("utf8")).split("\n")) {
118
+ if (line.length === 0)
119
+ continue;
120
+ writeSessionEvent("output", agent, {
121
+ instance_id: instanceId,
122
+ cmd_id: cmdId,
123
+ stream: "stdout",
124
+ line: clampField(line),
125
+ });
126
+ }
127
+ });
128
+ child.stderr?.on("data", (chunk) => {
129
+ process.stderr.write(chunk); // lint-ok-emission: harn session forwards child stderr verbatim; this IS the command's primary purpose
130
+ for (const line of stripCRNoise(chunk.toString("utf8")).split("\n")) {
131
+ if (line.length === 0)
132
+ continue;
133
+ writeSessionEvent("output", agent, {
134
+ instance_id: instanceId,
135
+ cmd_id: cmdId,
136
+ stream: "stderr",
137
+ line: clampField(line),
138
+ });
139
+ }
140
+ });
141
+ child.on("error", (err) => {
142
+ process.stderr.write(`✗ spawn failed: ${err.message}\n`);
143
+ process.exit(127);
144
+ });
145
+ child.on("close", (code, signal) => {
146
+ const durationMs = Date.now() - start;
147
+ writeSessionEvent("command_end", agent, {
148
+ instance_id: instanceId,
149
+ cmd_id: cmdId,
150
+ exit: code ?? null,
151
+ signal: signal ?? null,
152
+ duration_ms: durationMs,
153
+ });
154
+ process.exit(code ?? 1);
155
+ });
156
+ }
157
+ /** Shell-safe quote an argument for human-readable logging (not for eval). */
158
+ function quoteArg(arg) {
159
+ if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg))
160
+ return arg;
161
+ return `'${arg.replace(/'/g, `'\\''`)}'`;
162
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `harn sync`: keep a curated subset of `.harnery/` live across machines
3
+ * via rclone (typically a Google Drive remote, but any rclone remote works).
4
+ *
5
+ * Scope: a deliberately small set of file types: durable identities,
6
+ * archived scratchpads, council manifests. The high-churn machine-local
7
+ * stuff (events.ndjson, .pid-map/, active/, .last-intent.*) stays put.
8
+ *
9
+ * Subcommands:
10
+ * init: interactive: `rclone config` walks through Google OAuth, then
11
+ * we record the chosen remote name in ~/.config/harnery/sync.json
12
+ * status: diff local vs remote (rclone check --one-way)
13
+ * push: local to remote (rclone copy)
14
+ * pull: remote to local (rclone copy)
15
+ * list: show what's in the remote
16
+ *
17
+ * Power users override via env (HARNERY_SYNC_REMOTE, HARNERY_SYNC_PREFIX) or by
18
+ * editing the config file. Like `harn backup`, this surfaces rclone rather
19
+ * than abstracting it.
20
+ */
21
+ import type { Command } from "commander";
22
+ import type { EmitContext } from "../commander.js";
23
+ export declare function registerSyncCommand(program: Command, emit: EmitContext): void;
24
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAgHnD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAuK7E"}