@vellumai/assistant 0.11.6 → 0.11.7-staging.2

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 (478) hide show
  1. package/ARCHITECTURE.md +31 -19
  2. package/Dockerfile +1 -0
  3. package/docs/architecture/security.md +3 -3
  4. package/docs/flux-turn-detection-spike.md +8 -7
  5. package/docs/runbook-trusted-contacts.md +14 -0
  6. package/docs/stt-provider-onboarding.md +8 -4
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/avatar-manifest/package.json +18 -0
  9. package/node_modules/@vellumai/avatar-manifest/src/__tests__/manifest.test.ts +173 -0
  10. package/node_modules/@vellumai/avatar-manifest/src/__tests__/read.test.ts +114 -0
  11. package/node_modules/@vellumai/avatar-manifest/src/index.ts +29 -0
  12. package/node_modules/@vellumai/avatar-manifest/src/layout.ts +18 -0
  13. package/node_modules/@vellumai/avatar-manifest/src/manifest.ts +156 -0
  14. package/node_modules/@vellumai/avatar-manifest/src/read.ts +109 -0
  15. package/node_modules/@vellumai/avatar-manifest/tsconfig.json +20 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
  19. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
  20. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
  21. package/node_modules/@vellumai/ces-client/src/http-credentials.ts +161 -0
  22. package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
  23. package/node_modules/@vellumai/environments/package.json +2 -1
  24. package/node_modules/@vellumai/environments/src/shell.test.ts +56 -0
  25. package/node_modules/@vellumai/environments/src/shell.ts +65 -0
  26. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
  27. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
  28. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
  29. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
  30. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
  31. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +32 -0
  32. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -0
  33. package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +82 -0
  34. package/node_modules/@vellumai/gateway-client/src/__tests__/plugin-admission-denied-contract.test.ts +56 -0
  35. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +18 -0
  36. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -11
  37. package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +3 -1
  38. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +9 -0
  39. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +4 -0
  40. package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +75 -0
  41. package/node_modules/@vellumai/gateway-client/src/index.ts +17 -0
  42. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +8 -0
  43. package/node_modules/@vellumai/gateway-client/src/plugin-admission-denied-contract.ts +47 -0
  44. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +11 -0
  45. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
  46. package/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
  47. package/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
  48. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
  49. package/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
  50. package/openapi.yaml +419 -55
  51. package/package.json +4 -1
  52. package/scripts/sync-llm-catalog.ts +6 -0
  53. package/src/__tests__/approval-card-edit-inbound-handoff.test.ts +199 -0
  54. package/src/__tests__/approval-card-edit.test.ts +153 -0
  55. package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
  56. package/src/__tests__/available-skills.test.ts +54 -0
  57. package/src/__tests__/avatar-identity-sync.test.ts +5 -1
  58. package/src/__tests__/catalog-install-normalize.test.ts +9 -1
  59. package/src/__tests__/channel-policy.test.ts +1 -3
  60. package/src/__tests__/channel-readiness-discord.test.ts +9 -70
  61. package/src/__tests__/compactor-call-site-logging.test.ts +61 -0
  62. package/src/__tests__/config-loader-backfill.test.ts +69 -0
  63. package/src/__tests__/config-schema.test.ts +2 -3
  64. package/src/__tests__/conversation-agent-loop.test.ts +238 -0
  65. package/src/__tests__/conversation-attachments.test.ts +0 -1
  66. package/src/__tests__/conversation-error.test.ts +44 -0
  67. package/src/__tests__/conversation-evictor.test.ts +19 -0
  68. package/src/__tests__/conversation-fork-referential.test.ts +73 -63
  69. package/src/__tests__/conversation-fork-retrospective.test.ts +99 -74
  70. package/src/__tests__/conversation-runtime-assembly.test.ts +23 -0
  71. package/src/__tests__/conversation-slash.test.ts +9 -0
  72. package/src/__tests__/conversation-title-service.test.ts +97 -0
  73. package/src/__tests__/conversation-tool-setup-attribution.test.ts +16 -0
  74. package/src/__tests__/credential-broker-server-use.test.ts +0 -218
  75. package/src/__tests__/credential-broker.test.ts +43 -420
  76. package/src/__tests__/credential-record-write-through.test.ts +78 -0
  77. package/src/__tests__/credential-routes.test.ts +17 -1
  78. package/src/__tests__/credential-security-invariants.test.ts +8 -9
  79. package/src/__tests__/default-profile-catalog-fallback.test.ts +289 -0
  80. package/src/__tests__/delete-propagation.test.ts +92 -2
  81. package/src/__tests__/discord-callback-round-trip.test.ts +93 -0
  82. package/src/__tests__/discord-channel-config.test.ts +237 -0
  83. package/src/__tests__/edit-propagation.test.ts +42 -2
  84. package/src/__tests__/evict-conversations-for-reload.test.ts +51 -1
  85. package/src/__tests__/fallback-breaker.test.ts +1335 -0
  86. package/src/__tests__/gateway-threshold-reader-mock.ts +6 -0
  87. package/src/__tests__/guardian-card-withdrawal.test.ts +30 -0
  88. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -2
  89. package/src/__tests__/image-conversion.test.ts +38 -4
  90. package/src/__tests__/install-skill-routing.test.ts +25 -0
  91. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  92. package/src/__tests__/llm-resolver.test.ts +74 -0
  93. package/src/__tests__/llm-schema-fallback-profile.test.ts +359 -0
  94. package/src/__tests__/managed-fallback-dispatch.test.ts +430 -0
  95. package/src/__tests__/managed-profile-guard.test.ts +28 -0
  96. package/src/__tests__/managed-speech-defaults.test.ts +196 -1
  97. package/src/__tests__/mcp-cli.test.ts +23 -1
  98. package/src/__tests__/mcp-tool-annotations-risk.test.ts +43 -34
  99. package/src/__tests__/media-stream-stt-session.test.ts +2 -0
  100. package/src/__tests__/notification-decision-fallback.test.ts +106 -0
  101. package/src/__tests__/notification-discord-adapter.test.ts +162 -0
  102. package/src/__tests__/oauth-connect-orchestrator.test.ts +95 -0
  103. package/src/__tests__/persist-unsendable-image-downscale.test.ts +6 -8
  104. package/src/__tests__/persist-unsendable-image.test.ts +3 -3
  105. package/src/__tests__/platform.test.ts +19 -1
  106. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  107. package/src/__tests__/provider-catalog-visibility.test.ts +17 -0
  108. package/src/__tests__/provider-platform-proxy-integration.test.ts +8 -1
  109. package/src/__tests__/provider-usage-tracking.test.ts +56 -0
  110. package/src/__tests__/require-fresh-approval.test.ts +5 -2
  111. package/src/__tests__/retry-fallback-escalation.test.ts +1093 -0
  112. package/src/__tests__/schedule-retry.test.ts +183 -4
  113. package/src/__tests__/scheduler-reuse-conversation.test.ts +6 -6
  114. package/src/__tests__/secret-routes-platform-proxy.test.ts +55 -0
  115. package/src/__tests__/skill-load-tool.test.ts +34 -0
  116. package/src/__tests__/skill-tool-factory.test.ts +6 -1
  117. package/src/__tests__/skill-tool-manifest.test.ts +20 -0
  118. package/src/__tests__/skills.test.ts +25 -0
  119. package/src/__tests__/subagent-manager-notify.test.ts +38 -0
  120. package/src/__tests__/terminal-tools.test.ts +2 -0
  121. package/src/__tests__/tool-approval-handler.test.ts +146 -2
  122. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +108 -2
  123. package/src/__tests__/tool-audit.test.ts +111 -40
  124. package/src/__tests__/tool-executor-lifecycle-events.test.ts +228 -18
  125. package/src/__tests__/ui-shape-teaching.test.ts +1 -1
  126. package/src/__tests__/verification-control-plane-policy.test.ts +6 -2
  127. package/src/__tests__/voice-config-update.test.ts +43 -0
  128. package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +480 -0
  129. package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +167 -0
  130. package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +144 -0
  131. package/src/agent/loop.ts +31 -2
  132. package/src/approvals/guardian-card-withdrawal.ts +22 -0
  133. package/src/avatar/__tests__/ensure-raster.test.ts +291 -0
  134. package/src/avatar/avatar-manifest.ts +48 -100
  135. package/src/avatar/avatar-store.ts +7 -7
  136. package/src/avatar/ensure-raster.ts +146 -0
  137. package/src/avatar/resvg-lazy.test.ts +0 -1
  138. package/src/avatar/traits-png-sync.ts +9 -10
  139. package/src/background-wake/wake-intent-hooks.test.ts +0 -1
  140. package/src/backup/__tests__/paths.test.ts +6 -2
  141. package/src/backup/paths.ts +6 -4
  142. package/src/bundler/app-compiler.ts +2 -2
  143. package/src/bundler/compiler-tools.test.ts +36 -0
  144. package/src/bundler/compiler-tools.ts +54 -18
  145. package/src/calls/__tests__/telephony-synthesis-language.test.ts +81 -0
  146. package/src/calls/__tests__/voice-session-bridge.test.ts +57 -0
  147. package/src/calls/media-stream-stt-session.ts +2 -1
  148. package/src/calls/telephony-synthesis-language.ts +13 -5
  149. package/src/calls/voice-session-bridge.ts +19 -4
  150. package/src/channels/config.ts +23 -12
  151. package/src/cli/AGENTS.md +3 -1
  152. package/src/cli/commands/backup.help.ts +10 -13
  153. package/src/cli/commands/contacts.help.ts +16 -4
  154. package/src/cli/commands/contacts.ts +5 -1
  155. package/src/cli/commands/credentials.help.ts +1 -1
  156. package/src/cli/commands/inference-providers.ts +18 -53
  157. package/src/cli/commands/mcp.help.ts +6 -5
  158. package/src/cli/commands/mcp.ts +1 -1
  159. package/src/cli/commands/memory/memory-retrospective.ts +1 -0
  160. package/src/cli/commands/stt.help.ts +2 -2
  161. package/src/config/__tests__/backup-schema.test.ts +1 -1
  162. package/src/config/__tests__/default-profile-catalog.test.ts +83 -2
  163. package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
  164. package/src/config/__tests__/memory-retrospective-schema.test.ts +12 -15
  165. package/src/config/bundled-skills/computer-use/SKILL.md +6 -6
  166. package/src/config/bundled-skills/computer-use/TOOLS.json +9 -6
  167. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +3 -1
  168. package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
  169. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  170. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +16 -15
  171. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -1
  172. package/src/config/bundled-skills/settings/TOOLS.json +11 -5
  173. package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +85 -0
  174. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +33 -8
  175. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +54 -3
  176. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +1 -1
  177. package/src/config/default-profile-catalog.ts +195 -10
  178. package/src/config/default-profile-names.ts +41 -0
  179. package/src/config/feature-flag-registry.json +34 -2
  180. package/src/config/inference-profile-validation.ts +11 -2
  181. package/src/config/llm-resolver.ts +25 -0
  182. package/src/config/loader.ts +3 -0
  183. package/src/config/managed-speech-defaults.ts +160 -10
  184. package/src/config/schema.ts +2 -0
  185. package/src/config/schemas/__tests__/live-voice.test.ts +7 -6
  186. package/src/config/schemas/__tests__/stt.test.ts +94 -0
  187. package/src/config/schemas/backup.ts +1 -1
  188. package/src/config/schemas/channels.ts +32 -0
  189. package/src/config/schemas/live-voice.ts +13 -4
  190. package/src/config/schemas/llm.ts +263 -15
  191. package/src/config/schemas/mcp.ts +10 -2
  192. package/src/config/schemas/memory-retrospective.ts +1 -19
  193. package/src/config/schemas/services.ts +24 -0
  194. package/src/config/schemas/stt.ts +128 -5
  195. package/src/config/seed-inference-profiles.ts +32 -3
  196. package/src/config/skill-state.ts +5 -0
  197. package/src/config/skills.ts +21 -0
  198. package/src/contacts/notify-contacts-changed.ts +5 -2
  199. package/src/context/compactor.ts +74 -1
  200. package/src/daemon/__tests__/conversation-tool-setup.test.ts +138 -1
  201. package/src/daemon/config-watcher.ts +2 -1
  202. package/src/daemon/conversation-agent-loop-handlers.ts +27 -0
  203. package/src/daemon/conversation-agent-loop.ts +86 -10
  204. package/src/daemon/conversation-error.ts +25 -0
  205. package/src/daemon/conversation-evictor.ts +2 -4
  206. package/src/daemon/conversation-runtime-assembly.ts +19 -7
  207. package/src/daemon/conversation-skill-tools.ts +5 -1
  208. package/src/daemon/conversation-slash.ts +2 -2
  209. package/src/daemon/conversation-store.ts +8 -1
  210. package/src/daemon/conversation-tool-setup.ts +37 -0
  211. package/src/daemon/conversation.ts +0 -4
  212. package/src/daemon/handlers/channel-config-result.ts +30 -0
  213. package/src/daemon/handlers/config-discord-channel.ts +301 -0
  214. package/src/daemon/handlers/config-ingress.ts +9 -0
  215. package/src/daemon/handlers/config-slack-channel.ts +13 -15
  216. package/src/daemon/handlers/config-telegram.ts +2 -5
  217. package/src/daemon/handlers/conversations.ts +0 -2
  218. package/src/daemon/handlers/skills.ts +25 -7
  219. package/src/daemon/lifecycle.ts +3 -1
  220. package/src/daemon/message-types/messages.ts +0 -2
  221. package/src/daemon/tool-setup-types.ts +5 -3
  222. package/src/daemon/trust-context-types.test.ts +33 -0
  223. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  224. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +58 -4
  225. package/src/live-voice/__tests__/live-voice-managed-speech-fallback.test.ts +8 -3
  226. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +73 -11
  227. package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +148 -2
  228. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +64 -0
  229. package/src/live-voice/__tests__/live-voice-stt.test.ts +3 -0
  230. package/src/live-voice/__tests__/live-voice-text-turn.test.ts +391 -0
  231. package/src/live-voice/__tests__/protocol.test.ts +224 -0
  232. package/src/live-voice/live-voice-credential-preflight.ts +5 -1
  233. package/src/live-voice/live-voice-session-manager.ts +39 -2
  234. package/src/live-voice/live-voice-session.ts +224 -9
  235. package/src/live-voice/protocol.ts +187 -1
  236. package/src/messaging/providers/discord/api.ts +2 -1
  237. package/src/messaging/providers/discord/withdraw.ts +62 -0
  238. package/src/messaging/read-provider-metadata.ts +32 -0
  239. package/src/monitoring/__tests__/file-descriptors.test.ts +32 -0
  240. package/src/monitoring/__tests__/process-memory.test.ts +34 -1
  241. package/src/monitoring/db-integrity-sample.ts +1 -0
  242. package/src/monitoring/file-descriptors.ts +39 -6
  243. package/src/monitoring/process-memory.ts +37 -5
  244. package/src/monitoring/resource-sampler.ts +25 -8
  245. package/src/notifications/__tests__/activity-failed-dedupe.test.ts +161 -0
  246. package/src/notifications/__tests__/background-failure-signal.test.ts +107 -0
  247. package/src/notifications/__tests__/connected-channels.test.ts +12 -0
  248. package/src/notifications/__tests__/copy-composer.test.ts +83 -0
  249. package/src/notifications/__tests__/destination-resolver.test.ts +38 -0
  250. package/src/notifications/activity-failed-dedupe.ts +95 -0
  251. package/src/notifications/adapters/discord.ts +132 -0
  252. package/src/notifications/adapters/shared.ts +16 -0
  253. package/src/notifications/adapters/slack.ts +6 -1
  254. package/src/notifications/adapters/telegram.ts +5 -8
  255. package/src/notifications/approval-card-data.ts +94 -1
  256. package/src/notifications/background-failure-signal.ts +116 -0
  257. package/src/notifications/broadcaster.ts +3 -9
  258. package/src/notifications/copy-composer.ts +41 -8
  259. package/src/notifications/decision-engine.ts +55 -0
  260. package/src/notifications/destination-resolver.ts +45 -5
  261. package/src/notifications/emit-signal.ts +19 -5
  262. package/src/notifications/guardian-question-mode.ts +57 -0
  263. package/src/notifications/types.ts +2 -8
  264. package/src/oauth/__tests__/seed-providers-managed.test.ts +18 -0
  265. package/src/oauth/connect-orchestrator.ts +16 -0
  266. package/src/oauth/seed-providers.ts +262 -0
  267. package/src/permissions/checker.test.ts +21 -0
  268. package/src/permissions/checker.ts +6 -0
  269. package/src/permissions/gateway-threshold-reader.test.ts +184 -0
  270. package/src/permissions/gateway-threshold-reader.ts +144 -10
  271. package/src/permissions/prompter.ts +0 -6
  272. package/src/permissions/types.ts +5 -4
  273. package/src/persistence/__tests__/bulk-write-gate.test.ts +0 -38
  274. package/src/persistence/bulk-write-gate.ts +9 -10
  275. package/src/persistence/conversation-crud.ts +88 -134
  276. package/src/persistence/conversation-title-service.ts +43 -29
  277. package/src/persistence/embeddings/embedding-local.ts +14 -85
  278. package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -0
  279. package/src/persistence/lifecycle-events-store.test.ts +50 -0
  280. package/src/persistence/lifecycle-events-store.ts +75 -5
  281. package/src/platform/platform-patch-queue.test.ts +368 -0
  282. package/src/platform/platform-patch-queue.ts +190 -0
  283. package/src/platform/sync-avatar.test.ts +527 -0
  284. package/src/platform/sync-avatar.ts +209 -0
  285. package/src/platform/sync-identity.test.ts +75 -0
  286. package/src/platform/sync-identity.ts +17 -110
  287. package/src/plugin-api/model-profiles.test.ts +2 -2
  288. package/src/plugin-api/model-profiles.ts +7 -7
  289. package/src/plugin-api/transcription-session.ts +1 -1
  290. package/src/plugins/defaults/compaction/window-manager.ts +4 -0
  291. package/src/plugins/defaults/image-recovery/recover.ts +2 -2
  292. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +133 -34
  293. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +21 -31
  294. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +13 -9
  295. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +31 -4
  296. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +0 -11
  297. package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +27 -13
  298. package/src/plugins/defaults/memory/memory-retrospective-job.ts +183 -113
  299. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
  300. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
  301. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +1 -1
  302. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +4 -2
  303. package/src/plugins/defaults/memory/substrate/sweep-job.ts +9 -42
  304. package/src/plugins/defaults/memory/v2/rerank-local.ts +1 -0
  305. package/src/plugins/defaults/memory/worker.ts +7 -0
  306. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  307. package/src/providers/__tests__/retry-callsite.test.ts +55 -0
  308. package/src/providers/__tests__/vellum-connection-routing.test.ts +21 -3
  309. package/src/providers/connection-resolution.ts +2 -17
  310. package/src/providers/fallback-breaker.ts +389 -0
  311. package/src/providers/inference/__tests__/adapter-factory-opencode.test.ts +92 -0
  312. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +16 -0
  313. package/src/providers/inference/__tests__/base-url-security.test.ts +12 -0
  314. package/src/providers/inference/adapter-factory.ts +246 -3
  315. package/src/providers/inference/auth.ts +15 -14
  316. package/src/providers/inference/chatgpt-subscription-auth.ts +70 -0
  317. package/src/providers/inference/chatgpt-subscription-credentials.ts +84 -0
  318. package/src/providers/inference/resolve-auth.ts +1 -1
  319. package/src/providers/media-resolve.ts +2 -3
  320. package/src/providers/model-catalog.ts +100 -0
  321. package/src/providers/openai/__tests__/api-error-normalization.test.ts +22 -0
  322. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +198 -0
  323. package/src/providers/openai/api-error-normalization.ts +13 -0
  324. package/src/providers/openai/chat-completions-provider.ts +84 -0
  325. package/src/providers/opencode/client.test.ts +150 -0
  326. package/src/providers/opencode/client.ts +61 -0
  327. package/src/providers/platform-proxy/constants.ts +5 -0
  328. package/src/providers/provider-resolvability.ts +20 -0
  329. package/src/providers/provider-secret-catalog.ts +3 -2
  330. package/src/providers/retry.ts +956 -68
  331. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +42 -0
  332. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +136 -0
  333. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +120 -0
  334. package/src/providers/speech-to-text/__tests__/resolve.test.ts +316 -12
  335. package/src/providers/speech-to-text/deepgram-flux-frames.ts +83 -3
  336. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +132 -4
  337. package/src/providers/speech-to-text/provider-catalog.ts +191 -3
  338. package/src/providers/speech-to-text/resolve.ts +132 -24
  339. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +296 -0
  340. package/src/providers/types.ts +39 -0
  341. package/src/providers/usage-tracking.ts +12 -1
  342. package/src/providers/vellum/client.ts +29 -0
  343. package/src/providers/vellum-model-routing.test.ts +2 -0
  344. package/src/providers/vellum-model-routing.ts +3 -3
  345. package/src/runtime/AGENTS.md +1 -2
  346. package/src/runtime/__tests__/agent-wake.test.ts +105 -3
  347. package/src/runtime/__tests__/background-job-runner.test.ts +89 -3
  348. package/src/runtime/agent-wake.ts +44 -5
  349. package/src/runtime/background-job-runner.ts +68 -50
  350. package/src/runtime/channel-readiness-service.ts +0 -39
  351. package/src/runtime/http-server.ts +12 -4
  352. package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +18 -18
  353. package/src/runtime/routes/__tests__/backup-routes.test.ts +9 -5
  354. package/src/runtime/routes/__tests__/chatgpt-subscription-auth-routes.test.ts +372 -0
  355. package/src/runtime/routes/__tests__/contact-routes.test.ts +7 -0
  356. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +96 -0
  357. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +37 -0
  358. package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +2 -1
  359. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +87 -0
  360. package/src/runtime/routes/acp-claude-auth-routes.ts +25 -54
  361. package/src/runtime/routes/approval-routes.ts +0 -12
  362. package/src/runtime/routes/avatar-routes.ts +17 -30
  363. package/src/runtime/routes/backup-routes.ts +2 -2
  364. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +296 -113
  365. package/src/runtime/routes/contact-prompt-routes.ts +65 -6
  366. package/src/runtime/routes/contact-routes.ts +20 -15
  367. package/src/runtime/routes/conversation-query-routes.ts +98 -10
  368. package/src/runtime/routes/conversation-routes.ts +2 -2
  369. package/src/runtime/routes/credential-routes.ts +2 -1
  370. package/src/runtime/routes/guardian-approval-interception.ts +12 -9
  371. package/src/runtime/routes/inbound-message-handler.ts +47 -48
  372. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +18 -13
  373. package/src/runtime/routes/inbound-stages/admission-policy.ts +2 -2
  374. package/src/runtime/routes/inbound-stages/edit-intercept.ts +20 -2
  375. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +9 -8
  376. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
  377. package/src/runtime/routes/index.ts +2 -0
  378. package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
  379. package/src/runtime/routes/inference-profiles-routes.ts +12 -7
  380. package/src/runtime/routes/inference-provider-connection-routes.ts +2 -2
  381. package/src/runtime/routes/inference-send-routes.ts +2 -2
  382. package/src/runtime/routes/ingress-status-routes.ts +2 -2
  383. package/src/runtime/routes/integrations/discord.ts +119 -0
  384. package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
  385. package/src/runtime/routes/mcp-auth-routes.ts +12 -6
  386. package/src/runtime/routes/migration-routes.ts +3 -1
  387. package/src/runtime/routes/oauth-pending-flows.ts +136 -0
  388. package/src/runtime/routes/secret-routes.ts +7 -0
  389. package/src/runtime/routes/stt-routes.ts +38 -6
  390. package/src/runtime/routes/wake-conversation-routes.ts +8 -1
  391. package/src/runtime/routes/watch-routes.ts +9 -5
  392. package/src/runtime/sync/resource-sync-events.ts +2 -0
  393. package/src/runtime/trust-verdict-consumer.ts +3 -3
  394. package/src/schedule/__tests__/worker-feature-flags.test.ts +58 -0
  395. package/src/schedule/retry-policy.ts +8 -8
  396. package/src/schedule/run-script.ts +14 -23
  397. package/src/schedule/schedule-recovery.ts +0 -1
  398. package/src/schedule/scheduler.ts +89 -51
  399. package/src/schedule/worker.ts +57 -0
  400. package/src/security/__tests__/openai-device-auth.test.ts +355 -0
  401. package/src/security/ces-rpc-record-backend.ts +123 -0
  402. package/src/security/oauth2.ts +7 -0
  403. package/src/security/openai-device-auth.ts +364 -0
  404. package/src/security/secure-keys.ts +15 -0
  405. package/src/skills/available-skills.ts +10 -1
  406. package/src/skills/catalog-install.ts +19 -1
  407. package/src/skills/inline-command-runner.ts +6 -2
  408. package/src/skills/platform-compatibility.test.ts +49 -0
  409. package/src/skills/platform-compatibility.ts +65 -0
  410. package/src/skills/tool-manifest.ts +20 -0
  411. package/src/stt/__tests__/roles.test.ts +152 -0
  412. package/src/stt/daemon-batch-transcriber.ts +4 -1
  413. package/src/stt/roles.ts +180 -0
  414. package/src/stt/stt-stream-session.ts +3 -2
  415. package/src/stt/types.ts +33 -3
  416. package/src/subagent/manager.ts +12 -0
  417. package/src/telemetry/__tests__/live-voice-funnel.test.ts +34 -0
  418. package/src/telemetry/live-voice-funnel.ts +12 -2
  419. package/src/telemetry/telemetry-wire.generated.ts +6 -0
  420. package/src/telemetry/tool-audit.ts +83 -30
  421. package/src/telemetry/tool-executed-events-store.test.ts +0 -1
  422. package/src/telemetry/turn-outcome.ts +75 -4
  423. package/src/tools/client-os.ts +115 -0
  424. package/src/tools/computer-use/definitions.ts +11 -7
  425. package/src/tools/computer-use/skill-proxy-bridge.ts +2 -2
  426. package/src/tools/credentials/broker-types.ts +0 -71
  427. package/src/tools/credentials/broker.ts +6 -201
  428. package/src/tools/credentials/metadata-store.ts +65 -16
  429. package/src/tools/credentials/store.ts +2 -0
  430. package/src/tools/executor.ts +2 -8
  431. package/src/tools/host-shell.test.ts +75 -0
  432. package/src/tools/host-shell.ts +24 -0
  433. package/src/tools/host-terminal/host-shell.ts +15 -44
  434. package/src/tools/mcp/mcp-tool-factory.ts +44 -9
  435. package/src/tools/permission-checker.ts +73 -21
  436. package/src/tools/policy-context.ts +1 -0
  437. package/src/tools/shared/filesystem/image-read.ts +1 -1
  438. package/src/tools/skills/find-similar-skills.ts +10 -2
  439. package/src/tools/skills/load.ts +41 -6
  440. package/src/tools/skills/sandbox-runner.ts +8 -16
  441. package/src/tools/skills/skill-tool-factory.ts +1 -0
  442. package/src/tools/terminal/__tests__/safe-env.test.ts +64 -1
  443. package/src/tools/terminal/safe-env.ts +39 -9
  444. package/src/tools/terminal/shell.ts +12 -31
  445. package/src/tools/tool-approval-handler.ts +64 -10
  446. package/src/tools/tool-types.ts +10 -0
  447. package/src/tools/types.ts +19 -3
  448. package/src/tools/ui-surface/surface-shape-docs.ts +4 -3
  449. package/src/tools/workflows/manage-workflows.ts +2 -2
  450. package/src/tools/workflows/run-workflow.test.ts +2 -1
  451. package/src/util/__tests__/file-use.test.ts +61 -0
  452. package/src/util/__tests__/process-table.test.ts +66 -0
  453. package/src/util/__tests__/process-tree.test.ts +46 -0
  454. package/src/util/errors.ts +1 -0
  455. package/src/util/file-use.ts +91 -0
  456. package/src/util/host-process.test.ts +17 -0
  457. package/src/util/host-process.ts +75 -0
  458. package/src/util/image-conversion.ts +39 -7
  459. package/src/util/platform.ts +32 -13
  460. package/src/util/process-table.ts +249 -0
  461. package/src/util/process-tree.ts +85 -129
  462. package/src/util/provider-error-patterns.ts +20 -0
  463. package/src/util/spawn.ts +9 -2
  464. package/src/watch/__tests__/watch-retro.test.ts +48 -1
  465. package/src/watch/watch-retro.ts +46 -4
  466. package/src/workspace/git-service.ts +4 -14
  467. package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +360 -0
  468. package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +117 -0
  469. package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +204 -0
  470. package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +139 -0
  471. package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +160 -0
  472. package/src/workspace/migrations/registry.ts +8 -0
  473. package/src/__tests__/permission-types.test.ts +0 -17
  474. package/src/channels/gateway-discord-admission.ts +0 -32
  475. package/src/persistence/fork-message-copy.ts +0 -239
  476. package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +0 -221
  477. package/src/security/__tests__/oauth2-device-code.test.ts +0 -431
  478. package/src/security/oauth2-device-code.ts +0 -312
@@ -0,0 +1,75 @@
1
+ import { spawn } from "node:child_process";
2
+
3
+ export {
4
+ buildShellInvocation,
5
+ pathListDelimiter,
6
+ prependUniquePathEntries,
7
+ } from "@vellumai/environments/shell";
8
+
9
+ export interface KillableProcess {
10
+ pid?: number;
11
+ kill: unknown;
12
+ }
13
+
14
+ type WindowsTreeTerminator = (pid: number, onFailure: () => void) => void;
15
+
16
+ export function terminateProcessTree(
17
+ child: KillableProcess,
18
+ hostPlatform: NodeJS.Platform = process.platform,
19
+ terminateWindowsTree: WindowsTreeTerminator = runTaskkill,
20
+ ): void {
21
+ if (child.pid == null) {
22
+ killDirectChild(child, hostPlatform);
23
+ return;
24
+ }
25
+
26
+ if (hostPlatform === "win32") {
27
+ let fellBack = false;
28
+ const fallback = () => {
29
+ if (!fellBack) {
30
+ fellBack = true;
31
+ killDirectChild(child, hostPlatform);
32
+ }
33
+ };
34
+ terminateWindowsTree(child.pid, fallback);
35
+ return;
36
+ }
37
+
38
+ try {
39
+ process.kill(-child.pid, "SIGKILL");
40
+ } catch {
41
+ killDirectChild(child, hostPlatform);
42
+ }
43
+ }
44
+
45
+ function runTaskkill(pid: number, onFailure: () => void): void {
46
+ const killer = spawn("taskkill.exe", ["/PID", String(pid), "/T", "/F"], {
47
+ stdio: "ignore",
48
+ windowsHide: true,
49
+ });
50
+ killer.once("error", onFailure);
51
+ killer.once("close", (code) => {
52
+ if (code !== 0) {
53
+ onFailure();
54
+ }
55
+ });
56
+ }
57
+
58
+ function killDirectChild(
59
+ child: KillableProcess,
60
+ hostPlatform: NodeJS.Platform,
61
+ ): void {
62
+ if (typeof child.kill !== "function") {
63
+ return;
64
+ }
65
+ try {
66
+ const kill = child.kill as (signal?: NodeJS.Signals | number) => unknown;
67
+ if (hostPlatform === "win32") {
68
+ kill.call(child);
69
+ } else {
70
+ kill.call(child, "SIGKILL");
71
+ }
72
+ } catch {
73
+ // The process may have already exited.
74
+ }
75
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * JPEG conversion for images, backed by macOS `sips`.
2
+ * JPEG conversion for images, backed by sharp with a macOS `sips` fallback.
3
3
  *
4
4
  * Two consumers share this converter:
5
5
  * - transport optimization (`agent/image-optimize.ts`) downscales large
@@ -7,10 +7,8 @@
7
7
  * - storage normalization (attachment ingress + history hydration) converts
8
8
  * HEIF/HEIC — which Chromium-based clients cannot decode — to JPEG.
9
9
  *
10
- * Conversion runs `sips` (a macOS builtin); on other platforms or on any
11
- * failure it returns null and callers keep the original bytes. Results are
12
- * cached on disk keyed by content hash + conversion options, so repeated
13
- * conversions of the same image (or daemon restarts) skip the sips call.
10
+ * Results are cached on disk keyed by content hash + conversion options, so
11
+ * repeated conversions of the same image skip the encoder call.
14
12
  */
15
13
 
16
14
  import { createHash } from "node:crypto";
@@ -291,9 +289,41 @@ async function runSips(
291
289
  }
292
290
  }
293
291
 
292
+ async function runSharp(
293
+ inputBytes: Uint8Array,
294
+ options: ConvertToJpegOptions,
295
+ ): Promise<Buffer | null> {
296
+ try {
297
+ const { default: sharp } = await import("sharp");
298
+ let pipeline = sharp(inputBytes, { failOn: "error" }).autoOrient();
299
+ if (options.resizeToPx != null) {
300
+ pipeline = pipeline.resize(
301
+ options.resizeToPx.width,
302
+ options.resizeToPx.height,
303
+ { fit: "fill" },
304
+ );
305
+ } else if (options.maxDimensionPx != null) {
306
+ pipeline = pipeline.resize(
307
+ options.maxDimensionPx,
308
+ options.maxDimensionPx,
309
+ {
310
+ fit: "inside",
311
+ withoutEnlargement: true,
312
+ },
313
+ );
314
+ }
315
+ const out = await pipeline
316
+ .jpeg({ quality: options.quality ?? DEFAULT_JPEG_QUALITY })
317
+ .toBuffer();
318
+ return isCompleteJpeg(out) ? out : null;
319
+ } catch {
320
+ return null;
321
+ }
322
+ }
323
+
294
324
  /**
295
325
  * Convert an image to JPEG, optionally downscaling. Returns null when
296
- * conversion is unavailable (non-macOS) or fails; callers keep the original.
326
+ * conversion is unavailable or fails; callers keep the original.
297
327
  */
298
328
  export async function convertImageToJpeg(
299
329
  bytes: Uint8Array,
@@ -313,7 +343,9 @@ export async function convertImageToJpeg(
313
343
  return cached;
314
344
  }
315
345
 
316
- const converted = await runSips(bytes, options);
346
+ const converted =
347
+ (await runSharp(bytes, options)) ??
348
+ (process.platform === "darwin" ? await runSips(bytes, options) : null);
317
349
  if (!converted) {
318
350
  return null;
319
351
  }
@@ -1,7 +1,12 @@
1
1
  import { chmodSync, existsSync, mkdirSync, realpathSync } from "node:fs";
2
2
  import { homedir, tmpdir } from "node:os";
3
- import { basename, dirname, join, sep } from "node:path";
3
+ import { basename, dirname, isAbsolute, join, relative, sep } from "node:path";
4
4
 
5
+ import {
6
+ AVATAR_IMAGE_FILENAME,
7
+ AVATAR_MANIFEST_FILENAME,
8
+ resolveAvatarDir,
9
+ } from "@vellumai/avatar-manifest";
5
10
  import { SEEDS } from "@vellumai/environments";
6
11
 
7
12
  import { getWorkspaceDirOverride } from "../config/env-registry.js";
@@ -160,20 +165,14 @@ export function getSoundsDir(): string {
160
165
 
161
166
  /** Returns the avatar directory ($VELLUM_WORKSPACE_DIR/data/avatar). */
162
167
  export function getAvatarDir(): string {
163
- return join(getWorkspaceDir(), "data", "avatar");
168
+ return resolveAvatarDir(getWorkspaceDir());
164
169
  }
165
170
 
166
- /** Canonical filename for the custom avatar PNG. */
167
- export const AVATAR_IMAGE_FILENAME = "avatar-image.png";
168
-
169
171
  /** Returns the canonical avatar image path ($VELLUM_WORKSPACE_DIR/data/avatar/avatar-image.png). */
170
172
  export function getAvatarImagePath(): string {
171
173
  return join(getAvatarDir(), AVATAR_IMAGE_FILENAME);
172
174
  }
173
175
 
174
- /** Canonical filename for the avatar state manifest. */
175
- export const AVATAR_MANIFEST_FILENAME = "avatar.json";
176
-
177
176
  /** Returns the canonical avatar manifest path ($VELLUM_WORKSPACE_DIR/data/avatar/avatar.json). */
178
177
  export function getAvatarManifestPath(): string {
179
178
  return join(getAvatarDir(), AVATAR_MANIFEST_FILENAME);
@@ -442,12 +441,32 @@ export function getWorkspaceDir(): string {
442
441
  * /data/.vellum/workspace → /data/.vellum/workspace
443
442
  */
444
443
  export function getWorkspaceDirDisplay(): string {
445
- const abs = getWorkspaceDir();
446
- const home = homedir();
447
- if (abs.startsWith(home + "/") || abs === home) {
448
- return "~" + abs.slice(home.length);
444
+ return formatHomeRelativePath(getWorkspaceDir(), homedir());
445
+ }
446
+
447
+ interface PathOperations {
448
+ isAbsolute(path: string): boolean;
449
+ relative(from: string, to: string): string;
450
+ sep: string;
451
+ }
452
+
453
+ export function formatHomeRelativePath(
454
+ absolutePath: string,
455
+ homePath: string,
456
+ pathOperations: PathOperations = { isAbsolute, relative, sep },
457
+ ): string {
458
+ const relativeToHome = pathOperations.relative(homePath, absolutePath);
459
+ if (relativeToHome === "") {
460
+ return "~";
461
+ }
462
+ if (
463
+ relativeToHome !== ".." &&
464
+ !relativeToHome.startsWith(`..${pathOperations.sep}`) &&
465
+ !pathOperations.isAbsolute(relativeToHome)
466
+ ) {
467
+ return `~${pathOperations.sep}${relativeToHome}`;
449
468
  }
450
- return abs;
469
+ return absolutePath;
451
470
  }
452
471
 
453
472
  /** Returns $VELLUM_WORKSPACE_DIR/config.json */
@@ -0,0 +1,249 @@
1
+ import { execFile } from "node:child_process";
2
+ import { readdirSync, readFileSync } from "node:fs";
3
+ import { promisify } from "node:util";
4
+
5
+ const execFileAsync = promisify(execFile);
6
+
7
+ const PS_PROCESS_TABLE_COMMAND = [
8
+ "ps",
9
+ "-A",
10
+ "-ww",
11
+ "-o",
12
+ "pid=,ppid=,command=",
13
+ ];
14
+ const WINDOWS_PROCESS_TABLE_COMMAND = [
15
+ "powershell.exe",
16
+ "-NoProfile",
17
+ "-NonInteractive",
18
+ "-Command",
19
+ "$OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::new(); Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,Name,WorkingSetSize,HandleCount | ConvertTo-Json -Compress",
20
+ ];
21
+
22
+ export interface ProcessTableRow {
23
+ pid: number;
24
+ ppid: number;
25
+ /** Raw command line. Callers must redact it before logging or persistence. */
26
+ command: string;
27
+ rssBytes?: number;
28
+ handleCount?: number;
29
+ }
30
+
31
+ export interface ProcessTableOptions {
32
+ platform?: NodeJS.Platform;
33
+ processTable?: readonly ProcessTableRow[] | null;
34
+ }
35
+
36
+ export function getProcessTableRows(
37
+ options: ProcessTableOptions = {},
38
+ ): readonly ProcessTableRow[] {
39
+ if (options.processTable !== undefined) {
40
+ return options.processTable ?? [];
41
+ }
42
+ return listProcessTable(options.platform);
43
+ }
44
+
45
+ interface WindowsProcessRow {
46
+ ProcessId?: unknown;
47
+ ParentProcessId?: unknown;
48
+ CommandLine?: unknown;
49
+ Name?: unknown;
50
+ WorkingSetSize?: unknown;
51
+ HandleCount?: unknown;
52
+ }
53
+
54
+ function nonNegativeNumber(value: unknown): number | null {
55
+ if (typeof value !== "number" && typeof value !== "string") {
56
+ return null;
57
+ }
58
+ const parsed = Number(value);
59
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
60
+ }
61
+
62
+ function parseProcStat(
63
+ content: string,
64
+ ): { command: string; ppid: number } | null {
65
+ const lparen = content.indexOf("(");
66
+ const rparen = content.lastIndexOf(")");
67
+ if (lparen === -1 || rparen === -1 || rparen < lparen) {
68
+ return null;
69
+ }
70
+ const ppid = Number(content.slice(rparen + 2).split(" ")[1]);
71
+ if (!Number.isInteger(ppid)) {
72
+ return null;
73
+ }
74
+ return { command: content.slice(lparen + 1, rparen), ppid };
75
+ }
76
+
77
+ function listProcessesFromProc(): ProcessTableRow[] {
78
+ const rows: ProcessTableRow[] = [];
79
+ for (const entry of readdirSync("/proc")) {
80
+ const pid = Number(entry);
81
+ if (!Number.isInteger(pid) || pid <= 0) {
82
+ continue;
83
+ }
84
+
85
+ try {
86
+ const stat = parseProcStat(readFileSync(`/proc/${pid}/stat`, "utf8"));
87
+ if (!stat) {
88
+ continue;
89
+ }
90
+ const commandLine = readFileSync(`/proc/${pid}/cmdline`, "utf8")
91
+ .split("\0")
92
+ .filter(Boolean)
93
+ .join(" ");
94
+ rows.push({
95
+ pid,
96
+ ppid: stat.ppid,
97
+ command: commandLine || stat.command,
98
+ });
99
+ } catch {
100
+ // Processes can exit between reading the directory and their files.
101
+ }
102
+ }
103
+ return rows;
104
+ }
105
+
106
+ export function parsePsProcessTable(output: string): ProcessTableRow[] {
107
+ const rows: ProcessTableRow[] = [];
108
+ for (const line of output.split("\n")) {
109
+ const match = line.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);
110
+ if (!match) {
111
+ continue;
112
+ }
113
+ rows.push({
114
+ pid: Number(match[1]),
115
+ ppid: Number(match[2]),
116
+ command: match[3].trim(),
117
+ });
118
+ }
119
+ return rows;
120
+ }
121
+
122
+ export function parseWindowsProcessTable(output: string): ProcessTableRow[] {
123
+ const decoded: unknown = JSON.parse(output.trim().replace(/^\uFEFF/, ""));
124
+ const values = Array.isArray(decoded) ? decoded : [decoded];
125
+ const rows: ProcessTableRow[] = [];
126
+ for (const value of values) {
127
+ if (!value || typeof value !== "object") {
128
+ continue;
129
+ }
130
+ const processRow = value as WindowsProcessRow;
131
+ const pid = Number(processRow.ProcessId);
132
+ const ppid = Number(processRow.ParentProcessId);
133
+ if (!Number.isInteger(pid) || pid <= 0 || !Number.isInteger(ppid)) {
134
+ continue;
135
+ }
136
+ const commandLine =
137
+ typeof processRow.CommandLine === "string" ? processRow.CommandLine : "";
138
+ const name = typeof processRow.Name === "string" ? processRow.Name : "";
139
+ const rssBytes = nonNegativeNumber(processRow.WorkingSetSize);
140
+ const handleCount = nonNegativeNumber(processRow.HandleCount);
141
+ rows.push({
142
+ pid,
143
+ ppid,
144
+ command: commandLine || name,
145
+ ...(rssBytes == null ? {} : { rssBytes }),
146
+ ...(handleCount == null ? {} : { handleCount }),
147
+ });
148
+ }
149
+ return rows;
150
+ }
151
+
152
+ function runProcessTableCommand(
153
+ command: string[],
154
+ parser: (output: string) => ProcessTableRow[],
155
+ ): ProcessTableRow[] {
156
+ const result = Bun.spawnSync({
157
+ cmd: command,
158
+ stdout: "pipe",
159
+ stderr: "ignore",
160
+ });
161
+ if (result.exitCode !== 0) {
162
+ throw new Error(
163
+ `Process enumeration failed with exit code ${result.exitCode}`,
164
+ );
165
+ }
166
+ return parser(new TextDecoder().decode(result.stdout));
167
+ }
168
+
169
+ async function runProcessTableCommandAsync(
170
+ command: string[],
171
+ parser: (output: string) => ProcessTableRow[],
172
+ ): Promise<ProcessTableRow[]> {
173
+ const { stdout } = await execFileAsync(command[0], command.slice(1), {
174
+ encoding: "utf8",
175
+ maxBuffer: 8 * 1024 * 1024,
176
+ });
177
+ return parser(stdout);
178
+ }
179
+
180
+ function listProcessesFromPs(): ProcessTableRow[] {
181
+ return runProcessTableCommand(PS_PROCESS_TABLE_COMMAND, parsePsProcessTable);
182
+ }
183
+
184
+ function listProcessesFromPowerShell(): ProcessTableRow[] {
185
+ return runProcessTableCommand(
186
+ WINDOWS_PROCESS_TABLE_COMMAND,
187
+ parseWindowsProcessTable,
188
+ );
189
+ }
190
+
191
+ export function listProcessTable(
192
+ platform: NodeJS.Platform = process.platform,
193
+ ): ProcessTableRow[] {
194
+ if (platform === "win32") {
195
+ return listProcessesFromPowerShell();
196
+ }
197
+ if (platform === "linux") {
198
+ try {
199
+ return listProcessesFromProc();
200
+ } catch {
201
+ return listProcessesFromPs();
202
+ }
203
+ }
204
+ return listProcessesFromPs();
205
+ }
206
+
207
+ export async function listProcessTableAsync(
208
+ platform: NodeJS.Platform = process.platform,
209
+ ): Promise<ProcessTableRow[]> {
210
+ if (platform === "win32") {
211
+ return runProcessTableCommandAsync(
212
+ WINDOWS_PROCESS_TABLE_COMMAND,
213
+ parseWindowsProcessTable,
214
+ );
215
+ }
216
+ if (platform === "linux") {
217
+ try {
218
+ return listProcessesFromProc();
219
+ } catch {
220
+ return runProcessTableCommandAsync(
221
+ PS_PROCESS_TABLE_COMMAND,
222
+ parsePsProcessTable,
223
+ );
224
+ }
225
+ }
226
+ return runProcessTableCommandAsync(
227
+ PS_PROCESS_TABLE_COMMAND,
228
+ parsePsProcessTable,
229
+ );
230
+ }
231
+
232
+ export function readRawProcessCommand(pid: number): string | null {
233
+ if (process.platform === "linux") {
234
+ try {
235
+ return readFileSync(`/proc/${pid}/cmdline`, "utf8")
236
+ .split("\0")
237
+ .filter(Boolean)
238
+ .join(" ");
239
+ } catch {
240
+ return null;
241
+ }
242
+ }
243
+
244
+ try {
245
+ return listProcessTable().find((row) => row.pid === pid)?.command ?? null;
246
+ } catch {
247
+ return null;
248
+ }
249
+ }