harnery 0.45.1 → 0.46.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 (332) hide show
  1. package/dist/commander.d.ts +13 -0
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commands/admission.d.ts.map +1 -1
  4. package/dist/commands/admission.js +214 -27
  5. package/dist/commands/agents.d.ts +4 -0
  6. package/dist/commands/agents.d.ts.map +1 -1
  7. package/dist/commands/agents.js +102 -25
  8. package/dist/commands/browse.d.ts +3 -0
  9. package/dist/commands/browse.d.ts.map +1 -1
  10. package/dist/commands/browse.js +172 -8
  11. package/dist/commands/fetch.js +1 -0
  12. package/dist/commands/ledger-v3.d.ts.map +1 -1
  13. package/dist/commands/ledger-v3.js +8 -2
  14. package/dist/commands/presence.d.ts.map +1 -1
  15. package/dist/commands/presence.js +40 -0
  16. package/dist/commands/qa-run.d.ts.map +1 -1
  17. package/dist/commands/qa-run.js +4 -3
  18. package/dist/commands/review-pack.d.ts.map +1 -1
  19. package/dist/commands/review-pack.js +33 -6
  20. package/dist/commands/workflow.d.ts.map +1 -1
  21. package/dist/commands/workflow.js +6 -45
  22. package/dist/core/agents/coord-client.d.ts.map +1 -1
  23. package/dist/core/agents/coord-client.js +0 -18
  24. package/dist/core/agents/index.d.ts +1 -0
  25. package/dist/core/agents/index.d.ts.map +1 -1
  26. package/dist/core/agents/index.js +1 -0
  27. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  28. package/dist/core/agents/live-authority-v3.js +11 -4
  29. package/dist/core/agents/render/session-context.d.ts +0 -6
  30. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  31. package/dist/core/agents/render/session-context.js +1 -6
  32. package/dist/core/agents/session-events.d.ts.map +1 -1
  33. package/dist/core/agents/session-events.js +12 -4
  34. package/dist/core/agents/state/heartbeat-reader.d.ts +3 -0
  35. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
  36. package/dist/core/agents/state/live-coordination-view.d.ts +3 -1
  37. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  38. package/dist/core/agents/state/live-coordination-view.js +6 -2
  39. package/dist/core/agents/state/parent-reference-contract.d.ts +16 -0
  40. package/dist/core/agents/state/parent-reference-contract.d.ts.map +1 -0
  41. package/dist/core/agents/state/parent-reference-contract.js +1 -0
  42. package/dist/core/agents/state/parent-reference.d.ts +18 -0
  43. package/dist/core/agents/state/parent-reference.d.ts.map +1 -0
  44. package/dist/core/agents/state/parent-reference.js +119 -0
  45. package/dist/core/agents/state/pidmap.js +2 -2
  46. package/dist/core/agents/state/proc-start.d.ts +20 -31
  47. package/dist/core/agents/state/proc-start.d.ts.map +1 -1
  48. package/dist/core/agents/state/proc-start.js +37 -70
  49. package/dist/core/agents/state/service-process.d.ts +61 -0
  50. package/dist/core/agents/state/service-process.d.ts.map +1 -0
  51. package/dist/core/agents/state/service-process.js +143 -0
  52. package/dist/core/config.d.ts +39 -0
  53. package/dist/core/config.d.ts.map +1 -1
  54. package/dist/core/config.js +63 -0
  55. package/dist/core/context/index.d.ts +6 -4
  56. package/dist/core/context/index.d.ts.map +1 -1
  57. package/dist/core/context/index.js +194 -256
  58. package/dist/core/context/observation.d.ts +9 -9
  59. package/dist/core/context/observation.d.ts.map +1 -1
  60. package/dist/core/context/observation.js +37 -6
  61. package/dist/core/diagnostics/path-identity.d.ts +1 -1
  62. package/dist/core/diagnostics/path-identity.d.ts.map +1 -1
  63. package/dist/core/diagnostics/path-identity.js +51 -6
  64. package/dist/core/events/v3/canonical.js +43 -14
  65. package/dist/core/events/v3/index.d.ts +1 -1
  66. package/dist/core/events/v3/index.d.ts.map +1 -1
  67. package/dist/core/events/v3/index.js +1 -1
  68. package/dist/core/events/v3/producers/recorder.d.ts +34 -0
  69. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  70. package/dist/core/events/v3/producers/recorder.js +117 -13
  71. package/dist/core/events/v3/reader.d.ts.map +1 -1
  72. package/dist/core/events/v3/reader.js +53 -13
  73. package/dist/core/events/v3/runtime-build.d.ts +14 -0
  74. package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
  75. package/dist/core/events/v3/runtime-build.js +44 -0
  76. package/dist/core/events/v3/validate.d.ts.map +1 -1
  77. package/dist/core/events/v3/validate.js +36 -1
  78. package/dist/core/governor/index.d.ts +2 -1
  79. package/dist/core/governor/index.d.ts.map +1 -1
  80. package/dist/core/governor/index.js +2 -1
  81. package/dist/core/governor/service-read.d.ts +3 -10
  82. package/dist/core/governor/service-read.d.ts.map +1 -1
  83. package/dist/core/governor/service-read.js +10 -94
  84. package/dist/core/governor/service.d.ts +3 -7
  85. package/dist/core/governor/service.d.ts.map +1 -1
  86. package/dist/core/governor/service.js +17 -182
  87. package/dist/core/hooks/adapter/native-parent.d.ts +23 -0
  88. package/dist/core/hooks/adapter/native-parent.d.ts.map +1 -0
  89. package/dist/core/hooks/adapter/native-parent.js +91 -0
  90. package/dist/core/hooks/cli.js +79 -4
  91. package/dist/core/hooks/resolve/owner.d.ts +0 -11
  92. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  93. package/dist/core/hooks/resolve/owner.js +2 -25
  94. package/dist/core/hooks/shell-admission.d.ts +84 -0
  95. package/dist/core/hooks/shell-admission.d.ts.map +1 -0
  96. package/dist/core/hooks/shell-admission.js +622 -0
  97. package/dist/core/hooks/shell-commit-tree.d.ts +2 -0
  98. package/dist/core/hooks/shell-commit-tree.d.ts.map +1 -0
  99. package/dist/core/hooks/shell-commit-tree.js +104 -0
  100. package/dist/core/inbox/contract.d.ts +12 -0
  101. package/dist/core/inbox/contract.d.ts.map +1 -1
  102. package/dist/core/inbox/contract.js +16 -0
  103. package/dist/core/inbox/peer-messages.d.ts +41 -16
  104. package/dist/core/inbox/peer-messages.d.ts.map +1 -1
  105. package/dist/core/inbox/peer-messages.js +372 -15
  106. package/dist/core/inbox/service.d.ts +8 -1
  107. package/dist/core/inbox/service.d.ts.map +1 -1
  108. package/dist/core/inbox/service.js +83 -3
  109. package/dist/core/inbox/targets.d.ts +17 -3
  110. package/dist/core/inbox/targets.d.ts.map +1 -1
  111. package/dist/core/inbox/targets.js +77 -2
  112. package/dist/core/presence/git.d.ts +18 -12
  113. package/dist/core/presence/git.d.ts.map +1 -1
  114. package/dist/core/presence/git.js +32 -38
  115. package/dist/core/presence/index.d.ts +2 -2
  116. package/dist/core/presence/index.d.ts.map +1 -1
  117. package/dist/core/presence/index.js +8 -6
  118. package/dist/core/presence/mail.d.ts +133 -0
  119. package/dist/core/presence/mail.d.ts.map +1 -0
  120. package/dist/core/presence/mail.js +464 -0
  121. package/dist/core/resources/sampler.js +2 -2
  122. package/dist/core/resources/service-status.d.ts +2 -14
  123. package/dist/core/resources/service-status.d.ts.map +1 -1
  124. package/dist/core/resources/service-status.js +3 -23
  125. package/dist/core/resources/service.d.ts +3 -7
  126. package/dist/core/resources/service.d.ts.map +1 -1
  127. package/dist/core/resources/service.js +12 -101
  128. package/dist/core/resources/status.d.ts.map +1 -1
  129. package/dist/core/resources/status.js +3 -2
  130. package/dist/core/semantic/contract.d.ts +5 -5
  131. package/dist/core/semantic/service.d.ts.map +1 -1
  132. package/dist/core/semantic/service.js +9 -2
  133. package/dist/core/servers/index.d.ts +0 -2
  134. package/dist/core/servers/index.d.ts.map +1 -1
  135. package/dist/core/servers/index.js +3 -18
  136. package/dist/core/storage/modes.d.ts +4 -0
  137. package/dist/core/storage/modes.d.ts.map +1 -1
  138. package/dist/core/storage/modes.js +4 -0
  139. package/dist/core/storage/segments.d.ts.map +1 -1
  140. package/dist/core/storage/segments.js +5 -4
  141. package/dist/core/supervisor/service.d.ts +4 -7
  142. package/dist/core/supervisor/service.d.ts.map +1 -1
  143. package/dist/core/supervisor/service.js +23 -122
  144. package/dist/core/supervisor/services.js +2 -2
  145. package/dist/core/supervisor/status.d.ts +3 -17
  146. package/dist/core/supervisor/status.d.ts.map +1 -1
  147. package/dist/core/supervisor/status.js +7 -70
  148. package/dist/core/workflow/engine.js +2 -1
  149. package/dist/core/workflow/index.d.ts +3 -4
  150. package/dist/core/workflow/index.d.ts.map +1 -1
  151. package/dist/core/workflow/index.js +2 -2
  152. package/dist/core/workflow/proof.d.ts.map +1 -1
  153. package/dist/core/workflow/proof.js +30 -74
  154. package/dist/core/workflow/resume-lock.d.ts +17 -0
  155. package/dist/core/workflow/resume-lock.d.ts.map +1 -0
  156. package/dist/core/workflow/resume-lock.js +158 -0
  157. package/dist/core/workflow/run-state.d.ts +0 -21
  158. package/dist/core/workflow/run-state.d.ts.map +1 -1
  159. package/dist/core/workflow/run-state.js +3 -174
  160. package/dist/core/workflow/workspaces/leases.d.ts +4 -0
  161. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  162. package/dist/core/workflow/workspaces/leases.js +1 -1
  163. package/dist/core/workflow/workspaces/local-git.js +91 -210
  164. package/dist/core/workflow/workspaces/ownership.d.ts +0 -7
  165. package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -1
  166. package/dist/core/workflow/workspaces/ownership.js +3 -130
  167. package/dist/core/workflow/workspaces/reclaim.d.ts +4 -7
  168. package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
  169. package/dist/core/workflow/workspaces/reclaim.js +0 -4
  170. package/dist/core/workflow/workspaces/recovery.d.ts +1 -1
  171. package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
  172. package/dist/core/workflow/workspaces/recovery.js +1 -1
  173. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  174. package/dist/core/workflow/workspaces/state.js +1 -4
  175. package/dist/lib/admission-history.d.ts +96 -0
  176. package/dist/lib/admission-history.d.ts.map +1 -0
  177. package/dist/lib/admission-history.js +196 -0
  178. package/dist/lib/admission.d.ts +56 -7
  179. package/dist/lib/admission.d.ts.map +1 -1
  180. package/dist/lib/admission.js +161 -19
  181. package/dist/lib/browser/client.d.ts +18 -0
  182. package/dist/lib/browser/client.d.ts.map +1 -1
  183. package/dist/lib/browser/client.js +100 -12
  184. package/dist/lib/browser/content-checks.d.ts +3 -1
  185. package/dist/lib/browser/content-checks.d.ts.map +1 -1
  186. package/dist/lib/browser/content-checks.js +10 -2
  187. package/dist/lib/browser/critique.d.ts +32 -0
  188. package/dist/lib/browser/critique.d.ts.map +1 -1
  189. package/dist/lib/browser/critique.js +72 -3
  190. package/dist/lib/browser/geometry.d.ts +2 -0
  191. package/dist/lib/browser/geometry.d.ts.map +1 -1
  192. package/dist/lib/browser/geometry.js +61 -15
  193. package/dist/lib/browser/index.d.ts +1 -1
  194. package/dist/lib/browser/index.d.ts.map +1 -1
  195. package/dist/lib/browser/index.js +1 -1
  196. package/dist/lib/browser/page-review-contracts.d.ts +6 -1
  197. package/dist/lib/browser/page-review-contracts.d.ts.map +1 -1
  198. package/dist/lib/browser/page-review-contracts.js +6 -1
  199. package/dist/lib/browser/page-review-judge.d.ts +3 -1
  200. package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
  201. package/dist/lib/browser/page-review-judge.js +41 -11
  202. package/dist/lib/browser/page-review-pack.d.ts +3 -0
  203. package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
  204. package/dist/lib/browser/page-review-pack.js +5 -2
  205. package/dist/lib/browser/qa-run-contracts.d.ts +11 -0
  206. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
  207. package/dist/lib/browser/qa-run-contracts.js +11 -4
  208. package/dist/lib/browser/qa-run.d.ts.map +1 -1
  209. package/dist/lib/browser/qa-run.js +73 -16
  210. package/dist/lib/browser/runts.d.ts +4 -2
  211. package/dist/lib/browser/runts.d.ts.map +1 -1
  212. package/dist/lib/browser/runts.js +84 -33
  213. package/dist/lib/browser/windows-chrome.d.ts +14 -0
  214. package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
  215. package/dist/lib/browser/windows-chrome.js +42 -0
  216. package/dist/lib/browser/windows-login-sync.d.ts +110 -0
  217. package/dist/lib/browser/windows-login-sync.d.ts.map +1 -0
  218. package/dist/lib/browser/windows-login-sync.js +171 -0
  219. package/dist/lib/cookies/client.d.ts +30 -5
  220. package/dist/lib/cookies/client.d.ts.map +1 -1
  221. package/dist/lib/cookies/client.js +55 -10
  222. package/dist/lib/cookies/index.d.ts +1 -1
  223. package/dist/lib/cookies/index.d.ts.map +1 -1
  224. package/dist/lib/cookies/index.js +1 -1
  225. package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
  226. package/dist/lib/docs-metadata-sync.js +41 -2
  227. package/dist/lib/durable-job.d.ts +8 -0
  228. package/dist/lib/durable-job.d.ts.map +1 -1
  229. package/dist/lib/durable-job.js +10 -0
  230. package/dist/lib/http/client.d.ts +9 -8
  231. package/dist/lib/http/client.d.ts.map +1 -1
  232. package/dist/lib/http/client.js +44 -2
  233. package/dist/lib/instructions/templates.js +4 -4
  234. package/package.json +2 -2
  235. package/src/commander.ts +13 -0
  236. package/src/commands/admission.ts +272 -29
  237. package/src/commands/agents.ts +132 -27
  238. package/src/commands/browse.ts +208 -6
  239. package/src/commands/fetch.ts +1 -0
  240. package/src/commands/ledger-v3.ts +8 -2
  241. package/src/commands/presence.ts +49 -0
  242. package/src/commands/qa-run.ts +4 -3
  243. package/src/commands/review-pack.ts +41 -5
  244. package/src/commands/workflow.ts +8 -58
  245. package/src/core/agents/coord-client.ts +0 -20
  246. package/src/core/agents/index.ts +6 -0
  247. package/src/core/agents/live-authority-v3.ts +11 -4
  248. package/src/core/agents/render/session-context.ts +1 -7
  249. package/src/core/agents/session-events.ts +18 -3
  250. package/src/core/agents/state/heartbeat-reader.ts +3 -0
  251. package/src/core/agents/state/live-coordination-view.ts +13 -6
  252. package/src/core/agents/state/parent-reference-contract.ts +14 -0
  253. package/src/core/agents/state/parent-reference.ts +179 -0
  254. package/src/core/agents/state/pidmap.ts +2 -2
  255. package/src/core/agents/state/proc-start.ts +41 -69
  256. package/src/core/agents/state/service-process.ts +217 -0
  257. package/src/core/config.ts +85 -0
  258. package/src/core/context/index.ts +207 -272
  259. package/src/core/context/observation.ts +40 -9
  260. package/src/core/diagnostics/path-identity.ts +52 -6
  261. package/src/core/events/v3/canonical.ts +46 -13
  262. package/src/core/events/v3/index.ts +3 -0
  263. package/src/core/events/v3/producers/recorder.ts +151 -13
  264. package/src/core/events/v3/reader.ts +55 -11
  265. package/src/core/events/v3/runtime-build.ts +62 -0
  266. package/src/core/events/v3/validate.ts +42 -1
  267. package/src/core/governor/index.ts +1 -2
  268. package/src/core/governor/service-read.ts +15 -114
  269. package/src/core/governor/service.ts +36 -220
  270. package/src/core/hooks/adapter/native-parent.ts +109 -0
  271. package/src/core/hooks/cli.ts +83 -4
  272. package/src/core/hooks/resolve/owner.ts +2 -25
  273. package/src/core/hooks/shell-admission.ts +634 -0
  274. package/src/core/hooks/shell-commit-tree.ts +102 -0
  275. package/src/core/inbox/contract.ts +18 -0
  276. package/src/core/inbox/peer-messages.ts +501 -15
  277. package/src/core/inbox/service.ts +108 -3
  278. package/src/core/inbox/targets.ts +94 -3
  279. package/src/core/presence/git.ts +45 -37
  280. package/src/core/presence/index.ts +16 -8
  281. package/src/core/presence/mail.ts +620 -0
  282. package/src/core/resources/sampler.ts +3 -2
  283. package/src/core/resources/service-status.ts +6 -35
  284. package/src/core/resources/service.ts +23 -133
  285. package/src/core/resources/status.ts +3 -2
  286. package/src/core/semantic/service.ts +8 -2
  287. package/src/core/servers/index.ts +3 -23
  288. package/src/core/storage/modes.ts +6 -0
  289. package/src/core/storage/segments.ts +5 -4
  290. package/src/core/supervisor/service.ts +33 -155
  291. package/src/core/supervisor/services.ts +2 -2
  292. package/src/core/supervisor/status.ts +10 -85
  293. package/src/core/workflow/engine.ts +1 -1
  294. package/src/core/workflow/index.ts +2 -13
  295. package/src/core/workflow/proof.ts +35 -83
  296. package/src/core/workflow/resume-lock.ts +179 -0
  297. package/src/core/workflow/run-state.ts +3 -207
  298. package/src/core/workflow/workspaces/leases.ts +1 -1
  299. package/src/core/workflow/workspaces/local-git.ts +120 -239
  300. package/src/core/workflow/workspaces/ownership.ts +3 -158
  301. package/src/core/workflow/workspaces/reclaim.ts +3 -9
  302. package/src/core/workflow/workspaces/recovery.ts +1 -1
  303. package/src/core/workflow/workspaces/state.ts +1 -5
  304. package/src/lib/admission-history.ts +267 -0
  305. package/src/lib/admission.ts +217 -19
  306. package/src/lib/browser/client.ts +147 -35
  307. package/src/lib/browser/content-checks.ts +14 -3
  308. package/src/lib/browser/critique.ts +113 -3
  309. package/src/lib/browser/geometry.ts +63 -14
  310. package/src/lib/browser/index.ts +5 -0
  311. package/src/lib/browser/page-review-contracts.ts +6 -1
  312. package/src/lib/browser/page-review-judge.ts +58 -13
  313. package/src/lib/browser/page-review-pack.ts +13 -2
  314. package/src/lib/browser/qa-run-contracts.ts +30 -4
  315. package/src/lib/browser/qa-run.ts +78 -17
  316. package/src/lib/browser/runts.ts +85 -37
  317. package/src/lib/browser/windows-chrome.ts +50 -0
  318. package/src/lib/browser/windows-login-sync.ts +275 -0
  319. package/src/lib/cookies/client.ts +62 -10
  320. package/src/lib/cookies/index.ts +3 -0
  321. package/src/lib/docs-metadata-sync.ts +44 -2
  322. package/src/lib/durable-job.ts +15 -0
  323. package/src/lib/http/client.ts +63 -1
  324. package/src/lib/instructions/templates.ts +4 -4
  325. package/dist/core/agents/state/process-handle.d.ts +0 -26
  326. package/dist/core/agents/state/process-handle.d.ts.map +0 -1
  327. package/dist/core/agents/state/process-handle.js +0 -121
  328. package/dist/core/workflow/recovery-audit.d.ts +0 -30
  329. package/dist/core/workflow/recovery-audit.d.ts.map +0 -1
  330. package/dist/core/workflow/recovery-audit.js +0 -116
  331. package/src/core/agents/state/process-handle.ts +0 -165
  332. package/src/core/workflow/recovery-audit.ts +0 -181
@@ -28,6 +28,7 @@ import { agentDisplayName } from "../core/agents/state/activity-log.js";
28
28
  import { buildLifecycleSuggestedName, buildSuggestedName, readHeartbeat as readHeartbeatCache, } from "../core/agents/state/heartbeat-writer.js";
29
29
  import { describeLiveAuthorityBlockV3, liveAuthorityBlockHintV3, liveAuthorityBlockV3, readLiveCoordinationRow, readLiveCoordinationRows, } from "../core/agents/state/live-coordination-view.js";
30
30
  import { forkRelationLabels, resolveForkAncestry } from "../core/agents/state/names.js";
31
+ import { resolveAgentParentReference, } from "../core/agents/state/parent-reference.js";
31
32
  import { foldSessionState, } from "../core/agents/state/session-state.js";
32
33
  import { turnChangesStatusRow } from "../core/agents/turn-changes.js";
33
34
  import { turnElapsedStatusRow } from "../core/agents/turn-elapsed.js";
@@ -39,13 +40,13 @@ import { nativeInstanceIdV3 } from "../core/events/v3/live-route-observer.js";
39
40
  import { liveInstanceIdV3 } from "../core/events/v3/live-routing.js";
40
41
  import { countSummarizedSinceV3, listDiagnosticSummariesV3, } from "../core/events/v3/producers/diagnostic-summaries.js";
41
42
  import { listHookIntakeGroupsV3, listHookIntakeRecordsV3, } from "../core/events/v3/producers/intake.js";
42
- import { listHookProducerStateRecordsV3, readHookProducerStateV3, } from "../core/events/v3/producers/recorder.js";
43
+ import { listHookProducerStateRecordsV3, readHookProducerStateV3, scanHookProducerStateRecordsV3, } from "../core/events/v3/producers/recorder.js";
43
44
  import { readLedgerV3 } from "../core/events/v3/reader.js";
44
45
  import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../core/events/v3/writer.js";
45
46
  import { evaluateRunQualityIfDue } from "../core/guard/index.js";
46
47
  import { readRuntimeContextTelemetry, readRuntimeContextUsage, } from "../core/hooks/adapter/runtime-telemetry.js";
47
48
  import { HarneryInboxCapacityError } from "../core/inbox/contract.js";
48
- import { peerInbox, sendPeerMessage } from "../core/inbox/peer-messages.js";
49
+ import { peerInbox, sendPeerMessage, } from "../core/inbox/peer-messages.js";
49
50
  import { readRemoteMachines } from "../core/presence/index.js";
50
51
  import { formatResourceSummary, readResourceStatus } from "../core/resources/status.js";
51
52
  import { registerContextCommand } from "./context.js";
@@ -290,9 +291,13 @@ export function registerAgentsCommand(program, emitParam, programContext, binNam
290
291
  cmd
291
292
  .command("ping <name> <message...>")
292
293
  .description("Queue a durable message for one known task instance by name. Stale or " +
293
- "done tasks receive it when that same task resumes. Ambiguous names " +
294
+ "done tasks receive it when that same task resumes. A recipient on " +
295
+ "another machine is reached through the shared origin. Ambiguous names " +
294
296
  "require an exact instance; receipts do not confirm attention.")
295
297
  .option("--instance-id <id>", "Select the exact known recipient instance")
298
+ .option("--generation-id <id>", "Require the exact recipient generation")
299
+ .option("--operation-id <id>", "Reuse a frozen delivery operation after a caller retry")
300
+ .option("--operation-replay-only", "Require an existing plan after an ambiguous caller dispatch")
296
301
  .option("--require-live", "Refuse a recipient outside live presence")
297
302
  .option("--json", "JSON output")
298
303
  .action((name, message, opts) => {
@@ -1216,6 +1221,7 @@ async function runShow(name, opts) {
1216
1221
  tool_counts: report?.tool_counts ?? [],
1217
1222
  total_events: report?.total_events ?? 0,
1218
1223
  bq_error: bqError,
1224
+ parent_reference: resolveAgentParentReference(root, hb),
1219
1225
  };
1220
1226
  if (opts.json) {
1221
1227
  emit.config({ format: "json" });
@@ -1232,6 +1238,7 @@ async function runShow(name, opts) {
1232
1238
  lines.push(`agent-${data.name} ${subtitle}`);
1233
1239
  lines.push(` session ${formatAge(ageSecs)} old · kind=${data.kind} · session_id=${data.session_id.slice(0, 8)}…`);
1234
1240
  lines.push(` last heartbeat: ${formatAge(heartbeatAgeSecs)} ago`);
1241
+ lines.push(` parent: ${describeParentReference(data.parent_reference)}`);
1235
1242
  lines.push(` activity: ${data.activity}`);
1236
1243
  lines.push(` lifecycle: ${data.task_state}${data.task_state === "blocked" && data.task_state_reason ? `: ${data.task_state_reason}` : ""}`);
1237
1244
  if (data.files_held.length > 0) {
@@ -1900,6 +1907,7 @@ function runStatus(opts) {
1900
1907
  name: displayName,
1901
1908
  instance_id: hb.instance_id,
1902
1909
  kind: normalizeKind(hb.kind),
1910
+ parent_reference: resolveAgentParentReference(root, hb),
1903
1911
  session_age_secs: ageSecs,
1904
1912
  turn_elapsed_secs: turnElapsed ? turnElapsed.elapsed.secs : null,
1905
1913
  turn_complete: turnElapsed ? turnElapsed.elapsed.complete : null,
@@ -1952,6 +1960,7 @@ function runStatus(opts) {
1952
1960
  ["changes", turnChanges.value],
1953
1961
  ["activity", activityOf(hb)],
1954
1962
  ["lifecycle", lifecycleLabel(hb)],
1963
+ ["parent", describeParentReference(data.parent_reference)],
1955
1964
  ["context", ctxStr],
1956
1965
  ["resources", formatResourceSummary(resources)],
1957
1966
  ["files", filesStr],
@@ -2440,7 +2449,11 @@ export function collectEventLedgerHealthV3(root, nowMs = Date.now()) {
2440
2449
  const generations = [];
2441
2450
  const spanPressure = [];
2442
2451
  try {
2443
- for (const { state } of listHookProducerStateRecordsV3(root)) {
2452
+ const scan = scanHookProducerStateRecordsV3(root);
2453
+ for (const file of scan.invalid) {
2454
+ collectionErrors.push(`producer state skipped (${file.adapter}/${file.session_hash}.json): ${file.reason}`);
2455
+ }
2456
+ for (const { state } of scan.records) {
2444
2457
  if (state.spans.length >= SPAN_PRESSURE_SOFT_WATERMARK) {
2445
2458
  spanPressure.push({
2446
2459
  instance_id: state.instance_id,
@@ -3846,6 +3859,28 @@ function formatDuration(ms) {
3846
3859
  const h = Math.round((ms % 86_400_000) / 3_600_000);
3847
3860
  return h > 0 ? `${d}d${h}h` : `${d}d`;
3848
3861
  }
3862
+ export function describeParentReference(reference) {
3863
+ return reference.state === "verified"
3864
+ ? `${reference.parent_name ?? "unnamed"} (${reference.parent_instance_id}; ${reference.source}; ${reference.addressable ? "addressable" : "not addressable"})`
3865
+ : `${reference.state}: ${reference.reason}`;
3866
+ }
3867
+ export function formatPeerRecipientReceipt(recipient) {
3868
+ if (!recipient.ok)
3869
+ return `${recipient.code}: ${recipient.message}`;
3870
+ const address = `agent-${recipient.target.name} (${recipient.target.instance_id})`;
3871
+ if (recipient.delivery_state === "delivered")
3872
+ return `Previously acknowledged by the recipient machine for ${address}; task attention is not confirmed.`;
3873
+ if (recipient.delivery_state === "expired")
3874
+ return `The prior remote message for ${address} expired; no new delivery is established.`;
3875
+ if (recipient.target.machine)
3876
+ return (`Stored for ${address} on ${recipient.target.machine} as ${recipient.message_id}. ` +
3877
+ (recipient.published
3878
+ ? "Published to origin; recipient-machine import is not confirmed."
3879
+ : `Publication is not confirmed${recipient.publish_error ? ` (${recipient.publish_error})` : ""}.`));
3880
+ return recipient.state === "duplicate"
3881
+ ? `Previously stored for ${address} as ${recipient.message_id}; current surface state is not established by this receipt.`
3882
+ : `Stored for ${address} as ${recipient.message_id}; task attention is not confirmed.`;
3883
+ }
3849
3884
  function runPing(name, message, opts) {
3850
3885
  if (!message || message.trim().length === 0) {
3851
3886
  emit.error({ code: "empty_message", message: "message is required (and non-empty)" });
@@ -3869,10 +3904,17 @@ function runPing(name, message, opts) {
3869
3904
  try {
3870
3905
  sent = sendPeerMessage({
3871
3906
  coordRoot,
3872
- target: { name, instanceId: opts.instanceId, requireLive: opts.requireLive },
3907
+ target: {
3908
+ name,
3909
+ instanceId: opts.instanceId,
3910
+ generationId: opts.generationId,
3911
+ requireLive: opts.requireLive,
3912
+ },
3913
+ operationId: opts.operationId,
3914
+ operationReplayOnly: opts.operationReplayOnly,
3873
3915
  senderName: fromName,
3874
3916
  senderInstanceId: myOwner,
3875
- body: message.trim(),
3917
+ body: message,
3876
3918
  });
3877
3919
  }
3878
3920
  catch (error) {
@@ -3882,46 +3924,81 @@ function runPing(name, message, opts) {
3882
3924
  }
3883
3925
  throw error;
3884
3926
  }
3927
+ if (opts.json)
3928
+ emit.config({ format: "json" });
3929
+ const routing = {
3930
+ operation_id: sent.operation_id,
3931
+ child: sent.child,
3932
+ parent_reference: sent.parent_reference,
3933
+ parent_copy: sent.parent_copy,
3934
+ complete: sent.complete,
3935
+ };
3936
+ // Keep both actual recipient writes visible, including parent-only success.
3937
+ for (const recipient of [sent.child, sent.parent_copy]) {
3938
+ if (!("ok" in recipient) || !recipient.ok)
3939
+ continue;
3940
+ emitEventV3({
3941
+ owner: myOwner,
3942
+ session: nativeSessionIdentity(myHb, myOwner),
3943
+ adapter: normalizeAdapter(myHb?.platform),
3944
+ observation: {
3945
+ event_type: "coord.message_observed",
3946
+ direction: "sent",
3947
+ subject: recipient.target.instance_id,
3948
+ message_id: recipient.message_id,
3949
+ body: recipient === sent.child
3950
+ ? message
3951
+ : `[Parent copy for agent-${sent.child.target?.name} (${sent.child.target?.instance_id})]\n${message}`,
3952
+ },
3953
+ });
3954
+ }
3885
3955
  if (!sent.ok) {
3886
- emit.error({
3956
+ emit.data({
3957
+ ...routing,
3958
+ ok: false,
3887
3959
  code: sent.code,
3888
3960
  message: sent.message,
3961
+ from: fromName,
3889
3962
  ...(sent.candidates ? { candidates: sent.candidates } : {}),
3890
3963
  });
3891
- process.exit(1);
3964
+ process.exitCode = 1;
3965
+ return;
3892
3966
  }
3893
- // Canonical delivery record: sender is the envelope owner, recipient rides
3894
- // in data, so read-only observers can render the communication without
3895
- // joining journal files.
3896
- emitEventV3({
3897
- owner: myOwner,
3898
- session: nativeSessionIdentity(myHb, myOwner),
3899
- adapter: normalizeAdapter(myHb?.platform),
3900
- observation: {
3901
- event_type: "coord.message_observed",
3902
- direction: "sent",
3903
- subject: sent.target.instance_id,
3904
- message_id: sent.message_id,
3905
- body: message.trim(),
3906
- },
3907
- });
3967
+ const remote = "published" in sent ? sent : null;
3908
3968
  const data = {
3969
+ ...routing,
3909
3970
  peer: sent.target.name,
3910
3971
  peer_instance_id: sent.target.instance_id,
3972
+ ...(sent.target.machine ? { peer_machine: sent.target.machine } : {}),
3911
3973
  state: sent.state,
3912
3974
  message_id: sent.message_id,
3913
3975
  synced: sent.synced,
3914
3976
  body_bytes: sent.body_bytes,
3915
3977
  from: fromName,
3978
+ ...(remote
3979
+ ? {
3980
+ published: remote.published,
3981
+ ...(remote.delivery_state ? { delivery_state: remote.delivery_state } : {}),
3982
+ ...(remote.publish_error ? { publish_error: remote.publish_error } : {}),
3983
+ }
3984
+ : {}),
3916
3985
  };
3917
3986
  if (opts.json) {
3918
3987
  emit.config({ format: "json" });
3919
3988
  emit.data(data);
3989
+ if (!sent.complete)
3990
+ process.exitCode = 1;
3920
3991
  return;
3921
3992
  }
3922
3993
  emit.data(data);
3923
- emit.text(`${data.state} for agent-${data.peer} (${data.peer_instance_id}); ` +
3924
- `stored as ${data.message_id}, pending until surfaced to that task.\n`);
3994
+ if (!sent.complete)
3995
+ process.exitCode = 1;
3996
+ emit.text(`parent copy: ${"ok" in sent.parent_copy
3997
+ ? sent.parent_copy.ok
3998
+ ? formatPeerRecipientReceipt(sent.parent_copy)
3999
+ : `${sent.parent_copy.code}: ${sent.parent_copy.message}`
4000
+ : `skipped (${sent.parent_copy.reason})`}\n`);
4001
+ emit.text(`${formatPeerRecipientReceipt(sent.child)}\n`);
3925
4002
  }
3926
4003
  async function runWait(name, opts) {
3927
4004
  const timeoutMs = parseDurationToMs(opts.timeout);
@@ -50,6 +50,7 @@ interface BrowseOpts {
50
50
  collectOut?: string;
51
51
  networkHar?: string;
52
52
  login?: boolean;
53
+ syncLogin?: boolean;
53
54
  attached?: boolean;
54
55
  loginCloseFile?: string;
55
56
  controlFile?: string;
@@ -79,7 +80,9 @@ interface BrowseOpts {
79
80
  checkWidthFail?: boolean;
80
81
  checkWidthAnnotate?: boolean;
81
82
  checkRunts?: boolean | string;
83
+ checkScanNodeBudget?: string;
82
84
  checkRuntsMinChars?: string;
85
+ checkRuntsMaxFindings?: string;
83
86
  checkRuntsFail?: boolean;
84
87
  checkRuntsAnnotate?: boolean;
85
88
  checkOverflow?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"browse.d.ts","sourceRoot":"","sources":["../../src/commands/browse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browse.d.ts","sourceRoot":"","sources":["../../src/commands/browse.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ import { createPageDriver, createRng, DEFAULT_COLLECT_LIMITS, PACING_LIMITS, par
11
11
  import { Browser, browserProxyFromEnv, browserProxyGateFromEnv, captureDevOverlay, chromeMajorFromExecutable, DEFAULT_CRITIQUE_RUBRIC, extractObservedIp, installedChromeChannel, installedChromePath, parseAssertSpec, resolveUserAgent, runCritique, tilesFromFullPage, WEBRTC_PROXY_ONLY_ARG, writeNetscapeCookieFile, wslHeadedLaunchArgs, } from "../lib/browser/index.js";
12
12
  import { isWSL } from "../lib/browser/launch-args.js";
13
13
  import { allocateTileBudget, validatePageReviewAllocation, } from "../lib/browser/page-review-budget.js";
14
- import { PAGE_REVIEW_CAPTURE_PLAN_SCHEMA, } from "../lib/browser/page-review-contracts.js";
14
+ import { PAGE_REVIEW_CAPTURE_PLAN_SCHEMA, PAGE_REVIEW_MAX_TILE_BUDGET, } from "../lib/browser/page-review-contracts.js";
15
15
  import { findPackTile, gateHitsFromEnvelope, readPackContext, tileId, writePackContext, writePackExpandedTile, } from "../lib/browser/page-review-pack.js";
16
16
  import { retainPageReviewSourceIdentity } from "../lib/browser/page-review-source.js";
17
17
  import { buildQaManifest, classifySignatures, } from "../lib/browser/qa-plan.js";
@@ -22,7 +22,8 @@ import { startBrowserSessionServer, } from "../lib/browser/session-control.js";
22
22
  import { captureThumbnailFingerprint, registerCaptureThumbnail, } from "../lib/browser/thumbnail-association.js";
23
23
  import { reviewCandidateRects } from "../lib/browser/tiling.js";
24
24
  import { diffAgainstBaseline, saveBaseline, } from "../lib/browser/visual-diff.js";
25
- import { harvestDomain, harvestWindowsChromeCookies, keepWindowsChromeSession, stopWindowsChromeProfile, windowsChromePath, windowsLocalAppData, windowsPlainProfile, wslPathToWindows, } from "../lib/browser/windows-chrome.js";
25
+ import { harvestDomain, harvestWindowsChromeCookies, keepWindowsChromeSession, stopWindowsChromeProfile, windowsChromePath, windowsChromeProfileProcesses, windowsLocalAppData, windowsPathToWsl, windowsPlainProfile, wslPathToWindows, } from "../lib/browser/windows-chrome.js";
26
+ import { profileCookieDbMtimeMs, recordLoginSync, syncLoginCookies, } from "../lib/browser/windows-login-sync.js";
26
27
  import { applyExtraCookies, CookieJar, mergeCookies } from "../lib/cookies/index.js";
27
28
  import { commandPaceGate } from "../lib/pace/index.js";
28
29
  /**
@@ -57,8 +58,10 @@ const VIEWPORT_PRESETS = {
57
58
  // cookies/read: the many helper functions in this large file close over
58
59
  // `emit` so action callbacks stay concise.
59
60
  let emit;
61
+ let browseBinName = "harn";
60
62
  export function registerBrowseCommand(program, emitParam, context, binName = resolveBinName()) {
61
63
  emit = emitParam;
64
+ browseBinName = binName;
62
65
  program
63
66
  .command("browse <url>")
64
67
  .description("Headless Chromium with persistent profile + cookie jar. Default writes a trio of files (last.png, last.html, last.json) for the LLM iteration loop; --snapshot/--html/--json switch to stdout-print mode.")
@@ -108,9 +111,14 @@ export function registerBrowseCommand(program, emitParam, context, binName = res
108
111
  "Renders theme-aware pages in that scheme without page-specific toggles. " +
109
112
  "Absent = browser default (unchanged behavior).")
110
113
  .option("--login", "Open the URL in the installed Google Chrome with nothing attached (no DevTools protocol, no " +
111
- "Playwright) so a person can sign in; under WSL this is the Windows host's Chrome. Sign in, then " +
112
- "close the window or create the --login-close-file; later browse and browse-session runs reuse " +
113
- "the cookies. Sites cannot tell this window from the person's own browser.")
114
+ "Playwright) so a person can sign in; under WSL this is the Windows host's Chrome on a dedicated " +
115
+ "sign-in profile. Sign in, then close the window or create the --login-close-file; later browse " +
116
+ "and browse-session runs reuse the cookies. Under WSL the profile can also stay in use as an " +
117
+ "ordinary browser: each headless browse copies the target site's cookies from it when it changed " +
118
+ "and is closed, and an open profile is left alone (see --sync-login). Sites cannot tell this " +
119
+ "window from the person's own browser.")
120
+ .option("--sync-login", "WSL only: copy the URL's site cookies from the Windows sign-in profile into the cookie store " +
121
+ "now, then exit without loading the page. Refuses while Chrome is open on that profile.")
114
122
  .option("--attached", "With --login: open an automation-controlled Chrome that this process and --control-file can drive. " +
115
123
  "Sites can detect it and may lock the account, so use it only for agent-driven headed sessions on " +
116
124
  "sites you own. Never use it to sign in to a third-party account.")
@@ -173,6 +181,8 @@ export function registerBrowseCommand(program, emitParam, context, binName = res
173
181
  "Atomic tokens (URLs, emails, phone numbers) are excluded. Reports hits in the JSON " +
174
182
  "envelope under `runts` and annotates them on the screenshot.")
175
183
  .option("--check-runts-min-chars <n>", "Minimum block text length to scan (default 40; smaller labels can't meaningfully wrap).", "40")
184
+ .option("--check-runts-max-findings <n>", "Maximum runt findings to retain (integer 1..5000, default 50). Reaching the limit " +
185
+ "still marks the sweep incomplete; the separate 5000-block scan cap is unchanged.", "50")
176
186
  .option("--check-runts-fail", "Run a document-wide runt check when needed; exit 2 on a runt, missing scope, or incomplete sweep.")
177
187
  .option("--no-check-runts-annotate", "Skip drawing runt boxes on the screenshot (JSON still emitted).")
178
188
  .option("--check-align <selector>", "Check rendered child-content alignment inside this container (repeatable).", (value, previous = []) => [...previous, value], [])
@@ -206,6 +216,7 @@ export function registerBrowseCommand(program, emitParam, context, binName = res
206
216
  "Pairs closer than this are flagged; negative separation (overlap) always flags.", "6")
207
217
  .option("--check-crowd-fail", "Exit 2 when a crowd target fails, is unknown, or is missing.")
208
218
  .option("--no-check-crowd-annotate", "Skip crowd screenshot annotations.")
219
+ .option("--check-scan-node-budget <n>", "Explicit geometry/content traversal budget per scope (1–100000 nodes). Omit to keep each rule's existing limit; incomplete scans remain unknown.")
209
220
  .option("--check-placeholder [selector]", "Scan rendered text for unrendered template tokens and bound-value tells: " +
210
221
  "JS template literals, `{{x}}` handlebars, `[object Object]`, `Invalid Date`, " +
211
222
  "`NaN`, or an element whose whole text is literally 'undefined' / 'null'. Optional selector " +
@@ -241,7 +252,7 @@ export function registerBrowseCommand(program, emitParam, context, binName = res
241
252
  "reports `skipped`. Findings land under `critique` in the JSON envelope.")
242
253
  .option("--check-critique-band <px>", "Band height for default tiling (default 1400).", "1400")
243
254
  .option("--check-critique-overlap <px>", "Vertical overlap between bands so a finding at a seam stays visible (default 120).", "120")
244
- .option("--check-critique-max-tiles <n>", "Cap on tiles sent to the model, to bound cost (default 24).", "24")
255
+ .option("--check-critique-max-tiles <n>", `Cap on tiles sent to the model, to bound cost (default 24, at most ${PAGE_REVIEW_MAX_TILE_BUDGET}).`, "24")
245
256
  .option("--check-critique-rubric <text>", "Override the default critique rubric.")
246
257
  .option("--check-critique-fail", "Run a whole-page critique when needed; exit 2 unless the critique conclusively passes.")
247
258
  .option("--assert <expr>", "Assert a page value (repeatable). Grammar: '<op> <selector> => <expected>', where op is " +
@@ -336,6 +347,17 @@ async function runBrowse(url, opts, context) {
336
347
  const clipThreshold = parseNonNegativeNumber(opts.checkClipThreshold ?? "0", "--check-clip-threshold");
337
348
  const overlapThreshold = parseNonNegativeNumber(opts.checkOverlapThreshold ?? "0", "--check-overlap-threshold");
338
349
  const crowdMin = parseNonNegativeNumber(opts.checkCrowdMin ?? "6", "--check-crowd-min");
350
+ const scanNodeBudget = opts.checkScanNodeBudget === undefined
351
+ ? undefined
352
+ : parsePositiveInt(opts.checkScanNodeBudget, "--check-scan-node-budget");
353
+ if (scanNodeBudget !== undefined &&
354
+ (!Number.isSafeInteger(scanNodeBudget) || scanNodeBudget > 100_000)) {
355
+ throw new Error("--check-scan-node-budget must be an integer from 1 to 100000.");
356
+ }
357
+ const runtsMaxFindings = parsePositiveInt(opts.checkRuntsMaxFindings ?? "50", "--check-runts-max-findings");
358
+ if (runtsMaxFindings > 5000) {
359
+ throw new Error("--check-runts-max-findings must be an integer from 1 to 5000.");
360
+ }
339
361
  const hitProfile = parseTargetSizeProfile(opts.checkHitProfile ?? "wcag-aa");
340
362
  // Commander: `--no-cookies` turns `opts.cookies` into `false`. Default is `true`.
341
363
  const jar = opts.cookies === false
@@ -374,6 +396,14 @@ async function runBrowse(url, opts, context) {
374
396
  if (loginCloseFile && existsSync(loginCloseFile)) {
375
397
  throw new Error(`Login close signal already exists at ${loginCloseFile}. Remove the stale file before launching.`);
376
398
  }
399
+ if (opts.syncLogin) {
400
+ if (opts.login)
401
+ throw new Error("--sync-login cannot run with --login.");
402
+ if (!jar)
403
+ throw new Error("--sync-login needs the cookie store; drop --no-cookies.");
404
+ runSyncLogin(url, jar.path);
405
+ return;
406
+ }
377
407
  const collectPlan = opts.collect ? buildCollectPlan(opts) : null;
378
408
  const pace = commandPaceGate(opts.pace !== false, (message) => emit.log(message, "info"));
379
409
  if (loginMode === "plain") {
@@ -391,12 +421,15 @@ async function runBrowse(url, opts, context) {
391
421
  await runPlainLogin(url, opts.profile ?? DEFAULT_PROFILE, loginCloseFile, plainUa, emit);
392
422
  return;
393
423
  }
424
+ if (jar && loginMode === "none")
425
+ autoSyncLoginCookies(url, jar.path);
394
426
  const channel = resolveBrowserChannel(opts, Boolean(headed));
395
427
  const userAgent = resolveUserAgent({
396
428
  requested: opts.userAgent,
397
429
  env: process.env.HARNERY_BROWSER_UA,
398
430
  chromeMajor: launchedChromeMajor(channel),
399
431
  });
432
+ const cookieGuard = context?.cookieGuard?.();
400
433
  const browser = new Browser({
401
434
  profileDir: opts.profile ?? DEFAULT_PROFILE,
402
435
  headed,
@@ -408,6 +441,7 @@ async function runBrowse(url, opts, context) {
408
441
  waitUntil: opts.waitUntil,
409
442
  recordHarPath: opts.networkHar ? resolve(opts.networkHar) : undefined,
410
443
  extraHeaders: context?.extraHeaders,
444
+ ...(cookieGuard ? { cookieGuard } : {}),
411
445
  pace,
412
446
  launchArgs: resolveLaunchArgs(opts, Boolean(headed), Boolean(proxy)),
413
447
  ...(channel ? { channel } : {}),
@@ -498,6 +532,7 @@ async function runBrowse(url, opts, context) {
498
532
  runts = await browser.checkRunts({
499
533
  scope: typeof opts.checkRunts === "string" ? opts.checkRunts : null,
500
534
  minChars: Number.parseInt(opts.checkRuntsMinChars ?? "40", 10),
535
+ maxFindings: runtsMaxFindings,
501
536
  });
502
537
  }
503
538
  const hasLayoutLint = (opts.checkAlign?.length ?? 0) > 0 ||
@@ -508,6 +543,7 @@ async function runBrowse(url, opts, context) {
508
543
  let layoutLint;
509
544
  if (hasLayoutLint) {
510
545
  layoutLint = await browser.checkLayoutLint({
546
+ scanNodeBudget,
511
547
  align: (opts.checkAlign ?? []).map((selector) => ({
512
548
  selector,
513
549
  axis: alignAxis,
@@ -544,6 +580,7 @@ async function runBrowse(url, opts, context) {
544
580
  let content;
545
581
  if (hasContentChecks) {
546
582
  content = await browser.checkContent({
583
+ scanNodeBudget,
547
584
  placeholder: opts.checkPlaceholder !== undefined
548
585
  ? { scope: contentScope(opts.checkPlaceholder) }
549
586
  : null,
@@ -983,6 +1020,10 @@ async function runBrowse(url, opts, context) {
983
1020
  process.exitCode = 2;
984
1021
  }
985
1022
  }
1023
+ catch (error) {
1024
+ // A cookie guard that stopped the session is the real failure, not the closed-page errors it caused.
1025
+ throw browser.cookieGuardFault ?? error;
1026
+ }
986
1027
  finally {
987
1028
  process.removeListener("SIGINT", handleSigint);
988
1029
  process.removeListener("SIGTERM", handleSigterm);
@@ -991,6 +1032,8 @@ async function runBrowse(url, opts, context) {
991
1032
  if (receivedSignal)
992
1033
  process.exitCode = receivedSignal === "SIGINT" ? 130 : 143;
993
1034
  }
1035
+ if (browser.cookieGuardFault)
1036
+ throw browser.cookieGuardFault;
994
1037
  }
995
1038
  function parsePositiveInt(raw, flag) {
996
1039
  if (!/^\d+$/.test(raw.trim()) || Number.parseInt(raw, 10) < 1) {
@@ -1822,7 +1865,7 @@ async function runQaPlanning(browser, targetArg, renderedUrl, opts) {
1822
1865
  const pageHeight = await browser.currentPage.evaluate(() => Math.max(document.documentElement.scrollHeight, document.body?.scrollHeight ?? 0));
1823
1866
  const band = Number.parseInt(opts.checkCritiqueBand ?? "1400", 10);
1824
1867
  const overlap = Number.parseInt(opts.checkCritiqueOverlap ?? "120", 10);
1825
- const maxTiles = Number.parseInt(opts.checkCritiqueMaxTiles ?? "24", 10);
1868
+ const maxTiles = critiqueTilingKnobs(opts).maxTiles;
1826
1869
  const estimatedFullPageTiles = Math.min(maxTiles, Math.max(1, Math.ceil(pageHeight / Math.max(1, band - overlap))));
1827
1870
  const explicitScopes = [];
1828
1871
  for (const selector of opts.qaScope ?? []) {
@@ -1844,7 +1887,9 @@ async function runQaPlanning(browser, targetArg, renderedUrl, opts) {
1844
1887
  * routed provider's vision long-edge budget caps band height so tiles are
1845
1888
  * never silently downscaled by the model. */
1846
1889
  function critiqueTilingKnobs(opts, tileBudgetPx) {
1847
- const maxTiles = Math.max(1, Number.parseInt(opts.checkCritiqueMaxTiles ?? "24", 10));
1890
+ // No flag value can exceed the hard per-invocation ceiling.
1891
+ const requested = Number.parseInt(opts.checkCritiqueMaxTiles ?? "24", 10);
1892
+ const maxTiles = Math.min(PAGE_REVIEW_MAX_TILE_BUDGET, Math.max(1, Number.isFinite(requested) ? requested : 24));
1848
1893
  const bandFlag = Math.max(200, Number.parseInt(opts.checkCritiqueBand ?? "1400", 10));
1849
1894
  const band = tileBudgetPx ? Math.max(200, Math.min(bandFlag, tileBudgetPx)) : bandFlag;
1850
1895
  const overlap = Math.max(0, Number.parseInt(opts.checkCritiqueOverlap ?? "120", 10));
@@ -2356,6 +2401,114 @@ async function runPlainLogin(url, profileDir, loginCloseFile, userAgent, emit) {
2356
2401
  }
2357
2402
  emit.log(`[--login] Chrome closed; cookies persisted in ${profileDir}.`, "info");
2358
2403
  }
2404
+ /**
2405
+ * The WSL sign-in profile and the operations the cookie sync needs, or
2406
+ * `undefined` when this machine has none (not WSL, no Windows Chrome, or
2407
+ * `HARNERY_BROWSER_WSL_PLAIN=linux`).
2408
+ */
2409
+ function windowsLoginProfile() {
2410
+ if (!useWindowsPlainLogin())
2411
+ return undefined;
2412
+ const chromeLinux = windowsChromePath();
2413
+ const localAppData = windowsLocalAppData();
2414
+ if (!chromeLinux || !localAppData)
2415
+ return undefined;
2416
+ const chromeWindows = wslPathToWindows(chromeLinux);
2417
+ const profileWindows = windowsPlainProfile(localAppData);
2418
+ const profileLinux = windowsPathToWsl(profileWindows);
2419
+ return {
2420
+ profileWindows,
2421
+ deps: {
2422
+ cookieDbMtimeMs: () => profileCookieDbMtimeMs(profileLinux),
2423
+ profileProcesses: () => windowsChromeProfileProcesses(profileWindows),
2424
+ harvest: (domain) => harvestWindowsChromeCookies({
2425
+ chromeWindows,
2426
+ profileWindows,
2427
+ domain,
2428
+ pageTimeoutSeconds: 0,
2429
+ }),
2430
+ },
2431
+ };
2432
+ }
2433
+ /** One-line summary of a sync that read cookies. Names only, never values. */
2434
+ function loginSyncSummary(result, storePath) {
2435
+ if (result.status === "synced") {
2436
+ return `Copied ${result.merged} ${result.domain} cookies (${result.sessionCookies} browser-session) from the sign-in profile into ${storePath}: ${result.names.join(", ")}.`;
2437
+ }
2438
+ return `The sign-in profile's ${result.domain} cookies (${result.cookies}) match the last copy; the cookie store was left as it is.`;
2439
+ }
2440
+ /**
2441
+ * Before a headless run under WSL, copy the target site's cookies from the
2442
+ * sign-in profile when the profile changed since the last copy and no
2443
+ * Chrome is open on it. Failures are warnings; the run continues.
2444
+ * `HARNERY_BROWSER_LOGIN_SYNC=off` turns it off.
2445
+ */
2446
+ function autoSyncLoginCookies(url, storePath) {
2447
+ if ((process.env.HARNERY_BROWSER_LOGIN_SYNC ?? "").toLowerCase() === "off")
2448
+ return;
2449
+ let profile;
2450
+ let domain;
2451
+ try {
2452
+ profile = windowsLoginProfile();
2453
+ domain = harvestDomain(url);
2454
+ }
2455
+ catch {
2456
+ return;
2457
+ }
2458
+ if (!profile)
2459
+ return;
2460
+ try {
2461
+ const result = syncLoginCookies({ domain, storePath, deps: profile.deps });
2462
+ if (result.status === "open") {
2463
+ emit.log(`[login-sync] The shared sign-in window (Windows Chrome on ${profile.profileWindows}) is open and changed since ${domain} cookies were last copied; this run uses the cookie store as it is. Its ${domain} session reaches headless runs after you close that window, or run \`${browseBinName} browse --sync-login ${url}\` once it is closed.`, "info");
2464
+ }
2465
+ else if (result.status === "busy") {
2466
+ emit.log("[login-sync] Another run is copying sign-in cookies; this run did not wait.", "debug");
2467
+ }
2468
+ else if (result.status === "synced" || result.status === "unchanged") {
2469
+ emit.log(`[login-sync] ${loginSyncSummary(result, storePath)}`, "info");
2470
+ }
2471
+ }
2472
+ catch (err) {
2473
+ const message = err instanceof Error ? err.message : String(err);
2474
+ emit.log(`[login-sync] Could not copy ${domain} cookies from the sign-in profile; continuing with the cookie store as it is. ${message}`, "warn");
2475
+ }
2476
+ }
2477
+ /** `--sync-login`: copy the URL's site cookies from the sign-in profile now. */
2478
+ function runSyncLogin(url, storePath) {
2479
+ const profile = windowsLoginProfile();
2480
+ if (!profile) {
2481
+ throw new Error("--sync-login needs WSL with the Windows Google Chrome; this machine has no Windows sign-in profile.");
2482
+ }
2483
+ const domain = harvestDomain(url);
2484
+ const result = syncLoginCookies({ domain, storePath, deps: profile.deps, force: true });
2485
+ if (result.status === "no-profile") {
2486
+ throw new Error(`The sign-in profile ${profile.profileWindows} has no cookies yet; sign in with \`${browseBinName} browse --login ${url}\` first.`);
2487
+ }
2488
+ if (result.status === "open") {
2489
+ throw new Error(`Chrome is open on the sign-in profile ${profile.profileWindows} (process ${result.processes.join(", ")}). Close that window, then run --sync-login again.`);
2490
+ }
2491
+ if (result.status === "busy") {
2492
+ throw new Error("Another run is copying sign-in cookies right now; try again in a moment.");
2493
+ }
2494
+ if (result.cookies === 0) {
2495
+ emit.log(`[--sync-login] No ${domain} cookies were found in the sign-in profile.`, "warn");
2496
+ }
2497
+ else {
2498
+ emit.log(`[--sync-login] ${loginSyncSummary(result, storePath)}`, "info");
2499
+ }
2500
+ emit.data({
2501
+ loginSync: {
2502
+ domain,
2503
+ store: storePath,
2504
+ status: result.status,
2505
+ cookies: result.cookies,
2506
+ merged: result.merged,
2507
+ sessionCookies: result.sessionCookies,
2508
+ names: result.names,
2509
+ },
2510
+ });
2511
+ }
2359
2512
  /**
2360
2513
  * Under WSL, `--login` opens the Windows host's Google Chrome when one
2361
2514
  * is installed. Some sign-in flows reject every browser running inside WSL,
@@ -2411,6 +2564,17 @@ async function runWindowsPlainLogin(url, storePath, loginCloseFile, emit) {
2411
2564
  await Promise.race([exited, new Promise((r) => setTimeout(r, 5000))]);
2412
2565
  const domain = harvestDomain(url);
2413
2566
  const { cookies, pages } = harvestWindowsChromeCookies({ chromeWindows, profileWindows, domain });
2567
+ try {
2568
+ recordLoginSync({
2569
+ domain,
2570
+ storePath,
2571
+ cookies,
2572
+ cookieDbMtimeMs: profileCookieDbMtimeMs(windowsPathToWsl(profileWindows)),
2573
+ });
2574
+ }
2575
+ catch {
2576
+ // The record only saves the next headless run a repeat read.
2577
+ }
2414
2578
  const lastPage = pages[0] ?? null;
2415
2579
  const names = [...new Set(cookies.map((cookie) => cookie.name))].sort();
2416
2580
  const sessionCookies = cookies.filter((cookie) => cookie.expires <= 0).length;
@@ -74,6 +74,7 @@ async function runFetch(url, opts, emit, context) {
74
74
  signal: ac.signal,
75
75
  extraHeaders: context?.extraHeaders,
76
76
  extraCookies: context?.extraCookies,
77
+ clientRedirects: context?.clientRedirects?.() || undefined,
77
78
  responseType: "bytes",
78
79
  });
79
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-v3.d.ts","sourceRoot":"","sources":["../../src/commands/ledger-v3.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAwC1E,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAgbN"}
1
+ {"version":3,"file":"ledger-v3.d.ts","sourceRoot":"","sources":["../../src/commands/ledger-v3.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAwC1E,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAsbN"}
@@ -3,7 +3,7 @@ import { createHash } from "node:crypto";
3
3
  import { existsSync, mkdirSync, readFileSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
5
  import { compressSealedLegacyV1Segments, inventoryLegacyV1Segments, streamLegacyV1Rows, verifyLegacyV1HardFence, writeLegacyV1Canary, } from "../core/events/legacy-storage/index.js";
6
- import { cleanEventV3Archives, initializeEventLedgerV3, inventoryEventV3Archives, listHookProducerStateRecordsV3, readEventV3ControlState, recoverInvalidEventLedgerV3, sha256V3, } from "../core/events/v3/index.js";
6
+ import { cleanEventV3Archives, initializeEventLedgerV3, inventoryEventV3Archives, readEventV3ControlState, recoverInvalidEventLedgerV3, scanHookProducerStateRecordsV3, sha256V3, } from "../core/events/v3/index.js";
7
7
  import { authorizeEventV3SupportReplacement, inventoryEventV3Support, planEventV3SupportReplacement, planEventV3SupportTransaction, readEventV3SupportPackManifest, readEventV3SupportTransaction, streamEventV3SupportPackRecords, unpackEventV3SupportPack, verifyEventV3SupportTransactionShadow, writeEventV3SupportTransactionShadow, } from "../core/events/v3/support-storage/index.js";
8
8
  import { stateDirMode } from "../core/storage/modes.js";
9
9
  /** Inspect or initialize the universal V3 event ledger. */
@@ -19,7 +19,8 @@ export function registerLedgerV3Command(program, emit, context) {
19
19
  try {
20
20
  const root = resolve(options.root ?? coordRoot(context));
21
21
  const control = readEventV3ControlState(root);
22
- const producers = listHookProducerStateRecordsV3(root, { includeTerminal: true });
22
+ const scan = scanHookProducerStateRecordsV3(root, { includeTerminal: true });
23
+ const producers = scan.records;
23
24
  const counts = producers.reduce((summary, record) => {
24
25
  summary[record.state.adapter] = (summary[record.state.adapter] ?? 0) + 1;
25
26
  return summary;
@@ -30,6 +31,11 @@ export function registerLedgerV3Command(program, emit, context) {
30
31
  adapters: Object.keys(counts).sort(),
31
32
  producer_states: producers.length,
32
33
  producer_states_by_adapter: counts,
34
+ invalid_producer_states: scan.invalid.map((file) => ({
35
+ adapter: file.adapter,
36
+ session_hash: file.session_hash,
37
+ reason: file.reason,
38
+ })),
33
39
  },
34
40
  });
35
41
  }