@vellumai/assistant 0.7.0 → 0.7.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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -11,10 +11,13 @@ import {
11
11
  upsertContact,
12
12
  } from "../../contacts/contact-store.js";
13
13
  import type {
14
+ AssistantContactMetadata,
14
15
  ChannelPolicy,
15
16
  ChannelStatus,
17
+ ContactChannel,
16
18
  ContactRole,
17
19
  ContactType,
20
+ ContactWithChannels,
18
21
  } from "../../contacts/types.js";
19
22
  import { getDb } from "../../memory/db-connection.js";
20
23
  import {
@@ -24,7 +27,86 @@ import {
24
27
  redeemVoiceInviteCode,
25
28
  revokeIngressInvite,
26
29
  } from "../../runtime/invite-service.js";
27
- import { writeOutput } from "../output.js";
30
+ import { shouldOutputJson, writeOutput } from "../output.js";
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Human-readable formatters
34
+ // ---------------------------------------------------------------------------
35
+
36
+ function formatChannelSummary(ch: ContactChannel): string {
37
+ const parts = [ch.type, ch.address];
38
+ if (ch.status !== "active") parts.push(`(${ch.status})`);
39
+ if (ch.policy !== "allow") parts.push(`[${ch.policy}]`);
40
+ return parts.join(" ");
41
+ }
42
+
43
+ function formatContactRow(c: ContactWithChannels): string {
44
+ const channels =
45
+ c.channels.length > 0
46
+ ? c.channels.map(formatChannelSummary).join(", ")
47
+ : "(no channels)";
48
+ return `${c.id} ${c.displayName} ${c.role}/${c.contactType} ${channels}`;
49
+ }
50
+
51
+ function formatContactDetail(
52
+ c: ContactWithChannels,
53
+ assistantMeta?: AssistantContactMetadata,
54
+ ): string {
55
+ const lines: string[] = [];
56
+ lines.push(`ID: ${c.id}`);
57
+ lines.push(`Display Name: ${c.displayName}`);
58
+ lines.push(`Role: ${c.role}`);
59
+ lines.push(`Type: ${c.contactType}`);
60
+ if (c.notes) lines.push(`Notes: ${c.notes}`);
61
+ if (c.principalId) lines.push(`Principal: ${c.principalId}`);
62
+ lines.push(`Created: ${new Date(c.createdAt).toISOString()}`);
63
+ lines.push(`Updated: ${new Date(c.updatedAt).toISOString()}`);
64
+ lines.push(`Interactions: ${c.interactionCount}`);
65
+ if (c.channels.length > 0) {
66
+ lines.push("");
67
+ lines.push("Channels:");
68
+ for (const ch of c.channels) {
69
+ const flags = [
70
+ ch.isPrimary ? "primary" : null,
71
+ ch.status !== "active" ? ch.status : null,
72
+ ch.policy !== "allow" ? ch.policy : null,
73
+ ]
74
+ .filter(Boolean)
75
+ .join(", ");
76
+ const suffix = flags ? ` (${flags})` : "";
77
+ lines.push(` ${ch.id} ${ch.type} ${ch.address}${suffix}`);
78
+ }
79
+ }
80
+ if (assistantMeta?.metadata && "assistantId" in assistantMeta.metadata) {
81
+ lines.push("");
82
+ lines.push(
83
+ `Assistant: ${assistantMeta.species} ${assistantMeta.metadata.assistantId}`,
84
+ );
85
+ }
86
+ return lines.join("\n");
87
+ }
88
+
89
+ function formatChannelDetail(ch: ContactChannel): string {
90
+ const lines: string[] = [];
91
+ lines.push(`ID: ${ch.id}`);
92
+ lines.push(`Contact: ${ch.contactId}`);
93
+ lines.push(`Type: ${ch.type}`);
94
+ lines.push(`Address: ${ch.address}`);
95
+ lines.push(`Status: ${ch.status}`);
96
+ lines.push(`Policy: ${ch.policy}`);
97
+ if (ch.isPrimary) lines.push(`Primary: yes`);
98
+ if (ch.revokedReason) lines.push(`Revoked: ${ch.revokedReason}`);
99
+ if (ch.blockedReason) lines.push(`Blocked: ${ch.blockedReason}`);
100
+ return lines.join("\n");
101
+ }
102
+
103
+ function writeError(cmd: Command, message: string): void {
104
+ if (shouldOutputJson(cmd)) {
105
+ writeOutput(cmd, { ok: false, error: message });
106
+ } else {
107
+ process.stderr.write(`Error: ${message}\n`);
108
+ }
109
+ }
28
110
 
29
111
  export function registerContactsCommand(program: Command): void {
30
112
  const contacts = program
@@ -52,7 +134,7 @@ Examples:
52
134
  contacts
53
135
  .command("list")
54
136
  .description("List contacts")
55
- .option("--role <role>", "Filter by role (default: contact)", "contact")
137
+ .option("--role <role>", "Filter by role (contact, guardian, or omit for all)")
56
138
  .option("--limit <limit>", "Maximum number of contacts to return")
57
139
  .option("--query <query>", "Search query to filter contacts")
58
140
  .option(
@@ -67,7 +149,7 @@ Examples:
67
149
  "after",
68
150
  `
69
151
  Lists contacts with optional filtering. The --role flag accepts: contact
70
- or guardian (defaults to contact). The --limit flag sets
152
+ or guardian (omit to show all). The --limit flag sets
71
153
  the maximum number of results (defaults to 50).
72
154
 
73
155
  When --query, --channel-address, or --channel-type is provided, a search
@@ -116,10 +198,19 @@ Examples:
116
198
  })
117
199
  : listContacts(effectiveLimit, role);
118
200
 
119
- writeOutput(cmd, { ok: true, contacts: results });
201
+ if (shouldOutputJson(cmd)) {
202
+ writeOutput(cmd, { ok: true, contacts: results });
203
+ } else if (results.length === 0) {
204
+ process.stdout.write("No contacts found.\n");
205
+ } else {
206
+ for (const c of results) {
207
+ process.stdout.write(formatContactRow(c) + "\n");
208
+ }
209
+ process.stdout.write(`\n${results.length} contact(s)\n`);
210
+ }
120
211
  } catch (err) {
121
212
  const message = err instanceof Error ? err.message : String(err);
122
- writeOutput(cmd, { ok: false, error: message });
213
+ writeError(cmd, message);
123
214
  process.exitCode = 1;
124
215
  }
125
216
  },
@@ -147,7 +238,7 @@ Examples:
147
238
  getDb();
148
239
  const contact = getContact(id);
149
240
  if (!contact) {
150
- writeOutput(cmd, { ok: false, error: "Contact not found" });
241
+ writeError(cmd, "Contact not found");
151
242
  process.exitCode = 1;
152
243
  return;
153
244
  }
@@ -155,14 +246,20 @@ Examples:
155
246
  contact.contactType === "assistant"
156
247
  ? getAssistantContactMetadata(contact.id)
157
248
  : undefined;
158
- writeOutput(cmd, {
159
- ok: true,
160
- contact,
161
- assistantMetadata: assistantMeta ?? undefined,
162
- });
249
+ if (shouldOutputJson(cmd)) {
250
+ writeOutput(cmd, {
251
+ ok: true,
252
+ contact,
253
+ assistantMetadata: assistantMeta ?? undefined,
254
+ });
255
+ } else {
256
+ process.stdout.write(
257
+ formatContactDetail(contact, assistantMeta ?? undefined) + "\n",
258
+ );
259
+ }
163
260
  } catch (err) {
164
261
  const message = err instanceof Error ? err.message : String(err);
165
- writeOutput(cmd, { ok: false, error: message });
262
+ writeError(cmd, message);
166
263
  process.exitCode = 1;
167
264
  }
168
265
  });
@@ -191,10 +288,18 @@ Examples:
191
288
  try {
192
289
  getDb();
193
290
  const contact = mergeContacts(keepId, mergeId);
194
- writeOutput(cmd, { ok: true, contact });
291
+ if (shouldOutputJson(cmd)) {
292
+ writeOutput(cmd, { ok: true, contact });
293
+ } else {
294
+ process.stdout.write(
295
+ `Merged ${mergeId} into ${keepId}\n` +
296
+ formatContactDetail(contact) +
297
+ "\n",
298
+ );
299
+ }
195
300
  } catch (err) {
196
301
  const message = err instanceof Error ? err.message : String(err);
197
- writeOutput(cmd, { ok: false, error: message });
302
+ writeError(cmd, message);
198
303
  process.exitCode = 1;
199
304
  }
200
305
  },
@@ -256,18 +361,15 @@ Examples:
256
361
  try {
257
362
  channels = JSON.parse(opts.channels);
258
363
  if (!Array.isArray(channels)) {
259
- writeOutput(cmd, {
260
- ok: false,
261
- error: "--channels must be a JSON array",
262
- });
364
+ writeError(cmd, "--channels must be a JSON array");
263
365
  process.exitCode = 1;
264
366
  return;
265
367
  }
266
368
  } catch {
267
- writeOutput(cmd, {
268
- ok: false,
269
- error: `Invalid JSON for --channels: ${opts.channels}`,
270
- });
369
+ writeError(
370
+ cmd,
371
+ `Invalid JSON for --channels: ${opts.channels}`,
372
+ );
271
373
  process.exitCode = 1;
272
374
  return;
273
375
  }
@@ -292,10 +394,14 @@ Examples:
292
394
  | undefined,
293
395
  });
294
396
 
295
- writeOutput(cmd, { ok: true, contact: result });
397
+ if (shouldOutputJson(cmd)) {
398
+ writeOutput(cmd, { ok: true, contact: result });
399
+ } else {
400
+ process.stdout.write(formatContactDetail(result) + "\n");
401
+ }
296
402
  } catch (err) {
297
403
  const message = err instanceof Error ? err.message : String(err);
298
- writeOutput(cmd, { ok: false, error: message });
404
+ writeError(cmd, message);
299
405
  process.exitCode = 1;
300
406
  }
301
407
  },
@@ -363,10 +469,10 @@ Examples:
363
469
  ) => {
364
470
  try {
365
471
  if (!opts.status && !opts.policy) {
366
- writeOutput(cmd, {
367
- ok: false,
368
- error: "At least one of --status or --policy must be provided",
369
- });
472
+ writeError(
473
+ cmd,
474
+ "At least one of --status or --policy must be provided",
475
+ );
370
476
  process.exitCode = 1;
371
477
  return;
372
478
  }
@@ -375,10 +481,7 @@ Examples:
375
481
 
376
482
  const existing = getChannelById(channelId);
377
483
  if (!existing) {
378
- writeOutput(cmd, {
379
- ok: false,
380
- error: `Channel not found: ${channelId}`,
381
- });
484
+ writeError(cmd, `Channel not found: ${channelId}`);
382
485
  process.exitCode = 1;
383
486
  return;
384
487
  }
@@ -406,10 +509,20 @@ Examples:
406
509
  blockedReason,
407
510
  });
408
511
 
409
- writeOutput(cmd, { ok: true, channel: result });
512
+ if (!result) {
513
+ writeError(cmd, `Failed to update channel: ${channelId}`);
514
+ process.exitCode = 1;
515
+ return;
516
+ }
517
+
518
+ if (shouldOutputJson(cmd)) {
519
+ writeOutput(cmd, { ok: true, channel: result });
520
+ } else {
521
+ process.stdout.write(formatChannelDetail(result) + "\n");
522
+ }
410
523
  } catch (err) {
411
524
  const message = err instanceof Error ? err.message : String(err);
412
- writeOutput(cmd, { ok: false, error: message });
525
+ writeError(cmd, message);
413
526
  process.exitCode = 1;
414
527
  }
415
528
  },
@@ -463,14 +576,30 @@ Examples:
463
576
  sourceChannel: opts.sourceChannel,
464
577
  status: opts.status,
465
578
  });
466
- if (result.ok) {
579
+ if (!result.ok) {
580
+ writeError(cmd, (result as { error?: string }).error ?? "Failed");
581
+ process.exitCode = 1;
582
+ return;
583
+ }
584
+ if (shouldOutputJson(cmd)) {
467
585
  writeOutput(cmd, { ok: true, invites: result.data });
586
+ } else if (result.data.length === 0) {
587
+ process.stdout.write("No invites found.\n");
468
588
  } else {
469
- writeOutput(cmd, result);
470
- }
589
+ for (const inv of result.data) {
590
+ const parts = [
591
+ inv.id,
592
+ inv.sourceChannel,
593
+ inv.status,
594
+ inv.token ? `token:${inv.token}` : "",
595
+ ].filter(Boolean);
596
+ process.stdout.write(parts.join(" ") + "\n");
597
+ }
598
+ process.stdout.write(`\n${result.data.length} invite(s)\n`);
599
+ }
471
600
  } catch (err) {
472
601
  const message = err instanceof Error ? err.message : String(err);
473
- writeOutput(cmd, { ok: false, error: message });
602
+ writeError(cmd, message);
474
603
  process.exitCode = 1;
475
604
  }
476
605
  },
@@ -539,10 +668,10 @@ Examples:
539
668
  try {
540
669
  const maxUses = opts.maxUses ? Number(opts.maxUses) : undefined;
541
670
  if (maxUses !== undefined && !Number.isFinite(maxUses)) {
542
- writeOutput(cmd, {
543
- ok: false,
544
- error: `--max-uses must be a number, got: ${opts.maxUses}`,
545
- });
671
+ writeError(
672
+ cmd,
673
+ `--max-uses must be a number, got: ${opts.maxUses}`,
674
+ );
546
675
  process.exitCode = 1;
547
676
  return;
548
677
  }
@@ -550,10 +679,10 @@ Examples:
550
679
  ? Number(opts.expiresInMs)
551
680
  : undefined;
552
681
  if (expiresInMs !== undefined && !Number.isFinite(expiresInMs)) {
553
- writeOutput(cmd, {
554
- ok: false,
555
- error: `--expires-in-ms must be a number, got: ${opts.expiresInMs}`,
556
- });
682
+ writeError(
683
+ cmd,
684
+ `--expires-in-ms must be a number, got: ${opts.expiresInMs}`,
685
+ );
557
686
  process.exitCode = 1;
558
687
  return;
559
688
  }
@@ -569,17 +698,26 @@ Examples:
569
698
  guardianName: opts.guardianName,
570
699
  contactId: opts.contactId,
571
700
  });
572
- if (result.ok) {
573
- writeOutput(cmd, { ok: true, invite: result.data });
574
- } else {
575
- writeOutput(cmd, result);
576
- }
577
701
  if (!result.ok) {
702
+ writeError(
703
+ cmd,
704
+ (result as { error?: string }).error ?? "Failed",
705
+ );
578
706
  process.exitCode = 1;
707
+ return;
579
708
  }
709
+ if (shouldOutputJson(cmd)) {
710
+ writeOutput(cmd, { ok: true, invite: result.data });
711
+ } else {
712
+ process.stdout.write(
713
+ `Created invite ${result.data.id} (${result.data.sourceChannel})\n`,
714
+ );
715
+ if (result.data.token)
716
+ process.stdout.write(`Token: ${result.data.token}\n`);
717
+ }
580
718
  } catch (err) {
581
719
  const message = err instanceof Error ? err.message : String(err);
582
- writeOutput(cmd, { ok: false, error: message });
720
+ writeError(cmd, message);
583
721
  process.exitCode = 1;
584
722
  }
585
723
  },
@@ -605,15 +743,22 @@ Examples:
605
743
  try {
606
744
  getDb();
607
745
  const result = revokeIngressInvite(inviteId);
608
- if (result.ok) {
746
+ if (!result.ok) {
747
+ writeError(
748
+ cmd,
749
+ (result as { error?: string }).error ?? "Failed",
750
+ );
751
+ process.exitCode = 1;
752
+ return;
753
+ }
754
+ if (shouldOutputJson(cmd)) {
609
755
  writeOutput(cmd, { ok: true, invite: result.data });
610
756
  } else {
611
- writeOutput(cmd, result);
757
+ process.stdout.write(`Revoked invite ${inviteId}\n`);
612
758
  }
613
- if (!result.ok) process.exitCode = 1;
614
759
  } catch (err) {
615
760
  const message = err instanceof Error ? err.message : String(err);
616
- writeOutput(cmd, { ok: false, error: message });
761
+ writeError(cmd, message);
617
762
  process.exitCode = 1;
618
763
  }
619
764
  });
@@ -666,11 +811,10 @@ Examples:
666
811
  getDb();
667
812
  if (opts.code) {
668
813
  if (!opts.callerExternalUserId) {
669
- writeOutput(cmd, {
670
- ok: false,
671
- error:
672
- "--caller-external-user-id is required for voice code redemption",
673
- });
814
+ writeError(
815
+ cmd,
816
+ "--caller-external-user-id is required for voice code redemption",
817
+ );
674
818
  process.exitCode = 1;
675
819
  return;
676
820
  }
@@ -681,16 +825,22 @@ Examples:
681
825
  ...(opts.assistantId ? { assistantId: opts.assistantId } : {}),
682
826
  });
683
827
  if (result.ok) {
684
- writeOutput(cmd, {
685
- ok: true,
686
- type: result.type,
687
- memberId: result.memberId,
688
- ...(result.type === "redeemed"
689
- ? { inviteId: result.inviteId }
690
- : {}),
691
- });
828
+ if (shouldOutputJson(cmd)) {
829
+ writeOutput(cmd, {
830
+ ok: true,
831
+ type: result.type,
832
+ memberId: result.memberId,
833
+ ...(result.type === "redeemed"
834
+ ? { inviteId: result.inviteId }
835
+ : {}),
836
+ });
837
+ } else {
838
+ process.stdout.write(
839
+ `Redeemed (${result.type}), member: ${result.memberId}\n`,
840
+ );
841
+ }
692
842
  } else {
693
- writeOutput(cmd, { ok: false, error: result.reason });
843
+ writeError(cmd, result.reason);
694
844
  process.exitCode = 1;
695
845
  }
696
846
  } else {
@@ -704,18 +854,23 @@ Examples:
704
854
  ? { externalChatId: opts.externalChatId }
705
855
  : {}),
706
856
  });
707
- if (result.ok) {
708
- writeOutput(cmd, { ok: true, invite: result.data });
709
- } else {
710
- writeOutput(cmd, result);
711
- }
712
857
  if (!result.ok) {
858
+ writeError(
859
+ cmd,
860
+ (result as { error?: string }).error ?? "Failed",
861
+ );
713
862
  process.exitCode = 1;
863
+ return;
864
+ }
865
+ if (shouldOutputJson(cmd)) {
866
+ writeOutput(cmd, { ok: true, invite: result.data });
867
+ } else {
868
+ process.stdout.write("Invite redeemed.\n");
714
869
  }
715
870
  }
716
871
  } catch (err) {
717
872
  const message = err instanceof Error ? err.message : String(err);
718
- writeOutput(cmd, { ok: false, error: message });
873
+ writeError(cmd, message);
719
874
  process.exitCode = 1;
720
875
  }
721
876
  },
@@ -1,6 +1,7 @@
1
1
  import type { Command } from "commander";
2
2
 
3
3
  import { API_KEY_PROVIDERS } from "../../config/loader.js";
4
+ import { credentialKey } from "../../security/credential-key.js";
4
5
  import { getSecureKeyAsync } from "../../security/secure-keys.js";
5
6
  import {
6
7
  deleteSecureKeyViaDaemon,
@@ -61,7 +62,9 @@ Examples:
61
62
  .action(async () => {
62
63
  const stored: string[] = [];
63
64
  for (const provider of API_KEY_PROVIDERS) {
64
- const value = await getSecureKeyAsync(provider);
65
+ const value =
66
+ (await getSecureKeyAsync(credentialKey(provider, "api_key"))) ??
67
+ (await getSecureKeyAsync(provider));
65
68
  if (value) stored.push(provider);
66
69
  }
67
70
  if (stored.length === 0) {
@@ -4,21 +4,19 @@
4
4
  * Operator-facing subcommands for the v2 memory subsystem (concept-page
5
5
  * activation model). All commands are thin wrappers over two IPC routes:
6
6
  *
7
- * - `memory_v2/backfill` — enqueues one of four mutating jobs against the
8
- * memory job queue (`migrate`, `rebuild-edges`, `reembed`,
9
- * `activation-recompute`). Returns a `jobId` so the operator can poll
10
- * status from the regular memory subsystem.
7
+ * - `memory_v2/backfill` — enqueues one of three mutating jobs against the
8
+ * memory job queue (`migrate`, `reembed`, `activation-recompute`).
9
+ * Returns a `jobId` so the operator can poll status from the regular
10
+ * memory subsystem.
11
11
  * - `memory_v2/validate` — read-only structural validation of the v2
12
- * workspace state (concept pages + `memory/edges.json`). Returns an
13
- * aggregate report of orphan edges, oversized pages, and parse failures.
12
+ * workspace state. Returns an aggregate report of orphan outgoing-edge
13
+ * targets, oversized pages, and parse failures.
14
14
  *
15
15
  * Subcommands:
16
16
  *
17
17
  * - `migrate [--force]` — one-shot v1->v2 synthesis. Refuses to run a
18
18
  * second time unless `--force` is passed (the migration handler writes a
19
19
  * sentinel after a successful first run).
20
- * - `rebuild-edges` — recompute every concept page's `edges:` frontmatter
21
- * from the canonical `memory/edges.json` index.
22
20
  * - `reembed` — fan out an `embed_concept_page` job per page slug to
23
21
  * refresh dense + sparse vectors in Qdrant.
24
22
  * - `activation` — refresh persisted activation state for every
@@ -101,17 +99,16 @@ export function registerMemoryV2Command(program: Command): void {
101
99
  "after",
102
100
  `
103
101
  The v2 subsystem replaces the v1 graph + PKB with prose concept pages,
104
- bidirectional edges in memory/edges.json, and activation-based retrieval.
105
- v2 stays gated behind the memory-v2-enabled feature flag — these subcommands
106
- remain useful operator tools regardless of whether the flag is on.
102
+ directed edges stored in each page's frontmatter, and activation-based
103
+ retrieval. v2 stays gated behind the memory-v2-enabled feature flag —
104
+ these subcommands remain useful operator tools regardless of whether
105
+ the flag is on.
107
106
 
108
107
  Subcommands fall into three groups:
109
108
 
110
109
  Mutating (return a jobId enqueued on the memory job queue):
111
110
  migrate One-shot v1->v2 synthesis. Refuses to overwrite an
112
111
  existing v2 state without --force.
113
- rebuild-edges Regenerate every concept page's edges: frontmatter from
114
- memory/edges.json.
115
112
  reembed Refresh dense + sparse vectors for every concept page.
116
113
  activation Refresh persisted activation state for every conversation.
117
114
 
@@ -119,14 +116,13 @@ Subcommands fall into three groups:
119
116
  reembed-skills Re-seed v2 skill entries from the current skill catalog.
120
117
 
121
118
  Read-only:
122
- validate Print a diagnostic report of orphan edges, oversized
123
- pages, and parse failures.
119
+ validate Print a diagnostic report of orphan outgoing-edge
120
+ targets, oversized pages, and parse failures.
124
121
 
125
122
  Examples:
126
123
  $ assistant memory v2 validate
127
124
  $ assistant memory v2 migrate
128
125
  $ assistant memory v2 migrate --force
129
- $ assistant memory v2 rebuild-edges
130
126
  $ assistant memory v2 reembed
131
127
  $ assistant memory v2 reembed-skills
132
128
  $ assistant memory v2 activation`,
@@ -143,10 +139,10 @@ Examples:
143
139
  .addHelpText(
144
140
  "after",
145
141
  `
146
- Synthesises v2 concept pages from the v1 graph + PKB and writes
147
- memory/edges.json. The migration handler stores a sentinel at
148
- memory/.v2-state/.migration-complete-v1-to-v2 after a successful run and
149
- refuses to run again unless --force is passed.
142
+ Synthesises v2 concept pages from the v1 graph + PKB, writing each page's
143
+ outgoing directed edges directly into its frontmatter. The migration handler
144
+ stores a sentinel at memory/.v2-state/.migration-complete-v1-to-v2 after a
145
+ successful run and refuses to run again unless --force is passed.
150
146
 
151
147
  The job runs on the background memory worker — this command returns once
152
148
  the job is enqueued. Track progress via 'assistant memory status' or the
@@ -160,30 +156,6 @@ Examples:
160
156
  await runBackfillOp("migrate", { force: opts.force });
161
157
  });
162
158
 
163
- // ── rebuild-edges ─────────────────────────────────────────────────────
164
-
165
- v2.command("rebuild-edges")
166
- .description(
167
- "Regenerate every concept page's edges: frontmatter from memory/edges.json",
168
- )
169
- .addHelpText(
170
- "after",
171
- `
172
- Walks every concept page and rewrites the edges: frontmatter list to match
173
- the canonical memory/edges.json index. Useful after a manual edit to
174
- edges.json or to recover from a partially-written page that drifted from
175
- the index.
176
-
177
- The job runs on the background memory worker — this command returns once
178
- the job is enqueued.
179
-
180
- Examples:
181
- $ assistant memory v2 rebuild-edges`,
182
- )
183
- .action(async () => {
184
- await runBackfillOp("rebuild-edges");
185
- });
186
-
187
159
  // ── reembed ───────────────────────────────────────────────────────────
188
160
 
189
161
  v2.command("reembed")
@@ -276,13 +248,13 @@ Examples:
276
248
  .addHelpText(
277
249
  "after",
278
250
  `
279
- Walks every concept page and the memory/edges.json index, returning an
280
- aggregate report of:
251
+ Walks every concept page and aggregates outgoing edges from each page's
252
+ frontmatter, returning a diagnostic report of:
281
253
 
282
254
  pageCount Number of concept pages successfully parsed.
283
- edgeCount Number of edges in memory/edges.json.
284
- missingEdgeEndpoints Edges whose endpoints reference a slug that no
285
- concept page exists for (orphan endpoints).
255
+ edgeCount Total number of directed outgoing edges across pages.
256
+ missingEdgeEndpoints Outgoing edges whose target slug has no
257
+ corresponding concept page (orphan targets).
286
258
  oversizedPages Pages whose body exceeds memory.v2.max_page_chars
287
259
  (a soft cap; consolidation will eventually split).
288
260
  parseFailures Pages whose YAML frontmatter or schema validation
@@ -312,13 +284,13 @@ Examples:
312
284
  log.info(`Edges: ${report.edgeCount}`);
313
285
 
314
286
  if (report.missingEdgeEndpoints.length === 0) {
315
- log.info("Missing edge endpoints: none");
287
+ log.info("Missing outgoing edge targets: none");
316
288
  } else {
317
289
  log.info(
318
- `Missing edge endpoints: ${report.missingEdgeEndpoints.length}`,
290
+ `Missing outgoing edge targets: ${report.missingEdgeEndpoints.length}`,
319
291
  );
320
292
  for (const { from, to } of report.missingEdgeEndpoints) {
321
- log.info(` ${from} <-> ${to}`);
293
+ log.info(` ${from} -> ${to}`);
322
294
  }
323
295
  }
324
296