harnery 0.35.0 → 0.36.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 (616) hide show
  1. package/dist/commander.d.ts +30 -5
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +124 -96
  4. package/dist/commands/agents.d.ts +23 -3
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +379 -198
  7. package/dist/commands/backup.d.ts.map +1 -1
  8. package/dist/commands/backup.js +10 -10
  9. package/dist/commands/browse-session.d.ts.map +1 -1
  10. package/dist/commands/browse-session.js +12 -0
  11. package/dist/commands/browse.d.ts +1 -1
  12. package/dist/commands/browse.d.ts.map +1 -1
  13. package/dist/commands/browse.js +5 -4
  14. package/dist/commands/conversations.d.ts +10 -0
  15. package/dist/commands/conversations.d.ts.map +1 -0
  16. package/dist/commands/conversations.js +201 -0
  17. package/dist/commands/deinit.d.ts.map +1 -1
  18. package/dist/commands/deinit.js +5 -0
  19. package/dist/commands/docs.d.ts.map +1 -1
  20. package/dist/commands/docs.js +13 -2
  21. package/dist/commands/doctor.d.ts +5 -0
  22. package/dist/commands/doctor.d.ts.map +1 -1
  23. package/dist/commands/doctor.js +51 -7
  24. package/dist/commands/fetch.js +6 -5
  25. package/dist/commands/files.d.ts +22 -0
  26. package/dist/commands/files.d.ts.map +1 -0
  27. package/dist/commands/files.js +113 -0
  28. package/dist/commands/governor.js +14 -12
  29. package/dist/commands/inbox.d.ts +5 -0
  30. package/dist/commands/inbox.d.ts.map +1 -0
  31. package/dist/commands/inbox.js +57 -0
  32. package/dist/commands/init.d.ts +4 -5
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +63 -13
  35. package/dist/commands/ledger-v3.d.ts.map +1 -1
  36. package/dist/commands/ledger-v3.js +347 -1
  37. package/dist/commands/logs.d.ts +4 -0
  38. package/dist/commands/logs.d.ts.map +1 -0
  39. package/dist/commands/logs.js +169 -0
  40. package/dist/commands/messages.d.ts +5 -0
  41. package/dist/commands/messages.d.ts.map +1 -0
  42. package/dist/commands/messages.js +45 -0
  43. package/dist/commands/outline.d.ts +1 -1
  44. package/dist/commands/outline.d.ts.map +1 -1
  45. package/dist/commands/outline.js +2 -2
  46. package/dist/commands/read.d.ts +1 -1
  47. package/dist/commands/read.d.ts.map +1 -1
  48. package/dist/commands/read.js +2 -2
  49. package/dist/commands/semantic.d.ts.map +1 -1
  50. package/dist/commands/semantic.js +54 -2
  51. package/dist/commands/storage.d.ts +4 -0
  52. package/dist/commands/storage.d.ts.map +1 -0
  53. package/dist/commands/storage.js +238 -0
  54. package/dist/commands/tunnel.d.ts +5 -1
  55. package/dist/commands/tunnel.d.ts.map +1 -1
  56. package/dist/commands/tunnel.js +44 -31
  57. package/dist/commands/web.d.ts +3 -0
  58. package/dist/commands/web.d.ts.map +1 -1
  59. package/dist/commands/web.js +67 -7
  60. package/dist/commands/work.js +3 -3
  61. package/dist/commands/workflow.js +13 -13
  62. package/dist/core/adapters/profiles.d.ts +1 -1
  63. package/dist/core/agents/cli.js +209 -39
  64. package/dist/core/agents/live-authority-v3.d.ts +47 -1
  65. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  66. package/dist/core/agents/live-authority-v3.js +244 -10
  67. package/dist/core/agents/live-lifecycle-v3.js +6 -1
  68. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  69. package/dist/core/agents/live-observation-v3.js +6 -1
  70. package/dist/core/agents/render/prompt-context.d.ts +9 -3
  71. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  72. package/dist/core/agents/render/prompt-context.js +24 -7
  73. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  74. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  75. package/dist/core/agents/rules/stop-hook.js +94 -13
  76. package/dist/core/agents/rules/verdict.d.ts +1 -0
  77. package/dist/core/agents/rules/verdict.d.ts.map +1 -1
  78. package/dist/core/agents/session-events.d.ts.map +1 -1
  79. package/dist/core/agents/session-events.js +4 -0
  80. package/dist/core/agents/session-finalization-state-v3.js +1 -1
  81. package/dist/core/agents/session-finalizer-v3.js +5 -1
  82. package/dist/core/agents/state/activity-log.d.ts +3 -0
  83. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  84. package/dist/core/agents/state/activity-log.js +6 -3
  85. package/dist/core/agents/state/heartbeat-writer.d.ts +6 -0
  86. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  87. package/dist/core/agents/state/heartbeat-writer.js +18 -0
  88. package/dist/core/agents/state/live-coordination-view.d.ts +5 -7
  89. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  90. package/dist/core/agents/state/live-coordination-view.js +15 -90
  91. package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
  92. package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
  93. package/dist/core/agents/state/live-coordination-writer.js +92 -0
  94. package/dist/core/artifacts/index.d.ts +21 -0
  95. package/dist/core/artifacts/index.d.ts.map +1 -1
  96. package/dist/core/artifacts/index.js +46 -1
  97. package/dist/core/config.d.ts +62 -4
  98. package/dist/core/config.d.ts.map +1 -1
  99. package/dist/core/config.js +98 -4
  100. package/dist/core/conversations/archive.d.ts +49 -0
  101. package/dist/core/conversations/archive.d.ts.map +1 -0
  102. package/dist/core/conversations/archive.js +136 -0
  103. package/dist/core/conversations/catalog.d.ts +10 -0
  104. package/dist/core/conversations/catalog.d.ts.map +1 -0
  105. package/dist/core/conversations/catalog.js +72 -0
  106. package/dist/core/conversations/context-pack.d.ts +6 -0
  107. package/dist/core/conversations/context-pack.d.ts.map +1 -0
  108. package/dist/core/conversations/context-pack.js +60 -0
  109. package/dist/core/conversations/contract.d.ts +155 -0
  110. package/dist/core/conversations/contract.d.ts.map +1 -0
  111. package/dist/core/conversations/contract.js +1 -0
  112. package/dist/core/conversations/evaluation.d.ts +16 -0
  113. package/dist/core/conversations/evaluation.d.ts.map +1 -0
  114. package/dist/core/conversations/evaluation.js +9 -0
  115. package/dist/core/conversations/index.d.ts +10 -0
  116. package/dist/core/conversations/index.d.ts.map +1 -0
  117. package/dist/core/conversations/index.js +9 -0
  118. package/dist/core/conversations/lifecycle.d.ts +28 -0
  119. package/dist/core/conversations/lifecycle.d.ts.map +1 -0
  120. package/dist/core/conversations/lifecycle.js +29 -0
  121. package/dist/core/conversations/normalize.d.ts +14 -0
  122. package/dist/core/conversations/normalize.d.ts.map +1 -0
  123. package/dist/core/conversations/normalize.js +82 -0
  124. package/dist/core/conversations/query.d.ts +8 -0
  125. package/dist/core/conversations/query.d.ts.map +1 -0
  126. package/dist/core/conversations/query.js +280 -0
  127. package/dist/core/conversations/search-index.d.ts +9 -0
  128. package/dist/core/conversations/search-index.d.ts.map +1 -0
  129. package/dist/core/conversations/search-index.js +29 -0
  130. package/dist/core/events/legacy-storage/canary.d.ts +18 -0
  131. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
  132. package/dist/core/events/legacy-storage/canary.js +150 -0
  133. package/dist/core/events/legacy-storage/fence.d.ts +15 -0
  134. package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
  135. package/dist/core/events/legacy-storage/fence.js +115 -0
  136. package/dist/core/events/legacy-storage/index.d.ts +6 -0
  137. package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
  138. package/dist/core/events/legacy-storage/index.js +5 -0
  139. package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
  140. package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
  141. package/dist/core/events/legacy-storage/inventory.js +40 -0
  142. package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
  143. package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
  144. package/dist/core/events/legacy-storage/manifest.js +108 -0
  145. package/dist/core/events/legacy-storage/reader.d.ts +15 -0
  146. package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
  147. package/dist/core/events/legacy-storage/reader.js +154 -0
  148. package/dist/core/events/v3/authority-outbox.d.ts +7 -2
  149. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  150. package/dist/core/events/v3/authority-outbox.js +16 -3
  151. package/dist/core/events/v3/base-contract.d.ts +81 -41
  152. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  153. package/dist/core/events/v3/base-contract.js +17 -7
  154. package/dist/core/events/v3/bootstrap.d.ts +39 -0
  155. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  156. package/dist/core/events/v3/bootstrap.js +167 -3
  157. package/dist/core/events/v3/capabilities.js +3 -3
  158. package/dist/core/events/v3/control-witness.d.ts +44 -0
  159. package/dist/core/events/v3/control-witness.d.ts.map +1 -0
  160. package/dist/core/events/v3/control-witness.js +233 -0
  161. package/dist/core/events/v3/control-writer.d.ts +4 -0
  162. package/dist/core/events/v3/control-writer.d.ts.map +1 -0
  163. package/dist/core/events/v3/control-writer.js +16 -0
  164. package/dist/core/events/v3/control.d.ts +8 -2
  165. package/dist/core/events/v3/control.d.ts.map +1 -1
  166. package/dist/core/events/v3/control.js +46 -18
  167. package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
  168. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
  169. package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
  170. package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
  171. package/dist/core/events/v3/coordination-view.js +16 -1
  172. package/dist/core/events/v3/generated.d.ts +1 -1
  173. package/dist/core/events/v3/generated.js +1 -1
  174. package/dist/core/events/v3/index.d.ts +4 -2
  175. package/dist/core/events/v3/index.d.ts.map +1 -1
  176. package/dist/core/events/v3/index.js +3 -1
  177. package/dist/core/events/v3/live-route-observer.d.ts +31 -0
  178. package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
  179. package/dist/core/events/v3/live-route-observer.js +58 -0
  180. package/dist/core/events/v3/live-routing.d.ts +13 -21
  181. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  182. package/dist/core/events/v3/live-routing.js +45 -41
  183. package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
  184. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  185. package/dist/core/events/v3/producers/coordination-recorder.js +76 -10
  186. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
  187. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
  188. package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
  189. package/dist/core/events/v3/producers/hook-base.js +1 -1
  190. package/dist/core/events/v3/producers/intake.d.ts +7 -0
  191. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  192. package/dist/core/events/v3/producers/intake.js +25 -2
  193. package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
  194. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
  195. package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
  196. package/dist/core/events/v3/producers/recorder.d.ts +55 -1
  197. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  198. package/dist/core/events/v3/producers/recorder.js +353 -24
  199. package/dist/core/events/v3/reader.d.ts +51 -0
  200. package/dist/core/events/v3/reader.d.ts.map +1 -1
  201. package/dist/core/events/v3/reader.js +181 -1
  202. package/dist/core/events/v3/rotation-config.d.ts +9 -0
  203. package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
  204. package/dist/core/events/v3/rotation-config.js +91 -0
  205. package/dist/core/events/v3/runtime-build.d.ts +11 -0
  206. package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
  207. package/dist/core/events/v3/runtime-build.js +39 -0
  208. package/dist/core/events/v3/runtime-identity.d.ts +5 -0
  209. package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
  210. package/dist/core/events/v3/runtime-identity.js +18 -0
  211. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +6 -5
  212. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
  213. package/dist/core/events/v3/runtime-telemetry-capabilities.js +1 -1
  214. package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
  215. package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
  216. package/dist/core/events/v3/support-storage/classify.js +149 -0
  217. package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
  218. package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
  219. package/dist/core/events/v3/support-storage/eligibility.js +35 -0
  220. package/dist/core/events/v3/support-storage/index.d.ts +10 -0
  221. package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
  222. package/dist/core/events/v3/support-storage/index.js +9 -0
  223. package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
  224. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
  225. package/dist/core/events/v3/support-storage/inventory.js +94 -0
  226. package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
  227. package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
  228. package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
  229. package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
  230. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
  231. package/dist/core/events/v3/support-storage/maintenance.js +352 -0
  232. package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
  233. package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
  234. package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
  235. package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
  236. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
  237. package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
  238. package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
  239. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
  240. package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
  241. package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
  242. package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
  243. package/dist/core/events/v3/support-storage/recovery.js +22 -0
  244. package/dist/core/events/v3/turn-telemetry.d.ts +14 -8
  245. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  246. package/dist/core/events/v3/turn-telemetry.js +32 -2
  247. package/dist/core/events/v3/writer.d.ts +13 -1
  248. package/dist/core/events/v3/writer.d.ts.map +1 -1
  249. package/dist/core/events/v3/writer.js +126 -12
  250. package/dist/core/governor/plan-read.d.ts.map +1 -1
  251. package/dist/core/governor/plan-read.js +5 -21
  252. package/dist/core/governor/planning.js +6 -8
  253. package/dist/core/governor/service-read.d.ts +12 -0
  254. package/dist/core/governor/service-read.d.ts.map +1 -1
  255. package/dist/core/governor/service-read.js +266 -2
  256. package/dist/core/governor/service.d.ts +1 -0
  257. package/dist/core/governor/service.d.ts.map +1 -1
  258. package/dist/core/governor/service.js +53 -18
  259. package/dist/core/guard/evidence-v3.d.ts.map +1 -1
  260. package/dist/core/guard/evidence-v3.js +2 -0
  261. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  262. package/dist/core/hooks/adapter/events.js +1 -0
  263. package/dist/core/hooks/adapter/output.d.ts +4 -2
  264. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  265. package/dist/core/hooks/adapter/output.js +13 -5
  266. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +27 -4
  267. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -1
  268. package/dist/core/hooks/adapter/runtime-telemetry.js +307 -6
  269. package/dist/core/hooks/cli.js +212 -30
  270. package/dist/core/hooks/effects/image-capture.d.ts +1 -1
  271. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  272. package/dist/core/hooks/effects/image-capture.js +4 -2
  273. package/dist/core/hooks/remediation-cap.d.ts +8 -3
  274. package/dist/core/hooks/remediation-cap.d.ts.map +1 -1
  275. package/dist/core/hooks/remediation-cap.js +3 -11
  276. package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
  277. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  278. package/dist/core/hooks/resolve/coord-root.js +92 -11
  279. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  280. package/dist/core/hooks/resolve/owner.js +5 -0
  281. package/dist/core/hooks/resolve/transcript.d.ts +8 -0
  282. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  283. package/dist/core/hooks/resolve/transcript.js +11 -0
  284. package/dist/core/inbox/contract.d.ts +64 -0
  285. package/dist/core/inbox/contract.d.ts.map +1 -0
  286. package/dist/core/inbox/contract.js +13 -0
  287. package/dist/core/inbox/index.d.ts +5 -0
  288. package/dist/core/inbox/index.d.ts.map +1 -0
  289. package/dist/core/inbox/index.js +4 -0
  290. package/dist/core/inbox/lifecycle.d.ts +22 -0
  291. package/dist/core/inbox/lifecycle.d.ts.map +1 -0
  292. package/dist/core/inbox/lifecycle.js +41 -0
  293. package/dist/core/inbox/service.d.ts +36 -0
  294. package/dist/core/inbox/service.d.ts.map +1 -0
  295. package/dist/core/inbox/service.js +210 -0
  296. package/dist/core/inbox/watcher.d.ts +7 -0
  297. package/dist/core/inbox/watcher.d.ts.map +1 -0
  298. package/dist/core/inbox/watcher.js +26 -0
  299. package/dist/core/presence/codec-digest.d.ts.map +1 -1
  300. package/dist/core/presence/codec-digest.js +14 -3
  301. package/dist/core/presence/relay-client.d.ts +1 -0
  302. package/dist/core/presence/relay-client.d.ts.map +1 -1
  303. package/dist/core/presence/relay-client.js +52 -8
  304. package/dist/core/semantic/adapters.d.ts +11 -8
  305. package/dist/core/semantic/adapters.d.ts.map +1 -1
  306. package/dist/core/semantic/adapters.js +169 -31
  307. package/dist/core/semantic/contract.d.ts +532 -48
  308. package/dist/core/semantic/contract.d.ts.map +1 -1
  309. package/dist/core/semantic/contract.js +104 -3
  310. package/dist/core/semantic/index.d.ts +7 -3
  311. package/dist/core/semantic/index.d.ts.map +1 -1
  312. package/dist/core/semantic/index.js +7 -3
  313. package/dist/core/semantic/once.d.ts +6 -1
  314. package/dist/core/semantic/once.d.ts.map +1 -1
  315. package/dist/core/semantic/once.js +80 -9
  316. package/dist/core/semantic/prompt.d.ts.map +1 -1
  317. package/dist/core/semantic/prompt.js +14 -1
  318. package/dist/core/semantic/review.d.ts +144 -0
  319. package/dist/core/semantic/review.d.ts.map +1 -0
  320. package/dist/core/semantic/review.js +544 -0
  321. package/dist/core/semantic/routes.d.ts +10 -0
  322. package/dist/core/semantic/routes.d.ts.map +1 -0
  323. package/dist/core/semantic/routes.js +21 -0
  324. package/dist/core/semantic/scheduler.d.ts +14 -3
  325. package/dist/core/semantic/scheduler.d.ts.map +1 -1
  326. package/dist/core/semantic/scheduler.js +30 -6
  327. package/dist/core/semantic/service-status.d.ts +20 -0
  328. package/dist/core/semantic/service-status.d.ts.map +1 -1
  329. package/dist/core/semantic/service-status.js +60 -4
  330. package/dist/core/semantic/service.d.ts +1 -0
  331. package/dist/core/semantic/service.d.ts.map +1 -1
  332. package/dist/core/semantic/service.js +104 -15
  333. package/dist/core/semantic/soak.d.ts +75 -0
  334. package/dist/core/semantic/soak.d.ts.map +1 -0
  335. package/dist/core/semantic/soak.js +476 -0
  336. package/dist/core/semantic/storage.d.ts +11 -1
  337. package/dist/core/semantic/storage.d.ts.map +1 -1
  338. package/dist/core/semantic/storage.js +4 -3
  339. package/dist/core/semantic/usage.d.ts +43 -0
  340. package/dist/core/semantic/usage.d.ts.map +1 -0
  341. package/dist/core/semantic/usage.js +193 -0
  342. package/dist/core/semantic/validate.d.ts +3 -1
  343. package/dist/core/semantic/validate.d.ts.map +1 -1
  344. package/dist/core/semantic/validate.js +34 -1
  345. package/dist/core/storage/buffer.d.ts +28 -0
  346. package/dist/core/storage/buffer.d.ts.map +1 -0
  347. package/dist/core/storage/buffer.js +101 -0
  348. package/dist/core/storage/builtins.d.ts +3 -0
  349. package/dist/core/storage/builtins.d.ts.map +1 -0
  350. package/dist/core/storage/builtins.js +683 -0
  351. package/dist/core/storage/catalog.d.ts +19 -0
  352. package/dist/core/storage/catalog.d.ts.map +1 -0
  353. package/dist/core/storage/catalog.js +365 -0
  354. package/dist/core/storage/config.d.ts +16 -0
  355. package/dist/core/storage/config.d.ts.map +1 -0
  356. package/dist/core/storage/config.js +311 -0
  357. package/dist/core/storage/contract.d.ts +275 -0
  358. package/dist/core/storage/contract.d.ts.map +1 -0
  359. package/dist/core/storage/contract.js +3 -0
  360. package/dist/core/storage/durable-history.d.ts +36 -0
  361. package/dist/core/storage/durable-history.d.ts.map +1 -0
  362. package/dist/core/storage/durable-history.js +606 -0
  363. package/dist/core/storage/health.d.ts +4 -0
  364. package/dist/core/storage/health.d.ts.map +1 -0
  365. package/dist/core/storage/health.js +65 -0
  366. package/dist/core/storage/index.d.ts +16 -0
  367. package/dist/core/storage/index.d.ts.map +1 -0
  368. package/dist/core/storage/index.js +15 -0
  369. package/dist/core/storage/inventory.d.ts +25 -0
  370. package/dist/core/storage/inventory.d.ts.map +1 -0
  371. package/dist/core/storage/inventory.js +666 -0
  372. package/dist/core/storage/jsonl.d.ts +52 -0
  373. package/dist/core/storage/jsonl.d.ts.map +1 -0
  374. package/dist/core/storage/jsonl.js +156 -0
  375. package/dist/core/storage/log-retention.d.ts +52 -0
  376. package/dist/core/storage/log-retention.d.ts.map +1 -0
  377. package/dist/core/storage/log-retention.js +419 -0
  378. package/dist/core/storage/logger.d.ts +82 -0
  379. package/dist/core/storage/logger.d.ts.map +1 -0
  380. package/dist/core/storage/logger.js +411 -0
  381. package/dist/core/storage/maintenance-providers.d.ts +26 -0
  382. package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
  383. package/dist/core/storage/maintenance-providers.js +141 -0
  384. package/dist/core/storage/maintenance.d.ts +125 -0
  385. package/dist/core/storage/maintenance.d.ts.map +1 -0
  386. package/dist/core/storage/maintenance.js +609 -0
  387. package/dist/core/storage/metrics.d.ts +60 -0
  388. package/dist/core/storage/metrics.d.ts.map +1 -0
  389. package/dist/core/storage/metrics.js +134 -0
  390. package/dist/core/storage/policy.d.ts +7 -0
  391. package/dist/core/storage/policy.d.ts.map +1 -0
  392. package/dist/core/storage/policy.js +110 -0
  393. package/dist/core/storage/process-log.d.ts +38 -0
  394. package/dist/core/storage/process-log.d.ts.map +1 -0
  395. package/dist/core/storage/process-log.js +165 -0
  396. package/dist/core/storage/query.d.ts +34 -0
  397. package/dist/core/storage/query.d.ts.map +1 -0
  398. package/dist/core/storage/query.js +295 -0
  399. package/dist/core/storage/receipts.d.ts +23 -0
  400. package/dist/core/storage/receipts.d.ts.map +1 -0
  401. package/dist/core/storage/receipts.js +117 -0
  402. package/dist/core/storage/segments.d.ts +84 -0
  403. package/dist/core/storage/segments.d.ts.map +1 -0
  404. package/dist/core/storage/segments.js +542 -0
  405. package/dist/core/storage/sink-graph.d.ts +65 -0
  406. package/dist/core/storage/sink-graph.d.ts.map +1 -0
  407. package/dist/core/storage/sink-graph.js +213 -0
  408. package/dist/core/storage/storm-control.d.ts +23 -0
  409. package/dist/core/storage/storm-control.d.ts.map +1 -0
  410. package/dist/core/storage/storm-control.js +59 -0
  411. package/dist/core/work/state.d.ts.map +1 -1
  412. package/dist/core/work/state.js +10 -14
  413. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  414. package/dist/core/workflow/live-session-v3.js +2 -1
  415. package/dist/index.d.ts +2 -0
  416. package/dist/index.d.ts.map +1 -1
  417. package/dist/index.js +2 -0
  418. package/dist/lazy-commands.d.ts +26 -0
  419. package/dist/lazy-commands.d.ts.map +1 -0
  420. package/dist/lazy-commands.js +210 -0
  421. package/dist/lib/docs-lint.d.ts +2 -0
  422. package/dist/lib/docs-lint.d.ts.map +1 -1
  423. package/dist/lib/docs-lint.js +45 -80
  424. package/dist/lib/docs-metadata-audit.d.ts +3 -0
  425. package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
  426. package/dist/lib/docs-metadata-audit.js +13 -23
  427. package/dist/lib/docs-metadata-sync.d.ts +1 -0
  428. package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
  429. package/dist/lib/docs-metadata-sync.js +28 -10
  430. package/dist/lib/docs-repository-view.d.ts +22 -0
  431. package/dist/lib/docs-repository-view.d.ts.map +1 -0
  432. package/dist/lib/docs-repository-view.js +185 -0
  433. package/dist/lib/http/client.d.ts +11 -5
  434. package/dist/lib/http/client.d.ts.map +1 -1
  435. package/dist/lib/http/client.js +22 -4
  436. package/dist/lib/http/index.d.ts +1 -1
  437. package/dist/lib/http/index.d.ts.map +1 -1
  438. package/dist/lib/http/index.js +1 -1
  439. package/dist/lib/indexer-exclusions.d.ts +27 -0
  440. package/dist/lib/indexer-exclusions.d.ts.map +1 -0
  441. package/dist/lib/indexer-exclusions.js +176 -0
  442. package/dist/lib/instructions/templates.d.ts.map +1 -1
  443. package/dist/lib/instructions/templates.js +5 -0
  444. package/dist/lib/local-file-url.d.ts +9 -0
  445. package/dist/lib/local-file-url.d.ts.map +1 -0
  446. package/dist/lib/local-file-url.js +20 -0
  447. package/dist/lib/web-performance.d.ts +118 -0
  448. package/dist/lib/web-performance.d.ts.map +1 -0
  449. package/dist/lib/web-performance.js +192 -0
  450. package/package.json +29 -2
  451. package/schemas/config.schema.json +58 -0
  452. package/schemas/event-v3.schema.json +324 -112
  453. package/src/commander.ts +462 -95
  454. package/src/commands/agents.ts +517 -190
  455. package/src/commands/backup.ts +18 -14
  456. package/src/commands/browse-session.ts +12 -0
  457. package/src/commands/browse.ts +6 -7
  458. package/src/commands/conversations.ts +279 -0
  459. package/src/commands/deinit.ts +6 -0
  460. package/src/commands/docs.ts +25 -6
  461. package/src/commands/doctor.ts +75 -9
  462. package/src/commands/fetch.ts +7 -6
  463. package/src/commands/files.ts +143 -0
  464. package/src/commands/governor.ts +13 -12
  465. package/src/commands/inbox.ts +61 -0
  466. package/src/commands/init.ts +78 -16
  467. package/src/commands/ledger-v3.ts +421 -1
  468. package/src/commands/logs.ts +224 -0
  469. package/src/commands/messages.ts +61 -0
  470. package/src/commands/outline.ts +6 -2
  471. package/src/commands/read.ts +6 -2
  472. package/src/commands/semantic.ts +66 -1
  473. package/src/commands/storage.ts +310 -0
  474. package/src/commands/tunnel.ts +66 -52
  475. package/src/commands/web.ts +77 -7
  476. package/src/commands/work.ts +3 -3
  477. package/src/commands/workflow.ts +13 -13
  478. package/src/core/agents/cli.ts +259 -53
  479. package/src/core/agents/live-authority-v3.ts +341 -10
  480. package/src/core/agents/live-lifecycle-v3.ts +6 -1
  481. package/src/core/agents/live-observation-v3.ts +6 -1
  482. package/src/core/agents/render/prompt-context.ts +27 -6
  483. package/src/core/agents/rules/stop-hook.ts +107 -16
  484. package/src/core/agents/rules/verdict.ts +1 -0
  485. package/src/core/agents/session-events.ts +4 -0
  486. package/src/core/agents/session-finalization-state-v3.ts +1 -1
  487. package/src/core/agents/session-finalizer-v3.ts +4 -1
  488. package/src/core/agents/state/activity-log.ts +7 -2
  489. package/src/core/agents/state/heartbeat-writer.ts +27 -0
  490. package/src/core/agents/state/live-coordination-view.ts +16 -105
  491. package/src/core/agents/state/live-coordination-writer.ts +141 -0
  492. package/src/core/artifacts/index.ts +64 -1
  493. package/src/core/config.ts +126 -5
  494. package/src/core/conversations/archive.ts +237 -0
  495. package/src/core/conversations/catalog.ts +79 -0
  496. package/src/core/conversations/context-pack.ts +72 -0
  497. package/src/core/conversations/contract.ts +178 -0
  498. package/src/core/conversations/evaluation.ts +30 -0
  499. package/src/core/conversations/index.ts +9 -0
  500. package/src/core/conversations/lifecycle.ts +63 -0
  501. package/src/core/conversations/normalize.ts +105 -0
  502. package/src/core/conversations/query.ts +318 -0
  503. package/src/core/conversations/search-index.ts +48 -0
  504. package/src/core/events/legacy-storage/canary.ts +177 -0
  505. package/src/core/events/legacy-storage/fence.ts +129 -0
  506. package/src/core/events/legacy-storage/index.ts +5 -0
  507. package/src/core/events/legacy-storage/inventory.ts +51 -0
  508. package/src/core/events/legacy-storage/manifest.ts +136 -0
  509. package/src/core/events/legacy-storage/reader.ts +178 -0
  510. package/src/core/events/v3/authority-outbox.ts +22 -1
  511. package/src/core/events/v3/base-contract.ts +17 -7
  512. package/src/core/events/v3/bootstrap.ts +195 -2
  513. package/src/core/events/v3/capabilities.ts +3 -3
  514. package/src/core/events/v3/control-witness.ts +339 -0
  515. package/src/core/events/v3/control-writer.ts +16 -0
  516. package/src/core/events/v3/control.ts +54 -18
  517. package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
  518. package/src/core/events/v3/coordination-view.ts +17 -1
  519. package/src/core/events/v3/generated.ts +1 -1
  520. package/src/core/events/v3/index.ts +5 -2
  521. package/src/core/events/v3/live-route-observer.ts +80 -0
  522. package/src/core/events/v3/live-routing.ts +64 -46
  523. package/src/core/events/v3/producers/coordination-recorder.ts +95 -10
  524. package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
  525. package/src/core/events/v3/producers/hook-base.ts +1 -1
  526. package/src/core/events/v3/producers/intake.ts +30 -2
  527. package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
  528. package/src/core/events/v3/producers/recorder.ts +571 -33
  529. package/src/core/events/v3/reader.ts +243 -2
  530. package/src/core/events/v3/rotation-config.ts +98 -0
  531. package/src/core/events/v3/runtime-build.ts +41 -0
  532. package/src/core/events/v3/runtime-identity.ts +16 -0
  533. package/src/core/events/v3/runtime-telemetry-capabilities.ts +14 -8
  534. package/src/core/events/v3/support-storage/classify.ts +209 -0
  535. package/src/core/events/v3/support-storage/eligibility.ts +58 -0
  536. package/src/core/events/v3/support-storage/index.ts +9 -0
  537. package/src/core/events/v3/support-storage/inventory.ts +135 -0
  538. package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
  539. package/src/core/events/v3/support-storage/maintenance.ts +501 -0
  540. package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
  541. package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
  542. package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
  543. package/src/core/events/v3/support-storage/recovery.ts +43 -0
  544. package/src/core/events/v3/turn-telemetry.ts +58 -7
  545. package/src/core/events/v3/writer.ts +168 -16
  546. package/src/core/governor/plan-read.ts +5 -18
  547. package/src/core/governor/planning.ts +5 -8
  548. package/src/core/governor/service-read.ts +320 -2
  549. package/src/core/governor/service.ts +49 -22
  550. package/src/core/guard/evidence-v3.ts +1 -0
  551. package/src/core/hooks/adapter/events.ts +1 -0
  552. package/src/core/hooks/adapter/output.ts +12 -5
  553. package/src/core/hooks/adapter/runtime-telemetry.ts +408 -13
  554. package/src/core/hooks/cli.ts +226 -32
  555. package/src/core/hooks/effects/image-capture.ts +4 -1
  556. package/src/core/hooks/remediation-cap.ts +12 -6
  557. package/src/core/hooks/resolve/coord-root.ts +91 -11
  558. package/src/core/hooks/resolve/owner.ts +4 -0
  559. package/src/core/hooks/resolve/transcript.ts +18 -0
  560. package/src/core/inbox/contract.ts +81 -0
  561. package/src/core/inbox/index.ts +4 -0
  562. package/src/core/inbox/lifecycle.ts +104 -0
  563. package/src/core/inbox/service.ts +305 -0
  564. package/src/core/inbox/watcher.ts +36 -0
  565. package/src/core/presence/codec-digest.ts +15 -9
  566. package/src/core/presence/relay-client.ts +55 -7
  567. package/src/core/semantic/adapters.ts +200 -41
  568. package/src/core/semantic/contract.ts +135 -3
  569. package/src/core/semantic/index.ts +76 -2
  570. package/src/core/semantic/once.ts +93 -7
  571. package/src/core/semantic/prompt.ts +13 -1
  572. package/src/core/semantic/review.ts +803 -0
  573. package/src/core/semantic/routes.ts +30 -0
  574. package/src/core/semantic/scheduler.ts +49 -5
  575. package/src/core/semantic/service-status.ts +99 -5
  576. package/src/core/semantic/service.ts +116 -15
  577. package/src/core/semantic/soak.ts +638 -0
  578. package/src/core/semantic/storage.ts +20 -6
  579. package/src/core/semantic/usage.ts +272 -0
  580. package/src/core/semantic/validate.ts +31 -0
  581. package/src/core/storage/buffer.ts +124 -0
  582. package/src/core/storage/builtins.ts +916 -0
  583. package/src/core/storage/catalog.ts +467 -0
  584. package/src/core/storage/config.ts +423 -0
  585. package/src/core/storage/contract.ts +342 -0
  586. package/src/core/storage/durable-history.ts +738 -0
  587. package/src/core/storage/health.ts +76 -0
  588. package/src/core/storage/index.ts +15 -0
  589. package/src/core/storage/inventory.ts +859 -0
  590. package/src/core/storage/jsonl.ts +213 -0
  591. package/src/core/storage/log-retention.ts +555 -0
  592. package/src/core/storage/logger.ts +546 -0
  593. package/src/core/storage/maintenance-providers.ts +200 -0
  594. package/src/core/storage/maintenance.ts +929 -0
  595. package/src/core/storage/metrics.ts +199 -0
  596. package/src/core/storage/policy.ts +141 -0
  597. package/src/core/storage/process-log.ts +203 -0
  598. package/src/core/storage/query.ts +360 -0
  599. package/src/core/storage/receipts.ts +162 -0
  600. package/src/core/storage/segments.ts +721 -0
  601. package/src/core/storage/sink-graph.ts +343 -0
  602. package/src/core/storage/storm-control.ts +91 -0
  603. package/src/core/work/state.ts +12 -21
  604. package/src/core/workflow/live-session-v3.ts +2 -4
  605. package/src/index.ts +2 -0
  606. package/src/lazy-commands.ts +294 -0
  607. package/src/lib/docs-lint.ts +58 -77
  608. package/src/lib/docs-metadata-audit.ts +26 -21
  609. package/src/lib/docs-metadata-sync.ts +32 -9
  610. package/src/lib/docs-repository-view.ts +220 -0
  611. package/src/lib/http/client.ts +44 -8
  612. package/src/lib/http/index.ts +6 -1
  613. package/src/lib/indexer-exclusions.ts +173 -0
  614. package/src/lib/instructions/templates.ts +5 -0
  615. package/src/lib/local-file-url.ts +31 -0
  616. package/src/lib/web-performance.ts +335 -0
@@ -1,5 +1,6 @@
1
+ import { readFileSync, statSync } from "node:fs";
1
2
  import { resolve } from "node:path";
2
- import { createSemanticAdapters, discoverSemanticReaders, inspectSemanticDocument, readSemanticManifest, readSemanticServiceStatus, requestSemanticServiceStop, runSemanticOnce, runSemanticServiceDaemon, semanticPaths, spawnSemanticService, } from "../core/semantic/index.js";
3
+ import { createSemanticAdapters, discoverSemanticReaders, inspectSemanticDocument, prepareSemanticReviewStudy, readSemanticManifest, readSemanticServiceStatus, readSemanticSoakReport, requestSemanticServiceStop, runSemanticOnce, runSemanticServiceDaemon, semanticPaths, spawnSemanticService, storeSemanticReviewSubmission, } from "../core/semantic/index.js";
3
4
  export function registerSemanticCommand(program, emit, context) {
4
5
  const semantic = program
5
6
  .command("semantic")
@@ -40,7 +41,7 @@ export function registerSemanticCommand(program, emit, context) {
40
41
  });
41
42
  service
42
43
  .command("status")
43
- .description("Show singleton liveness, pass metrics, and pending work")
44
+ .description("Show reader liveness, rolling calls, token usage, routes, and pending work")
44
45
  .option("--root <path>", "Explicit coordination root")
45
46
  .action((options) => {
46
47
  try {
@@ -101,6 +102,57 @@ export function registerSemanticCommand(program, emit, context) {
101
102
  emitFailure(emit, "semantic_inspect_failed", error);
102
103
  }
103
104
  });
105
+ semantic
106
+ .command("soak")
107
+ .description("Summarize recent reader outcomes, controlled cues, stability, and token usage")
108
+ .option("--root <path>", "Explicit coordination root")
109
+ .option("--minutes <count>", "Lookback window in whole minutes", integer)
110
+ .action((options) => {
111
+ try {
112
+ emit.data(readSemanticSoakReport(resolve(options.root ?? coordRoot(context)), {
113
+ ...(options.minutes !== undefined ? { minutes: options.minutes } : {}),
114
+ }));
115
+ }
116
+ catch (error) {
117
+ emitFailure(emit, "semantic_soak_failed", error);
118
+ }
119
+ });
120
+ const review = semantic
121
+ .command("review")
122
+ .description("Prepare and record a local human review of accepted semantic readings");
123
+ review
124
+ .command("prepare")
125
+ .description("Capture current accepted readings and return the next bounded review set")
126
+ .option("--root <path>", "Explicit coordination root")
127
+ .option("--limit <count>", "Maximum candidates in this review set", integer)
128
+ .action((options) => {
129
+ try {
130
+ emit.data(prepareSemanticReviewStudy(resolve(options.root ?? coordRoot(context)), {
131
+ ...(options.limit !== undefined ? { limit: options.limit } : {}),
132
+ }));
133
+ }
134
+ catch (error) {
135
+ emitFailure(emit, "semantic_review_prepare_failed", error);
136
+ }
137
+ });
138
+ review
139
+ .command("submit")
140
+ .description("Validate one frozen review set and store its controlled-label receipt")
141
+ .requiredOption("--file <path>", "JSON submission file")
142
+ .option("--root <path>", "Explicit coordination root")
143
+ .action((options) => {
144
+ try {
145
+ const file = resolve(options.file);
146
+ const size = statSync(file).size;
147
+ if (size <= 0 || size > 128 * 1024) {
148
+ throw new Error("semantic review submission has invalid size");
149
+ }
150
+ emit.data(storeSemanticReviewSubmission(resolve(options.root ?? coordRoot(context)), JSON.parse(readFileSync(file, "utf8"))));
151
+ }
152
+ catch (error) {
153
+ emitFailure(emit, "semantic_review_submit_failed", error);
154
+ }
155
+ });
104
156
  semantic
105
157
  .command("doctor")
106
158
  .description("Inspect semantic reader availability without making a model request")
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext, HarneryProgramContext } from "../commander.js";
3
+ export declare function registerStorageCommand(program: Command, emit: EmitContext, context?: HarneryProgramContext): void;
4
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/commands/storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAwD1E,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CA+IN"}
@@ -0,0 +1,238 @@
1
+ import { resolve } from "node:path";
2
+ import { resolveCoordRoot as resolveCanonicalCoordRoot } from "../core/agents/coord-client.js";
3
+ import { createStorageCatalog } from "../core/storage/catalog.js";
4
+ import { storageHealth } from "../core/storage/health.js";
5
+ import { filterStorageInventory, inventoryStorage } from "../core/storage/inventory.js";
6
+ import { DEFAULT_MAINTENANCE_BUDGET, executeStorageMaintenance, HARNERY_MAINTENANCE_PRESSURE_SCHEMA, HarneryMaintenanceError, listMaintenanceTransactions, planStorageMaintenance, readMaintenanceTransaction, } from "../core/storage/maintenance.js";
7
+ import { createStructuredLogMaintenanceProviders } from "../core/storage/maintenance-providers.js";
8
+ const STORAGE_CLASSES = new Set([
9
+ "canonical-authority",
10
+ "recovery-state",
11
+ "operational-log",
12
+ "debug-log",
13
+ "durable-object-history",
14
+ "repairable-cache",
15
+ "managed-artifact",
16
+ ]);
17
+ export function registerStorageCommand(program, emit, context) {
18
+ const storage = program
19
+ .command("storage")
20
+ .description("Inspect registered Harnery storage without reading file bodies");
21
+ storage
22
+ .command("inventory")
23
+ .description("Inventory .harnery and explicitly registered external storage roots")
24
+ .option("--family <id>", "Show one registered storage family")
25
+ .option("--class <class>", "Show one registered storage class")
26
+ .option("--json", "Emit the stable versioned inventory schema")
27
+ .action(async (options) => {
28
+ await run(emit, async () => {
29
+ const catalog = catalogFor(context);
30
+ if (options.family && !catalog.get(options.family)) {
31
+ throw new StorageCommandError("unknown_storage_family", `unknown storage family: ${options.family}`);
32
+ }
33
+ const storageClass = parseStorageClass(options.class);
34
+ const report = filterStorageInventory(await inventoryStorage(catalog), {
35
+ ...(options.family ? { family_id: options.family } : {}),
36
+ ...(storageClass ? { storage_class: storageClass } : {}),
37
+ });
38
+ if (options.json) {
39
+ emit.config({ format: "json" });
40
+ emit.data(report);
41
+ }
42
+ else {
43
+ emit.rows(inventoryRows(report));
44
+ }
45
+ });
46
+ });
47
+ storage
48
+ .command("health")
49
+ .description("Report reason-coded health for every registered storage family")
50
+ .option("--json", "Emit the stable versioned health schema")
51
+ .action(async (options) => {
52
+ await run(emit, async () => {
53
+ const report = storageHealth(await inventoryStorage(catalogFor(context)));
54
+ if (options.json) {
55
+ emit.config({ format: "json" });
56
+ emit.data(report);
57
+ }
58
+ else {
59
+ emit.text(`storage health: ${report.status}\n`);
60
+ emit.rows(report.families.map((family) => ({
61
+ family_id: family.family_id,
62
+ status: family.status,
63
+ reasons: family.reason_codes.join(",") || "none",
64
+ maintenance: family.maintenance.state,
65
+ max_bytes: family.log_storage?.effective_policy?.max_bytes ?? "unavailable",
66
+ max_age_days: family.log_storage?.effective_policy?.max_age_days ?? "unavailable",
67
+ managed_bytes: family.log_storage?.usage.managed_bytes ?? "not-a-log",
68
+ unmanaged_bytes: family.log_storage?.usage.unmanaged_bytes ?? "not-a-log",
69
+ pressure: family.log_storage?.pressure.state ?? "not-a-log",
70
+ enforcement: family.log_storage?.retention.enforcement ?? "not-a-log",
71
+ })));
72
+ }
73
+ });
74
+ });
75
+ storage
76
+ .command("maintain")
77
+ .description("Plan bounded maintenance, or execute one exact transaction")
78
+ .option("--family <id>", "Limit a new plan to one registered family")
79
+ .option("--budget <duration>", "Wall-time budget such as 500ms, 5s, or 1m")
80
+ .option("--dry-run", "Plan without mutating source storage", true)
81
+ .option("--transaction <id>", "Execute one previously planned exact transaction")
82
+ .option("--yes", "Confirm execution of the exact transaction")
83
+ .option("--authorize-structured-log-deletion", "Authorize deletion only for exact manifest-backed structured-log actions")
84
+ .option("--json", "Emit the versioned transaction schema")
85
+ .action(async (options) => {
86
+ await run(emit, async () => {
87
+ const catalog = catalogFor(context);
88
+ const providers = [
89
+ ...createStructuredLogMaintenanceProviders(catalog),
90
+ ...(context?.storageMaintenanceProviders ?? []),
91
+ ];
92
+ const transaction = options.transaction
93
+ ? await executeStorageMaintenance(catalog, providers, options.transaction, {
94
+ yes: options.yes === true,
95
+ authorize_structured_log_deletion: options.authorizeStructuredLogDeletion === true,
96
+ })
97
+ : await planStorageMaintenance(catalog, providers, await pressureFor(catalog), {
98
+ ...(options.family ? { family_id: options.family } : {}),
99
+ budget: {
100
+ ...DEFAULT_MAINTENANCE_BUDGET,
101
+ max_duration_ms: parseDuration(options.budget),
102
+ },
103
+ persist: true,
104
+ });
105
+ if (options.json) {
106
+ emit.config({ format: "json" });
107
+ emit.data(transaction);
108
+ }
109
+ else {
110
+ emit.rows([
111
+ {
112
+ transaction_id: transaction.transaction_id,
113
+ state: transaction.state,
114
+ dry_run: transaction.dry_run,
115
+ actions: transaction.actions.length,
116
+ files: transaction.actions.reduce((sum, action) => sum + action.files, 0),
117
+ bytes: transaction.actions.reduce((sum, action) => sum + action.bytes, 0),
118
+ reasons: transaction.reason_codes.join(",") || "none",
119
+ },
120
+ ]);
121
+ }
122
+ });
123
+ });
124
+ storage
125
+ .command("status")
126
+ .description("Inspect maintenance transactions without changing storage")
127
+ .option("--transaction <id>", "Show one exact transaction")
128
+ .option("--json", "Emit versioned transaction records")
129
+ .action(async (options) => {
130
+ await run(emit, async () => {
131
+ const catalog = catalogFor(context);
132
+ const transactions = options.transaction
133
+ ? [readMaintenanceTransaction(catalog.context.coord_root, options.transaction)]
134
+ : listMaintenanceTransactions(catalog.context.coord_root);
135
+ if (options.json) {
136
+ emit.config({ format: "json" });
137
+ emit.data(transactions);
138
+ }
139
+ else {
140
+ emit.rows(transactions.map((transaction) => ({
141
+ transaction_id: transaction.transaction_id,
142
+ state: transaction.state,
143
+ created_at: transaction.created_at,
144
+ actions: transaction.actions.length,
145
+ reasons: transaction.reason_codes.join(",") || "none",
146
+ })));
147
+ }
148
+ });
149
+ });
150
+ }
151
+ function catalogFor(context) {
152
+ const coordRoot = resolve(context?.resolveCoordRoot?.() ??
153
+ context?.repoRoot ??
154
+ process.env.HARNERY_COORD_ROOT ??
155
+ resolveCanonicalCoordRoot() ??
156
+ process.cwd());
157
+ return createStorageCatalog({ coord_root: coordRoot, project_root: resolve(context?.repoRoot ?? coordRoot) }, context?.storage);
158
+ }
159
+ function parseStorageClass(value) {
160
+ if (value === undefined)
161
+ return undefined;
162
+ if (!STORAGE_CLASSES.has(value)) {
163
+ throw new StorageCommandError("unknown_storage_class", `unknown storage class: ${value}`);
164
+ }
165
+ return value;
166
+ }
167
+ async function pressureFor(catalog) {
168
+ const inventory = await inventoryStorage(catalog);
169
+ return {
170
+ schema: HARNERY_MAINTENANCE_PRESSURE_SCHEMA,
171
+ captured_at: inventory.captured_at,
172
+ families: inventory.families.map((family) => ({
173
+ family_id: family.family_id,
174
+ logical_bytes: family.totals.logical_bytes.state === "observed" ? family.totals.logical_bytes.value : 0,
175
+ regular_files: family.totals.regular_files.state === "observed" ? family.totals.regular_files.value : 0,
176
+ needs_maintenance: family.maintenance.state === "eligible",
177
+ observed_at: inventory.captured_at,
178
+ })),
179
+ };
180
+ }
181
+ function parseDuration(value) {
182
+ if (value === undefined)
183
+ return DEFAULT_MAINTENANCE_BUDGET.max_duration_ms;
184
+ const match = /^(\d+)(ms|s|m)$/.exec(value);
185
+ if (!match)
186
+ throw new StorageCommandError("invalid_maintenance_budget", `invalid duration: ${value}`);
187
+ const amount = Number(match[1]);
188
+ const multiplier = match[2] === "ms" ? 1 : match[2] === "s" ? 1_000 : 60_000;
189
+ const result = amount * multiplier;
190
+ if (!Number.isSafeInteger(result) || result <= 0 || result > 60 * 60 * 1_000) {
191
+ throw new StorageCommandError("invalid_maintenance_budget", `invalid duration: ${value}`);
192
+ }
193
+ return result;
194
+ }
195
+ function inventoryRows(report) {
196
+ return report.families.map((family) => ({
197
+ family_id: family.family_id,
198
+ class: family.storage_class,
199
+ state: family.state,
200
+ regular_files: measurementValue(family.totals.regular_files),
201
+ logical_bytes: measurementValue(family.totals.logical_bytes),
202
+ allocated_bytes: measurementValue(family.totals.allocated_bytes),
203
+ maintenance: family.maintenance.state,
204
+ max_bytes: family.log_storage?.effective_policy?.max_bytes ?? "unavailable",
205
+ max_age_days: family.log_storage?.effective_policy?.max_age_days ?? "unavailable",
206
+ managed_bytes: family.log_storage?.usage.managed_bytes ?? "not-a-log",
207
+ unmanaged_bytes: family.log_storage?.usage.unmanaged_bytes ?? "not-a-log",
208
+ pressure: family.log_storage?.pressure.state ?? "not-a-log",
209
+ enforcement: family.log_storage?.retention.enforcement ?? "not-a-log",
210
+ reasons: family.reason_codes.join(",") || "none",
211
+ }));
212
+ }
213
+ function measurementValue(measurement) {
214
+ return measurement.state === "observed"
215
+ ? measurement.value
216
+ : `unavailable:${measurement.reason_code}`;
217
+ }
218
+ class StorageCommandError extends Error {
219
+ code;
220
+ constructor(code, message) {
221
+ super(message);
222
+ this.code = code;
223
+ }
224
+ }
225
+ async function run(emit, action) {
226
+ try {
227
+ await action();
228
+ }
229
+ catch (error) {
230
+ emit.error({
231
+ code: error instanceof StorageCommandError || error instanceof HarneryMaintenanceError
232
+ ? error.code
233
+ : "storage_inspection_failed",
234
+ message: error instanceof Error ? error.message : String(error),
235
+ });
236
+ emit.setExitCode(1);
237
+ }
238
+ }
@@ -1,6 +1,10 @@
1
1
  import type { Command } from "commander";
2
2
  import type { EmitContext, HarneryProgramContext } from "../commander.js";
3
- import { type TunnelState } from "../lib/tunnel/state.js";
3
+ import { type TunnelProvider, type TunnelState } from "../lib/tunnel/state.js";
4
+ export declare function tunnelLogDestinations(name: string, provider: TunnelProvider, env?: NodeJS.ProcessEnv, root?: string): {
5
+ gate: string;
6
+ provider: string;
7
+ };
4
8
  /**
5
9
  * Restart ONE instance's gate in place, deliberately leaving the provider
6
10
  * process running.
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../src/commands/tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAa1E,OAAO,EAYL,KAAK,WAAW,EAGjB,MAAM,wBAAwB,CAAC;AA8rBhC;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAsE7F;AA+MD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,WAAW,EACtB,YAAY,CAAC,EAAE,qBAAqB,GACnC,IAAI,CA2EN"}
1
+ {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../src/commands/tunnel.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAQ1E,OAAO,EAWL,KAAK,cAAc,EACnB,KAAK,WAAW,EAGjB,MAAM,wBAAwB,CAAC;AAoDhC,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,cAAc,EACxB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,SAAgB,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAcpC;AAuoBD;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAsE7F;AA+MD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,WAAW,EACtB,YAAY,CAAC,EAAE,qBAAqB,GACnC,IAAI,CA2EN"}
@@ -1,12 +1,8 @@
1
- // Inline cachePath; see lib/tunnel/state.ts for rationale.
2
- function cachePath(tool, filename) {
3
- const dir = resolve(process.cwd(), ".cache", tool);
4
- return resolve(dir, filename);
5
- }
6
- import { spawn, spawnSync } from "node:child_process";
7
- import { existsSync, openSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync, readFileSync } from "node:fs";
8
3
  import { resolve } from "node:path";
9
4
  import { resolveBinName } from "../core/config.js";
5
+ import { processLogDestination, runRotatingProcessSync, spawnRotatingProcess, } from "../core/storage/process-log.js";
10
6
  import { clearState, DEFAULT_INSTANCE, ensureCloudflared, gateLogFile, isProcessAlive, listStates, providerLogFile, readConfig, readState, writeConfig, writeState, } from "../lib/tunnel/state.js";
11
7
  /**
12
8
  * `tunnel`: provider-backed tunnel in front of a local upstream.
@@ -24,6 +20,20 @@ const DEFAULT_TARGET = "127.0.0.1:8001";
24
20
  const DEFAULT_VHOST = "localhost";
25
21
  const DEFAULT_GATE_PORT = 9001;
26
22
  const MAX_GATE_PORT = DEFAULT_GATE_PORT + 99; // auto-allocation scan ceiling
23
+ export function tunnelLogDestinations(name, provider, env = process.env, root = process.cwd()) {
24
+ const destination = (filename) => processLogDestination({
25
+ coord_root: root,
26
+ project_root: root,
27
+ family_id: "tunnel-process-log",
28
+ filename,
29
+ legacy_path: resolve(root, ".cache", "tunnel", filename),
30
+ env,
31
+ });
32
+ return {
33
+ gate: destination(gateLogFile(name)),
34
+ provider: destination(providerLogFile(name, provider)),
35
+ };
36
+ }
27
37
  /**
28
38
  * Validate + normalize an instance name. Names become filename fragments
29
39
  * (state-<name>.json) and pgrep patterns, so they're restricted to a safe
@@ -270,7 +280,6 @@ function tailscaleCommand(mode) {
270
280
  return mode === "funnel" ? "funnel" : "serve";
271
281
  }
272
282
  function runTailscaleShare(mode, targetUrl, path, httpsPort, logPath) {
273
- const fd = openSync(logPath, "a");
274
283
  const args = [
275
284
  tailscaleCommand(mode),
276
285
  "--bg",
@@ -279,31 +288,36 @@ function runTailscaleShare(mode, targetUrl, path, httpsPort, logPath) {
279
288
  `--set-path=${path}`,
280
289
  targetUrl,
281
290
  ];
282
- const r = spawnSync("tailscale", args, {
283
- stdio: ["ignore", fd, fd],
291
+ const status = runRotatingProcessSync({
292
+ path: logPath,
293
+ command: "tailscale",
294
+ arguments: args,
284
295
  });
285
- if (r.status !== 0) {
296
+ if (status !== 0) {
286
297
  emit.error({
287
298
  code: "tunnel_tailscale_failed",
288
299
  message: `tailscale ${tailscaleCommand(mode)} failed. Check log: ${logPath}`,
289
300
  });
290
- process.exit(r.status ?? 1);
301
+ process.exit(status ?? 1);
291
302
  }
292
303
  }
293
304
  function stopTailscaleShare(state) {
294
305
  if (state.provider !== "tailscale" || !state.tailscale_mode)
295
306
  return true;
296
307
  const cmd = tailscaleCommand(state.tailscale_mode);
297
- const logPath = cachePath("tunnel", providerLogFile(state.name, "tailscale"));
298
- const fd = openSync(logPath, "a");
308
+ const logPath = tunnelLogDestinations(state.name, "tailscale").provider;
299
309
  const args = [
300
310
  cmd,
301
311
  `--https=${state.tailscale_https_port ?? 443}`,
302
312
  `--set-path=${state.tailscale_path ?? "/"}`,
303
313
  "off",
304
314
  ];
305
- const r = spawnSync("tailscale", args, { stdio: ["ignore", fd, fd] });
306
- if (r.status !== 0) {
315
+ const status = runRotatingProcessSync({
316
+ path: logPath,
317
+ command: "tailscale",
318
+ arguments: args,
319
+ });
320
+ if (status !== 0) {
307
321
  // The gate is torn down and its port is freed for reuse regardless, so a
308
322
  // surviving serve/funnel mapping could later re-expose whatever next binds
309
323
  // that port. Surface it loudly so the operator can clear it by hand.
@@ -339,12 +353,12 @@ function tunnelIsAlive(state) {
339
353
  * re-reads — that snapshot is precisely why `reload` has to exist.
340
354
  */
341
355
  function spawnGate(o) {
342
- const gateFd = openSync(o.gateLogPath, "a");
343
356
  // `--name`/`--port` on argv mirror the env vars; they're what makes the gate
344
357
  // process distinguishable per-instance in `pgrep -f` (see sweepStrays).
345
- const gateProc = spawn("bun", ["run", gateScriptPath(), "--name", o.name, "--port", String(o.gatePort)], {
346
- detached: true,
347
- stdio: ["ignore", gateFd, gateFd],
358
+ const gateProc = spawnRotatingProcess({
359
+ path: o.gateLogPath,
360
+ command: "bun",
361
+ arguments: ["run", gateScriptPath(), "--name", o.name, "--port", String(o.gatePort)],
348
362
  env: {
349
363
  ...process.env,
350
364
  HARNERY_TUNNEL_ALLOW: o.allowedIps.join(","),
@@ -414,10 +428,9 @@ async function up(opts) {
414
428
  });
415
429
  process.exit(1);
416
430
  }
417
- const gateLogPath = cachePath("tunnel", gateLogFile(name));
418
- const providerLogPath = cachePath("tunnel", providerLogFile(name, provider));
419
- writeFileSync(gateLogPath, "");
420
- writeFileSync(providerLogPath, "");
431
+ const logPaths = tunnelLogDestinations(name, provider);
432
+ const gateLogPath = logPaths.gate;
433
+ const providerLogPath = logPaths.provider;
421
434
  const gateProc = spawnGate({
422
435
  name,
423
436
  gatePort,
@@ -439,15 +452,15 @@ async function up(opts) {
439
452
  let registered = true;
440
453
  let cloudflaredPid;
441
454
  if (provider === "cloudflare") {
442
- const cfdFd = openSync(providerLogPath, "a");
443
455
  // Force HTTP/2 transport. The default QUIC transport wedges at precheck on
444
456
  // constrained hosts (e.g. WSL, where UDP receive buffers can't grow and ICMP
445
457
  // is restricted): the URL prints but the edge never registers. HTTP/2 is
446
458
  // marginally higher-latency but registers reliably, which is what a dev
447
459
  // tunnel needs.
448
- const cfdProc = spawn(cloudflaredBin, ["tunnel", "--protocol", "http2", "--url", `http://localhost:${gatePort}`], {
449
- detached: true,
450
- stdio: ["ignore", cfdFd, cfdFd],
460
+ const cfdProc = spawnRotatingProcess({
461
+ path: providerLogPath,
462
+ command: cloudflaredBin,
463
+ arguments: ["tunnel", "--protocol", "http2", "--url", `http://localhost:${gatePort}`],
451
464
  });
452
465
  cfdProc.unref();
453
466
  cloudflaredPid = cfdProc.pid;
@@ -649,7 +662,7 @@ export async function reloadOne(state) {
649
662
  vhost: state.vhost,
650
663
  provider: state.provider,
651
664
  allowedIps: cfg.allowed_ips,
652
- gateLogPath: cachePath("tunnel", gateLogFile(name)),
665
+ gateLogPath: tunnelLogDestinations(name, state.provider).gate,
653
666
  });
654
667
  await sleep(800);
655
668
  const pid = gateProc.pid;
@@ -794,8 +807,8 @@ function logs(opts) {
794
807
  const name = resolveName(opts.name);
795
808
  const state = readState(name);
796
809
  const provider = state?.provider ?? "cloudflare";
797
- const which = opts.provider ? providerLogFile(name, provider) : gateLogFile(name);
798
- const path = cachePath("tunnel", which);
810
+ const destinations = tunnelLogDestinations(name, provider);
811
+ const path = opts.provider ? destinations.provider : destinations.gate;
799
812
  if (!existsSync(path)) {
800
813
  emit.error({ code: "tunnel_no_log", message: `No log file at ${path}` });
801
814
  process.exit(1);
@@ -19,6 +19,9 @@ export declare function resolveMaxOldSpaceMb(flag?: string): number;
19
19
  * wins without clobbering flags the caller set (source maps, inspector, …).
20
20
  */
21
21
  export declare function nodeOptionsWithHeapCap(mb: number): string | undefined;
22
+ /** Preload the request diagnostics hook without replacing Next's HTTP server. */
23
+ export declare function nodeOptionsWithWebDiagnostics(webDir: string, mb: number): string;
24
+ export declare function webPerformanceLogDestination(coordRoot: string, env?: Readonly<Record<string, string | undefined>>): string;
22
25
  /**
23
26
  * Probe the exact localhost socket Next will claim. This is deliberately a
24
27
  * check-and-report step, not an alternate-port allocator: Harnery keeps one
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/commands/web.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAkCnD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKrE;AAyCD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAevE;AAsBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA6K5E"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/commands/web.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAyCnD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKrE;AAED,iFAAiF;AACjF,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,MAAM,CAQR;AAyCD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAevE;AAsBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAuN5E"}
@@ -2,9 +2,11 @@ import { spawn, spawnSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  import { createServer } from "node:net";
4
4
  import path from "node:path";
5
- import { fileURLToPath } from "node:url";
5
+ import { fileURLToPath, pathToFileURL } from "node:url";
6
6
  import { DEFAULT_WEB_PORT, resolveWebPort } from "../core/config.js";
7
7
  import { ensureSemanticServiceRunning } from "../core/semantic/service.js";
8
+ import { processLogDestination } from "../core/storage/process-log.js";
9
+ import { parsePerformanceWindow, readWebPerformanceReport, WEB_PERFORMANCE_LOG, } from "../lib/web-performance.js";
8
10
  import { lazyFetchWebRoot, webRunner } from "./web-fetch.js";
9
11
  /**
10
12
  * `harn web`: Next.js dashboard for harnery's coord state.
@@ -13,6 +15,7 @@ import { lazyFetchWebRoot, webRunner } from "./web-fetch.js";
13
15
  * up [--prod]: start the server (dev mode default; --prod runs next start)
14
16
  * build: next build (production bundle)
15
17
  * start: next start (must `harn web build` first)
18
+ * performance: summarize request latency and event-loop delays
16
19
  *
17
20
  * Launches the Next.js app under `harnery/web/` against the user's current
18
21
  * working directory. The web app reads `.harnery/` via `HARNERY_COORD_ROOT`;
@@ -66,6 +69,23 @@ export function nodeOptionsWithHeapCap(mb) {
66
69
  return inherited;
67
70
  return `${inherited} --max-old-space-size=${mb}`.trim();
68
71
  }
72
+ /** Preload the request diagnostics hook without replacing Next's HTTP server. */
73
+ export function nodeOptionsWithWebDiagnostics(webDir, mb) {
74
+ const inherited = nodeOptionsWithHeapCap(mb) ?? "";
75
+ if (inherited.includes("server-performance.mjs"))
76
+ return inherited;
77
+ const preload = pathToFileURL(path.join(webDir, "server-performance.mjs")).href;
78
+ return `${inherited} --import=${preload}`.trim();
79
+ }
80
+ export function webPerformanceLogDestination(coordRoot, env = process.env) {
81
+ return processLogDestination({
82
+ coord_root: coordRoot,
83
+ family_id: "web-performance-log",
84
+ filename: "active.jsonl",
85
+ legacy_path: path.join(coordRoot, ".harnery", "logs", WEB_PERFORMANCE_LOG),
86
+ env,
87
+ });
88
+ }
69
89
  async function startSemanticServiceWithWeb(coordRoot, emit) {
70
90
  const result = await ensureSemanticServiceRunning(coordRoot);
71
91
  if (result.state === "started")
@@ -185,9 +205,12 @@ export function registerWebCommand(program, emit) {
185
205
  return;
186
206
  await startSemanticServiceWithWeb(coordRoot, emit);
187
207
  const heapMb = resolveMaxOldSpaceMb(opts.maxOldSpace);
208
+ const nodeOptions = nodeOptionsWithWebDiagnostics(root, heapMb);
209
+ const performanceLogPath = webPerformanceLogDestination(coordRoot);
188
210
  emit.log(`harn web · http://localhost:${port} (${mode})`, "info");
189
211
  emit.log(`files origin · http://harnery-files.localhost:${port}`, "info");
190
212
  emit.log(`reading .harnery/ from: ${coordRoot}`, "info");
213
+ emit.log(`performance log · ${performanceLogPath}`, "info");
191
214
  if (heapMb > 0)
192
215
  emit.log(`heap ceiling · ${heapMb} MB`, "info");
193
216
  const child = spawn(webRunner(), ["run", mode], {
@@ -196,9 +219,9 @@ export function registerWebCommand(program, emit) {
196
219
  ...process.env,
197
220
  HARNERY_COORD_ROOT: coordRoot,
198
221
  HARNERY_WEB_PORT: String(port),
199
- ...(nodeOptionsWithHeapCap(heapMb)
200
- ? { NODE_OPTIONS: nodeOptionsWithHeapCap(heapMb) }
201
- : {}),
222
+ HARNERY_WEB_MODE: mode,
223
+ HARNERY_WEB_PERFORMANCE_LOG_PATH: performanceLogPath,
224
+ NODE_OPTIONS: nodeOptions,
202
225
  },
203
226
  stdio: "inherit",
204
227
  });
@@ -271,8 +294,11 @@ export function registerWebCommand(program, emit) {
271
294
  return;
272
295
  await startSemanticServiceWithWeb(coordRoot, emit);
273
296
  const heapMb = resolveMaxOldSpaceMb(opts.maxOldSpace);
297
+ const nodeOptions = nodeOptionsWithWebDiagnostics(root, heapMb);
298
+ const performanceLogPath = webPerformanceLogDestination(coordRoot);
274
299
  emit.log(`harn web · http://localhost:${port} (start)`, "info");
275
300
  emit.log(`reading .harnery/ from: ${coordRoot}`, "info");
301
+ emit.log(`performance log · ${performanceLogPath}`, "info");
276
302
  if (heapMb > 0)
277
303
  emit.log(`heap ceiling · ${heapMb} MB`, "info");
278
304
  const child = spawn(webRunner(), ["run", "start"], {
@@ -281,9 +307,9 @@ export function registerWebCommand(program, emit) {
281
307
  ...process.env,
282
308
  HARNERY_COORD_ROOT: coordRoot,
283
309
  HARNERY_WEB_PORT: String(port),
284
- ...(nodeOptionsWithHeapCap(heapMb)
285
- ? { NODE_OPTIONS: nodeOptionsWithHeapCap(heapMb) }
286
- : {}),
310
+ HARNERY_WEB_MODE: "start",
311
+ HARNERY_WEB_PERFORMANCE_LOG_PATH: performanceLogPath,
312
+ NODE_OPTIONS: nodeOptions,
287
313
  },
288
314
  stdio: "inherit",
289
315
  });
@@ -297,4 +323,38 @@ export function registerWebCommand(program, emit) {
297
323
  process.exitCode = code ?? 0;
298
324
  });
299
325
  });
326
+ web
327
+ .command("performance")
328
+ .description("Summarize dashboard request, event-loop, memory, and GC diagnostics")
329
+ .option("--coord-root <dir>", "Override the coordination root", process.cwd())
330
+ .option("--since <window>", "Include the last Nm, Nh, or Nd", "1h")
331
+ .option("--limit <n>", "Keep the N slowest requests and delays", "20")
332
+ .option("--json", "Emit structured JSON")
333
+ .action((opts) => {
334
+ const windowMs = parsePerformanceWindow(opts.since);
335
+ if (windowMs === null) {
336
+ emit.error({
337
+ code: "invalid_web_performance_window",
338
+ message: `invalid --since value '${opts.since}'`,
339
+ hint: "Use Nm, Nh, or Nd, for example 30m, 1h, or 7d.",
340
+ });
341
+ return;
342
+ }
343
+ const limit = Number(opts.limit);
344
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 500) {
345
+ emit.error({
346
+ code: "invalid_web_performance_limit",
347
+ message: `invalid --limit value '${opts.limit}'`,
348
+ hint: "Use an integer from 1 through 500.",
349
+ });
350
+ return;
351
+ }
352
+ if (opts.json)
353
+ emit.config({ format: "json" });
354
+ emit.data(readWebPerformanceReport({
355
+ root: opts.coordRoot,
356
+ since: opts.since,
357
+ limit,
358
+ }));
359
+ });
300
360
  }