harnery 0.36.0 → 0.37.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 (311) hide show
  1. package/dist/commander.js +4 -0
  2. package/dist/commands/agents.d.ts.map +1 -1
  3. package/dist/commands/agents.js +87 -46
  4. package/dist/commands/artifacts.d.ts.map +1 -1
  5. package/dist/commands/artifacts.js +26 -1
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +11 -0
  8. package/dist/commands/diagnostics.d.ts +4 -0
  9. package/dist/commands/diagnostics.d.ts.map +1 -0
  10. package/dist/commands/diagnostics.js +229 -0
  11. package/dist/commands/files.d.ts +12 -0
  12. package/dist/commands/files.d.ts.map +1 -1
  13. package/dist/commands/files.js +54 -1
  14. package/dist/commands/governor.d.ts.map +1 -1
  15. package/dist/commands/governor.js +4 -0
  16. package/dist/commands/ledger-v3.d.ts.map +1 -1
  17. package/dist/commands/ledger-v3.js +71 -2
  18. package/dist/commands/qa-run.d.ts +4 -0
  19. package/dist/commands/qa-run.d.ts.map +1 -0
  20. package/dist/commands/qa-run.js +141 -0
  21. package/dist/commands/resources.d.ts +4 -0
  22. package/dist/commands/resources.d.ts.map +1 -0
  23. package/dist/commands/resources.js +29 -0
  24. package/dist/commands/supervisor.d.ts +4 -0
  25. package/dist/commands/supervisor.d.ts.map +1 -0
  26. package/dist/commands/supervisor.js +101 -0
  27. package/dist/commands/web.d.ts.map +1 -1
  28. package/dist/commands/web.js +17 -0
  29. package/dist/commands/workflow.d.ts.map +1 -1
  30. package/dist/commands/workflow.js +4 -0
  31. package/dist/core/agents/cli.js +7 -3
  32. package/dist/core/agents/health.d.ts +17 -0
  33. package/dist/core/agents/health.d.ts.map +1 -0
  34. package/dist/core/agents/health.js +109 -0
  35. package/dist/core/agents/mailbox.d.ts +92 -0
  36. package/dist/core/agents/mailbox.d.ts.map +1 -0
  37. package/dist/core/agents/mailbox.js +325 -0
  38. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  39. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  40. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  41. package/dist/core/agents/render/prompt-context.d.ts +5 -0
  42. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  43. package/dist/core/agents/render/prompt-context.js +34 -13
  44. package/dist/core/agents/render/session-context.d.ts +8 -0
  45. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  46. package/dist/core/agents/render/session-context.js +34 -3
  47. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  48. package/dist/core/agents/rules/commit-conflict.js +50 -1
  49. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  50. package/dist/core/agents/rules/stop-hook.js +6 -10
  51. package/dist/core/agents/session-finalizer-v3.js +4 -1
  52. package/dist/core/artifacts/index.d.ts +26 -1
  53. package/dist/core/artifacts/index.d.ts.map +1 -1
  54. package/dist/core/artifacts/index.js +146 -6
  55. package/dist/core/config.d.ts +12 -0
  56. package/dist/core/config.d.ts.map +1 -1
  57. package/dist/core/config.js +43 -0
  58. package/dist/core/diagnostics/advice.d.ts +9 -0
  59. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  60. package/dist/core/diagnostics/advice.js +112 -0
  61. package/dist/core/diagnostics/bundle.d.ts +35 -0
  62. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  63. package/dist/core/diagnostics/bundle.js +874 -0
  64. package/dist/core/diagnostics/comparison.d.ts +5 -0
  65. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  66. package/dist/core/diagnostics/comparison.js +444 -0
  67. package/dist/core/diagnostics/contract.d.ts +245 -0
  68. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  69. package/dist/core/diagnostics/contract.js +18 -0
  70. package/dist/core/diagnostics/identity.d.ts +3 -0
  71. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  72. package/dist/core/diagnostics/identity.js +10 -0
  73. package/dist/core/diagnostics/index.d.ts +8 -0
  74. package/dist/core/diagnostics/index.d.ts.map +1 -0
  75. package/dist/core/diagnostics/index.js +7 -0
  76. package/dist/core/diagnostics/replay.d.ts +8 -0
  77. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  78. package/dist/core/diagnostics/replay.js +213 -0
  79. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  80. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  81. package/dist/core/diagnostics/sanitize.js +84 -0
  82. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  83. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  84. package/dist/core/events/legacy-storage/compression.js +107 -0
  85. package/dist/core/events/legacy-storage/index.d.ts +1 -0
  86. package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
  87. package/dist/core/events/legacy-storage/index.js +1 -0
  88. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  89. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  90. package/dist/core/events/v3/archive-retention.js +195 -0
  91. package/dist/core/events/v3/capabilities.d.ts +1 -1
  92. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  93. package/dist/core/events/v3/capabilities.js +1 -0
  94. package/dist/core/events/v3/index.d.ts +1 -0
  95. package/dist/core/events/v3/index.d.ts.map +1 -1
  96. package/dist/core/events/v3/index.js +1 -0
  97. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  98. package/dist/core/events/v3/live-routing.js +1 -0
  99. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  100. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  101. package/dist/core/events/v3/producers/hook-base.js +13 -2
  102. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  103. package/dist/core/events/v3/producers/intake.js +1 -0
  104. package/dist/core/events/v3/producers/recorder.d.ts +16 -0
  105. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  106. package/dist/core/events/v3/producers/recorder.js +88 -1
  107. package/dist/core/hooks/adapter/output.d.ts +8 -0
  108. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  109. package/dist/core/hooks/adapter/output.js +11 -1
  110. package/dist/core/hooks/cli.js +183 -192
  111. package/dist/core/hooks/health.d.ts +59 -0
  112. package/dist/core/hooks/health.d.ts.map +1 -0
  113. package/dist/core/hooks/health.js +84 -0
  114. package/dist/core/resources/contract.d.ts +90 -0
  115. package/dist/core/resources/contract.d.ts.map +1 -0
  116. package/dist/core/resources/contract.js +2 -0
  117. package/dist/core/resources/index.d.ts +6 -0
  118. package/dist/core/resources/index.d.ts.map +1 -0
  119. package/dist/core/resources/index.js +5 -0
  120. package/dist/core/resources/sampler.d.ts +27 -0
  121. package/dist/core/resources/sampler.d.ts.map +1 -0
  122. package/dist/core/resources/sampler.js +357 -0
  123. package/dist/core/resources/service-status.d.ts +3 -0
  124. package/dist/core/resources/service-status.d.ts.map +1 -0
  125. package/dist/core/resources/service-status.js +48 -0
  126. package/dist/core/resources/service.d.ts +26 -0
  127. package/dist/core/resources/service.d.ts.map +1 -0
  128. package/dist/core/resources/service.js +292 -0
  129. package/dist/core/resources/storage.d.ts +13 -0
  130. package/dist/core/resources/storage.d.ts.map +1 -0
  131. package/dist/core/resources/storage.js +30 -0
  132. package/dist/core/storage/atomic-json.d.ts +3 -0
  133. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  134. package/dist/core/storage/atomic-json.js +15 -0
  135. package/dist/core/storage/builtins.d.ts.map +1 -1
  136. package/dist/core/storage/builtins.js +45 -6
  137. package/dist/core/storage/logger.d.ts +2 -0
  138. package/dist/core/storage/logger.d.ts.map +1 -1
  139. package/dist/core/storage/logger.js +2 -0
  140. package/dist/core/storage/query.d.ts +14 -0
  141. package/dist/core/storage/query.d.ts.map +1 -1
  142. package/dist/core/storage/query.js +51 -0
  143. package/dist/core/supervisor/activity.d.ts +4 -0
  144. package/dist/core/supervisor/activity.d.ts.map +1 -0
  145. package/dist/core/supervisor/activity.js +141 -0
  146. package/dist/core/supervisor/contract.d.ts +268 -0
  147. package/dist/core/supervisor/contract.d.ts.map +1 -0
  148. package/dist/core/supervisor/contract.js +35 -0
  149. package/dist/core/supervisor/explanations.d.ts +4 -0
  150. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  151. package/dist/core/supervisor/explanations.js +71 -0
  152. package/dist/core/supervisor/findings.d.ts +20 -0
  153. package/dist/core/supervisor/findings.d.ts.map +1 -0
  154. package/dist/core/supervisor/findings.js +399 -0
  155. package/dist/core/supervisor/history.d.ts +9 -0
  156. package/dist/core/supervisor/history.d.ts.map +1 -0
  157. package/dist/core/supervisor/history.js +46 -0
  158. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  159. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  160. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  161. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  162. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  163. package/dist/core/supervisor/hook-health-storage.js +24 -0
  164. package/dist/core/supervisor/hook-health.d.ts +72 -0
  165. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  166. package/dist/core/supervisor/hook-health.js +203 -0
  167. package/dist/core/supervisor/hooks.d.ts +10 -0
  168. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  169. package/dist/core/supervisor/hooks.js +28 -0
  170. package/dist/core/supervisor/index.d.ts +15 -0
  171. package/dist/core/supervisor/index.d.ts.map +1 -0
  172. package/dist/core/supervisor/index.js +14 -0
  173. package/dist/core/supervisor/log-feed.d.ts +9 -0
  174. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  175. package/dist/core/supervisor/log-feed.js +103 -0
  176. package/dist/core/supervisor/service.d.ts +29 -0
  177. package/dist/core/supervisor/service.d.ts.map +1 -0
  178. package/dist/core/supervisor/service.js +450 -0
  179. package/dist/core/supervisor/services.d.ts +11 -0
  180. package/dist/core/supervisor/services.d.ts.map +1 -0
  181. package/dist/core/supervisor/services.js +155 -0
  182. package/dist/core/supervisor/status.d.ts +3 -0
  183. package/dist/core/supervisor/status.d.ts.map +1 -0
  184. package/dist/core/supervisor/status.js +48 -0
  185. package/dist/core/supervisor/storage.d.ts +30 -0
  186. package/dist/core/supervisor/storage.d.ts.map +1 -0
  187. package/dist/core/supervisor/storage.js +73 -0
  188. package/dist/core/supervisor/timeline.d.ts +3 -0
  189. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  190. package/dist/core/supervisor/timeline.js +87 -0
  191. package/dist/core/workflow/admission.d.ts +23 -0
  192. package/dist/core/workflow/admission.d.ts.map +1 -0
  193. package/dist/core/workflow/admission.js +136 -0
  194. package/dist/core/workflow/engine.d.ts.map +1 -1
  195. package/dist/core/workflow/engine.js +77 -2
  196. package/dist/core/workflow/index.d.ts +3 -2
  197. package/dist/core/workflow/index.d.ts.map +1 -1
  198. package/dist/core/workflow/index.js +2 -1
  199. package/dist/core/workflow/proof.d.ts +2 -1
  200. package/dist/core/workflow/proof.d.ts.map +1 -1
  201. package/dist/core/workflow/proof.js +39 -1
  202. package/dist/core/workflow/run-state.d.ts +3 -2
  203. package/dist/core/workflow/run-state.d.ts.map +1 -1
  204. package/dist/core/workflow/run-state.js +8 -1
  205. package/dist/core/workflow/types.d.ts +33 -1
  206. package/dist/core/workflow/types.d.ts.map +1 -1
  207. package/dist/core/workflow/types.js +2 -1
  208. package/dist/lib/browser/client.d.ts +5 -0
  209. package/dist/lib/browser/client.d.ts.map +1 -1
  210. package/dist/lib/browser/client.js +1 -0
  211. package/dist/lib/browser/index.d.ts +2 -0
  212. package/dist/lib/browser/index.d.ts.map +1 -1
  213. package/dist/lib/browser/index.js +2 -0
  214. package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
  215. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  216. package/dist/lib/browser/qa-run-contracts.js +226 -0
  217. package/dist/lib/browser/qa-run.d.ts +51 -0
  218. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  219. package/dist/lib/browser/qa-run.js +684 -0
  220. package/dist/lib/coord-root-id.d.ts +9 -0
  221. package/dist/lib/coord-root-id.d.ts.map +1 -0
  222. package/dist/lib/coord-root-id.js +17 -0
  223. package/dist/lib/instructions/apply.d.ts +3 -1
  224. package/dist/lib/instructions/apply.d.ts.map +1 -1
  225. package/dist/lib/instructions/apply.js +74 -3
  226. package/dist/lib/instructions/templates.d.ts.map +1 -1
  227. package/dist/lib/instructions/templates.js +6 -0
  228. package/package.json +12 -1
  229. package/src/commander.ts +26 -0
  230. package/src/commands/agents.ts +102 -49
  231. package/src/commands/artifacts.ts +40 -2
  232. package/src/commands/browse.ts +15 -0
  233. package/src/commands/diagnostics.ts +271 -0
  234. package/src/commands/files.ts +102 -2
  235. package/src/commands/governor.ts +8 -0
  236. package/src/commands/ledger-v3.ts +82 -0
  237. package/src/commands/qa-run.ts +184 -0
  238. package/src/commands/resources.ts +38 -0
  239. package/src/commands/supervisor.ts +141 -0
  240. package/src/commands/web.ts +19 -0
  241. package/src/commands/workflow.ts +8 -0
  242. package/src/core/agents/cli.ts +7 -3
  243. package/src/core/agents/health.ts +142 -0
  244. package/src/core/agents/mailbox.ts +373 -0
  245. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  246. package/src/core/agents/render/prompt-context.ts +42 -12
  247. package/src/core/agents/render/session-context.ts +37 -3
  248. package/src/core/agents/rules/commit-conflict.ts +58 -1
  249. package/src/core/agents/rules/stop-hook.ts +6 -12
  250. package/src/core/agents/session-finalizer-v3.ts +4 -1
  251. package/src/core/artifacts/index.ts +196 -10
  252. package/src/core/config.ts +111 -2
  253. package/src/core/diagnostics/advice.ts +147 -0
  254. package/src/core/diagnostics/bundle.ts +1142 -0
  255. package/src/core/diagnostics/comparison.ts +565 -0
  256. package/src/core/diagnostics/contract.ts +311 -0
  257. package/src/core/diagnostics/identity.ts +11 -0
  258. package/src/core/diagnostics/index.ts +7 -0
  259. package/src/core/diagnostics/replay.ts +314 -0
  260. package/src/core/diagnostics/sanitize.ts +97 -0
  261. package/src/core/events/legacy-storage/compression.ts +130 -0
  262. package/src/core/events/legacy-storage/index.ts +1 -0
  263. package/src/core/events/v3/archive-retention.ts +251 -0
  264. package/src/core/events/v3/capabilities.ts +2 -0
  265. package/src/core/events/v3/index.ts +9 -0
  266. package/src/core/events/v3/live-routing.ts +1 -0
  267. package/src/core/events/v3/producers/hook-base.ts +14 -2
  268. package/src/core/events/v3/producers/intake.ts +1 -0
  269. package/src/core/events/v3/producers/recorder.ts +110 -1
  270. package/src/core/hooks/adapter/output.ts +12 -1
  271. package/src/core/hooks/cli.ts +192 -215
  272. package/src/core/hooks/health.ts +146 -0
  273. package/src/core/resources/contract.ts +98 -0
  274. package/src/core/resources/index.ts +5 -0
  275. package/src/core/resources/sampler.ts +458 -0
  276. package/src/core/resources/service-status.ts +62 -0
  277. package/src/core/resources/service.ts +337 -0
  278. package/src/core/resources/storage.ts +44 -0
  279. package/src/core/storage/atomic-json.ts +15 -0
  280. package/src/core/storage/builtins.ts +62 -6
  281. package/src/core/storage/logger.ts +2 -0
  282. package/src/core/storage/query.ts +58 -0
  283. package/src/core/supervisor/activity.ts +193 -0
  284. package/src/core/supervisor/contract.ts +312 -0
  285. package/src/core/supervisor/explanations.ts +104 -0
  286. package/src/core/supervisor/findings.ts +788 -0
  287. package/src/core/supervisor/history.ts +61 -0
  288. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  289. package/src/core/supervisor/hook-health-storage.ts +25 -0
  290. package/src/core/supervisor/hook-health.ts +301 -0
  291. package/src/core/supervisor/hooks.ts +35 -0
  292. package/src/core/supervisor/index.ts +14 -0
  293. package/src/core/supervisor/log-feed.ts +131 -0
  294. package/src/core/supervisor/service.ts +511 -0
  295. package/src/core/supervisor/services.ts +203 -0
  296. package/src/core/supervisor/status.ts +59 -0
  297. package/src/core/supervisor/storage.ts +126 -0
  298. package/src/core/supervisor/timeline.ts +133 -0
  299. package/src/core/workflow/admission.ts +215 -0
  300. package/src/core/workflow/engine.ts +93 -1
  301. package/src/core/workflow/index.ts +10 -0
  302. package/src/core/workflow/proof.ts +54 -1
  303. package/src/core/workflow/run-state.ts +13 -1
  304. package/src/core/workflow/types.ts +39 -1
  305. package/src/lib/browser/client.ts +6 -0
  306. package/src/lib/browser/index.ts +29 -0
  307. package/src/lib/browser/qa-run-contracts.ts +380 -0
  308. package/src/lib/browser/qa-run.ts +784 -0
  309. package/src/lib/coord-root-id.ts +23 -0
  310. package/src/lib/instructions/apply.ts +81 -2
  311. package/src/lib/instructions/templates.ts +6 -0
@@ -0,0 +1,59 @@
1
+ import type { Adapter } from "../adapter.js";
2
+ export declare const HOOK_HEALTH_EVENT: "agent_hook.completed";
3
+ export declare const HOOK_HEALTH_RECEIPT_VERSION: 1;
4
+ export declare const HOOK_HEALTH_ERROR_PHASE_LIMIT = 8;
5
+ export type HookHealthOutcome = "completed" | "skipped" | "degraded" | "faulted";
6
+ export interface HookHealthState {
7
+ readonly started_at_ms: number;
8
+ readonly started_rss_bytes: number;
9
+ readonly event_name: string | null;
10
+ readonly adapter: Adapter | null;
11
+ readonly payload_bytes: number;
12
+ coord_root: string | null;
13
+ owner_id?: string;
14
+ skipped_reason?: string;
15
+ v3_state?: string;
16
+ error_phases: string[];
17
+ }
18
+ export interface HookHealthReceipt {
19
+ receipt_version: typeof HOOK_HEALTH_RECEIPT_VERSION;
20
+ hook_name: string;
21
+ adapter: Adapter | "unknown";
22
+ outcome: HookHealthOutcome;
23
+ exit_contract: "always-zero";
24
+ exit_code: 0;
25
+ duration_ms: number;
26
+ payload_bytes: number;
27
+ pid: number;
28
+ rss_start_bytes: number;
29
+ rss_end_bytes: number;
30
+ rss_delta_bytes: number;
31
+ retry_worker: boolean;
32
+ error_count: number;
33
+ error_phases: readonly string[];
34
+ owner_id?: string;
35
+ skipped_reason?: string;
36
+ v3_state?: string;
37
+ }
38
+ export declare function beginHookHealth(input: {
39
+ started_at_ms: number;
40
+ started_rss_bytes: number;
41
+ event_name: string | null;
42
+ adapter: Adapter | null;
43
+ payload_bytes: number;
44
+ }): HookHealthState;
45
+ export declare function observeHookDebug(state: HookHealthState | undefined, entry: Readonly<Record<string, unknown>>): void;
46
+ export declare function observeHookError(state: HookHealthState | undefined, phase: unknown): void;
47
+ export declare function finalizeHookHealth(state: HookHealthState, input: {
48
+ finished_at_ms: number;
49
+ finished_rss_bytes: number;
50
+ pid: number;
51
+ faulted?: boolean;
52
+ }): HookHealthReceipt;
53
+ export declare function writeHookHealthCompletion(state: HookHealthState | undefined, input: {
54
+ finished_at_ms: number;
55
+ finished_rss_bytes: number;
56
+ pid: number;
57
+ faulted?: boolean;
58
+ }): HookHealthReceipt | undefined;
59
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,eAAO,MAAM,iBAAiB,EAAG,sBAA+B,CAAC;AACjE,eAAO,MAAM,2BAA2B,EAAG,CAAU,CAAC;AACtD,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,OAAO,2BAA2B,CAAC;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,CAAC,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,eAAe,CAMlB;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,eAAe,GAAG,SAAS,EAClC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,IAAI,CAMN;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGzF;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,iBAAiB,CA+BnB;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,eAAe,GAAG,SAAS,EAClC,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,iBAAiB,GAAG,SAAS,CAS/B"}
@@ -0,0 +1,84 @@
1
+ import { processLogger } from "../storage/logger.js";
2
+ export const HOOK_HEALTH_EVENT = "agent_hook.completed";
3
+ export const HOOK_HEALTH_RECEIPT_VERSION = 1;
4
+ export const HOOK_HEALTH_ERROR_PHASE_LIMIT = 8;
5
+ export function beginHookHealth(input) {
6
+ return {
7
+ ...input,
8
+ coord_root: null,
9
+ error_phases: [],
10
+ };
11
+ }
12
+ export function observeHookDebug(state, entry) {
13
+ if (!state)
14
+ return;
15
+ const skipped = safeToken(entry.skipped);
16
+ if (skipped)
17
+ state.skipped_reason = skipped;
18
+ const v3State = safeToken(entry.event_v3_state);
19
+ if (v3State)
20
+ state.v3_state = v3State;
21
+ }
22
+ export function observeHookError(state, phase) {
23
+ if (!state || state.error_phases.length >= HOOK_HEALTH_ERROR_PHASE_LIMIT)
24
+ return;
25
+ state.error_phases.push(safeToken(phase) ?? "unknown");
26
+ }
27
+ export function finalizeHookHealth(state, input) {
28
+ const duration = Math.max(0, Math.floor(input.finished_at_ms - state.started_at_ms));
29
+ const rssStart = boundedInteger(state.started_rss_bytes);
30
+ const rssEnd = boundedInteger(input.finished_rss_bytes);
31
+ const hookName = safeToken(state.event_name) ?? "unknown";
32
+ return {
33
+ receipt_version: HOOK_HEALTH_RECEIPT_VERSION,
34
+ hook_name: hookName,
35
+ adapter: state.adapter ?? "unknown",
36
+ outcome: input.faulted
37
+ ? "faulted"
38
+ : state.error_phases.length > 0
39
+ ? "degraded"
40
+ : state.skipped_reason
41
+ ? "skipped"
42
+ : "completed",
43
+ exit_contract: "always-zero",
44
+ exit_code: 0,
45
+ duration_ms: duration,
46
+ payload_bytes: boundedInteger(state.payload_bytes),
47
+ pid: boundedInteger(input.pid),
48
+ rss_start_bytes: rssStart,
49
+ rss_end_bytes: rssEnd,
50
+ rss_delta_bytes: rssEnd - rssStart,
51
+ retry_worker: hookName === "runtime-context-retry",
52
+ error_count: state.error_phases.length,
53
+ error_phases: [...state.error_phases],
54
+ ...(state.owner_id ? { owner_id: state.owner_id } : {}),
55
+ ...(state.skipped_reason ? { skipped_reason: state.skipped_reason } : {}),
56
+ ...(state.v3_state ? { v3_state: state.v3_state } : {}),
57
+ };
58
+ }
59
+ export function writeHookHealthCompletion(state, input) {
60
+ if (!state?.coord_root)
61
+ return undefined;
62
+ const receipt = finalizeHookHealth(state, input);
63
+ try {
64
+ processLogger(state.coord_root, "agent-hook").info(HOOK_HEALTH_EVENT, { ...receipt });
65
+ }
66
+ catch {
67
+ // Hook health is observer-only. Logging can never change adapter behavior.
68
+ }
69
+ return receipt;
70
+ }
71
+ function safeToken(value) {
72
+ if (typeof value !== "string")
73
+ return undefined;
74
+ const normalized = value
75
+ .trim()
76
+ .slice(0, 128)
77
+ .replace(/[^a-zA-Z0-9._:/+-]+/g, "-");
78
+ return /^[a-zA-Z0-9]/.test(normalized) ? normalized : undefined;
79
+ }
80
+ function boundedInteger(value) {
81
+ if (!Number.isFinite(value))
82
+ return 0;
83
+ return Math.max(0, Math.min(Number.MAX_SAFE_INTEGER, Math.floor(value)));
84
+ }
@@ -0,0 +1,90 @@
1
+ export declare const RESOURCE_SNAPSHOT_SCHEMA_VERSION = 1;
2
+ export declare const RESOURCE_SERVICE_STATUS_SCHEMA_VERSION = 1;
3
+ export type ResourceSupportState = "supported" | "partial" | "unsupported" | "error";
4
+ export interface ResourceProcessSample {
5
+ pid: number;
6
+ ppid: number;
7
+ start_id: string;
8
+ state: string;
9
+ name: string;
10
+ command: string;
11
+ cpu_percent: number | null;
12
+ rss_bytes: number;
13
+ age_seconds: number;
14
+ owner_kind: "agent" | "service" | "unattributed";
15
+ owner_id: string | null;
16
+ owner_root_pid: number | null;
17
+ }
18
+ export interface ResourceProcessGroup {
19
+ kind: ResourceProcessSample["owner_kind"];
20
+ id: string;
21
+ process_count: number;
22
+ cpu_percent: number | null;
23
+ rss_bytes: number;
24
+ root_pids: number[];
25
+ }
26
+ export interface ResourceMachineSample {
27
+ cpu_percent: number | null;
28
+ cpu_logical_count: number;
29
+ load_average: [number, number, number] | null;
30
+ memory_total_bytes: number | null;
31
+ memory_available_bytes: number | null;
32
+ memory_used_bytes: number | null;
33
+ memory_percent: number | null;
34
+ swap_total_bytes: number | null;
35
+ swap_used_bytes: number | null;
36
+ process_count: number;
37
+ }
38
+ export interface ResourceSnapshot {
39
+ schema_version: typeof RESOURCE_SNAPSHOT_SCHEMA_VERSION;
40
+ sampled_at: string;
41
+ interval_ms: number | null;
42
+ sample_duration_ms: number;
43
+ collector_cpu_ms: number;
44
+ platform: NodeJS.Platform;
45
+ namespace: "host" | "wsl" | "unknown";
46
+ support: {
47
+ state: ResourceSupportState;
48
+ sampler: "procfs" | "unsupported";
49
+ reason?: string;
50
+ };
51
+ machine: ResourceMachineSample;
52
+ groups: ResourceProcessGroup[];
53
+ processes: ResourceProcessSample[];
54
+ visible_process_count: number;
55
+ omitted_process_count: number;
56
+ unattributed_process_count: number;
57
+ }
58
+ export interface ResourceServiceStatusRecord {
59
+ schema_version: typeof RESOURCE_SERVICE_STATUS_SCHEMA_VERSION;
60
+ pid: number;
61
+ start_token?: string;
62
+ host: string;
63
+ nonce: string;
64
+ state: "starting" | "running" | "stopping" | "stopped" | "error";
65
+ started_at: string;
66
+ heartbeat_at: string;
67
+ stopped_at?: string;
68
+ interval_ms: number;
69
+ sample_count: number;
70
+ last_sample_at?: string;
71
+ last_error_code?: string;
72
+ }
73
+ export interface ResourceServiceStatus {
74
+ running: boolean;
75
+ stale: boolean;
76
+ record?: ResourceServiceStatusRecord;
77
+ status_path: string;
78
+ snapshot_path: string;
79
+ }
80
+ export interface ResourceSamplerState {
81
+ sampled_at_ms: number;
82
+ cpu_total_ticks: number;
83
+ cpu_idle_ticks: number;
84
+ process_ticks: Map<string, number>;
85
+ }
86
+ export interface ResourceSampleResult {
87
+ snapshot: ResourceSnapshot;
88
+ state?: ResourceSamplerState;
89
+ }
90
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/core/resources/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export const RESOURCE_SNAPSHOT_SCHEMA_VERSION = 1;
2
+ export const RESOURCE_SERVICE_STATUS_SCHEMA_VERSION = 1;
@@ -0,0 +1,6 @@
1
+ export * from "./contract.js";
2
+ export * from "./sampler.js";
3
+ export * from "./service.js";
4
+ export * from "./service-status.js";
5
+ export * from "./storage.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from "./contract.js";
2
+ export * from "./sampler.js";
3
+ export * from "./service.js";
4
+ export * from "./service-status.js";
5
+ export * from "./storage.js";
@@ -0,0 +1,27 @@
1
+ import { type ResourceSampleResult, type ResourceSamplerState } from "./contract.js";
2
+ interface ResourceSamplerOptions {
3
+ procRoot?: string;
4
+ nowMs?: number;
5
+ clockTicks?: number;
6
+ pageSize?: number;
7
+ services?: readonly {
8
+ pid: number;
9
+ id: string;
10
+ }[];
11
+ unattributedCpuFloor?: number;
12
+ unattributedRssFloor?: number;
13
+ maxProcesses?: number;
14
+ }
15
+ export declare function sampleResources(coordRoot: string, previous?: ResourceSamplerState, options?: ResourceSamplerOptions): ResourceSampleResult;
16
+ export declare function parseLinuxProcessStat(line: string): {
17
+ pid: number;
18
+ name: string;
19
+ state: string;
20
+ ppid: number;
21
+ ticks: number;
22
+ startTicks: number;
23
+ rssPages: number;
24
+ } | null;
25
+ export declare function redactCommand(args: readonly string[]): string;
26
+ export {};
27
+ //# sourceMappingURL=sampler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sampler.d.ts","sourceRoot":"","sources":["../../../src/core/resources/sampler.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAE1B,MAAM,eAAe,CAAC;AA0BvB,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,OAAO,GAAE,sBAA2B,GACnC,oBAAoB,CAgItB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CA0BP;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAuB7D"}
@@ -0,0 +1,357 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync, readdirSync, readFileSync, readlinkSync } from "node:fs";
3
+ import { cpus, loadavg, platform, release } from "node:os";
4
+ import { basename, join } from "node:path";
5
+ import { performance } from "node:perf_hooks";
6
+ import { parsePidmapRow } from "../agents/state/pidmap.js";
7
+ import { checkPidToken } from "../agents/state/proc-start.js";
8
+ import { RESOURCE_SNAPSHOT_SCHEMA_VERSION, } from "./contract.js";
9
+ const DEFAULT_CLOCK_TICKS = 100;
10
+ const DEFAULT_PAGE_SIZE = 4_096;
11
+ const DEFAULT_UNATTRIBUTED_CPU_FLOOR = 0.5;
12
+ const DEFAULT_UNATTRIBUTED_RSS_FLOOR = 64 * 1_024 * 1_024;
13
+ const DEFAULT_MAX_PROCESSES = 500;
14
+ const MAX_COMMAND_CHARS = 240;
15
+ let cachedClockTicks;
16
+ let cachedPageSize;
17
+ export function sampleResources(coordRoot, previous, options = {}) {
18
+ const started = performance.now();
19
+ const cpuBefore = process.cpuUsage();
20
+ const nowMs = options.nowMs ?? Date.now();
21
+ const currentPlatform = platform();
22
+ if (currentPlatform !== "linux") {
23
+ return {
24
+ snapshot: unsupportedSnapshot(currentPlatform, nowMs, started, cpuBefore),
25
+ };
26
+ }
27
+ const procRoot = options.procRoot ?? "/proc";
28
+ if (!existsSync(join(procRoot, "stat"))) {
29
+ return {
30
+ snapshot: unsupportedSnapshot(currentPlatform, nowMs, started, cpuBefore, "procfs_unavailable"),
31
+ };
32
+ }
33
+ const clockTicks = options.clockTicks ?? systemClockTicks();
34
+ const pageSize = options.pageSize ?? systemPageSize();
35
+ const uptimeSeconds = parseUptime(readFileSync(join(procRoot, "uptime"), "utf8"));
36
+ const cpu = parseLinuxCpu(readFileSync(join(procRoot, "stat"), "utf8"));
37
+ const memory = parseMeminfo(readFileSync(join(procRoot, "meminfo"), "utf8"));
38
+ const readings = readLinuxProcesses(procRoot, clockTicks, pageSize, uptimeSeconds);
39
+ const anchors = readOwnershipAnchors(coordRoot, readings, options.services ?? []);
40
+ const byPid = new Map(readings.map((reading) => [reading.pid, reading]));
41
+ const processTicks = new Map();
42
+ const intervalMs = previous ? Math.max(0, nowMs - previous.sampled_at_ms) : null;
43
+ const totalTickDelta = previous ? Math.max(0, cpu.total - previous.cpu_total_ticks) : 0;
44
+ const logicalCpus = Math.max(1, cpus().length);
45
+ const processes = readings.map((reading) => {
46
+ const identity = `${reading.pid}:${reading.startTicks}`;
47
+ processTicks.set(identity, reading.ticks);
48
+ const priorTicks = previous?.process_ticks.get(identity);
49
+ const processDelta = priorTicks === undefined ? undefined : Math.max(0, reading.ticks - priorTicks);
50
+ const cpuPercent = processDelta === undefined || totalTickDelta <= 0
51
+ ? null
52
+ : round1((processDelta / totalTickDelta) * logicalCpus * 100);
53
+ const ownership = resolveOwnership(reading.pid, byPid, anchors);
54
+ return {
55
+ pid: reading.pid,
56
+ ppid: reading.ppid,
57
+ start_id: identity,
58
+ state: reading.state,
59
+ name: reading.name,
60
+ command: reading.command,
61
+ cpu_percent: cpuPercent,
62
+ rss_bytes: reading.rssBytes,
63
+ age_seconds: round1(reading.ageSeconds),
64
+ owner_kind: ownership?.kind ?? "unattributed",
65
+ owner_id: ownership?.id ?? null,
66
+ owner_root_pid: ownership?.rootPid ?? null,
67
+ };
68
+ });
69
+ const visible = processes
70
+ .filter((row) => row.owner_kind !== "unattributed" ||
71
+ (row.cpu_percent ?? 0) >=
72
+ (options.unattributedCpuFloor ?? DEFAULT_UNATTRIBUTED_CPU_FLOOR) ||
73
+ row.rss_bytes >= (options.unattributedRssFloor ?? DEFAULT_UNATTRIBUTED_RSS_FLOOR))
74
+ .sort(processSort)
75
+ .slice(0, options.maxProcesses ?? DEFAULT_MAX_PROCESSES);
76
+ const groups = aggregateGroups(visible);
77
+ const cpuPercent = previous && totalTickDelta > 0
78
+ ? round1(((totalTickDelta - Math.max(0, cpu.idle - previous.cpu_idle_ticks)) / totalTickDelta) *
79
+ 100)
80
+ : null;
81
+ const memoryTotal = memory.MemTotal ?? null;
82
+ const memoryAvailable = memory.MemAvailable ?? memory.MemFree ?? null;
83
+ const memoryUsed = memoryTotal !== null && memoryAvailable !== null
84
+ ? Math.max(0, memoryTotal - memoryAvailable)
85
+ : null;
86
+ const swapTotal = memory.SwapTotal ?? null;
87
+ const swapFree = memory.SwapFree ?? null;
88
+ const swapUsed = swapTotal !== null && swapFree !== null ? Math.max(0, swapTotal - swapFree) : null;
89
+ const collectorCpu = process.cpuUsage(cpuBefore);
90
+ const snapshot = {
91
+ schema_version: RESOURCE_SNAPSHOT_SCHEMA_VERSION,
92
+ sampled_at: new Date(nowMs).toISOString(),
93
+ interval_ms: intervalMs,
94
+ sample_duration_ms: round1(performance.now() - started),
95
+ collector_cpu_ms: round1((collectorCpu.user + collectorCpu.system) / 1_000),
96
+ platform: currentPlatform,
97
+ namespace: /microsoft|wsl/i.test(release()) ? "wsl" : "host",
98
+ support: { state: "supported", sampler: "procfs" },
99
+ machine: {
100
+ cpu_percent: cpuPercent,
101
+ cpu_logical_count: logicalCpus,
102
+ load_average: loadavg(),
103
+ memory_total_bytes: memoryTotal,
104
+ memory_available_bytes: memoryAvailable,
105
+ memory_used_bytes: memoryUsed,
106
+ memory_percent: memoryUsed !== null && memoryTotal ? round1((memoryUsed / memoryTotal) * 100) : null,
107
+ swap_total_bytes: swapTotal,
108
+ swap_used_bytes: swapUsed,
109
+ process_count: readings.length,
110
+ },
111
+ groups,
112
+ processes: visible,
113
+ visible_process_count: visible.length,
114
+ omitted_process_count: Math.max(0, readings.length - visible.length),
115
+ unattributed_process_count: visible.filter((row) => row.owner_kind === "unattributed").length,
116
+ };
117
+ return {
118
+ snapshot,
119
+ state: {
120
+ sampled_at_ms: nowMs,
121
+ cpu_total_ticks: cpu.total,
122
+ cpu_idle_ticks: cpu.idle,
123
+ process_ticks: processTicks,
124
+ },
125
+ };
126
+ }
127
+ export function parseLinuxProcessStat(line) {
128
+ const open = line.indexOf("(");
129
+ const close = line.lastIndexOf(")");
130
+ if (open <= 0 || close <= open)
131
+ return null;
132
+ const pid = Number(line.slice(0, open).trim());
133
+ const fields = line
134
+ .slice(close + 1)
135
+ .trim()
136
+ .split(/\s+/);
137
+ const state = fields[0] ?? "?";
138
+ const ppid = Number(fields[1]);
139
+ const userTicks = Number(fields[11]);
140
+ const systemTicks = Number(fields[12]);
141
+ const startTicks = Number(fields[19]);
142
+ const rssPages = Number(fields[21]);
143
+ if (![pid, ppid, userTicks, systemTicks, startTicks, rssPages].every(Number.isFinite))
144
+ return null;
145
+ return {
146
+ pid,
147
+ name: line.slice(open + 1, close),
148
+ state,
149
+ ppid,
150
+ ticks: userTicks + systemTicks,
151
+ startTicks,
152
+ rssPages: Math.max(0, rssPages),
153
+ };
154
+ }
155
+ export function redactCommand(args) {
156
+ const secretName = /(?:^|[-_])(token|secret|password|passwd|api[-_]?key|authorization)(?:$|[-_])/i;
157
+ const output = [];
158
+ let redactNext = false;
159
+ for (const raw of args) {
160
+ let value = raw;
161
+ if (redactNext) {
162
+ output.push("<redacted>");
163
+ redactNext = false;
164
+ continue;
165
+ }
166
+ const equals = value.indexOf("=");
167
+ if (equals > 0 && secretName.test(value.slice(0, equals))) {
168
+ value = `${value.slice(0, equals + 1)}<redacted>`;
169
+ }
170
+ else if (secretName.test(value.replace(/^--?/, ""))) {
171
+ redactNext = true;
172
+ }
173
+ value = value.replace(/(https?:\/\/)[^:@\s/]+:[^@\s/]+@/gi, "$1<redacted>@");
174
+ output.push(value.replace(/[\r\n\t]+/g, " "));
175
+ }
176
+ const joined = output.join(" ").trim();
177
+ return joined.length <= MAX_COMMAND_CHARS ? joined : `${joined.slice(0, MAX_COMMAND_CHARS - 1)}…`;
178
+ }
179
+ function readLinuxProcesses(procRoot, clockTicks, pageSize, uptimeSeconds) {
180
+ const rows = [];
181
+ for (const entry of readdirSync(procRoot, { withFileTypes: true })) {
182
+ if (!entry.isDirectory() || !/^\d+$/.test(entry.name))
183
+ continue;
184
+ const pidRoot = join(procRoot, entry.name);
185
+ try {
186
+ const parsed = parseLinuxProcessStat(readFileSync(join(pidRoot, "stat"), "utf8"));
187
+ if (!parsed)
188
+ continue;
189
+ const args = readFileSync(join(pidRoot, "cmdline"), "utf8").split("\0").filter(Boolean);
190
+ let name = parsed.name;
191
+ try {
192
+ name = basename(readlinkSync(join(pidRoot, "exe"))) || name;
193
+ }
194
+ catch {
195
+ // Kernel threads and racing processes may have no readable executable.
196
+ }
197
+ rows.push({
198
+ pid: parsed.pid,
199
+ ppid: parsed.ppid,
200
+ state: parsed.state,
201
+ name,
202
+ command: redactCommand(args.length > 0 ? args : [parsed.name]),
203
+ ticks: parsed.ticks,
204
+ startTicks: parsed.startTicks,
205
+ rssBytes: parsed.rssPages * pageSize,
206
+ ageSeconds: Math.max(0, uptimeSeconds - parsed.startTicks / clockTicks),
207
+ });
208
+ }
209
+ catch {
210
+ // Process exits and permission boundaries are normal during a table scan.
211
+ }
212
+ }
213
+ return rows;
214
+ }
215
+ function readOwnershipAnchors(coordRoot, readings, services) {
216
+ const byPid = new Set(readings.map((row) => row.pid));
217
+ const directory = join(coordRoot, ".harnery", "pid-map");
218
+ const anchors = new Map();
219
+ if (existsSync(directory)) {
220
+ for (const entry of readdirSync(directory)) {
221
+ if (!/^\d+$/.test(entry))
222
+ continue;
223
+ const pid = Number(entry);
224
+ if (!byPid.has(pid))
225
+ continue;
226
+ try {
227
+ const row = parsePidmapRow(readFileSync(join(directory, entry), "utf8"));
228
+ if (!row.instanceId || checkPidToken(pid, row.startToken) === "mismatch")
229
+ continue;
230
+ anchors.set(pid, { kind: "agent", id: row.instanceId });
231
+ }
232
+ catch {
233
+ // An unreadable or racing row cannot prove ownership.
234
+ }
235
+ }
236
+ }
237
+ for (const service of services) {
238
+ if (byPid.has(service.pid) && service.id.trim()) {
239
+ anchors.set(service.pid, { kind: "service", id: service.id.trim() });
240
+ }
241
+ }
242
+ return anchors;
243
+ }
244
+ function resolveOwnership(pid, byPid, anchors) {
245
+ const seen = new Set();
246
+ let cursor = pid;
247
+ for (let hops = 0; hops < 64 && cursor > 0 && !seen.has(cursor); hops++) {
248
+ seen.add(cursor);
249
+ const owner = anchors.get(cursor);
250
+ if (owner)
251
+ return { ...owner, rootPid: cursor };
252
+ cursor = byPid.get(cursor)?.ppid ?? 0;
253
+ }
254
+ return undefined;
255
+ }
256
+ function aggregateGroups(processes) {
257
+ const groups = new Map();
258
+ for (const row of processes) {
259
+ const id = row.owner_id ?? "unattributed";
260
+ const key = `${row.owner_kind}:${id}`;
261
+ const group = groups.get(key) ?? {
262
+ kind: row.owner_kind,
263
+ id,
264
+ process_count: 0,
265
+ cpu_percent: null,
266
+ rss_bytes: 0,
267
+ root_pids: [],
268
+ };
269
+ group.process_count += 1;
270
+ group.rss_bytes += row.rss_bytes;
271
+ if (row.cpu_percent !== null)
272
+ group.cpu_percent = round1((group.cpu_percent ?? 0) + row.cpu_percent);
273
+ if (row.owner_root_pid !== null && !group.root_pids.includes(row.owner_root_pid)) {
274
+ group.root_pids.push(row.owner_root_pid);
275
+ }
276
+ groups.set(key, group);
277
+ }
278
+ return [...groups.values()].sort((left, right) => (right.cpu_percent ?? -1) - (left.cpu_percent ?? -1) ||
279
+ right.rss_bytes - left.rss_bytes ||
280
+ left.id.localeCompare(right.id));
281
+ }
282
+ function processSort(left, right) {
283
+ return ((right.cpu_percent ?? -1) - (left.cpu_percent ?? -1) ||
284
+ right.rss_bytes - left.rss_bytes ||
285
+ left.pid - right.pid);
286
+ }
287
+ function parseLinuxCpu(content) {
288
+ const fields = content.split("\n")[0]?.trim().split(/\s+/).slice(1).map(Number) ?? [];
289
+ if (fields.length < 4 || fields.some((value) => !Number.isFinite(value))) {
290
+ throw new Error("procfs_cpu_invalid");
291
+ }
292
+ return {
293
+ total: fields.reduce((sum, value) => sum + value, 0),
294
+ idle: (fields[3] ?? 0) + (fields[4] ?? 0),
295
+ };
296
+ }
297
+ function parseMeminfo(content) {
298
+ const result = {};
299
+ for (const line of content.split("\n")) {
300
+ const match = /^([A-Za-z_()]+):\s+(\d+)\s+kB$/.exec(line.trim());
301
+ if (match)
302
+ result[match[1]] = Number(match[2]) * 1_024;
303
+ }
304
+ return result;
305
+ }
306
+ function parseUptime(content) {
307
+ const value = Number(content.trim().split(/\s+/, 1)[0]);
308
+ if (!Number.isFinite(value) || value < 0)
309
+ throw new Error("procfs_uptime_invalid");
310
+ return value;
311
+ }
312
+ function systemClockTicks() {
313
+ cachedClockTicks ??= positiveGetconf("CLK_TCK", DEFAULT_CLOCK_TICKS);
314
+ return cachedClockTicks;
315
+ }
316
+ function systemPageSize() {
317
+ cachedPageSize ??= positiveGetconf("PAGESIZE", DEFAULT_PAGE_SIZE);
318
+ return cachedPageSize;
319
+ }
320
+ function positiveGetconf(key, fallback) {
321
+ const result = spawnSync("getconf", [key], { encoding: "utf8", timeout: 1_000 });
322
+ const value = result.status === 0 ? Number(result.stdout.trim()) : Number.NaN;
323
+ return Number.isFinite(value) && value > 0 ? value : fallback;
324
+ }
325
+ function unsupportedSnapshot(currentPlatform, nowMs, started, cpuBefore, reason = "platform_unsupported") {
326
+ const collectorCpu = process.cpuUsage(cpuBefore);
327
+ return {
328
+ schema_version: RESOURCE_SNAPSHOT_SCHEMA_VERSION,
329
+ sampled_at: new Date(nowMs).toISOString(),
330
+ interval_ms: null,
331
+ sample_duration_ms: round1(performance.now() - started),
332
+ collector_cpu_ms: round1((collectorCpu.user + collectorCpu.system) / 1_000),
333
+ platform: currentPlatform,
334
+ namespace: "unknown",
335
+ support: { state: "unsupported", sampler: "unsupported", reason },
336
+ machine: {
337
+ cpu_percent: null,
338
+ cpu_logical_count: cpus().length,
339
+ load_average: null,
340
+ memory_total_bytes: null,
341
+ memory_available_bytes: null,
342
+ memory_used_bytes: null,
343
+ memory_percent: null,
344
+ swap_total_bytes: null,
345
+ swap_used_bytes: null,
346
+ process_count: 0,
347
+ },
348
+ groups: [],
349
+ processes: [],
350
+ visible_process_count: 0,
351
+ omitted_process_count: 0,
352
+ unattributed_process_count: 0,
353
+ };
354
+ }
355
+ function round1(value) {
356
+ return Math.round(value * 10) / 10;
357
+ }
@@ -0,0 +1,3 @@
1
+ import { type ResourceServiceStatus } from "./contract.js";
2
+ export declare function readResourceServiceStatus(coordRoot: string, nowMs?: number): ResourceServiceStatus;
3
+ //# sourceMappingURL=service-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-status.d.ts","sourceRoot":"","sources":["../../../src/core/resources/service-status.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,eAAe,CAAC;AAKvB,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,SAAa,GACjB,qBAAqB,CA0BvB"}