@mycadet/assistant 0.12.7 → 0.12.9

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 (904) hide show
  1. package/README.md +1 -1
  2. package/docs/activation-funnel-telemetry.md +6 -6
  3. package/docs/cadet-doctor.md +7 -7
  4. package/docs/desktop-browser-cli.md +7 -7
  5. package/docs/skills.md +2 -2
  6. package/docs/voice-input-diagnostics.md +1 -1
  7. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +2 -2
  8. package/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
  9. package/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
  10. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/package.json +2 -2
  11. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  12. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  13. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  14. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  15. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  16. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  17. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  18. package/node_modules/@mycadet/ces-client/package.json +1 -1
  19. package/node_modules/@mycadet/ces-client/src/__tests__/ces-client.test.ts +14 -14
  20. package/node_modules/@mycadet/ces-client/src/rpc-client.ts +1 -1
  21. package/node_modules/@mycadet/credential-storage/src/oauth-runtime.ts +1 -1
  22. package/node_modules/@mycadet/credential-storage/src/static-credentials.ts +1 -1
  23. package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
  24. package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
  25. package/node_modules/@mycadet/environments/src/types.ts +6 -6
  26. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/package.json +2 -2
  27. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  28. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  29. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  30. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  31. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  32. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  33. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  34. package/node_modules/@mycadet/gateway-client/src/binding-strength-contract.ts +5 -5
  35. package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +1 -1
  36. package/node_modules/@mycadet/gateway-client/src/inbound-contract.ts +2 -2
  37. package/node_modules/@mycadet/gateway-client/src/outbound-contract.ts +1 -1
  38. package/node_modules/@mycadet/service-contracts/package.json +2 -2
  39. package/node_modules/@mycadet/service-contracts/src/{platform-credential.ts → cloud-credential.ts} +9 -9
  40. package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
  41. package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
  42. package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
  43. package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
  44. package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
  45. package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
  46. package/openapi.yaml +6804 -799
  47. package/package.json +2 -2
  48. package/scripts/build-test-fixtures.ts +1 -1
  49. package/scripts/probe-skill-retrieval.ts +1 -1
  50. package/scripts/sync-llm-catalog.ts +2 -2
  51. package/scripts/voice-ttft-spike.ts +2 -2
  52. package/src/__tests__/adaptive-thinking-repair.test.ts +4 -4
  53. package/src/__tests__/agent-loop-override-profile.test.ts +4 -4
  54. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +1 -1
  55. package/src/__tests__/anthropic-provider.test.ts +2 -2
  56. package/src/__tests__/available-skills.test.ts +11 -12
  57. package/src/__tests__/avatar-identity-sync.test.ts +1 -1
  58. package/src/__tests__/byok-default-profile-ensure.test.ts +7 -7
  59. package/src/__tests__/call-domain.test.ts +1 -1
  60. package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +2 -2
  61. package/src/__tests__/catalog-files.test.ts +10 -10
  62. package/src/__tests__/catalog-install-normalize.test.ts +3 -3
  63. package/src/__tests__/channel-availability-routes.test.ts +8 -8
  64. package/src/__tests__/channel-readiness-routes.test.ts +4 -4
  65. package/src/__tests__/channel-readiness-service.test.ts +14 -14
  66. package/src/__tests__/channel-readiness-telegram-remote.test.ts +1 -1
  67. package/src/__tests__/chat-reveal-guard-priming.test.ts +5 -6
  68. package/src/__tests__/checker.test.ts +6 -6
  69. package/src/__tests__/clawhub.test.ts +1 -1
  70. package/src/__tests__/{platform-callback-registration.test.ts → cloud-callback-registration.test.ts} +66 -90
  71. package/src/__tests__/{platform-client-verify-credential.test.ts → cloud-client-verify-credential.test.ts} +14 -14
  72. package/src/__tests__/{managed-credential-catalog-cli.test.ts → cloud-credential-catalog-cli.test.ts} +41 -41
  73. package/src/__tests__/{managed-fallback-dispatch.test.ts → cloud-fallback-dispatch.test.ts} +21 -16
  74. package/src/__tests__/{managed-profile-guard.test.ts → cloud-profile-guard.test.ts} +77 -75
  75. package/src/__tests__/{platform-proxy-context.test.ts → cloud-proxy-context.test.ts} +44 -44
  76. package/src/__tests__/{managed-speech-defaults.test.ts → cloud-speech-defaults.test.ts} +41 -41
  77. package/src/__tests__/{managed-store.test.ts → cloud-store.test.ts} +99 -99
  78. package/src/__tests__/compaction-events.test.ts +7 -5
  79. package/src/__tests__/config-loader-backfill.test.ts +65 -65
  80. package/src/__tests__/config-loader-cloud-defaults.test.ts +373 -0
  81. package/src/__tests__/config-loader-corrupt.test.ts +1 -1
  82. package/src/__tests__/config-loader-validation-reset-notice.test.ts +1 -1
  83. package/src/__tests__/config-schema.test.ts +3 -3
  84. package/src/__tests__/{config-set-platform-guard.test.ts → config-set-cloud-guard.test.ts} +6 -6
  85. package/src/__tests__/config-set-route.test.ts +12 -8
  86. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -8
  87. package/src/__tests__/config-watcher.test.ts +1 -1
  88. package/src/__tests__/contacts-write.test.ts +1 -1
  89. package/src/__tests__/conversation-agent-loop.test.ts +2 -2
  90. package/src/__tests__/conversation-app-control-instantiation.test.ts +18 -18
  91. package/src/__tests__/conversation-error.test.ts +45 -45
  92. package/src/__tests__/conversation-inference-profile-route.test.ts +4 -4
  93. package/src/__tests__/conversation-rendered-delegation-state.test.ts +4 -4
  94. package/src/__tests__/conversation-skill-tools.test.ts +7 -8
  95. package/src/__tests__/conversation-slash.test.ts +2 -2
  96. package/src/__tests__/conversation-speed-override.test.ts +8 -10
  97. package/src/__tests__/conversation-summarize-up-to.test.ts +4 -4
  98. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -1
  99. package/src/__tests__/conversation-wait-for-idle.test.ts +7 -5
  100. package/src/__tests__/credential-execution-api-key-propagation.test.ts +5 -5
  101. package/src/__tests__/{credential-execution-managed-contract.test.ts → credential-execution-cloud-contract.test.ts} +24 -24
  102. package/src/__tests__/credential-health-service.test.ts +28 -40
  103. package/src/__tests__/credential-routes.test.ts +85 -165
  104. package/src/__tests__/credential-security-invariants.test.ts +6 -7
  105. package/src/__tests__/custom-profile-ensure.test.ts +1 -1
  106. package/src/__tests__/date-context.test.ts +1 -1
  107. package/src/__tests__/default-profile-catalog-fallback.test.ts +15 -15
  108. package/src/__tests__/delete-managed-skill-tool.test.ts +8 -8
  109. package/src/__tests__/discord-callback-round-trip.test.ts +1 -1
  110. package/src/__tests__/disk-usage.test.ts +3 -3
  111. package/src/__tests__/email-invite-adapter.test.ts +5 -5
  112. package/src/__tests__/{embedding-managed-proxy-selection.test.ts → embedding-cloud-proxy-selection.test.ts} +44 -43
  113. package/src/__tests__/emit-signal-routing-intent.test.ts +13 -15
  114. package/src/__tests__/events-dev-bypass-actor.test.ts +2 -2
  115. package/src/__tests__/fallback-breaker.test.ts +7 -7
  116. package/src/__tests__/feature-flag-test-helpers.ts +106 -0
  117. package/src/__tests__/gateway-flag-listener.test.ts +1 -1
  118. package/src/__tests__/gemini-image-service.test.ts +2 -2
  119. package/src/__tests__/gemini-provider.test.ts +5 -5
  120. package/src/__tests__/get-skill-detail-audit.test.ts +134 -288
  121. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  122. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +5 -5
  123. package/src/__tests__/host-cu-routes-targeted.test.ts +8 -8
  124. package/src/__tests__/image-credentials.test.ts +13 -13
  125. package/src/__tests__/inbound-admitted-introduction-nudge.test.ts +14 -6
  126. package/src/__tests__/inbound-trust-verdict.test.ts +14 -6
  127. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +11 -11
  128. package/src/__tests__/inference-profile-session-handler.test.ts +7 -7
  129. package/src/__tests__/inference-profile-session-ipc.test.ts +5 -5
  130. package/src/__tests__/inference-profile-validation-jev.test.ts +1 -1
  131. package/src/__tests__/init-feature-flag-overrides.test.ts +40 -24
  132. package/src/__tests__/input-repairs.test.ts +1 -1
  133. package/src/__tests__/install-skill-routing.test.ts +10 -8
  134. package/src/__tests__/integration-status.test.ts +5 -5
  135. package/src/__tests__/internal-telemetry-routes.test.ts +3 -3
  136. package/src/__tests__/invite-routes-http.test.ts +1 -1
  137. package/src/__tests__/llm-catalog-parity.test.ts +5 -7
  138. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -2
  139. package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -3
  140. package/src/__tests__/llm-resolver.test.ts +1 -1
  141. package/src/__tests__/llm-schema-fallback-profile.test.ts +25 -19
  142. package/src/__tests__/llm-usage-store.test.ts +1 -1
  143. package/src/__tests__/managed-skill-lifecycle.test.ts +12 -12
  144. package/src/__tests__/mcp-abort-signal.test.ts +1 -2
  145. package/src/__tests__/mcp-client-auth.test.ts +1 -2
  146. package/src/__tests__/mcp-config-secret-boundary.test.ts +44 -40
  147. package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -2
  148. package/src/__tests__/media-generate-image.test.ts +30 -30
  149. package/src/__tests__/memory-config-file-parity.test.ts +6 -6
  150. package/src/__tests__/migration-export-to-gcs.test.ts +4 -4
  151. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  152. package/src/__tests__/mtime-cache.test.ts +2 -2
  153. package/src/__tests__/{notification-platform-adapter.test.ts → notification-cloud-adapter.test.ts} +39 -39
  154. package/src/__tests__/notification-deep-link.test.ts +40 -40
  155. package/src/__tests__/oauth-apps-routes.test.ts +3 -3
  156. package/src/__tests__/oauth-cli.test.ts +9 -9
  157. package/src/__tests__/oauth-commands-routes.test.ts +16 -16
  158. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -2
  159. package/src/__tests__/oauth-provider-serializer.test.ts +11 -11
  160. package/src/__tests__/oauth-providers-routes.test.ts +12 -12
  161. package/src/__tests__/oauth-store.test.ts +1 -1
  162. package/src/__tests__/oauth2-gateway-transport.test.ts +3 -3
  163. package/src/__tests__/onboarding-persona-write.test.ts +2 -2
  164. package/src/__tests__/openai-image-service.test.ts +2 -2
  165. package/src/__tests__/openai-responses-cutover-guard.test.ts +2 -2
  166. package/src/__tests__/openai-responses-provider.test.ts +1 -1
  167. package/src/__tests__/path-policy.test.ts +4 -4
  168. package/src/__tests__/personal-memory-auth-bypass.test.ts +1 -1
  169. package/src/__tests__/platform-bash-auto-approve.test.ts +18 -18
  170. package/src/__tests__/plugin-api-model-profiles.test.ts +1 -1
  171. package/src/__tests__/plugin-api-provider.test.ts +1 -1
  172. package/src/__tests__/plugin-api-store-credential.test.ts +4 -1
  173. package/src/__tests__/plugin-api-webhook-url.test.ts +4 -5
  174. package/src/__tests__/plugin-import-boundary-guard.test.ts +8 -39
  175. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -2
  176. package/src/__tests__/{provider-platform-proxy-integration.test.ts → provider-cloud-proxy-integration.test.ts} +70 -72
  177. package/src/__tests__/provider-commit-message-generator.test.ts +1 -1
  178. package/src/__tests__/provider-connections-backfill.test.ts +9 -9
  179. package/src/__tests__/provider-error-scenarios.test.ts +8 -8
  180. package/src/__tests__/provider-registry-ollama.test.ts +1 -1
  181. package/src/__tests__/provider-send-message-override-profile.test.ts +5 -5
  182. package/src/__tests__/registry.test.ts +3 -3
  183. package/src/__tests__/requests-mock.ts +972 -0
  184. package/src/__tests__/resolve-trust-class.test.ts +1 -1
  185. package/src/__tests__/resource-pressure-guard.test.ts +6 -6
  186. package/src/__tests__/resource-pressure-routes.test.ts +5 -5
  187. package/src/__tests__/retry-fallback-escalation.test.ts +5 -5
  188. package/src/__tests__/sanitize-config-for-transfer.test.ts +1 -1
  189. package/src/__tests__/scaffold-managed-skill-tool.test.ts +97 -97
  190. package/src/__tests__/schedule-store.test.ts +1 -1
  191. package/src/__tests__/search-skills-unified.test.ts +9 -7
  192. package/src/__tests__/{secret-routes-platform-proxy.test.ts → secret-routes-cloud-proxy.test.ts} +48 -95
  193. package/src/__tests__/secret-routes-scrub.test.ts +2 -59
  194. package/src/__tests__/secure-keys.test.ts +1 -1
  195. package/src/__tests__/skill-load-plugin-scope.test.ts +2 -2
  196. package/src/__tests__/skill-load-tool.test.ts +1 -1
  197. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -19
  198. package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
  199. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  200. package/src/__tests__/skills-file-content-endpoint.test.ts +222 -536
  201. package/src/__tests__/skills-files-catalog-fallback.test.ts +259 -577
  202. package/src/__tests__/skills.test.ts +1 -1
  203. package/src/__tests__/slim-skill-category.test.ts +11 -9
  204. package/src/__tests__/stt-stream-session.test.ts +3 -3
  205. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  206. package/src/__tests__/subagent-disposal.test.ts +5 -5
  207. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  208. package/src/__tests__/subagent-fork-spawn.test.ts +5 -5
  209. package/src/__tests__/subagent-manager-notify.test.ts +5 -5
  210. package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -2
  211. package/src/__tests__/system-prompt.test.ts +1 -1
  212. package/src/__tests__/telegram-bot-username-resolution.test.ts +34 -52
  213. package/src/__tests__/telegram-config.test.ts +16 -16
  214. package/src/__tests__/telephony-tts-guard.test.ts +13 -13
  215. package/src/__tests__/test-preload.ts +17 -7
  216. package/src/__tests__/tool-audit.test.ts +1 -1
  217. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -5
  218. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  219. package/src/__tests__/turn-events-store.test.ts +1 -1
  220. package/src/__tests__/twilio-routes.test.ts +2 -1
  221. package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
  222. package/src/__tests__/unified-turn-context-client-os.test.ts +1 -1
  223. package/src/__tests__/validate-input.test.ts +5 -5
  224. package/src/__tests__/verification-outbound-delivery.test.ts +1 -1
  225. package/src/__tests__/voice-config-update.test.ts +15 -15
  226. package/src/__tests__/voice-ingress-preflight.test.ts +4 -4
  227. package/src/__tests__/web-search.test.ts +340 -859
  228. package/src/__tests__/workspace-git-service.test.ts +1 -1
  229. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +12 -12
  230. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +1 -1
  231. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +1 -1
  232. package/src/__tests__/workspace-migration-100-upgrade-quality-profile-to-fable-5.test.ts +1 -1
  233. package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +1 -1
  234. package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +1 -1
  235. package/src/__tests__/workspace-migration-113-swap-balanced-profile-to-glm-5p2.test.ts +1 -1
  236. package/src/__tests__/workspace-migration-114-swap-quality-profile-to-opus.test.ts +1 -1
  237. package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +1 -1
  238. package/src/__tests__/workspace-migration-125-repoint-managed-connections-to-cadet.test.ts +3 -3
  239. package/src/__tests__/workspace-migration-126-strip-managed-profile-bodies.test.ts +9 -9
  240. package/src/__tests__/workspace-migration-127-backfill-default-provider.test.ts +11 -11
  241. package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +3 -3
  242. package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
  243. package/src/__tests__/workspace-migration-133-collapse-provider-connections.test.ts +3 -3
  244. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +6 -6
  245. package/src/__tests__/workspace-migration-136-repair-stale-fireworks-kimi-model-id.test.ts +1 -1
  246. package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +1 -1
  247. package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +1 -1
  248. package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +1 -1
  249. package/src/__tests__/workspace-migration-151-repair-renamed-fireworks-deepseek-pro-model-id.test.ts +1 -1
  250. package/src/__tests__/workspace-migration-152-repair-retired-fireworks-minimax-m2p7-model-id.test.ts +1 -1
  251. package/src/__tests__/workspace-migration-159-rename-colliding-jev-profile-name.test.ts +1 -1
  252. package/src/__tests__/workspace-migration-160-repair-retired-fireworks-model-ids.test.ts +1 -1
  253. package/src/__tests__/workspace-migration-161-repair-retired-fireworks-glm-5p2-model-id.test.ts +1 -1
  254. package/src/api/events/cloud-disconnected.ts +21 -0
  255. package/src/api/events/host-bash.ts +1 -1
  256. package/src/api/events/host-cu.ts +1 -1
  257. package/src/api/events/host-file.ts +1 -1
  258. package/src/api/events/notification-intent.ts +1 -1
  259. package/src/api/events/show-cloud-login.ts +18 -0
  260. package/src/api/index.ts +11 -11
  261. package/src/api/responses/home.ts +1 -1
  262. package/src/api/surfaces.ts +4 -4
  263. package/src/approvals/guardian-request-resolvers.ts +2 -2
  264. package/src/avatar/accent-backfill.ts +1 -1
  265. package/src/avatar/identity-avatar.ts +1 -1
  266. package/src/avatar/notification-avatar.test.ts +2 -2
  267. package/src/avatar/notification-avatar.ts +2 -2
  268. package/src/avatar/resvg-lazy.test.ts +1 -1
  269. package/src/avatar/resvg-lazy.ts +3 -3
  270. package/src/avatar/sync-avatar.test.ts +76 -76
  271. package/src/avatar/sync-avatar.ts +15 -15
  272. package/src/avatar/traits-png-sync.ts +1 -1
  273. package/src/background-wake/background-wake-routes.test.ts +39 -39
  274. package/src/background-wake/{platform-client.test.ts → cloud-client.test.ts} +11 -11
  275. package/src/background-wake/{platform-client.ts → cloud-client.ts} +14 -14
  276. package/src/background-wake/publisher.ts +4 -4
  277. package/src/background-wake/wake-intent-hooks.test.ts +3 -3
  278. package/src/calls/__tests__/call-controller.test.ts +2 -2
  279. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -1
  280. package/src/calls/call-domain.ts +1 -1
  281. package/src/calls/resolve-call-tts-provider.ts +6 -6
  282. package/src/calls/telephony-credential-preflight.ts +3 -3
  283. package/src/calls/telephony-tts-capability.ts +5 -6
  284. package/src/calls/tts-call-strategy.ts +1 -1
  285. package/src/calls/voice-escalation-judge.ts +1 -1
  286. package/src/calls/voice-ingress-preflight.ts +4 -4
  287. package/src/cli/bundled-modules.ts +1 -1
  288. package/src/cli/commands/__tests__/apps.test.ts +18 -53
  289. package/src/cli/commands/__tests__/plugins.test.ts +13 -13
  290. package/src/cli/commands/__tests__/tts.test.ts +1 -1
  291. package/src/cli/commands/auth.help.ts +3 -3
  292. package/src/cli/commands/auth.ts +2 -4
  293. package/src/cli/commands/browser.help.ts +2 -2
  294. package/src/cli/commands/channels/index.help.ts +2 -2
  295. package/src/cli/commands/channels/index.ts +1 -1
  296. package/src/cli/commands/channels/send.ts +1 -1
  297. package/src/cli/commands/cloud/__tests__/callback-routes-list.test.ts +2 -2
  298. package/src/cli/commands/cloud/__tests__/connect.test.ts +1 -1
  299. package/src/cli/commands/cloud/__tests__/disconnect.test.ts +3 -4
  300. package/src/cli/commands/cloud/connect.ts +2 -2
  301. package/src/cli/commands/cloud/credits-format.ts +1 -1
  302. package/src/cli/commands/cloud/index.help.ts +35 -35
  303. package/src/cli/commands/cloud/index.ts +1 -1
  304. package/src/cli/commands/config.ts +2 -2
  305. package/src/cli/commands/credentials.ts +10 -12
  306. package/src/cli/commands/domain.ts +1 -1
  307. package/src/cli/commands/email.help.ts +1 -1
  308. package/src/cli/commands/email.ts +2 -2
  309. package/src/cli/commands/gateway.help.ts +1 -1
  310. package/src/cli/commands/gateway.ts +1 -1
  311. package/src/cli/commands/image-generation.help.ts +1 -1
  312. package/src/cli/commands/inference-providers.ts +1 -1
  313. package/src/cli/commands/inference.help.ts +2 -2
  314. package/src/cli/commands/memory/index.help.ts +1 -1
  315. package/src/cli/commands/oauth/connect.test.ts +2 -2
  316. package/src/cli/commands/oauth/connect.ts +1 -1
  317. package/src/cli/commands/oauth/index.help.ts +5 -5
  318. package/src/cli/commands/oauth/providers.ts +2 -2
  319. package/src/cli/commands/oauth/shared.ts +3 -3
  320. package/src/cli/commands/plugins.help.ts +2 -3
  321. package/src/cli/commands/plugins.ts +5 -5
  322. package/src/cli/commands/roadmap.help.ts +1 -1
  323. package/src/cli/commands/telemetry.help.ts +2 -2
  324. package/src/cli/commands/telemetry.ts +2 -2
  325. package/src/cli/commands/tts.help.ts +3 -3
  326. package/src/cli/commands/webhooks.help.ts +9 -9
  327. package/src/cli/commands/webhooks.ts +1 -1
  328. package/src/cli/lib/__tests__/inspect-plugin.test.ts +8 -8
  329. package/src/cli/lib/__tests__/{install-from-platform.test.ts → install-from-cloud.test.ts} +54 -54
  330. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +18 -18
  331. package/src/cli/lib/__tests__/{plugin-catalog-platform.test.ts → plugin-catalog-cloud.test.ts} +2 -2
  332. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +1 -1
  333. package/src/cli/lib/__tests__/plugin-catalog-resolve.test.ts +9 -9
  334. package/src/cli/lib/__tests__/plugin-details.test.ts +10 -10
  335. package/src/cli/lib/__tests__/plugins-install-offline.test.ts +24 -24
  336. package/src/cli/lib/bundled-marketplace.json +1 -1
  337. package/src/cli/lib/inspect-plugin.ts +2 -2
  338. package/src/cli/lib/{install-from-platform.ts → install-from-cloud.ts} +29 -29
  339. package/src/cli/lib/install-from-github.ts +4 -4
  340. package/src/cli/lib/plugin-catalog-cache.ts +7 -7
  341. package/src/cli/lib/{plugin-catalog-platform.ts → plugin-catalog-cloud.ts} +6 -6
  342. package/src/cli/lib/plugin-catalog-local.ts +2 -2
  343. package/src/cli/lib/publish-plugin.ts +9 -10
  344. package/src/cli/lib/search-plugins.ts +2 -2
  345. package/src/{platform → cloud}/client.test.ts +85 -86
  346. package/src/{platform → cloud}/client.ts +38 -46
  347. package/src/{platform/platform-patch-queue.test.ts → cloud/cloud-patch-queue.test.ts} +6 -9
  348. package/src/{platform/platform-patch-queue.ts → cloud/cloud-patch-queue.ts} +11 -11
  349. package/src/{platform/managed-speech.test.ts → cloud/cloud-speech.test.ts} +19 -19
  350. package/src/{platform/managed-speech.ts → cloud/cloud-speech.ts} +41 -41
  351. package/src/{platform → cloud}/consent-cache.test.ts +5 -5
  352. package/src/{platform → cloud}/consent-cache.ts +8 -8
  353. package/src/cloud/feature-gate.ts +8 -0
  354. package/src/{platform → cloud}/sync-identity.test.ts +4 -4
  355. package/src/{platform → cloud}/sync-identity.ts +6 -6
  356. package/src/config/__tests__/{platform-identity.test.ts → cloud-identity.test.ts} +54 -56
  357. package/src/config/__tests__/{platform-rehydration.test.ts → cloud-rehydration.test.ts} +47 -80
  358. package/src/config/__tests__/default-profile-catalog.test.ts +12 -12
  359. package/src/config/__tests__/default-provider.test.ts +4 -4
  360. package/src/config/__tests__/deployment-context-defaults.test.ts +23 -23
  361. package/src/config/__tests__/{jev-managed-profile.test.ts → jev-cloud-profile.test.ts} +3 -5
  362. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +2 -2
  363. package/src/config/__tests__/loader-last-known-good.test.ts +6 -6
  364. package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +2 -2
  365. package/src/config/__tests__/profile-materialization.test.ts +7 -7
  366. package/src/config/__tests__/seed-default-provider.test.ts +17 -17
  367. package/src/config/__tests__/substrate-twin-shadowing.test.ts +36 -26
  368. package/src/config/__tests__/sync-gated-profiles.test.ts +20 -20
  369. package/src/config/__tests__/webhook-routing.test.ts +51 -51
  370. package/src/config/bundled-skills/computer-use/TOOLS.json +12 -12
  371. package/src/config/bundled-skills/messaging/SKILL.md +8 -8
  372. package/src/config/bundled-skills/messaging/TOOLS.json +2 -2
  373. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  374. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  375. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -2
  376. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  377. package/src/config/bundled-skills/settings/tools/shared.ts +1 -1
  378. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +12 -12
  379. package/src/config/bundled-skills/skill-management/SKILL.md +3 -3
  380. package/src/config/bundled-skills/skill-management/TOOLS.json +8 -8
  381. package/src/config/bundled-skills/skill-management/tools/{delete-managed.ts → delete-cloud.ts} +2 -2
  382. package/src/config/bundled-skills/skill-management/tools/{scaffold-managed.ts → scaffold-cloud.ts} +2 -2
  383. package/src/config/call-site-defaults.ts +6 -6
  384. package/src/config/{platform-identity.ts → cloud-identity.ts} +39 -42
  385. package/src/config/cloud-rehydration.ts +35 -0
  386. package/src/config/{managed-speech-defaults.ts → cloud-speech-defaults.ts} +13 -13
  387. package/src/config/default-profile-catalog.ts +36 -38
  388. package/src/config/default-profile-names.ts +11 -11
  389. package/src/config/default-provider-resolution.ts +2 -2
  390. package/src/config/default-provider.ts +1 -1
  391. package/src/config/env-registry.ts +21 -26
  392. package/src/config/env.ts +33 -46
  393. package/src/config/feature-flag-registry.json +5 -5
  394. package/src/config/inference-profile-validation.ts +1 -1
  395. package/src/config/llm-resolver.ts +9 -10
  396. package/src/config/loader.ts +33 -17
  397. package/src/config/profile-materialization.ts +8 -8
  398. package/src/config/profile-text-generation.test.ts +1 -1
  399. package/src/config/sanitize-for-transfer.ts +1 -1
  400. package/src/config/schema.ts +6 -6
  401. package/src/config/schemas/__tests__/stt.test.ts +2 -2
  402. package/src/config/schemas/call-site-catalog.ts +1 -1
  403. package/src/config/schemas/channels.ts +8 -0
  404. package/src/config/schemas/{platform.ts → cloud.ts} +7 -6
  405. package/src/config/schemas/host-browser.ts +1 -0
  406. package/src/config/schemas/ingress.ts +29 -10
  407. package/src/config/schemas/llm.ts +36 -36
  408. package/src/config/schemas/memory-lifecycle.ts +11 -1
  409. package/src/config/schemas/services.ts +4 -4
  410. package/src/config/schemas/stt.ts +3 -3
  411. package/src/config/schemas/tts.ts +10 -5
  412. package/src/config/schemas/voice.ts +1 -1
  413. package/src/config/seed-inference-profiles.ts +19 -19
  414. package/src/config/skill-state.ts +2 -2
  415. package/src/config/skills.ts +4 -4
  416. package/src/config/substrate-twin-shadowing.ts +12 -17
  417. package/src/config/sync-gated-profiles.ts +8 -9
  418. package/src/config/webhook-routing.ts +19 -19
  419. package/src/contacts/contacts-write.ts +1 -1
  420. package/src/credential-execution/ces-runtime.ts +6 -6
  421. package/src/credential-execution/{managed-catalog.ts → cloud-catalog.ts} +24 -24
  422. package/src/credential-execution/prompted-credential.ts +2 -23
  423. package/src/credential-health/credential-health-service.ts +59 -70
  424. package/src/daemon/__tests__/can-spawn-subagents.test.ts +1 -1
  425. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +4 -4
  426. package/src/daemon/config-watcher.ts +2 -2
  427. package/src/daemon/conversation-agent-loop.ts +9 -9
  428. package/src/daemon/conversation-error.ts +36 -36
  429. package/src/daemon/conversation-skill-tools.ts +7 -7
  430. package/src/daemon/conversation-surfaces.ts +1 -1
  431. package/src/daemon/conversation-tool-setup.ts +2 -2
  432. package/src/daemon/conversation-turn-finalize.ts +1 -1
  433. package/src/daemon/conversation-workspace.ts +1 -1
  434. package/src/daemon/conversation.ts +1 -1
  435. package/src/daemon/credential-transcript-scrub.ts +32 -35
  436. package/src/daemon/daemon-readiness.ts +1 -1
  437. package/src/daemon/event-loop-watchdog.ts +2 -2
  438. package/src/daemon/handlers/config-ingress.ts +9 -9
  439. package/src/daemon/handlers/config-telegram.ts +6 -6
  440. package/src/daemon/handlers/skills.ts +20 -20
  441. package/src/daemon/host-cu-proxy.ts +1 -1
  442. package/src/daemon/lifecycle.ts +19 -19
  443. package/src/daemon/parse-actual-tokens-from-error.ts +3 -3
  444. package/src/daemon/providers-setup.ts +6 -6
  445. package/src/daemon/resource-pressure-guard-lifecycle.ts +1 -1
  446. package/src/daemon/resource-pressure-guard.ts +6 -6
  447. package/src/daemon/shutdown-handlers.ts +1 -1
  448. package/src/daemon/sqlite-corruption-watchdog.ts +3 -3
  449. package/src/daemon/trust-context.ts +1 -1
  450. package/src/desktop/desktop-automation-lease.ts +1 -1
  451. package/src/desktop/desktop-browser-endpoint.ts +2 -4
  452. package/src/desktop/desktop-computer-use-routing.test.ts +6 -6
  453. package/src/desktop/desktop-stream-bridge.test.ts +4 -4
  454. package/src/desktop/desktop-stream-bridge.ts +1 -1
  455. package/src/desktop/{virtual-desktop-platform.test.ts → virtual-desktop-cloud.test.ts} +6 -6
  456. package/src/desktop/virtual-desktop-feature.ts +7 -7
  457. package/src/email/byo-email-credential.ts +1 -1
  458. package/src/email/registered-inbox.test.ts +16 -16
  459. package/src/email/registered-inbox.ts +20 -20
  460. package/src/heartbeat/heartbeat-service.ts +1 -1
  461. package/src/hooks/hook-loader.ts +2 -2
  462. package/src/inbound/__tests__/oauth-callback-url.test.ts +2 -2
  463. package/src/inbound/__tests__/tunnel-probe.test.ts +8 -8
  464. package/src/inbound/{platform-callback-registration.ts → cloud-callback-registration.ts} +49 -60
  465. package/src/inbound/oauth-callback-url.ts +6 -6
  466. package/src/inbound/pod-webhook-claim.ts +2 -2
  467. package/src/inbound/public-ingress-urls.ts +3 -3
  468. package/src/inbound/tunnel-probe.ts +21 -15
  469. package/src/inbound/tunnel-webhooks-gate.ts +3 -3
  470. package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -1
  471. package/src/ipc/__tests__/email-ipc.test.ts +8 -8
  472. package/src/ipc/gateway-client.test.ts +55 -59
  473. package/src/ipc/gateway-flag-listener.ts +3 -3
  474. package/src/ipc/routes/db-proxy.ts +1 -1
  475. package/src/live-voice/__tests__/live-activity-reporter.test.ts +2 -2
  476. package/src/live-voice/__tests__/{live-voice-managed-speech-fallback.test.ts → live-voice-cloud-speech-fallback.test.ts} +15 -15
  477. package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +7 -7
  478. package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
  479. package/src/live-voice/live-activity-reporter.ts +7 -7
  480. package/src/live-voice/live-voice-credential-preflight.ts +6 -6
  481. package/src/live-voice/live-voice-session.ts +3 -3
  482. package/src/live-voice/live-voice-tts.ts +1 -1
  483. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +4 -4
  484. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +1 -1
  485. package/src/mcp/mcp-oauth-provider.ts +2 -2
  486. package/src/media/gemini-image-service.ts +11 -13
  487. package/src/media/image-credentials.ts +9 -9
  488. package/src/media/openai-image-service.ts +1 -1
  489. package/src/media/types.ts +3 -3
  490. package/src/messaging/providers/channel-transport.ts +1 -1
  491. package/src/messaging/providers/discord/transport.ts +1 -1
  492. package/src/messaging/providers/gmail/adapter.ts +1 -1
  493. package/src/messaging/providers/gmail/client.ts +4 -4
  494. package/src/messaging/providers/outlook/adapter.ts +1 -1
  495. package/src/messaging/providers/slack/adapter.ts +1 -1
  496. package/src/messaging/providers/slack/transport.ts +1 -1
  497. package/src/messaging/providers/telegram-bot/transport.ts +1 -1
  498. package/src/monitoring/db-integrity-check.ts +1 -1
  499. package/src/monitoring/db-integrity-sample.ts +2 -2
  500. package/src/monitoring/mount-watch.ts +1 -1
  501. package/src/monitoring/oom-kill-reporter.ts +1 -1
  502. package/src/monitoring/worker.ts +5 -5
  503. package/src/notifications/README.md +2 -2
  504. package/src/notifications/__tests__/broadcaster.test.ts +9 -9
  505. package/src/notifications/__tests__/completion-policy.test.ts +1 -1
  506. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +4 -4
  507. package/src/notifications/activity-failed-dedupe.ts +1 -1
  508. package/src/notifications/adapters/{platform.ts → cloud.ts} +8 -8
  509. package/src/notifications/broadcaster.ts +10 -10
  510. package/src/notifications/decision-engine.ts +1 -1
  511. package/src/notifications/destination-resolver.ts +1 -1
  512. package/src/notifications/emit-signal.ts +6 -6
  513. package/src/notifications/types.ts +2 -2
  514. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  515. package/src/oauth/__tests__/{seed-providers-managed.test.ts → seed-providers-cloud.test.ts} +13 -13
  516. package/src/oauth/byo-connection.test.ts +2 -2
  517. package/src/oauth/{platform-connection.test.ts → cloud-connection.test.ts} +41 -43
  518. package/src/oauth/{platform-connection.ts → cloud-connection.ts} +19 -19
  519. package/src/oauth/connection-resolver.test.ts +59 -61
  520. package/src/oauth/connection-resolver.ts +22 -22
  521. package/src/oauth/connection.ts +1 -1
  522. package/src/oauth/oauth-store.ts +8 -8
  523. package/src/oauth/provider-serializer.ts +4 -4
  524. package/src/oauth/revoke.ts +1 -1
  525. package/src/oauth/seed-providers.ts +32 -32
  526. package/src/permissions/approval-provenance.ts +1 -1
  527. package/src/permissions/checker.test.ts +18 -16
  528. package/src/permissions/checker.ts +3 -3
  529. package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
  530. package/src/persistence/embeddings/embedding-backend.test.ts +16 -16
  531. package/src/persistence/embeddings/embedding-backend.ts +13 -13
  532. package/src/persistence/embeddings/embedding-gemini.test.ts +9 -12
  533. package/src/persistence/embeddings/embedding-gemini.ts +11 -11
  534. package/src/persistence/embeddings/embedding-runtime-manager.ts +2 -2
  535. package/src/persistence/jobs-store.ts +1 -1
  536. package/src/persistence/lifecycle-events-store.ts +1 -1
  537. package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
  538. package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
  539. package/src/persistence/migrations/224-oauth-providers-managed-service-is-paid.ts +1 -1
  540. package/src/persistence/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +1 -1
  541. package/src/persistence/migrations/296-rewrite-balanced-economy-profile-pins.ts +2 -2
  542. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +1 -1
  543. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.ts +1 -1
  544. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +1 -1
  545. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +3 -3
  546. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +7 -7
  547. package/src/persistence/migrations/__tests__/319-remove-legacy-managed-connections.test.ts +2 -2
  548. package/src/persistence/schema/oauth.ts +1 -1
  549. package/src/plugin-api/index.ts +4 -4
  550. package/src/plugin-api/model-profiles.test.ts +1 -1
  551. package/src/plugin-api/model-profiles.ts +1 -1
  552. package/src/plugin-api/transcription-session.ts +1 -1
  553. package/src/plugin-api/vision-support.test.ts +1 -1
  554. package/src/plugin-api/webhook-url.ts +12 -12
  555. package/src/plugins/__tests__/source-fingerprint.test.ts +1 -1
  556. package/src/plugins/defaults/{platform-hosted → cloud-hosted}/__tests__/reengage.test.ts +5 -6
  557. package/src/plugins/defaults/cloud-hosted/package.json +14 -0
  558. package/src/plugins/defaults/{platform-hosted → cloud-hosted}/routes/reengage.ts +3 -3
  559. package/src/plugins/defaults/index.ts +6 -6
  560. package/src/plugins/defaults/main.ts +5 -5
  561. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +5 -5
  562. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +1 -1
  563. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +1 -1
  564. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -0
  565. package/src/plugins/defaults/memory/config.ts +4 -4
  566. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +2 -2
  567. package/src/plugins/defaults/memory/memory-retrospective-job.ts +7 -7
  568. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +5 -5
  569. package/src/plugins/defaults/memory/memory-retrospective-skill-card.ts +2 -2
  570. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +1 -1
  571. package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +1 -1
  572. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +20 -20
  573. package/src/plugins/defaults/memory/substrate/__tests__/cli-command-store.test.ts +1 -1
  574. package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +3 -3
  575. package/src/plugins/defaults/memory/substrate/boot-maintenance.ts +17 -17
  576. package/src/plugins/defaults/memory/substrate/cli-command-store.ts +2 -2
  577. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +1 -1
  578. package/src/plugins/defaults/memory/substrate/skill-store.ts +4 -4
  579. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +3 -3
  580. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +2 -2
  581. package/src/plugins/defaults/memory/v3/maintain-job.ts +10 -10
  582. package/src/plugins/defaults/memory/v3/orchestrate.ts +3 -3
  583. package/src/plugins/defaults/memory/worker.ts +5 -5
  584. package/src/plugins/defaults/workspace/injectors.ts +2 -2
  585. package/src/plugins/mtime-cache.ts +1 -1
  586. package/src/plugins/source-versions.ts +1 -1
  587. package/src/plugins/types.ts +1 -1
  588. package/src/prompts/__tests__/system-prompt.test.ts +1 -1
  589. package/src/prompts/normalize-onboarding.ts +1 -1
  590. package/src/prompts/persona-resolver.ts +1 -1
  591. package/src/prompts/templates/system-sections.ts +3 -3
  592. package/src/providers/__tests__/cadet-connection-routing.test.ts +7 -7
  593. package/src/providers/__tests__/cadet-mismatch-routing.test.ts +12 -12
  594. package/src/providers/__tests__/connection-model-compat.test.ts +2 -2
  595. package/src/providers/__tests__/dispatch-connection-routing.test.ts +10 -10
  596. package/src/providers/__tests__/inference.test.ts +2 -2
  597. package/src/providers/__tests__/preflight-resolved-config.test.ts +16 -16
  598. package/src/providers/__tests__/retry-callsite.test.ts +1 -1
  599. package/src/providers/__tests__/satellite-connection-routing.test.ts +4 -4
  600. package/src/providers/__tests__/search-provider-catalog.test.ts +2 -2
  601. package/src/providers/__tests__/voice-error-copy.test.ts +3 -3
  602. package/src/providers/anthropic/client.ts +1 -1
  603. package/src/providers/cadet/client.ts +1 -1
  604. package/src/providers/cadet-model-routing.test.ts +19 -19
  605. package/src/providers/cadet-model-routing.ts +23 -23
  606. package/src/providers/call-site-routing.ts +10 -10
  607. package/src/providers/{platform-proxy → cloud-proxy}/constants.ts +11 -11
  608. package/src/providers/{platform-proxy → cloud-proxy}/context.ts +26 -26
  609. package/src/providers/connection-resolution.ts +43 -43
  610. package/src/providers/fallback-breaker.ts +2 -2
  611. package/src/providers/fetch-provider-catalog.ts +3 -3
  612. package/src/providers/gemini/client.ts +5 -5
  613. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +3 -3
  614. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +8 -8
  615. package/src/providers/inference/__tests__/base-url-security.test.ts +4 -4
  616. package/src/providers/inference/adapter-factory.ts +35 -35
  617. package/src/providers/inference/auth.ts +10 -10
  618. package/src/providers/inference/backfill.ts +11 -11
  619. package/src/providers/inference/connection-availability.ts +24 -24
  620. package/src/providers/inference/connections.ts +18 -20
  621. package/src/providers/inference/profile-probe.ts +4 -4
  622. package/src/providers/inference/resolve-auth.ts +8 -8
  623. package/src/providers/jev/ask.test.ts +1 -1
  624. package/src/providers/jev/ask.ts +2 -2
  625. package/src/providers/model-catalog.ts +8 -9
  626. package/src/providers/openai/__tests__/api-error-normalization.test.ts +3 -3
  627. package/src/providers/openai/api-error-normalization.ts +2 -2
  628. package/src/providers/provider-availability.ts +4 -4
  629. package/src/providers/provider-env-vars.ts +1 -1
  630. package/src/providers/provider-secret-catalog.ts +1 -1
  631. package/src/providers/registry.ts +20 -20
  632. package/src/providers/retry.ts +26 -26
  633. package/src/providers/routing-identity.ts +10 -10
  634. package/src/providers/search-provider-catalog.ts +2 -2
  635. package/src/providers/speech-to-text/__tests__/{cadet-managed-realtime.test.ts → cadet-cloud-realtime.test.ts} +3 -3
  636. package/src/providers/speech-to-text/__tests__/{cadet-managed.test.ts → cadet-cloud.test.ts} +35 -35
  637. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +1 -1
  638. package/src/providers/speech-to-text/__tests__/resolve.test.ts +27 -27
  639. package/src/providers/speech-to-text/{cadet-managed-flux-realtime.ts → cadet-cloud-flux-realtime.ts} +6 -8
  640. package/src/providers/speech-to-text/{cadet-managed-realtime.ts → cadet-cloud-realtime.ts} +3 -3
  641. package/src/providers/speech-to-text/{cadet-managed.ts → cadet-cloud.ts} +18 -20
  642. package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +7 -7
  643. package/src/providers/speech-to-text/deepgram-flux-frames.ts +3 -3
  644. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +4 -4
  645. package/src/providers/speech-to-text/provider-catalog.ts +3 -3
  646. package/src/providers/speech-to-text/resolve.ts +26 -28
  647. package/src/providers/together/client.ts +1 -1
  648. package/src/providers/types.ts +4 -4
  649. package/src/providers/voice-error-copy.ts +1 -1
  650. package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +10 -10
  651. package/src/runtime/agent-wake.ts +1 -1
  652. package/src/runtime/auth/__tests__/middleware.test.ts +1 -1
  653. package/src/runtime/auth/middleware.ts +1 -1
  654. package/src/runtime/auth/scopes.ts +1 -1
  655. package/src/runtime/capabilities.ts +1 -1
  656. package/src/runtime/channel-invite-transports/discord.ts +1 -1
  657. package/src/runtime/channel-invite-transports/email.ts +2 -2
  658. package/src/runtime/channel-readiness-service.ts +15 -13
  659. package/src/runtime/channel-reply-session.test.ts +1 -1
  660. package/src/runtime/channel-reply-session.ts +1 -1
  661. package/src/runtime/http-server.ts +4 -4
  662. package/src/runtime/introduction-policy.ts +4 -4
  663. package/src/runtime/migrations/__tests__/origin-mode.test.ts +14 -14
  664. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +1 -1
  665. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +2 -2
  666. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +3 -4
  667. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +6 -7
  668. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +1 -1
  669. package/src/runtime/migrations/migration-transport.ts +3 -3
  670. package/src/runtime/migrations/origin-mode.ts +6 -9
  671. package/src/runtime/migrations/vbundle-import-policy.ts +2 -2
  672. package/src/runtime/migrations/vbundle-importer.ts +4 -4
  673. package/src/runtime/migrations/vbundle-streaming-importer.ts +6 -6
  674. package/src/runtime/migrations/vbundle-validator.ts +1 -1
  675. package/src/runtime/routes/__tests__/{platform-credits-routes.test.ts → cloud-credits-routes.test.ts} +9 -9
  676. package/src/runtime/routes/__tests__/{platform-invoice-routes.test.ts → cloud-invoice-routes.test.ts} +13 -13
  677. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +1 -1
  678. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +126 -82
  679. package/src/runtime/routes/__tests__/default-plugin-routes.test.ts +5 -5
  680. package/src/runtime/routes/__tests__/default-provider-routes.test.ts +10 -10
  681. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +18 -18
  682. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +18 -16
  683. package/src/runtime/routes/__tests__/inference-send-routes.test.ts +1 -1
  684. package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +1 -1
  685. package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +5 -20
  686. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -22
  687. package/src/runtime/routes/__tests__/oauth-proxy-routes.test.ts +27 -27
  688. package/src/runtime/routes/__tests__/plugins-routes.test.ts +5 -5
  689. package/src/runtime/routes/__tests__/ps-routes.test.ts +5 -3
  690. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +15 -15
  691. package/src/runtime/routes/__tests__/webhook-routes.test.ts +31 -31
  692. package/src/runtime/routes/app-management-routes.ts +1 -1
  693. package/src/runtime/routes/attachment-routes.ts +1 -1
  694. package/src/runtime/routes/auth-routes.ts +14 -14
  695. package/src/runtime/routes/avatar-routes.ts +0 -14
  696. package/src/runtime/routes/background-wake-routes.ts +4 -4
  697. package/src/runtime/routes/channel-availability-routes.ts +4 -4
  698. package/src/runtime/routes/client-routes.ts +5 -5
  699. package/src/runtime/routes/cloud-credentials.ts +45 -0
  700. package/src/runtime/routes/{platform-routes.ts → cloud-routes.ts} +86 -119
  701. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  702. package/src/runtime/routes/conversation-query-routes.ts +345 -667
  703. package/src/runtime/routes/credential-routes.ts +28 -30
  704. package/src/runtime/routes/default-provider-routes.ts +1 -1
  705. package/src/runtime/routes/desktop-setup-routes.test.ts +5 -5
  706. package/src/runtime/routes/desktop-setup-routes.ts +1 -1
  707. package/src/runtime/routes/domain-routes.ts +15 -21
  708. package/src/runtime/routes/email-routes.ts +13 -13
  709. package/src/runtime/routes/errors.ts +1 -1
  710. package/src/runtime/routes/gateway-status-routes.ts +1 -1
  711. package/src/runtime/routes/identity-routes.ts +3 -3
  712. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  713. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +1 -1
  714. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  715. package/src/runtime/routes/index.ts +1 -1
  716. package/src/runtime/routes/inference-profile-availability-guard.ts +5 -5
  717. package/src/runtime/routes/inference-profiles-routes.ts +11 -11
  718. package/src/runtime/routes/inference-provider-connection-routes.ts +24 -24
  719. package/src/runtime/routes/ingress-status-routes.ts +1 -1
  720. package/src/runtime/routes/integrations/a2a.ts +2 -2
  721. package/src/runtime/routes/integrations/twilio.ts +21 -35
  722. package/src/runtime/routes/internal-telemetry-routes.ts +2 -2
  723. package/src/runtime/routes/live-voice-routes.test.ts +4 -4
  724. package/src/runtime/routes/live-voice-routes.ts +6 -6
  725. package/src/runtime/routes/migration-routes.ts +34 -40
  726. package/src/runtime/routes/oauth-commands-routes.ts +31 -31
  727. package/src/runtime/routes/oauth-providers.ts +5 -5
  728. package/src/runtime/routes/oauth-proxy-passthrough.test.ts +1 -1
  729. package/src/runtime/routes/oauth-proxy-passthrough.ts +8 -8
  730. package/src/runtime/routes/oauth-proxy-routes.ts +15 -17
  731. package/src/runtime/routes/oauth-request-hints.test.ts +1 -1
  732. package/src/runtime/routes/oauth-request-hints.ts +1 -1
  733. package/src/runtime/routes/plugins-routes.ts +9 -9
  734. package/src/runtime/routes/profiler-routes.ts +1 -1
  735. package/src/runtime/routes/ps-routes.ts +4 -0
  736. package/src/runtime/routes/roadmap-routes.ts +18 -20
  737. package/src/runtime/routes/secret-routes.ts +20 -61
  738. package/src/runtime/routes/settings-routes.ts +18 -23
  739. package/src/runtime/routes/telemetry-routes.ts +4 -4
  740. package/src/runtime/routes/tts-routes.ts +4 -4
  741. package/src/runtime/routes/user-route-resolution.ts +1 -1
  742. package/src/runtime/routes/webhook-routes.ts +18 -18
  743. package/src/runtime/routes/workflow-routes.ts +5 -5
  744. package/src/runtime/sync/resource-sync-events.ts +2 -2
  745. package/src/runtime/verification-outbound-actions.ts +4 -4
  746. package/src/schedule/integration-status.ts +6 -6
  747. package/src/schedule/run-script.ts +1 -1
  748. package/src/schedule/schedule-timezone.ts +1 -1
  749. package/src/schedule/worker.ts +5 -5
  750. package/src/security/auth-fallback-events-store.ts +1 -1
  751. package/src/security/oauth2.ts +4 -4
  752. package/src/skills/available-skills.ts +4 -4
  753. package/src/skills/catalog-files.ts +8 -8
  754. package/src/skills/catalog-install.ts +12 -12
  755. package/src/skills/categories-cache.ts +3 -3
  756. package/src/skills/clawhub.ts +1 -1
  757. package/src/skills/{platform-compatibility.test.ts → cloud-compatibility.test.ts} +7 -7
  758. package/src/skills/{platform-compatibility.ts → cloud-compatibility.ts} +2 -4
  759. package/src/skills/{managed-store.ts → cloud-store.ts} +21 -23
  760. package/src/skills/inline-command-runner.ts +1 -1
  761. package/src/skills/install-meta.ts +1 -1
  762. package/src/skills/path-classifier.ts +4 -4
  763. package/src/skills/skill-history.ts +4 -4
  764. package/src/skills/skillssh-registry.ts +1 -1
  765. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +1 -1
  766. package/src/stt/daemon-batch-transcriber.ts +7 -7
  767. package/src/stt/types.ts +3 -3
  768. package/src/subagent/manager.ts +15 -15
  769. package/src/subagent/types.ts +1 -1
  770. package/src/telegram/__tests__/webhook-health.test.ts +16 -16
  771. package/src/telegram/webhook-health.ts +10 -10
  772. package/src/telemetry/__tests__/config-setting-events-store.test.ts +1 -1
  773. package/src/telemetry/__tests__/outbox-test-harness.ts +2 -2
  774. package/src/telemetry/config-setting-events-store.ts +1 -1
  775. package/src/telemetry/config-setting-snapshot.ts +1 -1
  776. package/src/telemetry/memory-corpus-size.ts +1 -1
  777. package/src/telemetry/memory-tier-reporter.test.ts +2 -2
  778. package/src/telemetry/memory-tier-reporter.ts +3 -3
  779. package/src/telemetry/telemetry-event-sources.test.ts +2 -2
  780. package/src/telemetry/telemetry-event-sources.ts +9 -9
  781. package/src/telemetry/telemetry-events-outbox.ts +2 -2
  782. package/src/telemetry/telemetry-wire-validation.test.ts +1 -1
  783. package/src/telemetry/telemetry-wire-validation.ts +3 -3
  784. package/src/telemetry/telemetry-wire.generated.ts +1 -1
  785. package/src/telemetry/tool-audit.ts +1 -1
  786. package/src/telemetry/tool-executed-events-store.test.ts +1 -1
  787. package/src/telemetry/trace-collection-policy.ts +4 -4
  788. package/src/telemetry/turn-events-store.ts +1 -1
  789. package/src/telemetry/turn-outcome.ts +1 -1
  790. package/src/telemetry/turn-trace-store.ts +2 -2
  791. package/src/telemetry/types.test.ts +1 -1
  792. package/src/telemetry/types.ts +19 -19
  793. package/src/telemetry/usage-telemetry-reporter.test.ts +42 -42
  794. package/src/telemetry/usage-telemetry-reporter.ts +17 -17
  795. package/src/telemetry/watchdog-direct-emit.test.ts +9 -9
  796. package/src/telemetry/watchdog-direct-emit.ts +10 -10
  797. package/src/tools/__tests__/side-effect-abort-guard.test.ts +2 -2
  798. package/src/tools/browser/cdp-client/factory.ts +1 -1
  799. package/src/tools/computer-use/target.ts +2 -2
  800. package/src/tools/credentials/store.ts +2 -20
  801. package/src/tools/network/__tests__/{managed-search-proxy.test.ts → cloud-search-proxy.test.ts} +20 -20
  802. package/src/tools/network/__tests__/web-search.test.ts +14 -14
  803. package/src/tools/network/{managed-search-proxy.ts → cloud-search-proxy.ts} +13 -13
  804. package/src/tools/network/web-search.ts +9 -9
  805. package/src/tools/permission-checker.ts +2 -2
  806. package/src/tools/shared/input-misuse.ts +1 -1
  807. package/src/tools/shared/input-repairs.ts +4 -4
  808. package/src/tools/skills/{delete-managed.ts → delete-cloud.ts} +4 -4
  809. package/src/tools/skills/find-similar-skills.test.ts +7 -7
  810. package/src/tools/skills/find-similar-skills.ts +15 -15
  811. package/src/tools/skills/load.ts +6 -6
  812. package/src/tools/skills/{scaffold-managed.ts → scaffold-cloud.ts} +16 -16
  813. package/src/tools/skills/skill-script-runner.ts +2 -2
  814. package/src/tools/terminal/safe-env.ts +3 -3
  815. package/src/tools/tool-types.ts +2 -2
  816. package/src/tools/types.ts +2 -2
  817. package/src/tools/ui-surface/surface-shape-docs.ts +2 -2
  818. package/src/tools/workflows/manage-workflows.ts +1 -1
  819. package/src/tools/workspace-tools/loader.ts +1 -1
  820. package/src/tts/__tests__/cadet-provider.test.ts +5 -5
  821. package/src/tts/provider-catalog.ts +1 -1
  822. package/src/tts/providers/cadet-provider.ts +23 -23
  823. package/src/tts/providers/cadet-tts-socket.ts +2 -2
  824. package/src/tts/tts-config-resolver.ts +1 -1
  825. package/src/tts/tts-voice-field.ts +3 -3
  826. package/src/usage/subagent-attribution.ts +1 -1
  827. package/src/util/__tests__/process-table.test.ts +47 -0
  828. package/src/util/canonicalize-identity.ts +1 -1
  829. package/src/util/cgroup-cpu.ts +5 -5
  830. package/src/util/cgroup-memory.ts +2 -2
  831. package/src/util/container-cpu-sampler.ts +4 -4
  832. package/src/util/disk-usage.ts +4 -4
  833. package/src/util/errors.ts +3 -3
  834. package/src/util/layout.ts +479 -0
  835. package/src/util/oom-priority.ts +1 -1
  836. package/src/util/platform.ts +12 -468
  837. package/src/util/process-table.ts +39 -5
  838. package/src/util/provider-error-patterns.ts +2 -2
  839. package/src/watch/__tests__/watch-retro.test.ts +2 -2
  840. package/src/watch/watch-retro.ts +1 -1
  841. package/src/watcher/__tests__/telemetry.test.ts +2 -2
  842. package/src/watcher/telemetry.ts +1 -1
  843. package/src/windows-compiled-cli.ts +1 -1
  844. package/src/workspace/adaptive-thinking-repair.ts +4 -4
  845. package/src/workspace/byok-default-profile-ensure.ts +7 -7
  846. package/src/workspace/git-service.ts +2 -2
  847. package/src/workspace/migrations/006-services-config.ts +1 -1
  848. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +1 -1
  849. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +1 -1
  850. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +1 -1
  851. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +1 -1
  852. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +4 -4
  853. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +3 -3
  854. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +4 -4
  855. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +5 -5
  856. package/src/workspace/migrations/100-upgrade-quality-profile-to-fable-5.ts +4 -4
  857. package/src/workspace/migrations/101-upgrade-balanced-economy-to-minimax-m3.ts +4 -4
  858. package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +5 -5
  859. package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +1 -1
  860. package/src/workspace/migrations/106-drop-collect-usage-data.ts +1 -1
  861. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +4 -4
  862. package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +11 -11
  863. package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +6 -6
  864. package/src/workspace/migrations/113-swap-balanced-profile-to-glm-5p2.ts +5 -5
  865. package/src/workspace/migrations/114-swap-quality-profile-to-opus.ts +4 -4
  866. package/src/workspace/migrations/115-drop-frontier-profile.ts +5 -5
  867. package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +5 -5
  868. package/src/workspace/migrations/125-repoint-managed-connections-to-cadet.ts +3 -3
  869. package/src/workspace/migrations/126-strip-managed-profile-bodies.ts +2 -2
  870. package/src/workspace/migrations/127-backfill-default-provider.ts +6 -6
  871. package/src/workspace/migrations/130-speech-mode-to-provider.ts +4 -4
  872. package/src/workspace/migrations/131-drop-web-fetch-mode.ts +1 -1
  873. package/src/workspace/migrations/132-web-search-mode-to-provider.ts +6 -6
  874. package/src/workspace/migrations/133-collapse-provider-connections.ts +3 -3
  875. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +4 -4
  876. package/src/workspace/migrations/136-repair-stale-fireworks-kimi-model-id.ts +2 -2
  877. package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +2 -2
  878. package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +2 -2
  879. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +4 -4
  880. package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +1 -1
  881. package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +2 -2
  882. package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +2 -2
  883. package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +2 -2
  884. package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +1 -1
  885. package/src/workspace/migrations/151-repair-renamed-fireworks-deepseek-pro-model-id.ts +2 -2
  886. package/src/workspace/migrations/152-repair-retired-fireworks-minimax-m2p7-model-id.ts +2 -2
  887. package/src/workspace/migrations/159-rename-colliding-jev-profile-name.ts +2 -2
  888. package/src/workspace/migrations/160-repair-retired-fireworks-model-ids.ts +2 -2
  889. package/src/workspace/migrations/161-repair-retired-fireworks-glm-5p2-model-id.ts +2 -2
  890. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +1 -1
  891. package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +1 -1
  892. package/src/workspace/migrations/registry.ts +6 -6
  893. package/src/workspace/top-level-renderer.ts +1 -1
  894. package/src/workspace/turn-commit.ts +2 -2
  895. package/src/__tests__/config-loader-platform-defaults.test.ts +0 -606
  896. package/src/__tests__/mock-gateway-ipc.ts +0 -260
  897. package/src/api/events/platform-disconnected.ts +0 -21
  898. package/src/api/events/show-platform-login.ts +0 -20
  899. package/src/config/platform-rehydration.ts +0 -60
  900. package/src/platform/feature-gate.ts +0 -8
  901. package/src/plugins/defaults/platform-hosted/package.json +0 -14
  902. package/src/runtime/routes/platform-managed-credentials.ts +0 -50
  903. /package/src/__tests__/{gateway-client-managed-outbound.test.ts → gateway-client-cloud-outbound.test.ts} +0 -0
  904. /package/src/__tests__/{secure-keys-managed-failover.test.ts → secure-keys-cloud-failover.test.ts} +0 -0
@@ -1,12 +1,10 @@
1
1
  /**
2
- * Handler-level tests for `getSkillFileContent`.
2
+ * Handler-level tests for `getSkillFileContent` — zero-leak.
3
3
  *
4
4
  * Covers:
5
5
  * - Installed skill, valid path → returns file content (text + binary).
6
6
  * - Installed skill, traversal path → 400 "Invalid path".
7
7
  * - Installed skill, missing file → 404 "File not found".
8
- * - Installed skill with missing on-disk directory → 404 "Skill directory
9
- * missing" without consulting the provider chain fallback.
10
8
  * - Uninstalled cadet catalog skill → cadet provider returns content.
11
9
  * - Uninstalled skills.sh skill → skills.sh provider returns content.
12
10
  * - Uninstalled clawhub skill → clawhub provider returns content.
@@ -14,357 +12,150 @@
14
12
  * - Hidden / SKIP_DIRS path segments → rejected with 400 before touching
15
13
  * either the installed-skill disk read or the provider chain fallback.
16
14
  *
17
- * The test exercises the daemon handler directly — route wiring is a thin
18
- * pass-through to this function. The provider modules are mocked so the
19
- * handler's wiring is exercised in isolation.
15
+ * Zero-leak: the REAL catalog loader resolves skills seeded into the
16
+ * workspace skills dir, the REAL path sanitizer validates every path (the
17
+ * former mock carried an inline copy that could drift), and the REAL
18
+ * provider chain runs — the only fakes are the HTTP transport
19
+ * (requests-mock, restored automatically per test) and the clawhub CLI
20
+ * subprocess (a PATH-shimmed `npx` that emits canned JSON while recording
21
+ * its argv). The former ghost-install test (resolver lists a skill whose
22
+ * directory is missing) is gone: through the real loader a resolved
23
+ * skill's directory always exists at resolution time — the handler's
24
+ * `existsSync` branch is defense-in-depth for mid-request unmount races
25
+ * that a deterministic test cannot reach.
20
26
  */
21
27
 
22
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
28
+ import {
29
+ existsSync,
30
+ mkdirSync,
31
+ readFileSync,
32
+ rmSync,
33
+ writeFileSync,
34
+ } from "node:fs";
23
35
  import { tmpdir } from "node:os";
24
36
  import { join } from "node:path";
25
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
26
-
27
- import type { SkillSummary } from "../config/skills.js";
28
- import type { SlimSkillResponse } from "../daemon/message-types/skills.js";
29
- import type { SkillFileEntry } from "../skills/catalog-files.js";
30
- import type { SkillFileProvider } from "../skills/skill-file-provider.js";
31
-
32
- // ---------------------------------------------------------------------------
33
- // Mocks — must be declared before importing the module under test
34
- // ---------------------------------------------------------------------------
35
-
36
- // Suppress logger output
37
- const noopLogger = {
38
- info: () => {},
39
- warn: () => {},
40
- error: () => {},
41
- debug: () => {},
42
- trace: () => {},
43
- fatal: () => {},
44
- child: () => noopLogger,
45
- };
37
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
46
38
 
47
- // ── Mutable mock state ──────────────────────────────────────────────────────
39
+ import { setAllFlagsOnForTesting } from "./feature-flag-test-helpers.js";
40
+ import { setConfig } from "./helpers/set-config.js";
41
+ import { mockHttp } from "./requests-mock.js";
48
42
 
49
- let mockResolvedSkills: Array<{
50
- summary: SkillSummary;
51
- state: "enabled" | "disabled";
52
- }> = [];
53
-
54
- // Per-provider mock state
55
- let mockCadetProvider: SkillFileProvider;
56
- let mockSkillsshProvider: SkillFileProvider;
57
- let mockClawhubProvider: SkillFileProvider;
58
-
59
- // Track provider calls
60
- const providerReadCalls: Array<{
61
- provider: string;
62
- skillId: string;
63
- path: string;
64
- }> = [];
65
-
66
- function makeNoopProvider(name: string): SkillFileProvider {
67
- return {
68
- canHandle(): boolean {
69
- return false;
70
- },
71
- async listFiles(): Promise<SkillFileEntry[] | null> {
72
- return null;
73
- },
74
- async readFileContent(
75
- skillId: string,
76
- path: string,
77
- ): Promise<SkillFileEntry | null> {
78
- providerReadCalls.push({ provider: name, skillId, path });
79
- return null;
80
- },
81
- async toSlimSkill(): Promise<SlimSkillResponse | null> {
82
- return null;
83
- },
84
- };
85
- }
86
-
87
- mock.module("../config/skills.js", () => ({
88
- loadSkillCatalog: () => mockResolvedSkills.map((r) => r.summary),
89
- }));
90
-
91
- mock.module("../config/skill-state.js", () => ({
92
- resolveSkillStates: () => mockResolvedSkills,
93
- skillFlagKey: () => null,
94
- }));
95
-
96
- mock.module("../config/assistant-feature-flags.js", () => ({
97
- isAssistantFeatureFlagEnabled: () => true,
98
- }));
99
-
100
- mock.module("../skills/catalog-cache.js", () => ({
101
- getCatalog: async () => [],
102
- }));
103
-
104
- // The `catalog-files.js` mock — provides path validation functions inline
105
- // and delegates provider creation to mock state.
106
- const INLINE_SKIP_DIRS = new Set(["node_modules", "__pycache__", ".git"]);
107
-
108
- function inlineSanitizeRelativePath(rawPath: string): string | null {
109
- if (typeof rawPath !== "string" || rawPath.length === 0) {
110
- return null;
111
- }
112
- if (rawPath.includes("\0")) {
113
- return null;
114
- }
115
- if (rawPath.startsWith("/")) {
116
- return null;
117
- }
118
- if (/^[a-zA-Z]:[/\\]/.test(rawPath)) {
119
- return null;
120
- }
121
- let candidate = rawPath.replace(/\\/g, "/");
122
- while (candidate.startsWith("./")) {
123
- candidate = candidate.slice(2);
124
- }
125
- if (candidate.length === 0) {
126
- return null;
127
- }
128
- const segments: string[] = [];
129
- for (const seg of candidate.split("/")) {
130
- if (seg === "" || seg === ".") {
131
- continue;
132
- }
133
- if (seg === "..") {
134
- if (segments.length === 0) {
135
- return null;
136
- }
137
- segments.pop();
138
- continue;
139
- }
140
- segments.push(seg);
141
- }
142
- if (segments.length === 0) {
143
- return null;
144
- }
145
- const normalized = segments.join("/");
146
- if (normalized.startsWith("/")) {
147
- return null;
148
- }
149
- if (/^[a-zA-Z]:[/\\]/.test(normalized)) {
150
- return null;
151
- }
152
- return normalized;
153
- }
154
-
155
- function inlineHasHiddenOrSkippedSegment(sanitized: string): boolean {
156
- for (const segment of sanitized.split("/")) {
157
- if (segment.length === 0) {
158
- continue;
159
- }
160
- if (segment.startsWith(".")) {
161
- return true;
162
- }
163
- if (INLINE_SKIP_DIRS.has(segment)) {
164
- return true;
165
- }
166
- }
167
- return false;
168
- }
169
-
170
- // The provider factory functions are called once at module init and the
171
- // returned objects are captured in the `fileProviders` array. To allow
172
- // per-test mock reassignment, return proxy objects that delegate every
173
- // method call to the CURRENT value of the mutable mock variable.
174
- mock.module("../skills/catalog-files.js", () => ({
175
- SKIP_DIRS: INLINE_SKIP_DIRS,
176
- sanitizeRelativePath: inlineSanitizeRelativePath,
177
- hasHiddenOrSkippedSegment: inlineHasHiddenOrSkippedSegment,
178
- catalogSkillToSlim: () => ({}),
179
- createCadetCatalogProvider: () => ({
180
- canHandle: (id: string) => mockCadetProvider.canHandle(id),
181
- listFiles: (id: string) => mockCadetProvider.listFiles(id),
182
- readFileContent: (id: string, p: string) =>
183
- mockCadetProvider.readFileContent(id, p),
184
- toSlimSkill: (id: string) => mockCadetProvider.toSlimSkill(id),
185
- }),
186
- readCatalogSkillFiles: async () => null,
187
- readCatalogSkillFileContent: async () => null,
188
- }));
189
-
190
- mock.module("../skills/skillssh-files.js", () => ({
191
- createSkillsShProvider: () => ({
192
- canHandle: (id: string) => mockSkillsshProvider.canHandle(id),
193
- listFiles: (id: string) => mockSkillsshProvider.listFiles(id),
194
- readFileContent: (id: string, p: string) =>
195
- mockSkillsshProvider.readFileContent(id, p),
196
- toSlimSkill: (id: string) => mockSkillsshProvider.toSlimSkill(id),
197
- }),
198
- }));
199
-
200
- mock.module("../skills/clawhub-files.js", () => ({
201
- createClawhubProvider: () => ({
202
- canHandle: (id: string) => mockClawhubProvider.canHandle(id),
203
- listFiles: (id: string) => mockClawhubProvider.listFiles(id),
204
- readFileContent: (id: string, p: string) =>
205
- mockClawhubProvider.readFileContent(id, p),
206
- toSlimSkill: (id: string) => mockClawhubProvider.toSlimSkill(id),
207
- }),
208
- }));
209
-
210
- mock.module("../skills/skill-file-provider.js", () => ({}));
211
-
212
- mock.module("../skills/catalog-install.js", () => ({
213
- installSkillLocally: async () => {},
214
- getRepoSkillsDir: () => undefined,
215
- }));
216
-
217
- mock.module("../skills/catalog-search.js", () => ({
218
- filterByQuery: () => [],
219
- }));
220
-
221
- mock.module("../skills/clawhub.js", () => ({
222
- clawhubCheckUpdates: mock(async () => []),
223
- clawhubInspect: mock(async () => ({})),
224
- clawhubInstall: mock(async () => ({ success: true })),
225
- clawhubSearch: mock(async () => ({ skills: [] })),
226
- clawhubUpdate: mock(async () => ({ success: true })),
227
- }));
228
-
229
- mock.module("../skills/skillssh-registry.js", () => ({
230
- installExternalSkill: mock(async () => {}),
231
- resolveSkillSource: () => {
232
- throw new Error("not used");
233
- },
234
- searchSkillsRegistry: mock(async () => []),
235
- }));
236
-
237
- mock.module("../skills/install-meta.js", () => ({
238
- readInstallMeta: () => null,
239
- }));
240
-
241
- mock.module("../skills/managed-store.js", () => ({
242
- createManagedSkill: () => ({ created: true }),
243
- deleteManagedSkill: () => ({ deleted: true }),
244
- validateManagedSkillId: () => null,
245
- }));
246
-
247
- mock.module("../plugins/defaults/memory/graph/capability-seed.js", () => ({
248
- deleteSkillCapabilityNode: () => {},
249
- seedSkillGraphNodes: () => {},
250
- seedUninstalledCatalogSkillMemories: async () => {},
251
- }));
252
-
253
- mock.module("../providers/provider-send-message.js", () => ({
254
- createTimeout: () => ({
255
- signal: AbortSignal.timeout(1000),
256
- cleanup: () => {},
257
- }),
258
- extractText: () => "",
259
- getConfiguredProvider: async () => null,
260
- userMessage: () => ({}),
261
- }));
262
-
263
- // Real isTextMimeType — we want actual classification here.
264
- // No mock needed; let it fall through to the real implementation.
265
-
266
- let mockPlatformBaseUrl = "https://platform.test";
267
- mock.module("../config/env.js", () => ({
268
- getPlatformBaseUrl: () => mockPlatformBaseUrl,
269
- }));
270
- mock.module("../config/env.ts", () => ({
271
- getPlatformBaseUrl: () => mockPlatformBaseUrl,
272
- }));
273
-
274
- mock.module("../daemon/handlers/shared.js", () => ({
275
- CONFIG_RELOAD_DEBOUNCE_MS: 100,
276
- ensureSkillEntry: () => ({ enabled: false }),
277
- log: noopLogger,
278
- }));
279
-
280
- // ---------------------------------------------------------------------------
281
- // Imports (after mocks)
282
- // ---------------------------------------------------------------------------
43
+ // Real env: the real getCloudBaseUrl() reads config.cloud.baseUrl — point it
44
+ // at a host mockHttp matches by path substring, so the platform-facing
45
+ // provider fetches flow through the real env → URL → fetch chain.
46
+ setConfig("cloud", { baseUrl: "https://test-cloud.mycadet.ai" });
283
47
 
284
48
  import {
285
49
  _resetFileProvidersForTest,
286
50
  getSkillFileContent,
287
51
  } from "../daemon/handlers/skills.js";
52
+ import { getCatalog, invalidateCatalogCache } from "../skills/catalog-cache.js";
53
+ import { getWorkspaceSkillsDir } from "../util/layout.js";
288
54
 
289
- type FetchFn = typeof globalThis.fetch;
55
+ // ---------------------------------------------------------------------------
56
+ // clawhub CLI subprocess shim — real spawn, canned stdout
57
+ // ---------------------------------------------------------------------------
290
58
 
291
- let originalFetch: FetchFn;
59
+ // clawhub-files drives the real `clawhub` CLI through `npx`. The shim is a
60
+ // real executable earlier on PATH that records its argv and emits canned
61
+ // JSON, so the spawn → stdout-parse → content contract runs for real.
62
+ const shimDir = join(tmpdir(), "skills-content-npx-shim");
63
+ const shimRecord = join(shimDir, "calls.log");
64
+ const shimScript = [
65
+ "#!/bin/sh",
66
+ 'if [ -n "${FAKE_NPX_RECORD:-}" ]; then',
67
+ ' printf \'%s\\n\' "$*" >> "$FAKE_NPX_RECORD"',
68
+ "fi",
69
+ "printf '%s' \"${FAKE_NPX_RESPONSE:-}\"",
70
+ "exit 0",
71
+ ].join("\n");
72
+
73
+ let originalPath: string | undefined;
74
+
75
+ const clawhubCalls = (): string[] => {
76
+ if (!existsSync(shimRecord)) {
77
+ return [];
78
+ }
79
+ return readFileSync(shimRecord, "utf-8")
80
+ .split("\n")
81
+ .filter((line) => line.trim().length > 0);
82
+ };
292
83
 
293
- function installFetchForbidden(): void {
294
- globalThis.fetch = (async () => {
295
- throw new Error("fetch should not have been called");
296
- }) as unknown as FetchFn;
84
+ function installNpxShim(inspectResponse: unknown): void {
85
+ mkdirSync(shimDir, { recursive: true });
86
+ writeFileSync(join(shimDir, "npx"), shimScript, { mode: 0o755 });
87
+ process.env.FAKE_NPX_RESPONSE = JSON.stringify(inspectResponse ?? {});
88
+ process.env.FAKE_NPX_RECORD = shimRecord;
89
+ originalPath = process.env.PATH;
90
+ process.env.PATH = `${shimDir}:${process.env.PATH ?? ""}`;
297
91
  }
298
92
 
299
- const tempDirs: string[] = [];
300
-
301
- function makeTempSkillDir(skillId: string): string {
302
- const root = mkdtempSync(join(tmpdir(), "skill-file-content-test-"));
303
- tempDirs.push(root);
304
- const skillDir = join(root, skillId);
305
- mkdirSync(skillDir, { recursive: true });
306
- return skillDir;
307
- }
93
+ // ---------------------------------------------------------------------------
94
+ // Workspace skill seeding — the real loader resolves these
95
+ // ---------------------------------------------------------------------------
308
96
 
309
- function writeFile(dir: string, relPath: string, content: string | Buffer) {
310
- const abs = join(dir, relPath);
311
- mkdirSync(join(abs, ".."), { recursive: true });
312
- writeFileSync(abs, content);
97
+ const seededSkillDirs: string[] = [];
98
+
99
+ function seedWorkspaceSkill(
100
+ id: string,
101
+ files: Record<string, string | Buffer> = {},
102
+ ): string {
103
+ const dir = join(getWorkspaceSkillsDir(), id);
104
+ mkdirSync(dir, { recursive: true });
105
+ writeFileSync(
106
+ join(dir, "SKILL.md"),
107
+ `---\nname: ${id}\ndescription: seeded test skill\n---\n# ${id}\n`,
108
+ );
109
+ for (const [relPath, content] of Object.entries(files)) {
110
+ const abs = join(dir, relPath);
111
+ mkdirSync(join(abs, ".."), { recursive: true });
112
+ writeFileSync(abs, content);
113
+ }
114
+ seededSkillDirs.push(dir);
115
+ return dir;
313
116
  }
314
117
 
315
- function installedSkill(id: string, directoryPath: string) {
118
+ // A catalog listing the given skills — served for the platform catalog fetch
119
+ // that warms the real cache (`getCatalog()` mirrors the list path running
120
+ // first, exactly how production warms it before a content read).
121
+ function catalogBody(ids: string[]): { skills: unknown[] } {
316
122
  return {
317
- summary: {
123
+ skills: ids.map((id) => ({
318
124
  id,
319
125
  name: id,
320
- displayName: id,
321
- description: id,
322
- directoryPath,
323
- skillFilePath: join(directoryPath, "SKILL.md"),
324
- source: "workspace" as const,
325
- },
326
- state: "enabled" as const,
126
+ description: `${id} catalog skill`,
127
+ })),
327
128
  };
328
129
  }
329
130
 
330
- // ---------------------------------------------------------------------------
331
- // Setup / teardown
332
- // ---------------------------------------------------------------------------
333
-
334
131
  beforeEach(() => {
335
- originalFetch = globalThis.fetch;
336
- mockResolvedSkills = [];
337
- mockPlatformBaseUrl = "https://platform.test";
338
- providerReadCalls.length = 0;
339
- mockCadetProvider = makeNoopProvider("cadet");
340
- mockSkillsshProvider = makeNoopProvider("skillssh");
341
- mockClawhubProvider = makeNoopProvider("clawhub");
342
- // Force provider chain re-creation from the (mocked) factory functions
132
+ setAllFlagsOnForTesting();
133
+ invalidateCatalogCache();
343
134
  _resetFileProvidersForTest();
135
+ installNpxShim({});
344
136
  });
345
137
 
346
138
  afterEach(() => {
347
- globalThis.fetch = originalFetch;
348
- for (const dir of tempDirs) {
349
- try {
350
- rmSync(dir, { recursive: true, force: true });
351
- } catch {
352
- // best effort
353
- }
139
+ if (originalPath !== undefined) {
140
+ process.env.PATH = originalPath;
141
+ originalPath = undefined;
354
142
  }
355
- tempDirs.length = 0;
143
+ delete process.env.FAKE_NPX_RESPONSE;
144
+ delete process.env.FAKE_NPX_RECORD;
145
+ rmSync(shimDir, { recursive: true, force: true });
146
+ for (const dir of seededSkillDirs) {
147
+ rmSync(dir, { recursive: true, force: true });
148
+ }
149
+ seededSkillDirs.length = 0;
356
150
  });
357
151
 
358
152
  // ---------------------------------------------------------------------------
359
- // Installed-skill path
153
+ // Installed-skill path (real loader → real disk reads)
360
154
  // ---------------------------------------------------------------------------
361
155
 
362
156
  describe("getSkillFileContent — installed skill", () => {
363
157
  test("returns text file content for a valid path", async () => {
364
- const skillDir = makeTempSkillDir("my-skill");
365
- writeFile(skillDir, "SKILL.md", "# hello world\n");
366
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
367
- installFetchForbidden();
158
+ seedWorkspaceSkill("my-skill");
368
159
 
369
160
  const result = await getSkillFileContent("my-skill", "SKILL.md");
370
161
  expect("error" in result).toBe(false);
@@ -373,20 +164,14 @@ describe("getSkillFileContent — installed skill", () => {
373
164
  }
374
165
  expect(result.path).toBe("SKILL.md");
375
166
  expect(result.name).toBe("SKILL.md");
376
- expect(result.size).toBe("# hello world\n".length);
377
167
  expect(result.isBinary).toBe(false);
378
- expect(result.content).toBe("# hello world\n");
168
+ expect(result.content).toContain("# my-skill");
379
169
  });
380
170
 
381
171
  test("returns content=null for binary files", async () => {
382
- const skillDir = makeTempSkillDir("my-skill");
383
- writeFile(
384
- skillDir,
385
- "img.png",
386
- Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
387
- );
388
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
389
- installFetchForbidden();
172
+ seedWorkspaceSkill("my-skill", {
173
+ "img.png": Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
174
+ });
390
175
 
391
176
  const result = await getSkillFileContent("my-skill", "img.png");
392
177
  expect("error" in result).toBe(false);
@@ -399,10 +184,7 @@ describe("getSkillFileContent — installed skill", () => {
399
184
  });
400
185
 
401
186
  test("rejects traversal paths with 400 Invalid path", async () => {
402
- const skillDir = makeTempSkillDir("my-skill");
403
- writeFile(skillDir, "SKILL.md", "ok");
404
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
405
- installFetchForbidden();
187
+ seedWorkspaceSkill("my-skill");
406
188
 
407
189
  for (const bad of ["../secrets", "..", "/etc/passwd", "./../escape"]) {
408
190
  const result = await getSkillFileContent("my-skill", bad);
@@ -416,10 +198,7 @@ describe("getSkillFileContent — installed skill", () => {
416
198
  });
417
199
 
418
200
  test("rejects paths containing null bytes with 400", async () => {
419
- const skillDir = makeTempSkillDir("my-skill");
420
- writeFile(skillDir, "SKILL.md", "ok");
421
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
422
- installFetchForbidden();
201
+ seedWorkspaceSkill("my-skill");
423
202
 
424
203
  const result = await getSkillFileContent("my-skill", "SKILL.md\0.png");
425
204
  expect("error" in result).toBe(true);
@@ -430,10 +209,7 @@ describe("getSkillFileContent — installed skill", () => {
430
209
  });
431
210
 
432
211
  test("returns 404 for a missing file inside an installed skill", async () => {
433
- const skillDir = makeTempSkillDir("my-skill");
434
- writeFile(skillDir, "SKILL.md", "ok");
435
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
436
- installFetchForbidden();
212
+ seedWorkspaceSkill("my-skill");
437
213
 
438
214
  const result = await getSkillFileContent("my-skill", "ghost.txt");
439
215
  expect("error" in result).toBe(true);
@@ -446,27 +222,31 @@ describe("getSkillFileContent — installed skill", () => {
446
222
  });
447
223
 
448
224
  // ---------------------------------------------------------------------------
449
- // Provider chain fallback — uninstalled skill content
225
+ // Provider chain fallback — uninstalled skill content (real providers over
226
+ // the mocked HTTP transport)
450
227
  // ---------------------------------------------------------------------------
451
228
 
452
229
  describe("getSkillFileContent — uninstalled skill (provider chain)", () => {
453
- test("delegates to cadet provider and returns the payload", async () => {
454
- mockResolvedSkills = [];
455
- installFetchForbidden();
456
-
457
- mockCadetProvider = {
458
- canHandle: () => true,
459
- listFiles: async () => null,
460
- readFileContent: async (_skillId, path) => ({
461
- path,
230
+ test("cadet provider returns the platform content payload", async () => {
231
+ const http = mockHttp();
232
+ http.on("GET", "/v1/skills/", {
233
+ status: 200,
234
+ body: catalogBody(["remote-skill"]),
235
+ });
236
+ http.on("GET", "/v1/skills/remote-skill/files/content/", {
237
+ status: 200,
238
+ body: {
239
+ path: "SKILL.md",
462
240
  name: "SKILL.md",
463
241
  size: 14,
464
- mimeType: "text/markdown",
465
- isBinary: false,
242
+ mime_type: "text/markdown",
243
+ is_binary: false,
466
244
  content: "# hello world\n",
467
- }),
468
- toSlimSkill: async () => null,
469
- };
245
+ },
246
+ });
247
+ // Warm the real catalog cache the same way production does: the list
248
+ // path runs before the content read.
249
+ await getCatalog();
470
250
 
471
251
  const result = await getSkillFileContent("remote-skill", "SKILL.md");
472
252
  expect("error" in result).toBe(false);
@@ -475,80 +255,77 @@ describe("getSkillFileContent — uninstalled skill (provider chain)", () => {
475
255
  }
476
256
  expect(result.path).toBe("SKILL.md");
477
257
  expect(result.name).toBe("SKILL.md");
478
- expect(result.size).toBe(14);
479
258
  expect(result.mimeType).toBe("text/markdown");
480
259
  expect(result.isBinary).toBe(false);
481
260
  expect(result.content).toBe("# hello world\n");
261
+ // The content fetch carried the sanitized path as its query.
262
+ expect(http.lastCall("GET")?.url).toContain(
263
+ "/v1/skills/remote-skill/files/content/?path=SKILL.md",
264
+ );
482
265
  });
483
266
 
484
- test("returns 404 when all providers return null", async () => {
485
- mockResolvedSkills = [];
486
- installFetchForbidden();
487
-
488
- // All providers return canHandle=false (default noop)
489
-
267
+ test("returns 404 when the clawhub CLI yields no content for a claimed slug", async () => {
268
+ // The real clawhub canHandle claims every valid slug; with an empty
269
+ // inspect payload the claimed read yields "File not found" (claimed but
270
+ // file absent), not "Skill not found".
490
271
  const result = await getSkillFileContent("ghost-skill", "SKILL.md");
491
272
  expect("error" in result).toBe(true);
492
273
  if (!("error" in result)) {
493
274
  return;
494
275
  }
495
276
  expect(result.status).toBe(404);
496
- expect(result.error).toBe("Skill not found");
277
+ expect(result.error).toBe("File not found");
497
278
  });
498
279
 
499
- test("skills.sh content fallback", async () => {
500
- mockResolvedSkills = [];
501
- installFetchForbidden();
502
-
503
- // Cadet doesn't handle
504
- mockCadetProvider = makeNoopProvider("cadet");
505
-
506
- // skills.sh handles and returns content
507
- mockSkillsshProvider = {
508
- canHandle: (id: string) => id.split("/").length >= 3,
509
- listFiles: async () => null,
510
- readFileContent: async (_skillId, path) => ({
511
- path,
512
- name: "SKILL.md",
513
- size: 20,
514
- mimeType: "text/markdown",
515
- isBinary: false,
516
- content: "# skillssh content\n",
517
- }),
518
- toSlimSkill: async () => null,
519
- };
520
-
521
- const result = await getSkillFileContent("owner/repo/my-skill", "SKILL.md");
280
+ test("skills.sh content fallback walks the GitHub API chain", async () => {
281
+ const http = mockHttp();
282
+ // 1. Dir probe (registered first — the entry URL contains this path).
283
+ http.on(
284
+ "GET",
285
+ "/repos/skillssh-owner/skillssh-repo/contents/skills/my-skill",
286
+ {
287
+ status: 200,
288
+ body: [],
289
+ },
290
+ );
291
+ // 2. Contents entry for the requested file (registered second — newest
292
+ // match wins, and this URL embeds the probe path).
293
+ http.on(
294
+ "GET",
295
+ "/repos/skillssh-owner/skillssh-repo/contents/skills/my-skill/SKILL.md",
296
+ {
297
+ status: 200,
298
+ body: {
299
+ type: "file",
300
+ size: 20,
301
+ download_url:
302
+ "https://raw.githubusercontent.test/skillssh-owner/skillssh-repo/HEAD/skills/my-skill/SKILL.md",
303
+ },
304
+ },
305
+ );
306
+ // 3. Raw content fetch (string body passes through verbatim).
307
+ http.on("GET", "raw.githubusercontent.test", {
308
+ status: 200,
309
+ body: "# skillssh content\n",
310
+ });
311
+
312
+ const result = await getSkillFileContent(
313
+ "skillssh-owner/skillssh-repo/my-skill",
314
+ "SKILL.md",
315
+ );
522
316
  expect("error" in result).toBe(false);
523
317
  if ("error" in result) {
524
318
  return;
525
319
  }
526
320
  expect(result.content).toBe("# skillssh content\n");
527
321
  expect(result.path).toBe("SKILL.md");
322
+ expect(result.isBinary).toBe(false);
528
323
  });
529
324
 
530
- test("clawhub content fallback", async () => {
531
- mockResolvedSkills = [];
532
- installFetchForbidden();
533
-
534
- // Cadet and skills.sh don't handle
535
- mockCadetProvider = makeNoopProvider("cadet");
536
- mockSkillsshProvider = makeNoopProvider("skillssh");
537
-
538
- // Clawhub handles and returns content
539
- mockClawhubProvider = {
540
- canHandle: () => true,
541
- listFiles: async () => null,
542
- readFileContent: async (_skillId, path) => ({
543
- path,
544
- name: "SKILL.md",
545
- size: 22,
546
- mimeType: "text/markdown",
547
- isBinary: false,
548
- content: "# clawhub content yo\n",
549
- }),
550
- toSlimSkill: async () => null,
551
- };
325
+ test("clawhub content fallback parses the CLI subprocess output", async () => {
326
+ // Re-install the shim with a canned inspect payload: the real
327
+ // clawhub-files code spawns it, parses stdout, and returns the content.
328
+ installNpxShim({ skillMdContent: "# clawhub content yo\n" });
552
329
 
553
330
  const result = await getSkillFileContent("cool-tool", "SKILL.md");
554
331
  expect("error" in result).toBe(false);
@@ -557,19 +334,20 @@ describe("getSkillFileContent — uninstalled skill (provider chain)", () => {
557
334
  }
558
335
  expect(result.content).toBe("# clawhub content yo\n");
559
336
  expect(result.path).toBe("SKILL.md");
337
+ // The real CLI argv reached the shim.
338
+ expect(clawhubCalls().some((argv) => argv.includes("inspect"))).toBe(true);
560
339
  });
561
340
 
562
- test("returns 'File not found' when provider canHandle returns true but readFileContent returns null", async () => {
563
- mockResolvedSkills = [];
564
- installFetchForbidden();
565
-
566
- // Cadet provider claims this skill but returns null for the specific file
567
- mockCadetProvider = {
568
- canHandle: () => true,
569
- listFiles: async () => null,
570
- readFileContent: async () => null,
571
- toSlimSkill: async () => null,
572
- };
341
+ test("returns 'File not found' when the cadet provider claims the skill but the file is missing", async () => {
342
+ const http = mockHttp();
343
+ http.on("GET", "/v1/skills/", {
344
+ status: 200,
345
+ body: catalogBody(["known-skill"]),
346
+ });
347
+ http.on("GET", "/v1/skills/known-skill/files/content/", {
348
+ status: 404,
349
+ });
350
+ await getCatalog();
573
351
 
574
352
  const result = await getSkillFileContent("known-skill", "nonexistent.txt");
575
353
  expect("error" in result).toBe(true);
@@ -580,47 +358,25 @@ describe("getSkillFileContent — uninstalled skill (provider chain)", () => {
580
358
  expect(result.error).toBe("File not found");
581
359
  });
582
360
 
583
- test("stop-on-first-match: does not try clawhub when cadet canHandle returns true", async () => {
584
- mockResolvedSkills = [];
585
- installFetchForbidden();
586
-
587
- const clawhubReadCalls: string[] = [];
588
-
589
- // Cadet provider claims the skill but returns null for file content
590
- mockCadetProvider = {
591
- canHandle: () => true,
592
- listFiles: async () => null,
593
- readFileContent: async () => null,
594
- toSlimSkill: async () => null,
595
- };
596
-
597
- // Clawhub would return content if asked, but should NOT be consulted
598
- mockClawhubProvider = {
599
- canHandle: () => true,
600
- listFiles: async () => null,
601
- readFileContent: async (_skillId, path) => {
602
- clawhubReadCalls.push(path);
603
- return {
604
- path,
605
- name: "SKILL.md",
606
- size: 10,
607
- mimeType: "text/markdown",
608
- isBinary: false,
609
- content: "# from clawhub\n",
610
- };
611
- },
612
- toSlimSkill: async () => null,
613
- };
361
+ test("stop-on-first-match: clawhub is not consulted when cadet claims the skill", async () => {
362
+ const http = mockHttp();
363
+ http.on("GET", "/v1/skills/", {
364
+ status: 200,
365
+ body: catalogBody(["simple-slug"]),
366
+ });
367
+ http.on("GET", "/v1/skills/simple-slug/files/content/", {
368
+ status: 404,
369
+ });
370
+ await getCatalog();
614
371
 
615
372
  const result = await getSkillFileContent("simple-slug", "SKILL.md");
616
- // Should be "File not found" (cadet handled but returned null)
617
373
  expect("error" in result).toBe(true);
618
374
  if (!("error" in result)) {
619
375
  return;
620
376
  }
621
377
  expect(result.error).toBe("File not found");
622
- // Clawhub should NOT have been called
623
- expect(clawhubReadCalls).toEqual([]);
378
+ // The clawhub CLI never spawned — the cadet claim short-circuits the chain.
379
+ expect(clawhubCalls()).toEqual([]);
624
380
  });
625
381
  });
626
382
 
@@ -629,11 +385,11 @@ describe("getSkillFileContent — uninstalled skill (provider chain)", () => {
629
385
  // ---------------------------------------------------------------------------
630
386
 
631
387
  describe("getSkillFileContent — skill not found", () => {
632
- test("returns 404 when the skill is neither installed nor handled by any provider", async () => {
633
- mockResolvedSkills = [];
634
- installFetchForbidden();
635
-
636
- const result = await getSkillFileContent("ghost-skill", "SKILL.md");
388
+ test("returns 404 when no provider canHandle the id", async () => {
389
+ // The real canHandle gates: cadet needs the id in the catalog cache,
390
+ // skills.sh needs ≥3 slash segments, clawhub needs a valid slug. An id
391
+ // failing all three (space → invalid slug) is claimed by nothing.
392
+ const result = await getSkillFileContent("no such skill", "SKILL.md");
637
393
  expect("error" in result).toBe(true);
638
394
  if (!("error" in result)) {
639
395
  return;
@@ -644,59 +400,12 @@ describe("getSkillFileContent — skill not found", () => {
644
400
  });
645
401
 
646
402
  // ---------------------------------------------------------------------------
647
- // Installed skill with missing directory (ghost install)
648
- // ---------------------------------------------------------------------------
649
-
650
- describe("getSkillFileContent — installed skill with missing directory", () => {
651
- test("returns 404 without consulting providers when the installed dir is gone", async () => {
652
- mockResolvedSkills = [
653
- installedSkill(
654
- "ghost-installed",
655
- "/tmp/definitely-does-not-exist-" + Date.now(),
656
- ),
657
- ];
658
- // Even if a provider would return content, the handler must NOT
659
- // fall through.
660
- mockCadetProvider = {
661
- canHandle: () => true,
662
- listFiles: async () => null,
663
- readFileContent: async () => ({
664
- path: "SKILL.md",
665
- name: "SKILL.md",
666
- size: 10,
667
- mimeType: "text/markdown",
668
- isBinary: false,
669
- content: "# from provider\n",
670
- }),
671
- toSlimSkill: async () => null,
672
- };
673
- installFetchForbidden();
674
-
675
- const result = await getSkillFileContent("ghost-installed", "SKILL.md");
676
-
677
- expect("error" in result).toBe(true);
678
- if (!("error" in result)) {
679
- return;
680
- }
681
- expect(result.status).toBe(404);
682
- expect(result.error).toContain("ghost-installed");
683
- expect(result.error).toContain("directory missing");
684
- // Provider chain must not have been consulted.
685
- expect(providerReadCalls).toEqual([]);
686
- });
687
- });
688
-
689
- // ---------------------------------------------------------------------------
690
- // Hidden / SKIP_DIRS path rejection
403
+ // Hidden / SKIP_DIRS path rejection (real sanitizer, no inline copy)
691
404
  // ---------------------------------------------------------------------------
692
405
 
693
406
  describe("getSkillFileContent — hidden / SKIP_DIRS rejection", () => {
694
407
  test("rejects dotfile reads from an installed skill with 400 Invalid path", async () => {
695
- const skillDir = makeTempSkillDir("leaky-skill");
696
- writeFile(skillDir, "SKILL.md", "# ok\n");
697
- writeFile(skillDir, ".env", "SECRET=abc\n");
698
- mockResolvedSkills = [installedSkill("leaky-skill", skillDir)];
699
- installFetchForbidden();
408
+ seedWorkspaceSkill("leaky-skill", { ".env": "SECRET=abc\n" });
700
409
 
701
410
  const result = await getSkillFileContent("leaky-skill", ".env");
702
411
  expect("error" in result).toBe(true);
@@ -708,22 +417,6 @@ describe("getSkillFileContent — hidden / SKIP_DIRS rejection", () => {
708
417
  });
709
418
 
710
419
  test("rejects dotfile reads for an uninstalled skill before any provider read", async () => {
711
- mockResolvedSkills = []; // not installed
712
- installFetchForbidden();
713
- mockCadetProvider = {
714
- canHandle: () => true,
715
- listFiles: async () => null,
716
- readFileContent: async () => ({
717
- path: ".env",
718
- name: ".env",
719
- size: 12,
720
- mimeType: "text/plain",
721
- isBinary: false,
722
- content: "SECRET=xyz\n",
723
- }),
724
- toSlimSkill: async () => null,
725
- };
726
-
727
420
  const result = await getSkillFileContent("catalog-leaky", ".env");
728
421
  expect("error" in result).toBe(true);
729
422
  if (!("error" in result)) {
@@ -731,15 +424,14 @@ describe("getSkillFileContent — hidden / SKIP_DIRS rejection", () => {
731
424
  }
732
425
  expect(result.status).toBe(400);
733
426
  expect(result.error).toBe("Invalid path");
734
- // The hidden-segment check must run before the provider chain.
735
- expect(providerReadCalls).toEqual([]);
427
+ // The hidden-segment check must run before the provider chain — the
428
+ // clawhub CLI (the only provider whose canHandle accepts this id) never
429
+ // spawned.
430
+ expect(clawhubCalls()).toEqual([]);
736
431
  });
737
432
 
738
433
  test("rejects paths whose parent directory is a dotfile segment", async () => {
739
- const skillDir = makeTempSkillDir("my-skill");
740
- writeFile(skillDir, "SKILL.md", "# ok\n");
741
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
742
- installFetchForbidden();
434
+ seedWorkspaceSkill("my-skill");
743
435
 
744
436
  for (const bad of [".git/config", "docs/.hidden/file.md"]) {
745
437
  const result = await getSkillFileContent("my-skill", bad);
@@ -753,10 +445,7 @@ describe("getSkillFileContent — hidden / SKIP_DIRS rejection", () => {
753
445
  });
754
446
 
755
447
  test("rejects paths inside SKIP_DIRS segments with 400 Invalid path", async () => {
756
- const skillDir = makeTempSkillDir("my-skill");
757
- writeFile(skillDir, "SKILL.md", "# ok\n");
758
- mockResolvedSkills = [installedSkill("my-skill", skillDir)];
759
- installFetchForbidden();
448
+ seedWorkspaceSkill("my-skill");
760
449
 
761
450
  for (const bad of [
762
451
  "node_modules/foo/index.js",
@@ -774,17 +463,14 @@ describe("getSkillFileContent — hidden / SKIP_DIRS rejection", () => {
774
463
  });
775
464
 
776
465
  test("regular SKILL.md still reads successfully (sanity)", async () => {
777
- const skillDir = makeTempSkillDir("healthy-skill");
778
- writeFile(skillDir, "SKILL.md", "# hello\n");
779
- mockResolvedSkills = [installedSkill("healthy-skill", skillDir)];
780
- installFetchForbidden();
466
+ seedWorkspaceSkill("healthy-skill");
781
467
 
782
468
  const result = await getSkillFileContent("healthy-skill", "SKILL.md");
783
469
  expect("error" in result).toBe(false);
784
470
  if ("error" in result) {
785
471
  return;
786
472
  }
787
- expect(result.content).toBe("# hello\n");
473
+ expect(result.content).toContain("# healthy-skill");
788
474
  expect(result.name).toBe("SKILL.md");
789
475
  });
790
476
  });