@intent-systems/nexus 2026.1.5-4 → 2026.1.5-8

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 (347) hide show
  1. package/dist/agents/agent-id.js +41 -0
  2. package/dist/agents/auth-profiles.js +114 -25
  3. package/dist/agents/identity-state.js +101 -0
  4. package/dist/agents/model-auth.js +1 -0
  5. package/dist/agents/model-fallback.js +15 -9
  6. package/dist/agents/model-selection.js +1 -1
  7. package/dist/agents/models-config.js +17 -11
  8. package/dist/agents/pi-embedded-runner.js +101 -9
  9. package/dist/agents/sandbox.js +12 -3
  10. package/dist/agents/skill-runner.js +41 -6
  11. package/dist/agents/skill-usage.js +117 -17
  12. package/dist/agents/skills-status.js +4 -3
  13. package/dist/agents/skills.js +38 -30
  14. package/dist/agents/subagent-registry.js +25 -11
  15. package/dist/agents/system-prompt.js +16 -0
  16. package/dist/agents/tool-policy.js +19 -3
  17. package/dist/agents/tools/browser-tool.js +5 -2
  18. package/dist/agents/tools/image-tool.js +93 -8
  19. package/dist/agents/tools/sessions-announce-target.js +5 -1
  20. package/dist/agents/workspace.js +81 -59
  21. package/dist/auto-reply/command-detection.js +2 -1
  22. package/dist/auto-reply/reply/directive-handling.js +153 -28
  23. package/dist/auto-reply/reply/directives.js +17 -2
  24. package/dist/auto-reply/reply/model-selection.js +8 -3
  25. package/dist/auto-reply/reply/queue.js +2 -2
  26. package/dist/auto-reply/reply.js +1 -1
  27. package/dist/auto-reply/thinking.js +15 -0
  28. package/dist/browser/chrome.js +1 -1
  29. package/dist/browser/client.js +2 -0
  30. package/dist/browser/config.js +6 -2
  31. package/dist/browser/pw-tools-core.js +3 -0
  32. package/dist/browser/routes/agent.js +14 -0
  33. package/dist/canvas-host/server.js +1 -1
  34. package/dist/capabilities/detector.js +46 -15
  35. package/dist/capabilities/registry.js +2 -1
  36. package/dist/cli/cloud-cli.js +70 -7
  37. package/dist/cli/credential-cli.js +214 -23
  38. package/dist/cli/gateway-cli.js +1 -1
  39. package/dist/cli/log-cli.js +25 -0
  40. package/dist/cli/pairing-cli.js +1 -1
  41. package/dist/cli/program.js +82 -8
  42. package/dist/cli/run-main.js +1 -1
  43. package/dist/cli/skills-cli.js +165 -30
  44. package/dist/cli/skills-hub-cli.js +68 -36
  45. package/dist/cli/tool-connector-cli.js +99 -24
  46. package/dist/cli/upstream-sync-cli.js +253 -96
  47. package/dist/cli/usage-cli.js +14 -0
  48. package/dist/commands/auth-choice-options.js +6 -1
  49. package/dist/commands/auth-choice.js +157 -5
  50. package/dist/commands/bootstrap-preset.js +26 -12
  51. package/dist/commands/capabilities.js +33 -6
  52. package/dist/commands/claude-md.js +3 -2
  53. package/dist/commands/config-view.js +1 -1
  54. package/dist/commands/config.js +85 -0
  55. package/dist/commands/configure.js +4 -4
  56. package/dist/commands/credential.js +497 -36
  57. package/dist/commands/cursor-hooks.js +240 -0
  58. package/dist/commands/cursor-rules.js +14 -188
  59. package/dist/commands/doctor.js +5 -4
  60. package/dist/commands/identity.js +29 -32
  61. package/dist/commands/init.js +304 -20
  62. package/dist/commands/log.js +134 -0
  63. package/dist/commands/models/fallbacks.js +1 -1
  64. package/dist/commands/models/image-fallbacks.js +1 -1
  65. package/dist/commands/models/list.js +1 -1
  66. package/dist/commands/models/scan.js +1 -1
  67. package/dist/commands/onboard-auth.js +27 -2
  68. package/dist/commands/onboard-eve-identity.js +8 -9
  69. package/dist/commands/onboard-non-interactive.js +4 -2
  70. package/dist/commands/onboard-quickstart.js +18 -11
  71. package/dist/commands/quest-state.js +271 -0
  72. package/dist/commands/quest.js +53 -13
  73. package/dist/commands/reset.js +1 -1
  74. package/dist/commands/sessions-ingest.js +5 -4
  75. package/dist/commands/setup.js +4 -2
  76. package/dist/commands/skills-manifest.js +89 -29
  77. package/dist/commands/status.js +193 -73
  78. package/dist/commands/suggestions.js +1 -1
  79. package/dist/commands/usage-tracking.js +32 -0
  80. package/dist/commands/usage-upload.js +6 -1
  81. package/dist/config/defaults.js +1 -3
  82. package/dist/config/includes.js +5 -7
  83. package/dist/config/io.js +88 -16
  84. package/dist/config/legacy.js +4 -2
  85. package/dist/config/paths.js +16 -0
  86. package/dist/config/sessions.js +9 -5
  87. package/dist/config/zod-schema.js +4 -3
  88. package/dist/control-plane/broker/broker.js +131 -78
  89. package/dist/control-plane/compaction.js +3 -5
  90. package/dist/control-plane/factory.js +2 -2
  91. package/dist/control-plane/index.js +2 -2
  92. package/dist/control-plane/odu/agents.js +28 -23
  93. package/dist/control-plane/odu/interaction-tools.js +62 -50
  94. package/dist/control-plane/odu/prompt-loader.js +8 -8
  95. package/dist/control-plane/odu/runtime.js +87 -75
  96. package/dist/control-plane/odu-control-plane.js +14 -12
  97. package/dist/control-plane/single-agent.js +13 -13
  98. package/dist/credentials/store.js +133 -7
  99. package/dist/daemon/launchd.js +14 -0
  100. package/dist/entry.js +0 -0
  101. package/dist/gateway/server-browser.js +5 -4
  102. package/dist/gateway/server-methods/cron.js +11 -1
  103. package/dist/gateway/server.js +14 -7
  104. package/dist/infra/bonjour.js +1 -1
  105. package/dist/infra/event-log.js +8 -2
  106. package/dist/infra/path-env.js +1 -2
  107. package/dist/infra/provider-usage.auth.js +5 -3
  108. package/dist/infra/provider-usage.fetch.claude.js +16 -6
  109. package/dist/infra/provider-usage.fetch.minimax.js +8 -3
  110. package/dist/infra/provider-usage.js +9 -5
  111. package/dist/infra/restart.js +2 -2
  112. package/dist/infra/usage-settings.js +78 -0
  113. package/dist/infra/usage-suggestions.js +17 -5
  114. package/dist/infra/usage-upload.js +38 -1
  115. package/dist/infra/voicewake.js +2 -2
  116. package/dist/media/image-ops.js +3 -1
  117. package/dist/memory/index.js +2 -381
  118. package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud +0 -0
  119. package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud-rs +0 -0
  120. package/dist/pairing/pairing-store.js +24 -0
  121. package/dist/providers/github-copilot-auth.js +1 -1
  122. package/dist/routing/resolve-route.js +6 -6
  123. package/dist/routing/session-key.js +3 -1
  124. package/dist/sessions/send-policy.js +5 -5
  125. package/dist/slack/monitor.js +22 -1
  126. package/dist/telegram/reaction-level.js +2 -1
  127. package/dist/utils.js +8 -3
  128. package/dist/wizard/onboarding.js +29 -7
  129. package/docs/AGENTS.default.md +1 -1
  130. package/docs/configuration.md +1 -1
  131. package/docs/feature-inventory/overview.md +2 -2
  132. package/docs/reference/templates/AGENTS.md +172 -109
  133. package/docs/templates/AGENTS.md +140 -199
  134. package/docs/templates/BOOTSTRAP.md +40 -20
  135. package/docs/templates/IDENTITY.md +6 -0
  136. package/docs/templates/USER.md +22 -2
  137. package/package.json +3 -1
  138. package/skills/{notion → connectors/notion}/SKILL.md +1 -1
  139. package/skills/{filesystem → guides/filesystem}/SKILL.md +1 -1
  140. package/skills/{onboarding → guides/onboarding}/SKILL.md +1 -1
  141. package/skills/{onboarding → guides/onboarding}/docs/CAPABILITY_TAXONOMY.md +5 -5
  142. package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR.md +8 -8
  143. package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_ONBOARDING.md +2 -2
  144. package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_SKILLS.md +26 -20
  145. package/skills/{onboarding → guides/onboarding}/docs/GOAL_STATE_ARCHITECTURE.md +38 -43
  146. package/skills/{onboarding → guides/onboarding}/docs/NEXUS_SYSTEM_OVERVIEW.md +4 -4
  147. package/skills/{onboarding → guides/onboarding}/docs/SKILLS_HUB_SPEC.md +1 -1
  148. package/skills/{onboarding → guides/onboarding}/docs/SKILLS_SPECIFICATION.md +8 -7
  149. package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_DESIGN.md +16 -16
  150. package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_PRD.md +10 -12
  151. package/skills/guides/onboarding/docs/canonical/00_CONFLICT_ANALYSIS.md +463 -0
  152. package/skills/guides/onboarding/docs/canonical/01_NEXUS_OVERVIEW.md +167 -0
  153. package/skills/guides/onboarding/docs/canonical/02_CLI_REFERENCE.md +404 -0
  154. package/skills/guides/onboarding/docs/canonical/03_STATE_ARCHITECTURE.md +357 -0
  155. package/skills/guides/onboarding/docs/canonical/04_SKILL_SPECIFICATION.md +393 -0
  156. package/skills/guides/onboarding/docs/canonical/05_CAPABILITY_TAXONOMY.md +298 -0
  157. package/skills/guides/onboarding/docs/canonical/06_CAPABILITIES_REFERENCE.md +207 -0
  158. package/skills/guides/onboarding/docs/canonical/07_AGENT_BINDINGS.md +85 -0
  159. package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/nexus-cloud.md +2 -2
  160. package/skills/{onboarding → guides/onboarding}/scripts/ralph/progress.txt +1 -1
  161. package/skills/{nexus-cloud → tools/nexus-cloud}/SKILL.md +2 -1
  162. package/skills/{nexus-cloud → tools/nexus-cloud}/docs/setup.md +1 -1
  163. package/docs/templates/PROFILE.md +0 -14
  164. /package/skills/{brave-search → connectors/brave-search}/SKILL.md +0 -0
  165. /package/skills/{brave-search → connectors/brave-search}/docs/setup.md +0 -0
  166. /package/skills/{brave-search → connectors/brave-search}/docs/troubleshooting.md +0 -0
  167. /package/skills/{brave-search → connectors/brave-search}/docs/usage.md +0 -0
  168. /package/skills/{brave-search → connectors/brave-search}/scripts/content.mjs +0 -0
  169. /package/skills/{brave-search → connectors/brave-search}/scripts/search.mjs +0 -0
  170. /package/skills/{discord → connectors/discord}/SKILL.md +0 -0
  171. /package/skills/{gemini → connectors/gemini}/SKILL.md +0 -0
  172. /package/skills/{github → connectors/github}/SKILL.md +0 -0
  173. /package/skills/{github → connectors/github}/docs/setup.md +0 -0
  174. /package/skills/{github → connectors/github}/docs/troubleshooting.md +0 -0
  175. /package/skills/{google-oauth → connectors/google-oauth}/SKILL.md +0 -0
  176. /package/skills/{slack → connectors/slack}/SKILL.md +0 -0
  177. /package/skills/{telegram → connectors/telegram}/SKILL.md +0 -0
  178. /package/skills/{telegram → connectors/telegram}/docs/pairing.md +0 -0
  179. /package/skills/{telegram → connectors/telegram}/docs/setup.md +0 -0
  180. /package/skills/{telegram → connectors/telegram}/docs/webhook.md +0 -0
  181. /package/skills/{wacli → connectors/wacli}/SKILL.md +0 -0
  182. /package/skills/{wacli → connectors/wacli}/docs/auth.md +0 -0
  183. /package/skills/{wacli → connectors/wacli}/docs/backup.md +0 -0
  184. /package/skills/{wacli → connectors/wacli}/docs/troubleshooting.md +0 -0
  185. /package/skills/{browser-use-agent-sdk → guides/browser-use-agent-sdk}/SKILL.md +0 -0
  186. /package/skills/{json-render → guides/json-render}/SKILL.md +0 -0
  187. /package/skills/{json-render → guides/json-render}/assets/components/README.md +0 -0
  188. /package/skills/{json-render → guides/json-render}/assets/components/catalog.ts +0 -0
  189. /package/skills/{json-render → guides/json-render}/assets/components/registry.tsx +0 -0
  190. /package/skills/{json-render → guides/json-render}/assets/demo/App.css +0 -0
  191. /package/skills/{json-render → guides/json-render}/assets/demo/App.tsx +0 -0
  192. /package/skills/{json-render → guides/json-render}/assets/demo/README.md +0 -0
  193. /package/skills/{json-render → guides/json-render}/assets/demo/catalog.ts +0 -0
  194. /package/skills/{json-render → guides/json-render}/assets/demo/data/nexus-core.json +0 -0
  195. /package/skills/{json-render → guides/json-render}/assets/demo/index.css +0 -0
  196. /package/skills/{json-render → guides/json-render}/assets/demo/registry.tsx +0 -0
  197. /package/skills/{json-render → guides/json-render}/docs/nexus-state-demo.md +0 -0
  198. /package/skills/{json-render → guides/json-render}/docs/shadcn-preset.md +0 -0
  199. /package/skills/{json-render → guides/json-render}/scripts/create-vite-demo.sh +0 -0
  200. /package/skills/{json-render → guides/json-render}/scripts/llm-server/README.md +0 -0
  201. /package/skills/{json-render → guides/json-render}/scripts/llm-server/catalog.ts +0 -0
  202. /package/skills/{json-render → guides/json-render}/scripts/llm-server/package-lock.json +0 -0
  203. /package/skills/{json-render → guides/json-render}/scripts/llm-server/package.json +0 -0
  204. /package/skills/{json-render → guides/json-render}/scripts/llm-server/server.ts +0 -0
  205. /package/skills/{onboarding → guides/onboarding}/docs/CAPABILITIES.md +0 -0
  206. /package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_CREDENTIALS.md +0 -0
  207. /package/skills/{onboarding → guides/onboarding}/docs/DOCUMENTATION_OVERVIEW.md +0 -0
  208. /package/skills/{onboarding → guides/onboarding}/docs/ENTITY_MODEL.md +0 -0
  209. /package/skills/{onboarding → guides/onboarding}/docs/SKILL_INVENTORY.md +0 -0
  210. /package/skills/{onboarding → guides/onboarding}/docs/STATE_ARCHITECTURE.md +0 -0
  211. /package/skills/{onboarding → guides/onboarding}/docs/TROUBLESHOOTING.md +0 -0
  212. /package/skills/{onboarding → guides/onboarding}/docs/USER_JOURNEY.md +0 -0
  213. /package/skills/{onboarding → guides/onboarding}/docs/WOW_MOMENTS.md +0 -0
  214. /package/skills/{onboarding → guides/onboarding}/docs/agent-apple-id.md +0 -0
  215. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/1password.md +0 -0
  216. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/TEMPLATE.md +0 -0
  217. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/aix.md +0 -0
  218. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/bird.md +0 -0
  219. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/brave-search.md +0 -0
  220. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/comms.md +0 -0
  221. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/computer-use.md +0 -0
  222. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/cron-and-heartbeat.md +0 -0
  223. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/eve.md +0 -0
  224. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/github.md +0 -0
  225. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/gog.md +0 -0
  226. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/homebrew-prereqs.md +0 -0
  227. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/qmd.md +0 -0
  228. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/telegram.md +0 -0
  229. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/wacli.md +0 -0
  230. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/weather.md +0 -0
  231. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prd.json +0 -0
  232. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prompt.md +0 -0
  233. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.log +0 -0
  234. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.sh +0 -0
  235. /package/skills/{onboarding → guides/onboarding}/scripts/setup-cursor-skills.sh +0 -0
  236. /package/skills/{1password → tools/1password}/SKILL.md +0 -0
  237. /package/skills/{1password → tools/1password}/docs/setup.md +0 -0
  238. /package/skills/{1password → tools/1password}/docs/troubleshooting.md +0 -0
  239. /package/skills/{1password → tools/1password}/references/cli-examples.md +0 -0
  240. /package/skills/{1password → tools/1password}/references/get-started.md +0 -0
  241. /package/skills/{agent-browser → tools/agent-browser}/SKILL.md +0 -0
  242. /package/skills/{agent-browser → tools/agent-browser}/docs/browser-use-eval.md +0 -0
  243. /package/skills/{agent-browser → tools/agent-browser}/docs/first-tests.md +0 -0
  244. /package/skills/{agent-browser → tools/agent-browser}/docs/wordle-nyt-eval.js +0 -0
  245. /package/skills/{aix → tools/aix}/SKILL.md +0 -0
  246. /package/skills/{aix → tools/aix}/docs/embeddings.md +0 -0
  247. /package/skills/{aix → tools/aix}/docs/setup.md +0 -0
  248. /package/skills/{aix → tools/aix}/docs/troubleshooting.md +0 -0
  249. /package/skills/{aix → tools/aix}/references/sql.md +0 -0
  250. /package/skills/{apple-notes → tools/apple-notes}/SKILL.md +0 -0
  251. /package/skills/{apple-reminders → tools/apple-reminders}/SKILL.md +0 -0
  252. /package/skills/{bear-notes → tools/bear-notes}/SKILL.md +0 -0
  253. /package/skills/{bird → tools/bird}/SKILL.md +0 -0
  254. /package/skills/{bird → tools/bird}/docs/auth.md +0 -0
  255. /package/skills/{bird → tools/bird}/docs/troubleshooting.md +0 -0
  256. /package/skills/{blogwatcher → tools/blogwatcher}/SKILL.md +0 -0
  257. /package/skills/{blucli → tools/blucli}/SKILL.md +0 -0
  258. /package/skills/{camsnap → tools/camsnap}/SKILL.md +0 -0
  259. /package/skills/{clawdhub → tools/clawdhub}/SKILL.md +0 -0
  260. /package/skills/{coding-agent → tools/coding-agent}/SKILL.md +0 -0
  261. /package/skills/{comms → tools/comms}/SKILL.md +0 -0
  262. /package/skills/{comms → tools/comms}/docs/adapters.md +0 -0
  263. /package/skills/{comms → tools/comms}/docs/setup.md +0 -0
  264. /package/skills/{comms → tools/comms}/docs/troubleshooting.md +0 -0
  265. /package/skills/{comms → tools/comms}/references/schema.md +0 -0
  266. /package/skills/{computer-use → tools/computer-use}/SKILL.md +0 -0
  267. /package/skills/{computer-use → tools/computer-use}/docs/open-interpreter.md +0 -0
  268. /package/skills/{computer-use → tools/computer-use}/docs/peekaboo.md +0 -0
  269. /package/skills/{computer-use → tools/computer-use}/docs/setup.md +0 -0
  270. /package/skills/{computer-use → tools/computer-use}/docs/troubleshooting.md +0 -0
  271. /package/skills/{eightctl → tools/eightctl}/SKILL.md +0 -0
  272. /package/skills/{eve → tools/eve}/SKILL.md +0 -0
  273. /package/skills/{eve → tools/eve}/docs/dual-account.md +0 -0
  274. /package/skills/{eve → tools/eve}/docs/intelligence.md +0 -0
  275. /package/skills/{eve → tools/eve}/docs/setup.md +0 -0
  276. /package/skills/{eve → tools/eve}/docs/troubleshooting.md +0 -0
  277. /package/skills/{eve → tools/eve}/scripts/setup-dual-account.sh +0 -0
  278. /package/skills/{food-order → tools/food-order}/SKILL.md +0 -0
  279. /package/skills/{gh → tools/gh}/SKILL.md +0 -0
  280. /package/skills/{gh → tools/gh}/docs/usage.md +0 -0
  281. /package/skills/{gifgrep → tools/gifgrep}/SKILL.md +0 -0
  282. /package/skills/{gog → tools/gog}/SKILL.md +0 -0
  283. /package/skills/{gog → tools/gog}/docs/portability.md +0 -0
  284. /package/skills/{gog → tools/gog}/docs/setup.md +0 -0
  285. /package/skills/{gog → tools/gog}/docs/troubleshooting.md +0 -0
  286. /package/skills/{gog → tools/gog}/scripts/cdp/README.md +0 -0
  287. /package/skills/{gog → tools/gog}/scripts/cdp/add_test_users.py +0 -0
  288. /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts.py +0 -0
  289. /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts_manual.py +0 -0
  290. /package/skills/{gog → tools/gog}/scripts/cdp/create_oauth_client.py +0 -0
  291. /package/skills/{gog → tools/gog}/scripts/cdp/launch_cdp_chrome.sh +0 -0
  292. /package/skills/{goplaces → tools/goplaces}/SKILL.md +0 -0
  293. /package/skills/{imsg → tools/imsg}/SKILL.md +0 -0
  294. /package/skills/{local-places → tools/local-places}/SERVER_README.md +0 -0
  295. /package/skills/{local-places → tools/local-places}/SKILL.md +0 -0
  296. /package/skills/{local-places → tools/local-places}/pyproject.toml +0 -0
  297. /package/skills/{local-places → tools/local-places}/src/local_places/__init__.py +0 -0
  298. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
  299. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
  300. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
  301. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
  302. /package/skills/{local-places → tools/local-places}/src/local_places/google_places.py +0 -0
  303. /package/skills/{local-places → tools/local-places}/src/local_places/main.py +0 -0
  304. /package/skills/{local-places → tools/local-places}/src/local_places/schemas.py +0 -0
  305. /package/skills/{mcporter → tools/mcporter}/SKILL.md +0 -0
  306. /package/skills/{model-usage → tools/model-usage}/SKILL.md +0 -0
  307. /package/skills/{model-usage → tools/model-usage}/references/codexbar-cli.md +0 -0
  308. /package/skills/{model-usage → tools/model-usage}/scripts/model_usage.py +0 -0
  309. /package/skills/{nano-banana-pro → tools/nano-banana-pro}/SKILL.md +0 -0
  310. /package/skills/{nano-banana-pro → tools/nano-banana-pro}/scripts/generate_image.py +0 -0
  311. /package/skills/{nano-pdf → tools/nano-pdf}/SKILL.md +0 -0
  312. /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/security.md +0 -0
  313. /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/troubleshooting.md +0 -0
  314. /package/skills/{obsidian → tools/obsidian}/SKILL.md +0 -0
  315. /package/skills/{openai-image-gen → tools/openai-image-gen}/SKILL.md +0 -0
  316. /package/skills/{openai-image-gen → tools/openai-image-gen}/scripts/gen.py +0 -0
  317. /package/skills/{openai-whisper → tools/openai-whisper}/SKILL.md +0 -0
  318. /package/skills/{openai-whisper-api → tools/openai-whisper-api}/SKILL.md +0 -0
  319. /package/skills/{openai-whisper-api → tools/openai-whisper-api}/scripts/transcribe.sh +0 -0
  320. /package/skills/{openhue → tools/openhue}/SKILL.md +0 -0
  321. /package/skills/{oracle → tools/oracle}/SKILL.md +0 -0
  322. /package/skills/{ordercli → tools/ordercli}/SKILL.md +0 -0
  323. /package/skills/{peekaboo → tools/peekaboo}/SKILL.md +0 -0
  324. /package/skills/{qmd → tools/qmd}/SKILL.md +0 -0
  325. /package/skills/{qmd → tools/qmd}/docs/mcp.md +0 -0
  326. /package/skills/{qmd → tools/qmd}/docs/ollama.md +0 -0
  327. /package/skills/{qmd → tools/qmd}/docs/setup.md +0 -0
  328. /package/skills/{sag → tools/sag}/SKILL.md +0 -0
  329. /package/skills/{skill-cli-template → tools/skill-cli-template}/SKILL.md +0 -0
  330. /package/skills/{songsee → tools/songsee}/SKILL.md +0 -0
  331. /package/skills/{sonoscli → tools/sonoscli}/SKILL.md +0 -0
  332. /package/skills/{spotify-player → tools/spotify-player}/SKILL.md +0 -0
  333. /package/skills/{summarize → tools/summarize}/SKILL.md +0 -0
  334. /package/skills/{things-mac → tools/things-mac}/SKILL.md +0 -0
  335. /package/skills/{tmux → tools/tmux}/SKILL.md +0 -0
  336. /package/skills/{tmux → tools/tmux}/scripts/find-sessions.sh +0 -0
  337. /package/skills/{tmux → tools/tmux}/scripts/wait-for-text.sh +0 -0
  338. /package/skills/{trello → tools/trello}/SKILL.md +0 -0
  339. /package/skills/{upstream-sync → tools/upstream-sync}/SKILL.md +0 -0
  340. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/auto-port.sh +0 -0
  341. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-all.sh +0 -0
  342. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-nexus.sh +0 -0
  343. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-pi-ai.sh +0 -0
  344. /package/skills/{video-frames → tools/video-frames}/SKILL.md +0 -0
  345. /package/skills/{video-frames → tools/video-frames}/scripts/frame.sh +0 -0
  346. /package/skills/{weather → tools/weather}/SKILL.md +0 -0
  347. /package/skills/{weather → tools/weather}/docs/usage.md +0 -0
@@ -233,12 +233,7 @@ function resolveStorageField(storage, field) {
233
233
  return storage.fields?.accessToken ?? storage.fields?.token ?? null;
234
234
  return null;
235
235
  }
236
- async function readSecretFromStorage(record, field) {
237
- const storage = record.storage;
238
- if (storage.provider === "plaintext") {
239
- const value = field === "key" ? record.key : field === "token" ? record.token : record.accessToken;
240
- return typeof value === "string" && value.trim() ? value.trim() : null;
241
- }
236
+ async function readRawFromStorage(storage, field) {
242
237
  if (storage.provider === "keychain") {
243
238
  try {
244
239
  const { stdout } = await execFileAsync("security", [
@@ -256,6 +251,13 @@ async function readSecretFromStorage(record, field) {
256
251
  return null;
257
252
  }
258
253
  }
254
+ if (storage.provider === "env") {
255
+ const envValue = process.env[storage.var];
256
+ if (typeof envValue !== "string")
257
+ return null;
258
+ const trimmed = envValue.trim();
259
+ return trimmed ? trimmed : null;
260
+ }
259
261
  if (storage.provider === "1password") {
260
262
  const fieldName = resolveStorageField(storage, field);
261
263
  if (!fieldName)
@@ -272,7 +274,10 @@ async function readSecretFromStorage(record, field) {
272
274
  }
273
275
  if (storage.provider === "external") {
274
276
  try {
275
- const { stdout } = await execAsync(storage.syncCommand);
277
+ const command = storage.command ?? storage.syncCommand;
278
+ if (!command)
279
+ return null;
280
+ const { stdout } = await execAsync(command);
276
281
  const trimmed = stdout.trim();
277
282
  return trimmed ? trimmed : null;
278
283
  }
@@ -282,6 +287,127 @@ async function readSecretFromStorage(record, field) {
282
287
  }
283
288
  return null;
284
289
  }
290
+ async function readSecretFromStorage(record, field) {
291
+ const storage = record.storage;
292
+ const raw = await readRawFromStorage(storage, field);
293
+ if (!raw)
294
+ return null;
295
+ const wantsJson = storage.format === "json" || Boolean(storage.jsonPath);
296
+ if (!wantsJson)
297
+ return raw;
298
+ try {
299
+ const parsed = JSON.parse(raw);
300
+ const pathSpec = storage.jsonPath ?? field;
301
+ const resolved = resolveJsonPath(parsed, pathSpec);
302
+ if (typeof resolved === "string")
303
+ return resolved.trim() || null;
304
+ if (typeof resolved === "number")
305
+ return String(resolved);
306
+ return null;
307
+ }
308
+ catch {
309
+ return null;
310
+ }
311
+ }
312
+ function resolveJsonPath(value, pathSpec) {
313
+ const parts = pathSpec.split(".").filter(Boolean);
314
+ let current = value;
315
+ for (const part of parts) {
316
+ if (!current || typeof current !== "object")
317
+ return undefined;
318
+ const match = /^(.+?)\[(\d+)\]$/.exec(part);
319
+ if (match) {
320
+ const [, key, indexRaw] = match;
321
+ const index = Number.parseInt(indexRaw, 10);
322
+ if (Number.isNaN(index))
323
+ return undefined;
324
+ const next = current[key ?? ""];
325
+ if (!Array.isArray(next))
326
+ return undefined;
327
+ current = next[index];
328
+ continue;
329
+ }
330
+ current = current[part];
331
+ }
332
+ return current;
333
+ }
334
+ export function resolveDefaultEnvVar(params) {
335
+ const service = params.service.toLowerCase();
336
+ const type = params.type;
337
+ const known = {
338
+ anthropic: {
339
+ api_key: "ANTHROPIC_API_KEY",
340
+ token: "ANTHROPIC_OAUTH_TOKEN",
341
+ oauth: "ANTHROPIC_OAUTH_TOKEN",
342
+ },
343
+ openai: { api_key: "OPENAI_API_KEY" },
344
+ gemini: { api_key: "GEMINI_API_KEY" },
345
+ "brave-search": { api_key: "BRAVE_API_KEY" },
346
+ github: { token: "GITHUB_TOKEN" },
347
+ "github-copilot": { token: "COPILOT_GITHUB_TOKEN" },
348
+ discord: { token: "DISCORD_BOT_TOKEN" },
349
+ slack: { token: "SLACK_BOT_TOKEN" },
350
+ openrouter: { api_key: "OPENROUTER_API_KEY" },
351
+ zai: { api_key: "ZAI_API_KEY" },
352
+ minimax: { api_key: "MINIMAX_API_KEY", token: "MINIMAX_API_KEY" },
353
+ "openai-codex": { oauth: "NEXUS_OPENAI_CODEX_TOKEN" },
354
+ "google-antigravity": { oauth: "NEXUS_GOOGLE_ANTIGRAVITY_TOKEN" },
355
+ chutes: { oauth: "NEXUS_CHUTES_TOKEN" },
356
+ "nexus-cloud": { token: "NEXUS_CLOUD_TOKEN" },
357
+ "nexus-hub": { token: "NEXUS_HUB_TOKEN" },
358
+ };
359
+ const mapped = known[service]?.[type];
360
+ if (mapped)
361
+ return mapped;
362
+ const suffix = type === "api_key"
363
+ ? "API_KEY"
364
+ : type === "oauth"
365
+ ? "OAUTH_TOKEN"
366
+ : type === "token"
367
+ ? "TOKEN"
368
+ : "CONFIG";
369
+ const normalized = service.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
370
+ return `NEXUS_${normalized}_${suffix}`;
371
+ }
372
+ export async function resolveOAuthBundle(record) {
373
+ if (record.type !== "oauth")
374
+ return {};
375
+ const raw = await readRawFromStorage(record.storage, "accessToken");
376
+ if (!raw)
377
+ return {};
378
+ const wantsJson = record.storage.format === "json" || Boolean(record.storage.jsonPath);
379
+ if (!wantsJson) {
380
+ return { accessToken: raw, expiresAt: record.expiresAt };
381
+ }
382
+ try {
383
+ const parsed = JSON.parse(raw);
384
+ if (record.storage.jsonPath) {
385
+ const access = resolveJsonPath(parsed, record.storage.jsonPath);
386
+ if (typeof access === "string") {
387
+ return { accessToken: access };
388
+ }
389
+ }
390
+ const accessToken = typeof parsed.accessToken === "string"
391
+ ? parsed.accessToken
392
+ : typeof parsed.access_token === "string"
393
+ ? parsed.access_token
394
+ : undefined;
395
+ const refreshToken = typeof parsed.refreshToken === "string"
396
+ ? parsed.refreshToken
397
+ : typeof parsed.refresh_token === "string"
398
+ ? parsed.refresh_token
399
+ : undefined;
400
+ const expiresAt = typeof parsed.expiresAt === "number" || typeof parsed.expiresAt === "string"
401
+ ? parsed.expiresAt
402
+ : typeof parsed.expires_at === "number" || typeof parsed.expires_at === "string"
403
+ ? parsed.expires_at
404
+ : undefined;
405
+ return { accessToken, refreshToken, expiresAt };
406
+ }
407
+ catch {
408
+ return {};
409
+ }
410
+ }
285
411
  export async function storeKeychainSecret(params) {
286
412
  try {
287
413
  await execFileAsync("security", [
@@ -74,9 +74,23 @@ export async function readLaunchAgentProgramArguments(env) {
74
74
  const workingDirectory = workingDirMatch
75
75
  ? plistUnescape(workingDirMatch[1] ?? "").trim()
76
76
  : "";
77
+ const envMatch = plist.match(/<key>EnvironmentVariables<\/key>\s*<dict>([\s\S]*?)<\/dict>/i);
78
+ let environment;
79
+ if (envMatch) {
80
+ const entries = Array.from(envMatch[1].matchAll(/<key>([\s\S]*?)<\/key>\s*<string>([\s\S]*?)<\/string>/gi))
81
+ .map((match) => [
82
+ plistUnescape(match[1] ?? "").trim(),
83
+ plistUnescape(match[2] ?? "").trim(),
84
+ ])
85
+ .filter(([key, value]) => key && value);
86
+ if (entries.length > 0) {
87
+ environment = Object.fromEntries(entries);
88
+ }
89
+ }
77
90
  return {
78
91
  programArguments: args.filter(Boolean),
79
92
  ...(workingDirectory ? { workingDirectory } : {}),
93
+ ...(environment ? { environment } : {}),
80
94
  };
81
95
  }
82
96
  catch {
package/dist/entry.js CHANGED
File without changes
@@ -1,11 +1,12 @@
1
1
  export async function startBrowserControlServerIfEnabled() {
2
- if (process.env.NEXUS_SKIP_BROWSER_CONTROL_SERVER === "1" ||
3
- process.env.NEXUS_SKIP_BROWSER_CONTROL_SERVER === "1")
2
+ if (process.env.NEXUS_SKIP_BROWSER_CONTROL_SERVER === "1")
4
3
  return null;
5
4
  // Lazy import: keeps startup fast, but still bundles for the embedded
6
5
  // gateway (bun --compile) via the static specifier path.
7
- const override = (process.env.NEXUS_BROWSER_CONTROL_MODULE ?? process.env.NEXUS_BROWSER_CONTROL_MODULE)?.trim();
8
- const mod = override ? await import(override) : await import("../browser/server.js");
6
+ const override = process.env.NEXUS_BROWSER_CONTROL_MODULE?.trim();
7
+ const mod = override
8
+ ? await import(override)
9
+ : await import("../browser/server.js");
9
10
  await mod.startBrowserControlServerFromConfig();
10
11
  return { stop: mod.stopBrowserControlServer };
11
12
  }
@@ -41,9 +41,19 @@ export const cronHandlers = {
41
41
  },
42
42
  "cron.update": async ({ params, respond, context }) => {
43
43
  const normalizedPatch = normalizeCronJobPatch(params?.patch);
44
- const candidate = normalizedPatch && typeof params === "object" && params !== null
44
+ const withPatch = normalizedPatch && typeof params === "object" && params !== null
45
45
  ? { ...params, patch: normalizedPatch }
46
46
  : params;
47
+ const candidate = withPatch && typeof withPatch === "object" && withPatch !== null
48
+ ? (() => {
49
+ const entry = withPatch;
50
+ if (!entry.id && entry.jobId) {
51
+ const { jobId, ...rest } = entry;
52
+ return { ...rest, id: jobId };
53
+ }
54
+ return entry;
55
+ })()
56
+ : withPatch;
47
57
  if (!validateCronUpdateParams(candidate)) {
48
58
  respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid cron.update params: ${formatValidationErrors(validateCronUpdateParams.errors)}`));
49
59
  return;
@@ -2,10 +2,10 @@ import { randomUUID } from "node:crypto";
2
2
  import os from "node:os";
3
3
  import chalk from "chalk";
4
4
  import { WebSocketServer } from "ws";
5
- import { createSubagentRegistry } from "../agents/subagent-registry.js";
6
5
  import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
7
6
  import { loadModelCatalog, resetModelCatalogCacheForTest, } from "../agents/model-catalog.js";
8
7
  import { resolveConfiguredModelRef } from "../agents/model-selection.js";
8
+ import { createSubagentRegistry } from "../agents/subagent-registry.js";
9
9
  import { CANVAS_HOST_PATH } from "../canvas-host/a2ui.js";
10
10
  import { createCanvasHostHandler, startCanvasHost, } from "../canvas-host/server.js";
11
11
  import { createDefaultDeps } from "../cli/deps.js";
@@ -256,7 +256,8 @@ export async function startGatewayServer(port = 18789, opts = {}) {
256
256
  allowTailscale,
257
257
  };
258
258
  let hooksConfig = resolveHooksConfig(cfgAtStart);
259
- const canvasHostEnabled = process.env.NEXUS_SKIP_CANVAS_HOST !== "1" && cfgAtStart.canvasHost?.enabled !== false;
259
+ const canvasHostEnabled = process.env.NEXUS_SKIP_CANVAS_HOST !== "1" &&
260
+ cfgAtStart.canvasHost?.enabled !== false;
260
261
  assertGatewayAuthConfigured(resolvedAuth);
261
262
  if (tailscaleMode === "funnel" && authMode !== "password") {
262
263
  throw new Error("tailscale funnel requires gateway auth mode=password (set gateway.auth.password or NEXUS_GATEWAY_PASSWORD)");
@@ -464,7 +465,7 @@ export async function startGatewayServer(port = 18789, opts = {}) {
464
465
  return resolveMainSessionKey(cfg);
465
466
  return resolveAgentMainSessionKey({ cfg, agentId });
466
467
  };
467
- const enqueueCronSystemEvent = (text, opts) => {
468
+ const _enqueueCronSystemEvent = (text, opts) => {
468
469
  const sessionKey = resolveCronMainSessionKey(opts?.agentId);
469
470
  if (sessionKey) {
470
471
  enqueueSystemEvent(text, { sessionKey });
@@ -586,7 +587,9 @@ export async function startGatewayServer(port = 18789, opts = {}) {
586
587
  }
587
588
  if (process.env.NEXUS_BRIDGE_PORT !== undefined) {
588
589
  const parsed = Number.parseInt(process.env.NEXUS_BRIDGE_PORT, 10);
589
- return Number.isFinite(parsed) && parsed > 0 ? parsed : deriveDefaultBridgePort(port);
590
+ return Number.isFinite(parsed) && parsed > 0
591
+ ? parsed
592
+ : deriveDefaultBridgePort(port);
590
593
  }
591
594
  return deriveDefaultBridgePort(port);
592
595
  })();
@@ -1049,7 +1052,9 @@ export async function startGatewayServer(port = 18789, opts = {}) {
1049
1052
  type: "hello-ok",
1050
1053
  protocol: PROTOCOL_VERSION,
1051
1054
  server: {
1052
- version: process.env.NEXUS_VERSION ?? process.env.npm_package_version ?? "dev",
1055
+ version: process.env.NEXUS_VERSION ??
1056
+ process.env.npm_package_version ??
1057
+ "dev",
1053
1058
  commit: process.env.GIT_COMMIT,
1054
1059
  host: os.hostname(),
1055
1060
  connId,
@@ -1240,7 +1245,8 @@ export async function startGatewayServer(port = 18789, opts = {}) {
1240
1245
  }
1241
1246
  // Launch configured channels (WhatsApp Web, Discord, Slack, Telegram) so gateway replies via the
1242
1247
  // surface the message came from. Tests can opt out via NEXUS_SKIP_CHANNELS (or legacy _PROVIDERS).
1243
- const skipChannels = process.env.NEXUS_SKIP_CHANNELS === "1" || process.env.NEXUS_SKIP_PROVIDERS === "1";
1248
+ const skipChannels = process.env.NEXUS_SKIP_CHANNELS === "1" ||
1249
+ process.env.NEXUS_SKIP_PROVIDERS === "1";
1244
1250
  if (!skipChannels) {
1245
1251
  try {
1246
1252
  await startProviders();
@@ -1315,7 +1321,8 @@ export async function startGatewayServer(port = 18789, opts = {}) {
1315
1321
  }
1316
1322
  }
1317
1323
  if (plan.restartProviders.size > 0) {
1318
- const skipChannelReload = process.env.NEXUS_SKIP_CHANNELS === "1" || process.env.NEXUS_SKIP_PROVIDERS === "1";
1324
+ const skipChannelReload = process.env.NEXUS_SKIP_CHANNELS === "1" ||
1325
+ process.env.NEXUS_SKIP_PROVIDERS === "1";
1319
1326
  if (skipChannelReload) {
1320
1327
  logChannels.info("skipping channel reload (NEXUS_SKIP_CHANNELS=1)");
1321
1328
  }
@@ -2,7 +2,7 @@ import os from "node:os";
2
2
  import { logDebug, logWarn } from "../logger.js";
3
3
  import { getLogger } from "../logging.js";
4
4
  function isDisabledByEnv() {
5
- if (process.env.NEXUS_DISABLE_BONJOUR === "1" || process.env.NEXUS_DISABLE_BONJOUR === "1")
5
+ if (process.env.NEXUS_DISABLE_BONJOUR === "1")
6
6
  return true;
7
7
  if (process.env.NODE_ENV === "test")
8
8
  return true;
@@ -200,7 +200,11 @@ export function recordCliCommandFinish(status = "ok") {
200
200
  export function recordCliCommandFailure(error) {
201
201
  if (!cliSession?.activeCommand)
202
202
  return;
203
- const message = error instanceof Error ? error.message : typeof error === "string" ? error : "unknown error";
203
+ const message = error instanceof Error
204
+ ? error.message
205
+ : typeof error === "string"
206
+ ? error
207
+ : "unknown error";
204
208
  writeEvent({
205
209
  id: createEventId(),
206
210
  ts: Date.now(),
@@ -227,7 +231,9 @@ export function recordCliSessionEnd(params) {
227
231
  invocation_kind: cliSession.invocationKind,
228
232
  status: params.status,
229
233
  error: params.error,
230
- data: params.exitCode !== undefined ? { exit_code: params.exitCode } : undefined,
234
+ data: params.exitCode !== undefined
235
+ ? { exit_code: params.exitCode }
236
+ : undefined,
231
237
  });
232
238
  cliSession = null;
233
239
  }
@@ -79,10 +79,9 @@ function candidateBinDirs(opts) {
79
79
  * under launchd/minimal environments (and inside the macOS bun bundle).
80
80
  */
81
81
  export function ensureNexusCliOnPath(opts = {}) {
82
- if (process.env.NEXUS_PATH_BOOTSTRAPPED === "1" || process.env.NEXUS_PATH_BOOTSTRAPPED === "1")
82
+ if (process.env.NEXUS_PATH_BOOTSTRAPPED === "1")
83
83
  return;
84
84
  process.env.NEXUS_PATH_BOOTSTRAPPED = "1";
85
- process.env.NEXUS_PATH_BOOTSTRAPPED = "1"; // keep for backward compat
86
85
  const existing = opts.pathEnv ?? process.env.PATH ?? "";
87
86
  const prepend = candidateBinDirs(opts);
88
87
  if (prepend.length === 0)
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { CLAUDE_CLI_PROFILE_ID, ensureAuthProfileStore, listProfilesForProvider, resolveApiKeyForProfile, resolveAuthProfileOrder, } from "../agents/auth-profiles.js";
5
- import { getCustomProviderApiKey, resolveEnvApiKey } from "../agents/model-auth.js";
5
+ import { getCustomProviderApiKey, resolveEnvApiKey, } from "../agents/model-auth.js";
6
6
  import { normalizeProviderId } from "../agents/model-selection.js";
7
7
  import { loadConfig } from "../config/config.js";
8
8
  function parseGoogleToken(apiKey) {
@@ -53,7 +53,8 @@ function resolveZaiApiKey() {
53
53
  }
54
54
  }
55
55
  function resolveMinimaxApiKey() {
56
- const envDirect = process.env.MINIMAX_CODE_PLAN_KEY?.trim() || process.env.MINIMAX_API_KEY?.trim();
56
+ const envDirect = process.env.MINIMAX_CODE_PLAN_KEY?.trim() ||
57
+ process.env.MINIMAX_API_KEY?.trim();
57
58
  if (envDirect)
58
59
  return envDirect;
59
60
  const envResolved = resolveEnvApiKey("minimax");
@@ -112,7 +113,8 @@ async function resolveOAuthToken(params) {
112
113
  if (!resolved?.apiKey)
113
114
  continue;
114
115
  let token = resolved.apiKey;
115
- if (params.provider === "google-gemini-cli" || params.provider === "google-antigravity") {
116
+ if (params.provider === "google-gemini-cli" ||
117
+ params.provider === "google-antigravity") {
116
118
  const parsed = parseGoogleToken(resolved.apiKey);
117
119
  token = parsed?.token ?? resolved.apiKey;
118
120
  }
@@ -1,7 +1,8 @@
1
1
  import { fetchJson } from "./provider-usage.fetch.shared.js";
2
2
  import { clampPercent, PROVIDER_LABELS } from "./provider-usage.shared.js";
3
3
  function resolveClaudeWebSessionKey() {
4
- const direct = process.env.CLAUDE_AI_SESSION_KEY?.trim() ?? process.env.CLAUDE_WEB_SESSION_KEY?.trim();
4
+ const direct = process.env.CLAUDE_AI_SESSION_KEY?.trim() ??
5
+ process.env.CLAUDE_WEB_SESSION_KEY?.trim();
5
6
  if (direct?.startsWith("sk-ant-"))
6
7
  return direct;
7
8
  const cookieHeader = process.env.CLAUDE_WEB_COOKIE?.trim();
@@ -33,14 +34,18 @@ async function fetchClaudeWebUsage(sessionKey, timeoutMs, fetchFn) {
33
34
  windows.push({
34
35
  label: "5h",
35
36
  usedPercent: clampPercent(data.five_hour.utilization),
36
- resetAt: data.five_hour.resets_at ? new Date(data.five_hour.resets_at).getTime() : undefined,
37
+ resetAt: data.five_hour.resets_at
38
+ ? new Date(data.five_hour.resets_at).getTime()
39
+ : undefined,
37
40
  });
38
41
  }
39
42
  if (data.seven_day?.utilization !== undefined) {
40
43
  windows.push({
41
44
  label: "Week",
42
45
  usedPercent: clampPercent(data.seven_day.utilization),
43
- resetAt: data.seven_day.resets_at ? new Date(data.seven_day.resets_at).getTime() : undefined,
46
+ resetAt: data.seven_day.resets_at
47
+ ? new Date(data.seven_day.resets_at).getTime()
48
+ : undefined,
44
49
  });
45
50
  }
46
51
  const modelWindow = data.seven_day_sonnet || data.seven_day_opus;
@@ -82,7 +87,8 @@ export async function fetchClaudeUsage(token, timeoutMs, fetchFn) {
82
87
  // Claude CLI setup-token yields tokens that can be used for inference, but may not
83
88
  // include user:profile scope required by the OAuth usage endpoint. When a claude.ai
84
89
  // browser sessionKey is available, fall back to the web API.
85
- if (res.status === 403 && message?.includes("scope requirement user:profile")) {
90
+ if (res.status === 403 &&
91
+ message?.includes("scope requirement user:profile")) {
86
92
  const sessionKey = resolveClaudeWebSessionKey();
87
93
  if (sessionKey) {
88
94
  const web = await fetchClaudeWebUsage(sessionKey, timeoutMs, fetchFn);
@@ -104,14 +110,18 @@ export async function fetchClaudeUsage(token, timeoutMs, fetchFn) {
104
110
  windows.push({
105
111
  label: "5h",
106
112
  usedPercent: clampPercent(data.five_hour.utilization),
107
- resetAt: data.five_hour.resets_at ? new Date(data.five_hour.resets_at).getTime() : undefined,
113
+ resetAt: data.five_hour.resets_at
114
+ ? new Date(data.five_hour.resets_at).getTime()
115
+ : undefined,
108
116
  });
109
117
  }
110
118
  if (data.seven_day?.utilization !== undefined) {
111
119
  windows.push({
112
120
  label: "Week",
113
121
  usedPercent: clampPercent(data.seven_day.utilization),
114
- resetAt: data.seven_day.resets_at ? new Date(data.seven_day.resets_at).getTime() : undefined,
122
+ resetAt: data.seven_day.resets_at
123
+ ? new Date(data.seven_day.resets_at).getTime()
124
+ : undefined,
115
125
  });
116
126
  }
117
127
  const modelWindow = data.seven_day_sonnet || data.seven_day_opus;
@@ -178,8 +178,12 @@ export async function fetchMinimaxUsage(apiKey, timeoutMs, fetchFn) {
178
178
  error: "Invalid JSON",
179
179
  };
180
180
  }
181
- const baseResp = isRecord(data.base_resp) ? data.base_resp : undefined;
182
- if (baseResp && typeof baseResp.status_code === "number" && baseResp.status_code !== 0) {
181
+ const baseResp = isRecord(data.base_resp)
182
+ ? data.base_resp
183
+ : undefined;
184
+ if (baseResp &&
185
+ typeof baseResp.status_code === "number" &&
186
+ baseResp.status_code !== 0) {
183
187
  return {
184
188
  provider: "minimax",
185
189
  displayName: PROVIDER_LABELS.minimax,
@@ -197,7 +201,8 @@ export async function fetchMinimaxUsage(apiKey, timeoutMs, fetchFn) {
197
201
  error: "Unsupported response shape",
198
202
  };
199
203
  }
200
- const resetAt = parseEpoch(pickString(payload, RESET_KEYS)) ?? parseEpoch(pickNumber(payload, RESET_KEYS));
204
+ const resetAt = parseEpoch(pickString(payload, RESET_KEYS)) ??
205
+ parseEpoch(pickNumber(payload, RESET_KEYS));
201
206
  const windows = [
202
207
  {
203
208
  label: deriveWindowLabel(payload),
@@ -1,8 +1,8 @@
1
- import { resolveProviderAuths } from "./provider-usage.auth.js";
1
+ import { resolveProviderAuths, } from "./provider-usage.auth.js";
2
2
  import { fetchClaudeUsage } from "./provider-usage.fetch.claude.js";
3
3
  import { fetchMinimaxUsage } from "./provider-usage.fetch.minimax.js";
4
- import { clampPercent, PROVIDER_LABELS } from "./provider-usage.shared.js";
5
4
  import { fetchJson } from "./provider-usage.fetch.shared.js";
5
+ import { clampPercent, PROVIDER_LABELS } from "./provider-usage.shared.js";
6
6
  function resolveProviders(params) {
7
7
  if (params.providers && params.providers.length > 0) {
8
8
  return params.providers;
@@ -50,7 +50,9 @@ async function fetchZaiUsage(apiKey, timeoutMs, fetchFn) {
50
50
  const limit = data?.data?.limits?.find((entry) => entry?.type === "TOKENS_LIMIT") ??
51
51
  data?.data?.limits?.[0];
52
52
  const usedPercent = clampPercent(limit?.percentage ?? 0);
53
- const resetAt = limit?.nextResetTime ? Date.parse(limit.nextResetTime) : undefined;
53
+ const resetAt = limit?.nextResetTime
54
+ ? Date.parse(limit.nextResetTime)
55
+ : undefined;
54
56
  const windows = [];
55
57
  if (Number.isFinite(usedPercent)) {
56
58
  windows.push({
@@ -102,7 +104,7 @@ export async function loadProviderUsageSummary(params) {
102
104
  }
103
105
  return { updatedAt: now, providers: snapshots };
104
106
  }
105
- export function formatUsageSummaryLine(summary, opts = {}) {
107
+ export function formatUsageSummaryLine(summary, _opts = {}) {
106
108
  const providers = summary.providers ?? [];
107
109
  let best;
108
110
  for (const provider of providers) {
@@ -133,7 +135,9 @@ export function formatUsageReportLines(summary, opts = {}) {
133
135
  }
134
136
  for (const window of provider.windows) {
135
137
  const remaining = Math.max(0, 100 - window.usedPercent);
136
- const reset = window.resetAt ? formatResetLabel(window.resetAt, now) : null;
138
+ const reset = window.resetAt
139
+ ? formatResetLabel(window.resetAt, now)
140
+ : null;
137
141
  const extras = [provider.plan ? `plan ${provider.plan}` : null, reset]
138
142
  .filter(Boolean)
139
143
  .join(", ");
@@ -4,7 +4,7 @@ const DEFAULT_SYSTEMD_UNIT = "nexus-gateway.service";
4
4
  export function triggerNexusRestart() {
5
5
  if (process.platform !== "darwin") {
6
6
  if (process.platform === "linux") {
7
- const unit = process.env.NEXUS_SYSTEMD_UNIT || process.env.NEXUS_SYSTEMD_UNIT || DEFAULT_SYSTEMD_UNIT;
7
+ const unit = process.env.NEXUS_SYSTEMD_UNIT || DEFAULT_SYSTEMD_UNIT;
8
8
  const userRestart = spawnSync("systemctl", ["--user", "restart", unit], {
9
9
  stdio: "ignore",
10
10
  });
@@ -21,7 +21,7 @@ export function triggerNexusRestart() {
21
21
  }
22
22
  return "supervisor";
23
23
  }
24
- const label = process.env.NEXUS_LAUNCHD_LABEL || process.env.NEXUS_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL;
24
+ const label = process.env.NEXUS_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL;
25
25
  const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
26
26
  const target = uid !== undefined ? `gui/${uid}/${label}` : label;
27
27
  spawnSync("launchctl", ["kickstart", "-k", target], { stdio: "ignore" });
@@ -0,0 +1,78 @@
1
+ const SETTINGS_URL_ENV = "NEXUS_USAGE_SETTINGS_URL";
2
+ const UPLOAD_URL_ENV = "NEXUS_USAGE_UPLOAD_URL";
3
+ const UPLOAD_TOKEN_ENV = "NEXUS_USAGE_UPLOAD_TOKEN";
4
+ export function resolveUsageSettingsUrl(env = process.env) {
5
+ const override = env[SETTINGS_URL_ENV]?.trim();
6
+ if (override)
7
+ return override;
8
+ const uploadUrl = env[UPLOAD_URL_ENV]?.trim();
9
+ if (!uploadUrl)
10
+ return null;
11
+ return uploadUrl.replace(/\/api\/usage\/upload\/?$/, "/api/usage/settings");
12
+ }
13
+ function resolveAuthHeaders(env = process.env) {
14
+ const token = env[UPLOAD_TOKEN_ENV]?.trim();
15
+ if (!token)
16
+ return {};
17
+ return { Authorization: `Bearer ${token}` };
18
+ }
19
+ function parseSettingsResponse(payload) {
20
+ if (!payload || typeof payload !== "object")
21
+ return null;
22
+ const data = payload;
23
+ if (typeof data.canOptOut !== "boolean" || typeof data.optOut !== "boolean") {
24
+ return null;
25
+ }
26
+ return {
27
+ ok: typeof data.ok === "boolean" ? data.ok : true,
28
+ canOptOut: data.canOptOut,
29
+ optOut: data.optOut,
30
+ planName: typeof data.planName === "string" ? data.planName : undefined,
31
+ error: typeof data.error === "string" ? data.error : undefined,
32
+ };
33
+ }
34
+ export async function fetchUsageTrackingSettings(env = process.env) {
35
+ const url = resolveUsageSettingsUrl(env);
36
+ if (!url)
37
+ return null;
38
+ const headers = resolveAuthHeaders(env);
39
+ if (!headers.Authorization)
40
+ return null;
41
+ try {
42
+ const res = await fetch(url, { headers });
43
+ const payload = await res.json().catch(() => null);
44
+ const parsed = parseSettingsResponse(payload);
45
+ if (!parsed)
46
+ return null;
47
+ return { ...parsed, ok: res.ok && parsed.ok };
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ export async function updateUsageTrackingSettings(optOut, env = process.env) {
54
+ const url = resolveUsageSettingsUrl(env);
55
+ if (!url)
56
+ return null;
57
+ const headers = {
58
+ "Content-Type": "application/json",
59
+ ...resolveAuthHeaders(env),
60
+ };
61
+ if (!headers.Authorization)
62
+ return null;
63
+ try {
64
+ const res = await fetch(url, {
65
+ method: "POST",
66
+ headers,
67
+ body: JSON.stringify({ optOut }),
68
+ });
69
+ const payload = await res.json().catch(() => null);
70
+ const parsed = parseSettingsResponse(payload);
71
+ if (!parsed)
72
+ return null;
73
+ return { ...parsed, ok: res.ok && parsed.ok };
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
@@ -58,17 +58,26 @@ export async function loadUsageEvents(opts = {}) {
58
58
  catch {
59
59
  continue;
60
60
  }
61
- const sessionId = String(raw.session_id ?? "");
61
+ const sessionId = typeof raw.session_id === "string" || typeof raw.session_id === "number"
62
+ ? String(raw.session_id)
63
+ : "";
62
64
  const seq = Number(raw.seq ?? 0);
63
65
  const ts = Number(raw.ts ?? 0);
64
- const source = String(raw.source ?? "");
65
- if (!sessionId || !Number.isFinite(seq) || !Number.isFinite(ts) || !source) {
66
+ const source = typeof raw.source === "string" || typeof raw.source === "number"
67
+ ? String(raw.source)
68
+ : "";
69
+ if (!sessionId ||
70
+ !Number.isFinite(seq) ||
71
+ !Number.isFinite(ts) ||
72
+ !source) {
66
73
  continue;
67
74
  }
68
75
  if (opts.sinceMs && ts < opts.sinceMs) {
69
76
  continue;
70
77
  }
71
- if (opts.sources && opts.sources.length > 0 && !opts.sources.includes(source)) {
78
+ if (opts.sources &&
79
+ opts.sources.length > 0 &&
80
+ !opts.sources.includes(source)) {
72
81
  continue;
73
82
  }
74
83
  const evt = {
@@ -76,7 +85,10 @@ export async function loadUsageEvents(opts = {}) {
76
85
  seq,
77
86
  ts,
78
87
  source,
79
- eventType: String(raw.event_type ?? ""),
88
+ eventType: typeof raw.event_type === "string" ||
89
+ typeof raw.event_type === "number"
90
+ ? String(raw.event_type)
91
+ : "",
80
92
  commandPath: typeof raw.command_path === "string" ? raw.command_path : undefined,
81
93
  stream: typeof raw.stream === "string" ? raw.stream : undefined,
82
94
  data: raw.data && typeof raw.data === "object"