@phigon/observer 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/README.md +303 -0
  2. package/dist/bin/guardian-runner-darwin-amd64 +0 -0
  3. package/dist/bin/guardian-runner-darwin-arm64 +0 -0
  4. package/dist/bin/guardian-runner-linux-amd64 +0 -0
  5. package/dist/bin/guardian-runner-linux-arm64 +0 -0
  6. package/dist/bin/guardian-runner-windows-amd64.exe +0 -0
  7. package/dist/bin/guardian-runner-windows-arm64.exe +0 -0
  8. package/dist/src/action-policy.d.ts +38 -0
  9. package/dist/src/action-policy.d.ts.map +1 -0
  10. package/dist/src/action-policy.js +269 -0
  11. package/dist/src/action-policy.js.map +1 -0
  12. package/dist/src/activity/adapters/claude.d.ts +3 -0
  13. package/dist/src/activity/adapters/claude.d.ts.map +1 -0
  14. package/dist/src/activity/adapters/claude.js +89 -0
  15. package/dist/src/activity/adapters/claude.js.map +1 -0
  16. package/dist/src/activity/adapters/codex.d.ts +3 -0
  17. package/dist/src/activity/adapters/codex.d.ts.map +1 -0
  18. package/dist/src/activity/adapters/codex.js +277 -0
  19. package/dist/src/activity/adapters/codex.js.map +1 -0
  20. package/dist/src/activity/adapters/copilot.d.ts +2 -0
  21. package/dist/src/activity/adapters/copilot.d.ts.map +1 -0
  22. package/dist/src/activity/adapters/copilot.js +4 -0
  23. package/dist/src/activity/adapters/copilot.js.map +1 -0
  24. package/dist/src/activity/adapters/generic.d.ts +2 -0
  25. package/dist/src/activity/adapters/generic.d.ts.map +1 -0
  26. package/dist/src/activity/adapters/generic.js +4 -0
  27. package/dist/src/activity/adapters/generic.js.map +1 -0
  28. package/dist/src/activity/adapters/hermes.d.ts +2 -0
  29. package/dist/src/activity/adapters/hermes.d.ts.map +1 -0
  30. package/dist/src/activity/adapters/hermes.js +4 -0
  31. package/dist/src/activity/adapters/hermes.js.map +1 -0
  32. package/dist/src/activity/adapters/openai-compatible.d.ts +4 -0
  33. package/dist/src/activity/adapters/openai-compatible.d.ts.map +1 -0
  34. package/dist/src/activity/adapters/openai-compatible.js +116 -0
  35. package/dist/src/activity/adapters/openai-compatible.js.map +1 -0
  36. package/dist/src/activity/adapters/openclaw.d.ts +2 -0
  37. package/dist/src/activity/adapters/openclaw.d.ts.map +1 -0
  38. package/dist/src/activity/adapters/openclaw.js +4 -0
  39. package/dist/src/activity/adapters/openclaw.js.map +1 -0
  40. package/dist/src/activity/adapters/opencode.d.ts +3 -0
  41. package/dist/src/activity/adapters/opencode.d.ts.map +1 -0
  42. package/dist/src/activity/adapters/opencode.js +137 -0
  43. package/dist/src/activity/adapters/opencode.js.map +1 -0
  44. package/dist/src/activity/bridges.d.ts +7 -0
  45. package/dist/src/activity/bridges.d.ts.map +1 -0
  46. package/dist/src/activity/bridges.js +17 -0
  47. package/dist/src/activity/bridges.js.map +1 -0
  48. package/dist/src/activity/collector.d.ts +90 -0
  49. package/dist/src/activity/collector.d.ts.map +1 -0
  50. package/dist/src/activity/collector.js +706 -0
  51. package/dist/src/activity/collector.js.map +1 -0
  52. package/dist/src/activity/index.d.ts +14 -0
  53. package/dist/src/activity/index.d.ts.map +1 -0
  54. package/dist/src/activity/index.js +14 -0
  55. package/dist/src/activity/index.js.map +1 -0
  56. package/dist/src/activity/ingest.d.ts +15 -0
  57. package/dist/src/activity/ingest.d.ts.map +1 -0
  58. package/dist/src/activity/ingest.js +103 -0
  59. package/dist/src/activity/ingest.js.map +1 -0
  60. package/dist/src/activity/native-capabilities.d.ts +14 -0
  61. package/dist/src/activity/native-capabilities.d.ts.map +1 -0
  62. package/dist/src/activity/native-capabilities.js +85 -0
  63. package/dist/src/activity/native-capabilities.js.map +1 -0
  64. package/dist/src/activity/normalize.d.ts +17 -0
  65. package/dist/src/activity/normalize.d.ts.map +1 -0
  66. package/dist/src/activity/normalize.js +416 -0
  67. package/dist/src/activity/normalize.js.map +1 -0
  68. package/dist/src/activity/opencode-sqlite-source.d.ts +19 -0
  69. package/dist/src/activity/opencode-sqlite-source.d.ts.map +1 -0
  70. package/dist/src/activity/opencode-sqlite-source.js +305 -0
  71. package/dist/src/activity/opencode-sqlite-source.js.map +1 -0
  72. package/dist/src/activity/policy.d.ts +48 -0
  73. package/dist/src/activity/policy.d.ts.map +1 -0
  74. package/dist/src/activity/policy.js +436 -0
  75. package/dist/src/activity/policy.js.map +1 -0
  76. package/dist/src/activity/record.d.ts +7 -0
  77. package/dist/src/activity/record.d.ts.map +1 -0
  78. package/dist/src/activity/record.js +61 -0
  79. package/dist/src/activity/record.js.map +1 -0
  80. package/dist/src/activity/source-reader.d.ts +46 -0
  81. package/dist/src/activity/source-reader.d.ts.map +1 -0
  82. package/dist/src/activity/source-reader.js +594 -0
  83. package/dist/src/activity/source-reader.js.map +1 -0
  84. package/dist/src/activity/types.d.ts +21 -0
  85. package/dist/src/activity/types.d.ts.map +1 -0
  86. package/dist/src/activity/types.js +2 -0
  87. package/dist/src/activity/types.js.map +1 -0
  88. package/dist/src/agent-action-executor.d.ts +21 -0
  89. package/dist/src/agent-action-executor.d.ts.map +1 -0
  90. package/dist/src/agent-action-executor.js +248 -0
  91. package/dist/src/agent-action-executor.js.map +1 -0
  92. package/dist/src/agentic-guardian.d.ts +50 -0
  93. package/dist/src/agentic-guardian.d.ts.map +1 -0
  94. package/dist/src/agentic-guardian.js +220 -0
  95. package/dist/src/agentic-guardian.js.map +1 -0
  96. package/dist/src/atomic-replace.d.ts +4 -0
  97. package/dist/src/atomic-replace.d.ts.map +1 -0
  98. package/dist/src/atomic-replace.js +18 -0
  99. package/dist/src/atomic-replace.js.map +1 -0
  100. package/dist/src/cli.d.ts +11 -0
  101. package/dist/src/cli.d.ts.map +1 -0
  102. package/dist/src/cli.js +1244 -0
  103. package/dist/src/cli.js.map +1 -0
  104. package/dist/src/config.d.ts +68 -0
  105. package/dist/src/config.d.ts.map +1 -0
  106. package/dist/src/config.js +260 -0
  107. package/dist/src/config.js.map +1 -0
  108. package/dist/src/credential-store.d.ts +22 -0
  109. package/dist/src/credential-store.d.ts.map +1 -0
  110. package/dist/src/credential-store.js +91 -0
  111. package/dist/src/credential-store.js.map +1 -0
  112. package/dist/src/custom-agent-registry.d.ts +26 -0
  113. package/dist/src/custom-agent-registry.d.ts.map +1 -0
  114. package/dist/src/custom-agent-registry.js +288 -0
  115. package/dist/src/custom-agent-registry.js.map +1 -0
  116. package/dist/src/discovery/adapters/claude.d.ts +3 -0
  117. package/dist/src/discovery/adapters/claude.d.ts.map +1 -0
  118. package/dist/src/discovery/adapters/claude.js +26 -0
  119. package/dist/src/discovery/adapters/claude.js.map +1 -0
  120. package/dist/src/discovery/adapters/codex.d.ts +3 -0
  121. package/dist/src/discovery/adapters/codex.d.ts.map +1 -0
  122. package/dist/src/discovery/adapters/codex.js +23 -0
  123. package/dist/src/discovery/adapters/codex.js.map +1 -0
  124. package/dist/src/discovery/adapters/custom.d.ts +4 -0
  125. package/dist/src/discovery/adapters/custom.d.ts.map +1 -0
  126. package/dist/src/discovery/adapters/custom.js +24 -0
  127. package/dist/src/discovery/adapters/custom.js.map +1 -0
  128. package/dist/src/discovery/adapters/generic.d.ts +3 -0
  129. package/dist/src/discovery/adapters/generic.d.ts.map +1 -0
  130. package/dist/src/discovery/adapters/generic.js +126 -0
  131. package/dist/src/discovery/adapters/generic.js.map +1 -0
  132. package/dist/src/discovery/adapters/hermes.d.ts +3 -0
  133. package/dist/src/discovery/adapters/hermes.d.ts.map +1 -0
  134. package/dist/src/discovery/adapters/hermes.js +22 -0
  135. package/dist/src/discovery/adapters/hermes.js.map +1 -0
  136. package/dist/src/discovery/adapters/openclaw.d.ts +3 -0
  137. package/dist/src/discovery/adapters/openclaw.d.ts.map +1 -0
  138. package/dist/src/discovery/adapters/openclaw.js +22 -0
  139. package/dist/src/discovery/adapters/openclaw.js.map +1 -0
  140. package/dist/src/discovery/engine.d.ts +17 -0
  141. package/dist/src/discovery/engine.d.ts.map +1 -0
  142. package/dist/src/discovery/engine.js +164 -0
  143. package/dist/src/discovery/engine.js.map +1 -0
  144. package/dist/src/discovery/evidence.d.ts +29 -0
  145. package/dist/src/discovery/evidence.d.ts.map +1 -0
  146. package/dist/src/discovery/evidence.js +2 -0
  147. package/dist/src/discovery/evidence.js.map +1 -0
  148. package/dist/src/discovery/index.d.ts +11 -0
  149. package/dist/src/discovery/index.d.ts.map +1 -0
  150. package/dist/src/discovery/index.js +11 -0
  151. package/dist/src/discovery/index.js.map +1 -0
  152. package/dist/src/discovery/known-agent.d.ts +17 -0
  153. package/dist/src/discovery/known-agent.d.ts.map +1 -0
  154. package/dist/src/discovery/known-agent.js +193 -0
  155. package/dist/src/discovery/known-agent.js.map +1 -0
  156. package/dist/src/discovery/process-identity.d.ts +19 -0
  157. package/dist/src/discovery/process-identity.d.ts.map +1 -0
  158. package/dist/src/discovery/process-identity.js +73 -0
  159. package/dist/src/discovery/process-identity.js.map +1 -0
  160. package/dist/src/discovery/system-evidence.d.ts +9 -0
  161. package/dist/src/discovery/system-evidence.d.ts.map +1 -0
  162. package/dist/src/discovery/system-evidence.js +270 -0
  163. package/dist/src/discovery/system-evidence.js.map +1 -0
  164. package/dist/src/discovery/types.d.ts +21 -0
  165. package/dist/src/discovery/types.d.ts.map +1 -0
  166. package/dist/src/discovery/types.js +2 -0
  167. package/dist/src/discovery/types.js.map +1 -0
  168. package/dist/src/event-queue.d.ts +32 -0
  169. package/dist/src/event-queue.d.ts.map +1 -0
  170. package/dist/src/event-queue.js +125 -0
  171. package/dist/src/event-queue.js.map +1 -0
  172. package/dist/src/event-spool.d.ts +19 -0
  173. package/dist/src/event-spool.d.ts.map +1 -0
  174. package/dist/src/event-spool.js +350 -0
  175. package/dist/src/event-spool.js.map +1 -0
  176. package/dist/src/generated/phigon/v1/action_pb.d.ts +223 -0
  177. package/dist/src/generated/phigon/v1/action_pb.d.ts.map +1 -0
  178. package/dist/src/generated/phigon/v1/action_pb.js +96 -0
  179. package/dist/src/generated/phigon/v1/action_pb.js.map +1 -0
  180. package/dist/src/generated/phigon/v1/common_pb.d.ts +255 -0
  181. package/dist/src/generated/phigon/v1/common_pb.d.ts.map +1 -0
  182. package/dist/src/generated/phigon/v1/common_pb.js +242 -0
  183. package/dist/src/generated/phigon/v1/common_pb.js.map +1 -0
  184. package/dist/src/generated/phigon/v1/history_sync_pb.d.ts +119 -0
  185. package/dist/src/generated/phigon/v1/history_sync_pb.d.ts.map +1 -0
  186. package/dist/src/generated/phigon/v1/history_sync_pb.js +46 -0
  187. package/dist/src/generated/phigon/v1/history_sync_pb.js.map +1 -0
  188. package/dist/src/generated/phigon/v1/identity_pb.d.ts +235 -0
  189. package/dist/src/generated/phigon/v1/identity_pb.d.ts.map +1 -0
  190. package/dist/src/generated/phigon/v1/identity_pb.js +31 -0
  191. package/dist/src/generated/phigon/v1/identity_pb.js.map +1 -0
  192. package/dist/src/generated/phigon/v1/observer_service_pb.d.ts +362 -0
  193. package/dist/src/generated/phigon/v1/observer_service_pb.d.ts.map +1 -0
  194. package/dist/src/generated/phigon/v1/observer_service_pb.js +120 -0
  195. package/dist/src/generated/phigon/v1/observer_service_pb.js.map +1 -0
  196. package/dist/src/generated/phigon/v1/policy_pb.d.ts +456 -0
  197. package/dist/src/generated/phigon/v1/policy_pb.d.ts.map +1 -0
  198. package/dist/src/generated/phigon/v1/policy_pb.js +161 -0
  199. package/dist/src/generated/phigon/v1/policy_pb.js.map +1 -0
  200. package/dist/src/generated/phigon/v1/supervision_pb.d.ts +849 -0
  201. package/dist/src/generated/phigon/v1/supervision_pb.d.ts.map +1 -0
  202. package/dist/src/generated/phigon/v1/supervision_pb.js +384 -0
  203. package/dist/src/generated/phigon/v1/supervision_pb.js.map +1 -0
  204. package/dist/src/generated/phigon/v1/telemetry_pb.d.ts +761 -0
  205. package/dist/src/generated/phigon/v1/telemetry_pb.d.ts.map +1 -0
  206. package/dist/src/generated/phigon/v1/telemetry_pb.js +309 -0
  207. package/dist/src/generated/phigon/v1/telemetry_pb.js.map +1 -0
  208. package/dist/src/guardian-containment.d.ts +30 -0
  209. package/dist/src/guardian-containment.d.ts.map +1 -0
  210. package/dist/src/guardian-containment.js +113 -0
  211. package/dist/src/guardian-containment.js.map +1 -0
  212. package/dist/src/guardian-decision-journal.d.ts +29 -0
  213. package/dist/src/guardian-decision-journal.d.ts.map +1 -0
  214. package/dist/src/guardian-decision-journal.js +55 -0
  215. package/dist/src/guardian-decision-journal.js.map +1 -0
  216. package/dist/src/guardian-execution-manifest.d.ts +29 -0
  217. package/dist/src/guardian-execution-manifest.d.ts.map +1 -0
  218. package/dist/src/guardian-execution-manifest.js +95 -0
  219. package/dist/src/guardian-execution-manifest.js.map +1 -0
  220. package/dist/src/guardian-hosted-client.d.ts +10 -0
  221. package/dist/src/guardian-hosted-client.d.ts.map +1 -0
  222. package/dist/src/guardian-hosted-client.js +45 -0
  223. package/dist/src/guardian-hosted-client.js.map +1 -0
  224. package/dist/src/guardian-managed-exec.d.ts +21 -0
  225. package/dist/src/guardian-managed-exec.d.ts.map +1 -0
  226. package/dist/src/guardian-managed-exec.js +249 -0
  227. package/dist/src/guardian-managed-exec.js.map +1 -0
  228. package/dist/src/guardian-model-bridge.d.ts +13 -0
  229. package/dist/src/guardian-model-bridge.d.ts.map +1 -0
  230. package/dist/src/guardian-model-bridge.js +87 -0
  231. package/dist/src/guardian-model-bridge.js.map +1 -0
  232. package/dist/src/guardian-native.d.ts +3 -0
  233. package/dist/src/guardian-native.d.ts.map +1 -0
  234. package/dist/src/guardian-native.js +13 -0
  235. package/dist/src/guardian-native.js.map +1 -0
  236. package/dist/src/guardian-process-monitor.d.ts +20 -0
  237. package/dist/src/guardian-process-monitor.d.ts.map +1 -0
  238. package/dist/src/guardian-process-monitor.js +98 -0
  239. package/dist/src/guardian-process-monitor.js.map +1 -0
  240. package/dist/src/health.d.ts +35 -0
  241. package/dist/src/health.d.ts.map +1 -0
  242. package/dist/src/health.js +41 -0
  243. package/dist/src/health.js.map +1 -0
  244. package/dist/src/historical-identity-store.d.ts +20 -0
  245. package/dist/src/historical-identity-store.d.ts.map +1 -0
  246. package/dist/src/historical-identity-store.js +391 -0
  247. package/dist/src/historical-identity-store.js.map +1 -0
  248. package/dist/src/index.d.ts +14 -0
  249. package/dist/src/index.d.ts.map +1 -0
  250. package/dist/src/index.js +14 -0
  251. package/dist/src/index.js.map +1 -0
  252. package/dist/src/installation.d.ts +2 -0
  253. package/dist/src/installation.d.ts.map +1 -0
  254. package/dist/src/installation.js +44 -0
  255. package/dist/src/installation.js.map +1 -0
  256. package/dist/src/machine-command-executor.d.ts +28 -0
  257. package/dist/src/machine-command-executor.d.ts.map +1 -0
  258. package/dist/src/machine-command-executor.js +166 -0
  259. package/dist/src/machine-command-executor.js.map +1 -0
  260. package/dist/src/pair.d.ts +21 -0
  261. package/dist/src/pair.d.ts.map +1 -0
  262. package/dist/src/pair.js +125 -0
  263. package/dist/src/pair.js.map +1 -0
  264. package/dist/src/remove-machine.d.ts +15 -0
  265. package/dist/src/remove-machine.d.ts.map +1 -0
  266. package/dist/src/remove-machine.js +77 -0
  267. package/dist/src/remove-machine.js.map +1 -0
  268. package/dist/src/stream-client.d.ts +42 -0
  269. package/dist/src/stream-client.d.ts.map +1 -0
  270. package/dist/src/stream-client.js +867 -0
  271. package/dist/src/stream-client.js.map +1 -0
  272. package/dist/src/stream-state.d.ts +13 -0
  273. package/dist/src/stream-state.d.ts.map +1 -0
  274. package/dist/src/stream-state.js +128 -0
  275. package/dist/src/stream-state.js.map +1 -0
  276. package/dist/src/windows-process.d.ts +7 -0
  277. package/dist/src/windows-process.d.ts.map +1 -0
  278. package/dist/src/windows-process.js +17 -0
  279. package/dist/src/windows-process.js.map +1 -0
  280. package/package.json +78 -0
  281. package/scripts/install.mjs +308 -0
  282. package/scripts/managed-service.mjs +132 -0
  283. package/scripts/verify-guardian-release.mjs +42 -0
  284. package/scripts/windows-app-control.mjs +117 -0
@@ -0,0 +1,20 @@
1
+ import type { AgentInventory } from "./generated/phigon/v1/identity_pb.js";
2
+ import type { ActionPolicyPersistence } from "./action-policy.js";
3
+ import type { HTTPGuardianDecisionClient } from "./agentic-guardian.js";
4
+ import type { GuardianContainmentExecutor } from "./guardian-containment.js";
5
+ import type { GuardianDecisionJournal } from "./guardian-decision-journal.js";
6
+ import type { GuardianHostedClient } from "./guardian-hosted-client.js";
7
+ export declare class GuardianProcessMonitor {
8
+ private readonly options;
9
+ constructor(options: Readonly<{
10
+ machineId: string;
11
+ policyStore: Pick<ActionPolicyPersistence, "load">;
12
+ decisionClient: Pick<HTTPGuardianDecisionClient, "decide">;
13
+ containment: Pick<GuardianContainmentExecutor, "execute">;
14
+ journal: Pick<GuardianDecisionJournal, "append">;
15
+ onStatus: (message: string) => void;
16
+ coverageClient?: Pick<GuardianHostedClient, "post">;
17
+ }>);
18
+ review(inventory: AgentInventory, signal: AbortSignal): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=guardian-process-monitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardian-process-monitor.d.ts","sourceRoot":"","sources":["../../src/guardian-process-monitor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAIxE,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,QAAQ,CAAC;QAC7C,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;QACnD,cAAc,EAAE,IAAI,CAAC,0BAA0B,EAAE,QAAQ,CAAC,CAAC;QAC3D,WAAW,EAAE,IAAI,CAAC,2BAA2B,EAAE,SAAS,CAAC,CAAC;QAC1D,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;QACjD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;QACpC,cAAc,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;KACrD,CAAC;IAEI,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAuE5E"}
@@ -0,0 +1,98 @@
1
+ import { timestampDate } from "@bufbuild/protobuf/wkt";
2
+ import { AgentState } from "./generated/phigon/v1/common_pb.js";
3
+ // Discovery is a detection boundary, not a pre-execution sandbox. It can contain
4
+ // agents launched outside the managed CLI only after a central admin decision.
5
+ export class GuardianProcessMonitor {
6
+ options;
7
+ constructor(options) {
8
+ this.options = options;
9
+ }
10
+ async review(inventory, signal) {
11
+ if (signal.aborted)
12
+ return;
13
+ const policy = await this.options.policyStore.load(this.options.machineId);
14
+ if (policy === null) {
15
+ this.options.onStatus("Guardian process review is waiting for its administrator policy.");
16
+ return;
17
+ }
18
+ let reviewed = 0;
19
+ let denied = 0;
20
+ let containmentFailed = 0;
21
+ let unverified = 0;
22
+ if (inventory.partial)
23
+ this.options.onStatus("Guardian discovery is incomplete; process protection coverage is degraded.");
24
+ for (const agent of inventory.agents) {
25
+ if (signal.aborted)
26
+ return;
27
+ if (agent.state !== AgentState.RUNNING || agent.startedAt === undefined ||
28
+ agent.processId < 1n || agent.processId > BigInt(Number.MAX_SAFE_INTEGER) ||
29
+ !agent.capabilities.includes("process-instance")) {
30
+ if (agent.state === AgentState.RUNNING)
31
+ unverified++;
32
+ continue;
33
+ }
34
+ const resource = JSON.stringify({
35
+ claimed_agent_id: agent.agentId,
36
+ display_name: agent.displayName,
37
+ runtime: agent.runtime,
38
+ executable_path_digest: agent.executablePathDigest,
39
+ lifecycle: "already_running",
40
+ });
41
+ const context = {
42
+ expectedEffect: "Continue running this discovered AI agent. This is a periodic process review; no proposed command or verified model selection is available.",
43
+ };
44
+ try {
45
+ const decision = await this.options.decisionClient.decide({
46
+ policyDigest: policy.policyDigest, agentId: agent.agentId,
47
+ processId: Number(agent.processId), processStartedAt: timestampDate(agent.startedAt).toISOString(),
48
+ action: "agent.start", resource, context,
49
+ }, signal);
50
+ if (signal.aborted)
51
+ return;
52
+ reviewed++;
53
+ const containment = decision.decision === "deny" && decision.intervention !== "none" && decision.intervention !== "block_action"
54
+ ? await this.options.containment.execute({
55
+ intervention: decision.intervention, agentId: agent.agentId,
56
+ processId: Number(agent.processId), expectedStartedAt: timestampDate(agent.startedAt).toISOString(),
57
+ }) : undefined;
58
+ // Allows are already audited centrally. Report denied running processes
59
+ // even when the admin authorized only action blocking, never escalation.
60
+ if (decision.decision !== "allow") {
61
+ denied++;
62
+ if (containment !== undefined && containment.state !== "succeeded")
63
+ containmentFailed++;
64
+ const detail = containment?.detail ?? "The running process was not stopped: its policy did not authorize process containment.";
65
+ this.options.onStatus(`Phigon Guardian: ${agent.agentId}. ${decision.reason} ${detail}`);
66
+ await this.options.journal.append({
67
+ agentId: agent.agentId, action: "agent.start", resource,
68
+ outcome: decision.decision === "deny" ? "denied" : "approval_required",
69
+ reason: decision.reason, decisionSource: "guardian_process_monitor",
70
+ latencyMs: decision.latencyMs, policyDigest: policy.policyDigest, context,
71
+ ...(decision.adminContract === undefined ? {} : { adminContract: decision.adminContract }),
72
+ ...(decision.intervention === "none" ? {} : { intervention: decision.intervention }),
73
+ ...(containment === undefined ? {} : { containment }),
74
+ model: decision.model, risk: decision.risk, confidence: decision.confidence,
75
+ });
76
+ }
77
+ }
78
+ catch {
79
+ unverified++;
80
+ this.options.onStatus(`Guardian could not verify process ${agent.agentId}; containment coverage is unavailable for this review.`);
81
+ }
82
+ }
83
+ if (!signal.aborted && this.options.coverageClient) {
84
+ try {
85
+ await this.options.coverageClient.post("/v1/machine/guardian/coverage", {
86
+ policy_digest: policy.policyDigest, platform: process.platform,
87
+ process_review: inventory.partial || unverified > 0 || containmentFailed > 0 ? "degraded" : "active",
88
+ discovery_partial: inventory.partial === true,
89
+ reviewed, denied, containment_failed: containmentFailed, unverified,
90
+ }, signal, 10_000);
91
+ }
92
+ catch {
93
+ this.options.onStatus("Guardian could not deliver its coverage report; central protection status will become stale.");
94
+ }
95
+ }
96
+ }
97
+ }
98
+ //# sourceMappingURL=guardian-process-monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardian-process-monitor.js","sourceRoot":"","sources":["../../src/guardian-process-monitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { ObserverConfig } from "./config.js";
2
+ export type ObserverStreamCursorHealth = Readonly<{
3
+ machineId: string;
4
+ acknowledgedSequence: string;
5
+ updatedAt: string;
6
+ }>;
7
+ export type ObserverHealth = Readonly<{
8
+ status: "ready" | "needs-pairing";
9
+ observerVersion: string;
10
+ controlPlaneOrigin: string;
11
+ grpcOrigin: string;
12
+ dataDirectory: string;
13
+ heartbeatIntervalMs: number;
14
+ discoveryIntervalMs: number;
15
+ activityRateLimitPerMinute: number;
16
+ activityQueueCapacity: number;
17
+ machineTokenConfigured: boolean;
18
+ observabilityProfile: string;
19
+ enabledCollectionCategories: readonly string[];
20
+ safeCollectionDefaults: boolean;
21
+ host: Readonly<{
22
+ architecture: string;
23
+ hostname: string;
24
+ platform: NodeJS.Platform;
25
+ release: string;
26
+ }>;
27
+ runtime: Readonly<{
28
+ node: string;
29
+ }>;
30
+ streamCursor?: ObserverStreamCursorHealth;
31
+ streamCursorIssue?: string;
32
+ checkedAt: string;
33
+ }>;
34
+ export declare function createHealthSnapshot(config: ObserverConfig, observerVersion: string, now?: Date, streamCursor?: ObserverStreamCursorHealth, streamCursorIssue?: string): ObserverHealth;
35
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/health.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AASlD,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,MAAM,EAAE,OAAO,GAAG,eAAe,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B,EAAE,MAAM,CAAC;IACnC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,OAAO,CAAC;IAChC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2BAA2B,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,sBAAsB,EAAE,OAAO,CAAC;IAChC,IAAI,EAAE,QAAQ,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,eAAe,EAAE,MAAM,EACvB,GAAG,GAAE,IAAiB,EACtB,YAAY,CAAC,EAAE,0BAA0B,EACzC,iBAAiB,CAAC,EAAE,MAAM,GACzB,cAAc,CAoChB"}
@@ -0,0 +1,41 @@
1
+ import { arch, hostname, platform, release } from "node:os";
2
+ const metadataOnlyCategories = new Set([
3
+ "processMetadata",
4
+ "fileMetadata",
5
+ "networkMetadata",
6
+ "browserMetadata",
7
+ ]);
8
+ export function createHealthSnapshot(config, observerVersion, now = new Date(), streamCursor, streamCursorIssue) {
9
+ return Object.freeze({
10
+ status: config.machineTokenConfigured ? "ready" : "needs-pairing",
11
+ observerVersion,
12
+ controlPlaneOrigin: config.controlPlaneUrl.origin,
13
+ grpcOrigin: config.grpcUrl.origin,
14
+ dataDirectory: config.dataDirectory,
15
+ heartbeatIntervalMs: config.heartbeatIntervalMs,
16
+ discoveryIntervalMs: config.discoveryIntervalMs,
17
+ activityRateLimitPerMinute: config.activityRateLimitPerMinute,
18
+ activityQueueCapacity: config.activityQueueCapacity,
19
+ machineTokenConfigured: config.machineTokenConfigured,
20
+ observabilityProfile: config.observabilityProfile,
21
+ enabledCollectionCategories: Object.freeze(Object.entries(config.policy)
22
+ .filter(([, enabled]) => enabled)
23
+ .map(([category]) => category)),
24
+ safeCollectionDefaults: Object.entries(config.policy).every(([category, enabled]) => !enabled || metadataOnlyCategories.has(category)),
25
+ host: Object.freeze({
26
+ architecture: arch(),
27
+ hostname: hostname(),
28
+ platform: platform(),
29
+ release: release(),
30
+ }),
31
+ runtime: Object.freeze({
32
+ node: process.version,
33
+ }),
34
+ ...(streamCursor === undefined
35
+ ? {}
36
+ : { streamCursor: Object.freeze(streamCursor) }),
37
+ ...(streamCursorIssue === undefined ? {} : { streamCursorIssue }),
38
+ checkedAt: now.toISOString(),
39
+ });
40
+ }
41
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAG5D,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,iBAAiB;IACjB,cAAc;IACd,iBAAiB;IACjB,iBAAiB;CAClB,CAAC,CAAC;AAoCH,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,eAAuB,EACvB,MAAY,IAAI,IAAI,EAAE,EACtB,YAAyC,EACzC,iBAA0B;IAE1B,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;QACjE,eAAe;QACf,kBAAkB,EAAE,MAAM,CAAC,eAAe,CAAC,MAAM;QACjD,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;QACjC,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;QAC7D,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;QACnD,sBAAsB,EAAE,MAAM,CAAC,sBAAsB;QACrD,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;QACjD,2BAA2B,EAAE,MAAM,CAAC,MAAM,CACxC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;aAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;aAChC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CACjC;QACD,sBAAsB,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CACzD,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAC1E;QACD,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;YAClB,YAAY,EAAE,IAAI,EAAE;YACpB,QAAQ,EAAE,QAAQ,EAAE;YACpB,QAAQ,EAAE,QAAQ,EAAE;YACpB,OAAO,EAAE,OAAO,EAAE;SACnB,CAAC;QACF,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,IAAI,EAAE,OAAO,CAAC,OAAO;SACtB,CAAC;QACF,GAAG,CAAC,YAAY,KAAK,SAAS;YAC5B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC;QACjE,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;KAC7B,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type AgentIdentity, type AgentInventory } from "./generated/phigon/v1/identity_pb.js";
2
+ export type HistoricalIdentityScope = Readonly<{
3
+ tenantId: string;
4
+ machineId: string;
5
+ }>;
6
+ /**
7
+ * Stores only sanitized inventory metadata needed to keep stopped runtime and
8
+ * unattributed source history targets addressable after observer restart.
9
+ * Activity content, raw source IDs, raw process keys, credentials, and paths
10
+ * are never accepted by this catalog.
11
+ */
12
+ export declare class HistoricalIdentityStore {
13
+ #private;
14
+ constructor(dataDirectory: string, scope: HistoricalIdentityScope);
15
+ load(): Promise<readonly AgentIdentity[]>;
16
+ remember(candidates: readonly AgentIdentity[]): Promise<readonly AgentIdentity[]>;
17
+ identities(): readonly AgentIdentity[];
18
+ }
19
+ export declare function mergeInventoryWithHistoricalIdentities(inventory: AgentInventory, historical: readonly AgentIdentity[]): AgentInventory;
20
+ //# sourceMappingURL=historical-identity-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historical-identity-store.d.ts","sourceRoot":"","sources":["../../src/historical-identity-store.ts"],"names":[],"mappings":"AAoBA,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,sCAAsC,CAAC;AAW9C,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAwBH;;;;;GAKG;AACH,qBAAa,uBAAuB;;gBAUhC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,uBAAuB;IAQhC,IAAI,IAAI,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IAKnC,QAAQ,CACZ,UAAU,EAAE,SAAS,aAAa,EAAE,GACnC,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IAgCpC,UAAU,IAAI,SAAS,aAAa,EAAE;CAyFvC;AAED,wBAAgB,sCAAsC,CACpD,SAAS,EAAE,cAAc,EACzB,UAAU,EAAE,SAAS,aAAa,EAAE,GACnC,cAAc,CAyChB"}
@@ -0,0 +1,391 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { chmod, mkdir, readFile, rename, stat, unlink, writeFile, } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { create } from "@bufbuild/protobuf";
5
+ import { timestampDate, timestampFromDate, } from "@bufbuild/protobuf/wkt";
6
+ import { AgentKind, AgentState, } from "./generated/phigon/v1/common_pb.js";
7
+ import { AgentIdentitySchema, AgentInventorySchema, } from "./generated/phigon/v1/identity_pb.js";
8
+ const catalogVersion = 1;
9
+ const maxCatalogBytes = 1 << 20;
10
+ const maxHistoricalIdentities = 256;
11
+ const catalogFileName = "historical-agent-identities.json";
12
+ const processKeyCapabilityPattern = /^process-key-sha256:[a-f0-9]{32}$/u;
13
+ const capabilityPattern = /^[a-z0-9][a-z0-9:._+-]{0,63}$/u;
14
+ const scopedIDPattern = /^[A-Za-z0-9._:-]{1,128}$/u;
15
+ /**
16
+ * Stores only sanitized inventory metadata needed to keep stopped runtime and
17
+ * unattributed source history targets addressable after observer restart.
18
+ * Activity content, raw source IDs, raw process keys, credentials, and paths
19
+ * are never accepted by this catalog.
20
+ */
21
+ export class HistoricalIdentityStore {
22
+ #dataDirectory;
23
+ #path;
24
+ #scope;
25
+ #identities = new Map();
26
+ #loadPromise;
27
+ #saveChain = Promise.resolve();
28
+ #needsRewrite = false;
29
+ constructor(dataDirectory, scope) {
30
+ validateScope(scope);
31
+ this.#dataDirectory = dataDirectory;
32
+ this.#path = join(dataDirectory, catalogFileName);
33
+ this.#scope = Object.freeze({ ...scope });
34
+ }
35
+ load() {
36
+ this.#loadPromise ??= this.#loadOnce();
37
+ return this.#loadPromise;
38
+ }
39
+ async remember(candidates) {
40
+ await this.load();
41
+ const operation = this.#saveChain
42
+ .catch(() => undefined)
43
+ .then(async () => {
44
+ let changed = this.#needsRewrite;
45
+ for (const candidate of candidates) {
46
+ const sanitized = sanitizedHistoricalIdentity(candidate);
47
+ if (sanitized === undefined)
48
+ continue;
49
+ const previous = this.#identities.get(sanitized.agentId);
50
+ if (previous === undefined ||
51
+ serializedIdentity(previous) !== serializedIdentity(sanitized)) {
52
+ this.#identities.set(sanitized.agentId, sanitized);
53
+ changed = true;
54
+ }
55
+ }
56
+ if (this.#bound())
57
+ changed = true;
58
+ if (changed) {
59
+ await this.#save();
60
+ this.#needsRewrite = false;
61
+ }
62
+ return this.identities();
63
+ });
64
+ this.#saveChain = operation.then(() => undefined, () => undefined);
65
+ return operation;
66
+ }
67
+ identities() {
68
+ return [...this.#identities.values()].sort((left, right) => left.agentId.localeCompare(right.agentId));
69
+ }
70
+ async #loadOnce() {
71
+ let raw;
72
+ try {
73
+ const metadata = await stat(this.#path);
74
+ if (!metadata.isFile() || metadata.size > maxCatalogBytes) {
75
+ this.#needsRewrite = true;
76
+ return [];
77
+ }
78
+ raw = await readFile(this.#path, "utf8");
79
+ }
80
+ catch (error) {
81
+ if (isNodeError(error) && error.code === "ENOENT")
82
+ return [];
83
+ throw error;
84
+ }
85
+ let parsed;
86
+ try {
87
+ parsed = JSON.parse(raw);
88
+ }
89
+ catch {
90
+ this.#needsRewrite = true;
91
+ return [];
92
+ }
93
+ const catalog = parsedCatalog(parsed);
94
+ if (catalog === undefined ||
95
+ catalog.tenant_id !== this.#scope.tenantId ||
96
+ catalog.machine_id !== this.#scope.machineId) {
97
+ this.#needsRewrite = true;
98
+ return [];
99
+ }
100
+ for (const stored of catalog.identities) {
101
+ const identity = parsedIdentity(stored);
102
+ if (identity === undefined) {
103
+ this.#identities.clear();
104
+ this.#needsRewrite = true;
105
+ return [];
106
+ }
107
+ this.#identities.set(identity.agentId, identity);
108
+ }
109
+ return this.identities();
110
+ }
111
+ #bound() {
112
+ if (this.#identities.size <= maxHistoricalIdentities)
113
+ return false;
114
+ const retained = [...this.#identities.values()]
115
+ .sort(recentIdentityFirst)
116
+ .slice(0, maxHistoricalIdentities);
117
+ this.#identities.clear();
118
+ for (const identity of retained) {
119
+ this.#identities.set(identity.agentId, identity);
120
+ }
121
+ return true;
122
+ }
123
+ async #save() {
124
+ await mkdir(this.#dataDirectory, { recursive: true, mode: 0o700 });
125
+ await chmod(this.#dataDirectory, 0o700);
126
+ const temporaryPath = `${this.#path}.${process.pid}.${randomUUID()}.tmp`;
127
+ const catalog = {
128
+ version: catalogVersion,
129
+ tenant_id: this.#scope.tenantId,
130
+ machine_id: this.#scope.machineId,
131
+ updated_at: new Date().toISOString(),
132
+ identities: this.identities().map(storedIdentity),
133
+ };
134
+ try {
135
+ await writeFile(temporaryPath, `${JSON.stringify(catalog)}\n`, { encoding: "utf8", flag: "wx", mode: 0o600 });
136
+ await rename(temporaryPath, this.#path);
137
+ await chmod(this.#path, 0o600);
138
+ }
139
+ catch (error) {
140
+ try {
141
+ await unlink(temporaryPath);
142
+ }
143
+ catch {
144
+ // The temporary file may not have been created.
145
+ }
146
+ throw error;
147
+ }
148
+ }
149
+ }
150
+ export function mergeInventoryWithHistoricalIdentities(inventory, historical) {
151
+ const byID = new Map();
152
+ for (const identity of historical) {
153
+ const sanitized = sanitizedHistoricalIdentity(identity);
154
+ if (sanitized !== undefined)
155
+ byID.set(sanitized.agentId, sanitized);
156
+ }
157
+ // A fresh discovery observation is authoritative for the same lifetime.
158
+ for (const identity of inventory.agents) {
159
+ byID.set(identity.agentId, identity);
160
+ }
161
+ const candidates = [...byID.values()];
162
+ const runtimeProducts = new Set(candidates
163
+ .filter((identity) => identity.capabilities.includes("process-instance"))
164
+ .flatMap(agentProductCapabilities));
165
+ const combined = candidates.filter((identity) => identity.capabilities.includes("process-instance") ||
166
+ !agentProductCapabilities(identity).some((capability) => runtimeProducts.has(capability)));
167
+ const selected = combined
168
+ .sort(inventoryRetentionOrder)
169
+ .slice(0, maxHistoricalIdentities)
170
+ .sort((left, right) => left.agentId.localeCompare(right.agentId));
171
+ const overflow = combined.length > selected.length;
172
+ const overflowNotice = "Historical agent identities exceeded inventory capacity.";
173
+ const notices = overflow && !inventory.notices.includes(overflowNotice)
174
+ ? [...inventory.notices.slice(0, 31), overflowNotice]
175
+ : [...inventory.notices];
176
+ return create(AgentInventorySchema, {
177
+ ...inventory,
178
+ agents: selected,
179
+ partial: inventory.partial || overflow,
180
+ notices,
181
+ });
182
+ }
183
+ function sanitizedHistoricalIdentity(value) {
184
+ const capabilities = validatedCapabilities(value.capabilities);
185
+ if (!/^agt_[a-f0-9]{32}$/u.test(value.agentId) ||
186
+ value.kind < AgentKind.CLAUDE ||
187
+ value.kind > AgentKind.GENERIC ||
188
+ !validBoundedText(value.displayName, 128, true) ||
189
+ !validBoundedText(value.version, 64, false) ||
190
+ !validBoundedText(value.runtime, 128, false) ||
191
+ !validDigest(value.executablePathDigest) ||
192
+ capabilities === undefined ||
193
+ value.lastObservedAt === undefined) {
194
+ return undefined;
195
+ }
196
+ const processIdentity = capabilities.includes("process-instance");
197
+ const sourceIdentity = capabilities.includes("source-isolated");
198
+ if (processIdentity === sourceIdentity)
199
+ return undefined;
200
+ if (processIdentity &&
201
+ capabilities.filter((capability) => processKeyCapabilityPattern.test(capability)).length !== 1) {
202
+ return undefined;
203
+ }
204
+ if (sourceIdentity &&
205
+ (!capabilities.includes("unattributed") || value.processId !== 0n)) {
206
+ return undefined;
207
+ }
208
+ const lastObserved = validTimestamp(timestampDate(value.lastObservedAt));
209
+ const startedAt = value.startedAt === undefined
210
+ ? undefined
211
+ : validTimestamp(timestampDate(value.startedAt));
212
+ if (lastObserved === undefined ||
213
+ (value.startedAt !== undefined && startedAt === undefined)) {
214
+ return undefined;
215
+ }
216
+ return create(AgentIdentitySchema, {
217
+ agentId: value.agentId,
218
+ kind: value.kind,
219
+ displayName: value.displayName,
220
+ version: value.version,
221
+ runtime: value.runtime,
222
+ state: processIdentity ? AgentState.STOPPED : AgentState.UNKNOWN,
223
+ processId: processIdentity ? value.processId : 0n,
224
+ ...(startedAt === undefined
225
+ ? {}
226
+ : { startedAt: timestampFromDate(startedAt) }),
227
+ lastObservedAt: timestampFromDate(lastObserved),
228
+ capabilities,
229
+ executablePathDigest: value.executablePathDigest,
230
+ });
231
+ }
232
+ function storedIdentity(value) {
233
+ return {
234
+ agent_id: value.agentId,
235
+ kind: value.kind,
236
+ display_name: value.displayName,
237
+ version: value.version,
238
+ runtime: value.runtime,
239
+ state: value.state,
240
+ process_id: value.processId.toString(),
241
+ ...(value.startedAt === undefined
242
+ ? {}
243
+ : { started_at: timestampDate(value.startedAt).toISOString() }),
244
+ last_observed_at: value.lastObservedAt === undefined
245
+ ? new Date(0).toISOString()
246
+ : timestampDate(value.lastObservedAt).toISOString(),
247
+ capabilities: [...value.capabilities],
248
+ executable_path_digest: value.executablePathDigest,
249
+ };
250
+ }
251
+ function parsedCatalog(value) {
252
+ if (typeof value !== "object" ||
253
+ value === null ||
254
+ !("version" in value) ||
255
+ value.version !== catalogVersion ||
256
+ !("tenant_id" in value) ||
257
+ typeof value.tenant_id !== "string" ||
258
+ !("machine_id" in value) ||
259
+ typeof value.machine_id !== "string" ||
260
+ !("updated_at" in value) ||
261
+ typeof value.updated_at !== "string" ||
262
+ validDateString(value.updated_at) === undefined ||
263
+ !("identities" in value) ||
264
+ !Array.isArray(value.identities) ||
265
+ value.identities.length > maxHistoricalIdentities) {
266
+ return undefined;
267
+ }
268
+ return value;
269
+ }
270
+ function parsedIdentity(value) {
271
+ if (typeof value !== "object" ||
272
+ value === null ||
273
+ !("agent_id" in value) ||
274
+ typeof value.agent_id !== "string" ||
275
+ !("kind" in value) ||
276
+ typeof value.kind !== "number" ||
277
+ !("display_name" in value) ||
278
+ typeof value.display_name !== "string" ||
279
+ !("version" in value) ||
280
+ typeof value.version !== "string" ||
281
+ !("runtime" in value) ||
282
+ typeof value.runtime !== "string" ||
283
+ !("state" in value) ||
284
+ typeof value.state !== "number" ||
285
+ !("process_id" in value) ||
286
+ typeof value.process_id !== "string" ||
287
+ !/^\d{1,20}$/u.test(value.process_id) ||
288
+ !("last_observed_at" in value) ||
289
+ typeof value.last_observed_at !== "string" ||
290
+ !("capabilities" in value) ||
291
+ !Array.isArray(value.capabilities) ||
292
+ value.capabilities.some((capability) => typeof capability !== "string") ||
293
+ !("executable_path_digest" in value) ||
294
+ typeof value.executable_path_digest !== "string") {
295
+ return undefined;
296
+ }
297
+ const startedAt = "started_at" in value
298
+ ? typeof value.started_at === "string"
299
+ ? validDateString(value.started_at)
300
+ : undefined
301
+ : null;
302
+ const lastObservedAt = validDateString(value.last_observed_at);
303
+ if (startedAt === undefined || lastObservedAt === undefined) {
304
+ return undefined;
305
+ }
306
+ let processID;
307
+ try {
308
+ processID = BigInt(value.process_id);
309
+ }
310
+ catch {
311
+ return undefined;
312
+ }
313
+ if (processID > 18446744073709551615n)
314
+ return undefined;
315
+ const candidate = create(AgentIdentitySchema, {
316
+ agentId: value.agent_id,
317
+ kind: value.kind,
318
+ displayName: value.display_name,
319
+ version: value.version,
320
+ runtime: value.runtime,
321
+ state: value.state,
322
+ processId: processID,
323
+ ...(startedAt === null
324
+ ? {}
325
+ : { startedAt: timestampFromDate(startedAt) }),
326
+ lastObservedAt: timestampFromDate(lastObservedAt),
327
+ capabilities: value.capabilities,
328
+ executablePathDigest: value.executable_path_digest,
329
+ });
330
+ return sanitizedHistoricalIdentity(candidate);
331
+ }
332
+ function validatedCapabilities(capabilities) {
333
+ if (capabilities.length === 0 ||
334
+ capabilities.length > 64 ||
335
+ capabilities.some((capability) => !capabilityPattern.test(capability))) {
336
+ return undefined;
337
+ }
338
+ return [...new Set(capabilities)].sort();
339
+ }
340
+ function agentProductCapabilities(identity) {
341
+ return identity.capabilities.filter((capability) => capability.startsWith("agent-product:"));
342
+ }
343
+ function validBoundedText(value, maxBytes, required) {
344
+ return ((!required || value.length > 0) &&
345
+ Buffer.byteLength(value, "utf8") <= maxBytes &&
346
+ !/[\u0000-\u001f\u007f]/u.test(value));
347
+ }
348
+ function validDigest(value) {
349
+ return value.length <= 128 && /^[A-Za-z0-9._:-]*$/u.test(value);
350
+ }
351
+ function validDateString(value) {
352
+ if (value.length > 64)
353
+ return undefined;
354
+ return validTimestamp(new Date(value));
355
+ }
356
+ function validTimestamp(value) {
357
+ return Number.isNaN(value.getTime()) ? undefined : value;
358
+ }
359
+ function validateScope(scope) {
360
+ if (!scopedIDPattern.test(scope.tenantId) ||
361
+ !scopedIDPattern.test(scope.machineId)) {
362
+ throw new Error("Historical identity scope is invalid.");
363
+ }
364
+ }
365
+ function recentIdentityFirst(left, right) {
366
+ const leftObserved = left.lastObservedAt === undefined
367
+ ? 0
368
+ : timestampDate(left.lastObservedAt).getTime();
369
+ const rightObserved = right.lastObservedAt === undefined
370
+ ? 0
371
+ : timestampDate(right.lastObservedAt).getTime();
372
+ return rightObserved - leftObserved || left.agentId.localeCompare(right.agentId);
373
+ }
374
+ function inventoryRetentionOrder(left, right) {
375
+ const leftCurrent = left.state === AgentState.RUNNING ? 1 : 0;
376
+ const rightCurrent = right.state === AgentState.RUNNING ? 1 : 0;
377
+ if (leftCurrent !== rightCurrent)
378
+ return rightCurrent - leftCurrent;
379
+ const leftSource = left.capabilities.includes("source-isolated") ? 1 : 0;
380
+ const rightSource = right.capabilities.includes("source-isolated") ? 1 : 0;
381
+ if (leftSource !== rightSource)
382
+ return rightSource - leftSource;
383
+ return recentIdentityFirst(left, right);
384
+ }
385
+ function serializedIdentity(value) {
386
+ return JSON.stringify(storedIdentity(value));
387
+ }
388
+ function isNodeError(error) {
389
+ return error instanceof Error && "code" in error;
390
+ }
391
+ //# sourceMappingURL=historical-identity-store.js.map