@intent-systems/nexus 2026.1.5-11

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 (838) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/LICENSE +21 -0
  3. package/README-header.png +0 -0
  4. package/README.md +462 -0
  5. package/dist/agents/agent-id.js +41 -0
  6. package/dist/agents/agent-paths.js +16 -0
  7. package/dist/agents/agent-scope.js +44 -0
  8. package/dist/agents/auth-profiles.js +715 -0
  9. package/dist/agents/bash-process-registry.js +126 -0
  10. package/dist/agents/bash-tools.js +838 -0
  11. package/dist/agents/chutes-oauth.js +47 -0
  12. package/dist/agents/clawdbot-tools.js +62 -0
  13. package/dist/agents/context.js +34 -0
  14. package/dist/agents/defaults.js +6 -0
  15. package/dist/agents/identity-state.js +101 -0
  16. package/dist/agents/memory-search.js +80 -0
  17. package/dist/agents/model-auth.js +116 -0
  18. package/dist/agents/model-catalog.js +55 -0
  19. package/dist/agents/model-fallback.js +216 -0
  20. package/dist/agents/model-scan.js +263 -0
  21. package/dist/agents/model-selection.js +152 -0
  22. package/dist/agents/models-config.js +177 -0
  23. package/dist/agents/nexus-tools.js +46 -0
  24. package/dist/agents/pi-embedded-block-chunker.js +188 -0
  25. package/dist/agents/pi-embedded-helpers.js +139 -0
  26. package/dist/agents/pi-embedded-runner.js +1024 -0
  27. package/dist/agents/pi-embedded-subscribe.js +541 -0
  28. package/dist/agents/pi-embedded-utils.js +20 -0
  29. package/dist/agents/pi-embedded.js +1 -0
  30. package/dist/agents/pi-extensions/compaction-safeguard.js +140 -0
  31. package/dist/agents/pi-tool-definition-adapter.js +17 -0
  32. package/dist/agents/pi-tools.js +510 -0
  33. package/dist/agents/pi-tools.schema.js +358 -0
  34. package/dist/agents/sandbox-paths.js +68 -0
  35. package/dist/agents/sandbox.js +676 -0
  36. package/dist/agents/shell-utils.js +53 -0
  37. package/dist/agents/skill-runner.js +256 -0
  38. package/dist/agents/skill-state.js +164 -0
  39. package/dist/agents/skill-tools.js +191 -0
  40. package/dist/agents/skill-usage.js +143 -0
  41. package/dist/agents/skills-install.js +244 -0
  42. package/dist/agents/skills-status.js +154 -0
  43. package/dist/agents/skills.js +476 -0
  44. package/dist/agents/subagent-registry.js +335 -0
  45. package/dist/agents/subagent-registry.store.js +47 -0
  46. package/dist/agents/system-prompt.js +195 -0
  47. package/dist/agents/timeout.js +26 -0
  48. package/dist/agents/tool-display.js +155 -0
  49. package/dist/agents/tool-display.json +236 -0
  50. package/dist/agents/tool-images.js +138 -0
  51. package/dist/agents/tool-policy.js +103 -0
  52. package/dist/agents/tools/agent-step.js +41 -0
  53. package/dist/agents/tools/browser-tool.js +298 -0
  54. package/dist/agents/tools/canvas-tool.js +193 -0
  55. package/dist/agents/tools/common.js +88 -0
  56. package/dist/agents/tools/cron-tool.js +141 -0
  57. package/dist/agents/tools/discord-actions-guild.js +186 -0
  58. package/dist/agents/tools/discord-actions-messaging.js +313 -0
  59. package/dist/agents/tools/discord-actions-moderation.js +70 -0
  60. package/dist/agents/tools/discord-actions.js +56 -0
  61. package/dist/agents/tools/discord-schema.js +199 -0
  62. package/dist/agents/tools/discord-tool.js +16 -0
  63. package/dist/agents/tools/gateway-tool.js +46 -0
  64. package/dist/agents/tools/gateway.js +28 -0
  65. package/dist/agents/tools/image-tool.js +225 -0
  66. package/dist/agents/tools/memory-tool.js +92 -0
  67. package/dist/agents/tools/nodes-tool.js +413 -0
  68. package/dist/agents/tools/nodes-utils.js +92 -0
  69. package/dist/agents/tools/sessions-announce-target.js +39 -0
  70. package/dist/agents/tools/sessions-helpers.js +88 -0
  71. package/dist/agents/tools/sessions-history-tool.js +137 -0
  72. package/dist/agents/tools/sessions-list-tool.js +196 -0
  73. package/dist/agents/tools/sessions-send-helpers.js +103 -0
  74. package/dist/agents/tools/sessions-send-tool.js +371 -0
  75. package/dist/agents/tools/sessions-spawn-tool.js +319 -0
  76. package/dist/agents/tools/slack-actions.js +129 -0
  77. package/dist/agents/tools/slack-schema.js +59 -0
  78. package/dist/agents/tools/slack-tool.js +16 -0
  79. package/dist/agents/tools/telegram-actions.js +159 -0
  80. package/dist/agents/tools/telegram-schema.js +28 -0
  81. package/dist/agents/tools/telegram-tool.js +16 -0
  82. package/dist/agents/tools/whatsapp-login-tool.js +63 -0
  83. package/dist/agents/usage.js +58 -0
  84. package/dist/agents/workspace.js +286 -0
  85. package/dist/auto-reply/chunk.js +177 -0
  86. package/dist/auto-reply/command-auth.js +44 -0
  87. package/dist/auto-reply/command-detection.js +23 -0
  88. package/dist/auto-reply/envelope.js +30 -0
  89. package/dist/auto-reply/group-activation.js +20 -0
  90. package/dist/auto-reply/heartbeat.js +58 -0
  91. package/dist/auto-reply/model.js +22 -0
  92. package/dist/auto-reply/reply/abort.js +14 -0
  93. package/dist/auto-reply/reply/agent-runner.js +426 -0
  94. package/dist/auto-reply/reply/bash-command.js +314 -0
  95. package/dist/auto-reply/reply/block-streaming.js +34 -0
  96. package/dist/auto-reply/reply/body.js +29 -0
  97. package/dist/auto-reply/reply/commands.js +332 -0
  98. package/dist/auto-reply/reply/directive-handling.js +751 -0
  99. package/dist/auto-reply/reply/directives.js +74 -0
  100. package/dist/auto-reply/reply/dispatch-from-config.js +23 -0
  101. package/dist/auto-reply/reply/followup-runner.js +181 -0
  102. package/dist/auto-reply/reply/groups.js +152 -0
  103. package/dist/auto-reply/reply/mentions.js +64 -0
  104. package/dist/auto-reply/reply/model-selection.js +214 -0
  105. package/dist/auto-reply/reply/queue.js +399 -0
  106. package/dist/auto-reply/reply/reply-dispatcher.js +68 -0
  107. package/dist/auto-reply/reply/reply-tags.js +26 -0
  108. package/dist/auto-reply/reply/session-updates.js +103 -0
  109. package/dist/auto-reply/reply/session.js +169 -0
  110. package/dist/auto-reply/reply/typing.js +125 -0
  111. package/dist/auto-reply/reply.js +655 -0
  112. package/dist/auto-reply/send-policy.js +28 -0
  113. package/dist/auto-reply/status.js +197 -0
  114. package/dist/auto-reply/templating.js +9 -0
  115. package/dist/auto-reply/thinking.js +64 -0
  116. package/dist/auto-reply/tokens.js +2 -0
  117. package/dist/auto-reply/tool-meta.js +74 -0
  118. package/dist/auto-reply/transcription.js +57 -0
  119. package/dist/auto-reply/types.js +1 -0
  120. package/dist/browser/bridge-server.js +37 -0
  121. package/dist/browser/cdp.js +382 -0
  122. package/dist/browser/chrome.js +432 -0
  123. package/dist/browser/client-actions-core.js +67 -0
  124. package/dist/browser/client-actions-observe.js +24 -0
  125. package/dist/browser/client-actions-types.js +1 -0
  126. package/dist/browser/client-actions.js +3 -0
  127. package/dist/browser/client-fetch.js +43 -0
  128. package/dist/browser/client.js +107 -0
  129. package/dist/browser/config.js +159 -0
  130. package/dist/browser/constants.js +5 -0
  131. package/dist/browser/profiles-service.js +124 -0
  132. package/dist/browser/profiles.js +96 -0
  133. package/dist/browser/pw-ai.js +2 -0
  134. package/dist/browser/pw-session.js +144 -0
  135. package/dist/browser/pw-tools-core.js +366 -0
  136. package/dist/browser/routes/agent.js +549 -0
  137. package/dist/browser/routes/basic.js +155 -0
  138. package/dist/browser/routes/index.js +8 -0
  139. package/dist/browser/routes/tabs.js +105 -0
  140. package/dist/browser/routes/utils.js +62 -0
  141. package/dist/browser/screenshot.js +40 -0
  142. package/dist/browser/server-context.js +377 -0
  143. package/dist/browser/server.js +81 -0
  144. package/dist/browser/target-id.js +18 -0
  145. package/dist/browser/trash.js +21 -0
  146. package/dist/canvas-host/a2ui/a2ui.bundle.js +17768 -0
  147. package/dist/canvas-host/a2ui/index.html +246 -0
  148. package/dist/canvas-host/a2ui.js +187 -0
  149. package/dist/canvas-host/server.js +382 -0
  150. package/dist/capabilities/detector.js +245 -0
  151. package/dist/capabilities/registry.js +99 -0
  152. package/dist/channel-web.js +8 -0
  153. package/dist/channels/location.js +44 -0
  154. package/dist/channels/web/index.js +2 -0
  155. package/dist/cli/browser-cli-actions-input.js +459 -0
  156. package/dist/cli/browser-cli-actions-observe.js +56 -0
  157. package/dist/cli/browser-cli-examples.js +31 -0
  158. package/dist/cli/browser-cli-inspect.js +97 -0
  159. package/dist/cli/browser-cli-manage.js +286 -0
  160. package/dist/cli/browser-cli-shared.js +1 -0
  161. package/dist/cli/browser-cli.js +26 -0
  162. package/dist/cli/canvas-cli.js +416 -0
  163. package/dist/cli/cloud-cli.js +399 -0
  164. package/dist/cli/credential-cli.js +418 -0
  165. package/dist/cli/cron-cli.js +454 -0
  166. package/dist/cli/deps.js +17 -0
  167. package/dist/cli/dns-cli.js +180 -0
  168. package/dist/cli/gateway-cli.js +665 -0
  169. package/dist/cli/gateway-rpc.js +20 -0
  170. package/dist/cli/hooks-cli.js +135 -0
  171. package/dist/cli/log-cli.js +25 -0
  172. package/dist/cli/memory-cli.js +101 -0
  173. package/dist/cli/models-cli.js +248 -0
  174. package/dist/cli/nodes-camera.js +57 -0
  175. package/dist/cli/nodes-canvas.js +26 -0
  176. package/dist/cli/nodes-cli.js +946 -0
  177. package/dist/cli/nodes-screen.js +37 -0
  178. package/dist/cli/pairing-cli.js +100 -0
  179. package/dist/cli/parse-duration.js +20 -0
  180. package/dist/cli/plugins-cli.js +158 -0
  181. package/dist/cli/ports.js +97 -0
  182. package/dist/cli/profile.js +81 -0
  183. package/dist/cli/program.js +236 -0
  184. package/dist/cli/prompt.js +19 -0
  185. package/dist/cli/run-main.js +48 -0
  186. package/dist/cli/skills-cli.js +290 -0
  187. package/dist/cli/skills-hub-cli.js +1465 -0
  188. package/dist/cli/telegram-cli.js +56 -0
  189. package/dist/cli/tool-connector-cli.js +193 -0
  190. package/dist/cli/tui-cli.js +35 -0
  191. package/dist/cli/upstream-sync-cli.js +2990 -0
  192. package/dist/cli/usage-cli.js +38 -0
  193. package/dist/cli/wait.js +8 -0
  194. package/dist/commands/agent-via-gateway.js +115 -0
  195. package/dist/commands/agent.js +665 -0
  196. package/dist/commands/antigravity-oauth.js +327 -0
  197. package/dist/commands/auth-choice-options.js +85 -0
  198. package/dist/commands/auth-choice.js +286 -0
  199. package/dist/commands/auth-token.js +31 -0
  200. package/dist/commands/bootstrap-preset.js +228 -0
  201. package/dist/commands/capabilities.js +63 -0
  202. package/dist/commands/chutes-oauth.js +144 -0
  203. package/dist/commands/claude-md.js +138 -0
  204. package/dist/commands/config-view.js +11 -0
  205. package/dist/commands/config.js +85 -0
  206. package/dist/commands/configure.js +648 -0
  207. package/dist/commands/credential.js +697 -0
  208. package/dist/commands/cursor-hooks.js +240 -0
  209. package/dist/commands/cursor-rules.js +56 -0
  210. package/dist/commands/doctor-state-migrations.js +358 -0
  211. package/dist/commands/doctor-ui.js +113 -0
  212. package/dist/commands/doctor.js +674 -0
  213. package/dist/commands/health.js +112 -0
  214. package/dist/commands/identity.js +51 -0
  215. package/dist/commands/init.js +450 -0
  216. package/dist/commands/log.js +134 -0
  217. package/dist/commands/models/aliases.js +85 -0
  218. package/dist/commands/models/fallbacks.js +123 -0
  219. package/dist/commands/models/image-fallbacks.js +123 -0
  220. package/dist/commands/models/list.js +347 -0
  221. package/dist/commands/models/scan.js +271 -0
  222. package/dist/commands/models/set-image.js +27 -0
  223. package/dist/commands/models/set.js +27 -0
  224. package/dist/commands/models/shared.js +73 -0
  225. package/dist/commands/models.js +7 -0
  226. package/dist/commands/onboard-auth.js +126 -0
  227. package/dist/commands/onboard-channels.js +814 -0
  228. package/dist/commands/onboard-eve-identity.js +97 -0
  229. package/dist/commands/onboard-github.js +153 -0
  230. package/dist/commands/onboard-helpers.js +303 -0
  231. package/dist/commands/onboard-interactive.js +17 -0
  232. package/dist/commands/onboard-non-interactive.js +230 -0
  233. package/dist/commands/onboard-providers.js +829 -0
  234. package/dist/commands/onboard-quickstart.js +192 -0
  235. package/dist/commands/onboard-remote.js +120 -0
  236. package/dist/commands/onboard-skills.js +148 -0
  237. package/dist/commands/onboard-types.js +1 -0
  238. package/dist/commands/onboard.js +19 -0
  239. package/dist/commands/openai-codex-model-default.js +38 -0
  240. package/dist/commands/poll.js +64 -0
  241. package/dist/commands/quest-state.js +271 -0
  242. package/dist/commands/quest.js +67 -0
  243. package/dist/commands/reset.js +61 -0
  244. package/dist/commands/send.js +124 -0
  245. package/dist/commands/sessions-ingest.js +360 -0
  246. package/dist/commands/sessions.js +212 -0
  247. package/dist/commands/setup.js +61 -0
  248. package/dist/commands/signal-install.js +135 -0
  249. package/dist/commands/skills-manifest.js +514 -0
  250. package/dist/commands/status.js +259 -0
  251. package/dist/commands/suggestions.js +54 -0
  252. package/dist/commands/systemd-linger.js +71 -0
  253. package/dist/commands/update.js +16 -0
  254. package/dist/commands/usage-tracking.js +32 -0
  255. package/dist/commands/usage-upload.js +32 -0
  256. package/dist/config/config.js +6 -0
  257. package/dist/config/defaults.js +138 -0
  258. package/dist/config/group-policy.js +49 -0
  259. package/dist/config/includes.js +181 -0
  260. package/dist/config/io.js +260 -0
  261. package/dist/config/legacy-migrate.js +13 -0
  262. package/dist/config/legacy.js +427 -0
  263. package/dist/config/paths.js +98 -0
  264. package/dist/config/port-defaults.js +32 -0
  265. package/dist/config/schema.js +173 -0
  266. package/dist/config/sessions.js +615 -0
  267. package/dist/config/talk.js +31 -0
  268. package/dist/config/types.js +1 -0
  269. package/dist/config/validation.js +29 -0
  270. package/dist/config/zod-schema.js +1111 -0
  271. package/dist/control-plane/broker/broker.js +1022 -0
  272. package/dist/control-plane/compaction.js +282 -0
  273. package/dist/control-plane/factory.js +31 -0
  274. package/dist/control-plane/index.js +10 -0
  275. package/dist/control-plane/odu/agents.js +192 -0
  276. package/dist/control-plane/odu/interaction-tools.js +208 -0
  277. package/dist/control-plane/odu/prompt-loader.js +95 -0
  278. package/dist/control-plane/odu/runtime.js +479 -0
  279. package/dist/control-plane/odu/types.js +6 -0
  280. package/dist/control-plane/odu-control-plane.js +316 -0
  281. package/dist/control-plane/single-agent.js +249 -0
  282. package/dist/control-plane/types.js +11 -0
  283. package/dist/control-ui/assets/index-D8Q5AI4D.js +2393 -0
  284. package/dist/control-ui/assets/index-D8Q5AI4D.js.map +1 -0
  285. package/dist/control-ui/assets/index-g06q5Xc3.css +1 -0
  286. package/dist/control-ui/favicon.ico +0 -0
  287. package/dist/control-ui/index.html +16 -0
  288. package/dist/credentials/store.js +449 -0
  289. package/dist/cron/isolated-agent.js +529 -0
  290. package/dist/cron/normalize.js +73 -0
  291. package/dist/cron/parse.js +24 -0
  292. package/dist/cron/run-log.js +72 -0
  293. package/dist/cron/schedule.js +24 -0
  294. package/dist/cron/service.js +471 -0
  295. package/dist/cron/store.js +43 -0
  296. package/dist/cron/types.js +1 -0
  297. package/dist/daemon/constants.js +10 -0
  298. package/dist/daemon/launchd.js +309 -0
  299. package/dist/daemon/legacy.js +63 -0
  300. package/dist/daemon/program-args.js +141 -0
  301. package/dist/daemon/schtasks.js +269 -0
  302. package/dist/daemon/service.js +69 -0
  303. package/dist/daemon/systemd.js +332 -0
  304. package/dist/discord/index.js +2 -0
  305. package/dist/discord/monitor.js +1089 -0
  306. package/dist/discord/probe.js +54 -0
  307. package/dist/discord/send.js +652 -0
  308. package/dist/discord/token.js +8 -0
  309. package/dist/entry.js +16 -0
  310. package/dist/gateway/auth.js +121 -0
  311. package/dist/gateway/call.js +103 -0
  312. package/dist/gateway/chat-attachments.js +41 -0
  313. package/dist/gateway/client.js +180 -0
  314. package/dist/gateway/config-reload.js +279 -0
  315. package/dist/gateway/control-ui.js +184 -0
  316. package/dist/gateway/hooks-mapping.js +282 -0
  317. package/dist/gateway/hooks.js +168 -0
  318. package/dist/gateway/net.js +29 -0
  319. package/dist/gateway/protocol/index.js +62 -0
  320. package/dist/gateway/protocol/schema.js +577 -0
  321. package/dist/gateway/server-bridge-subscriptions.js +93 -0
  322. package/dist/gateway/server-bridge.js +1066 -0
  323. package/dist/gateway/server-browser.js +12 -0
  324. package/dist/gateway/server-channels.js +680 -0
  325. package/dist/gateway/server-chat.js +159 -0
  326. package/dist/gateway/server-constants.js +8 -0
  327. package/dist/gateway/server-discovery.js +62 -0
  328. package/dist/gateway/server-http.js +165 -0
  329. package/dist/gateway/server-methods/agent-job.js +114 -0
  330. package/dist/gateway/server-methods/agent.js +254 -0
  331. package/dist/gateway/server-methods/channels.js +239 -0
  332. package/dist/gateway/server-methods/chat.js +207 -0
  333. package/dist/gateway/server-methods/config.js +50 -0
  334. package/dist/gateway/server-methods/connect.js +6 -0
  335. package/dist/gateway/server-methods/cron.js +99 -0
  336. package/dist/gateway/server-methods/health.js +28 -0
  337. package/dist/gateway/server-methods/models.js +16 -0
  338. package/dist/gateway/server-methods/nodes.js +294 -0
  339. package/dist/gateway/server-methods/providers.js +257 -0
  340. package/dist/gateway/server-methods/send.js +254 -0
  341. package/dist/gateway/server-methods/sessions.js +382 -0
  342. package/dist/gateway/server-methods/skills.js +83 -0
  343. package/dist/gateway/server-methods/system.js +118 -0
  344. package/dist/gateway/server-methods/talk.js +22 -0
  345. package/dist/gateway/server-methods/types.js +1 -0
  346. package/dist/gateway/server-methods/voicewake.js +30 -0
  347. package/dist/gateway/server-methods/web.js +81 -0
  348. package/dist/gateway/server-methods/wizard.js +100 -0
  349. package/dist/gateway/server-methods.js +53 -0
  350. package/dist/gateway/server-providers.js +687 -0
  351. package/dist/gateway/server-shared.js +1 -0
  352. package/dist/gateway/server-utils.js +35 -0
  353. package/dist/gateway/server.js +1492 -0
  354. package/dist/gateway/session-utils.js +355 -0
  355. package/dist/gateway/ws-log.js +343 -0
  356. package/dist/gateway/ws-logging.js +8 -0
  357. package/dist/globals.js +41 -0
  358. package/dist/hooks/gmail-ops.js +236 -0
  359. package/dist/hooks/gmail-setup-utils.js +278 -0
  360. package/dist/hooks/gmail-watcher.js +190 -0
  361. package/dist/hooks/gmail.js +177 -0
  362. package/dist/imessage/client.js +165 -0
  363. package/dist/imessage/index.js +3 -0
  364. package/dist/imessage/monitor.js +365 -0
  365. package/dist/imessage/probe.js +26 -0
  366. package/dist/imessage/send.js +83 -0
  367. package/dist/imessage/targets.js +176 -0
  368. package/dist/index.js +55 -0
  369. package/dist/infra/agent-events.js +46 -0
  370. package/dist/infra/binaries.js +9 -0
  371. package/dist/infra/bonjour-discovery.js +163 -0
  372. package/dist/infra/bonjour.js +200 -0
  373. package/dist/infra/bridge/server.js +564 -0
  374. package/dist/infra/canvas-host-url.js +54 -0
  375. package/dist/infra/channel-summary.js +78 -0
  376. package/dist/infra/control-ui-assets.js +112 -0
  377. package/dist/infra/dotenv.js +15 -0
  378. package/dist/infra/env.js +8 -0
  379. package/dist/infra/errors.js +28 -0
  380. package/dist/infra/event-log.js +257 -0
  381. package/dist/infra/gateway-lock.js +8 -0
  382. package/dist/infra/git-commit.js +91 -0
  383. package/dist/infra/heartbeat-events.js +21 -0
  384. package/dist/infra/heartbeat-runner.js +458 -0
  385. package/dist/infra/heartbeat-wake.js +61 -0
  386. package/dist/infra/is-main.js +37 -0
  387. package/dist/infra/json-file.js +21 -0
  388. package/dist/infra/machine-name.js +40 -0
  389. package/dist/infra/nexus-root.js +56 -0
  390. package/dist/infra/node-pairing.js +212 -0
  391. package/dist/infra/path-env.js +92 -0
  392. package/dist/infra/ports.js +87 -0
  393. package/dist/infra/provider-summary.js +80 -0
  394. package/dist/infra/provider-usage.auth.js +191 -0
  395. package/dist/infra/provider-usage.fetch.claude.js +139 -0
  396. package/dist/infra/provider-usage.fetch.codex.js +62 -0
  397. package/dist/infra/provider-usage.fetch.copilot.js +42 -0
  398. package/dist/infra/provider-usage.fetch.gemini.js +57 -0
  399. package/dist/infra/provider-usage.fetch.js +6 -0
  400. package/dist/infra/provider-usage.fetch.minimax.js +219 -0
  401. package/dist/infra/provider-usage.fetch.shared.js +11 -0
  402. package/dist/infra/provider-usage.fetch.zai.js +62 -0
  403. package/dist/infra/provider-usage.format.js +77 -0
  404. package/dist/infra/provider-usage.js +149 -0
  405. package/dist/infra/provider-usage.load.js +54 -0
  406. package/dist/infra/provider-usage.shared.js +19 -0
  407. package/dist/infra/provider-usage.types.js +1 -0
  408. package/dist/infra/restart.js +29 -0
  409. package/dist/infra/retry.js +16 -0
  410. package/dist/infra/runtime-guard.js +59 -0
  411. package/dist/infra/shell-env.js +88 -0
  412. package/dist/infra/system-events.js +71 -0
  413. package/dist/infra/system-presence.js +217 -0
  414. package/dist/infra/tailnet.js +46 -0
  415. package/dist/infra/tailscale.js +149 -0
  416. package/dist/infra/unhandled-rejections.js +19 -0
  417. package/dist/infra/usage-settings.js +78 -0
  418. package/dist/infra/usage-suggestions.js +253 -0
  419. package/dist/infra/usage-upload.js +327 -0
  420. package/dist/infra/voicewake.js +78 -0
  421. package/dist/infra/widearea-dns.js +123 -0
  422. package/dist/infra/ws.js +13 -0
  423. package/dist/logger.js +52 -0
  424. package/dist/logging/redact.js +109 -0
  425. package/dist/logging.js +506 -0
  426. package/dist/macos/gateway-daemon.js +145 -0
  427. package/dist/macos/relay.js +49 -0
  428. package/dist/markdown/fences.js +58 -0
  429. package/dist/media/constants.js +33 -0
  430. package/dist/media/host.js +42 -0
  431. package/dist/media/image-ops.js +121 -0
  432. package/dist/media/mime.js +123 -0
  433. package/dist/media/parse.js +83 -0
  434. package/dist/media/server.js +64 -0
  435. package/dist/media/store.js +139 -0
  436. package/dist/memory/embeddings.js +146 -0
  437. package/dist/memory/index.js +3 -0
  438. package/dist/memory/internal.js +163 -0
  439. package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud +0 -0
  440. package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud-rs +0 -0
  441. package/dist/native/nexus-cloud/darwin-x64/nexus-cloud-rs +0 -0
  442. package/dist/native/nexus-cloud/linux-arm64/nexus-cloud-rs +0 -0
  443. package/dist/native/nexus-cloud/linux-x64/nexus-cloud-rs +0 -0
  444. package/dist/native/nexus-cloud/win32-x64/nexus-cloud-rs.exe +0 -0
  445. package/dist/pairing/pairing-store.js +218 -0
  446. package/dist/plugins/cli.js +42 -0
  447. package/dist/plugins/discovery.js +253 -0
  448. package/dist/plugins/install.js +181 -0
  449. package/dist/plugins/loader.js +290 -0
  450. package/dist/plugins/registry.js +105 -0
  451. package/dist/plugins/status.js +29 -0
  452. package/dist/plugins/tools.js +39 -0
  453. package/dist/plugins/types.js +1 -0
  454. package/dist/polls.js +43 -0
  455. package/dist/process/command-queue.js +97 -0
  456. package/dist/process/exec.js +75 -0
  457. package/dist/provider-web.js +8 -0
  458. package/dist/providers/github-copilot-auth.js +123 -0
  459. package/dist/providers/github-copilot-models.js +35 -0
  460. package/dist/providers/github-copilot-token.js +11 -0
  461. package/dist/providers/location.js +48 -0
  462. package/dist/providers/web/index.js +2 -0
  463. package/dist/routing/resolve-route.js +144 -0
  464. package/dist/routing/session-key.js +65 -0
  465. package/dist/runtime.js +8 -0
  466. package/dist/sessions/level-overrides.js +9 -0
  467. package/dist/sessions/send-policy.js +68 -0
  468. package/dist/signal/client.js +134 -0
  469. package/dist/signal/daemon.js +69 -0
  470. package/dist/signal/index.js +3 -0
  471. package/dist/signal/monitor.js +411 -0
  472. package/dist/signal/probe.js +46 -0
  473. package/dist/signal/send.js +91 -0
  474. package/dist/skills/scan-runner.js +204 -0
  475. package/dist/slack/actions.js +97 -0
  476. package/dist/slack/index.js +5 -0
  477. package/dist/slack/monitor.js +1291 -0
  478. package/dist/slack/probe.js +47 -0
  479. package/dist/slack/send.js +131 -0
  480. package/dist/slack/token.js +10 -0
  481. package/dist/telegram/allowed-updates.js +8 -0
  482. package/dist/telegram/bot.js +724 -0
  483. package/dist/telegram/download.js +34 -0
  484. package/dist/telegram/index.js +4 -0
  485. package/dist/telegram/monitor.js +47 -0
  486. package/dist/telegram/pairing-store.js +77 -0
  487. package/dist/telegram/probe.js +63 -0
  488. package/dist/telegram/proxy.js +9 -0
  489. package/dist/telegram/reaction-level.js +46 -0
  490. package/dist/telegram/send.js +151 -0
  491. package/dist/telegram/sent-message-cache.js +65 -0
  492. package/dist/telegram/token.js +30 -0
  493. package/dist/telegram/update-offset-store.js +61 -0
  494. package/dist/telegram/webhook-set.js +12 -0
  495. package/dist/telegram/webhook.js +56 -0
  496. package/dist/tui/commands.js +87 -0
  497. package/dist/tui/components/assistant-message.js +16 -0
  498. package/dist/tui/components/chat-log.js +92 -0
  499. package/dist/tui/components/custom-editor.js +55 -0
  500. package/dist/tui/components/selectors.js +8 -0
  501. package/dist/tui/components/tool-execution.js +111 -0
  502. package/dist/tui/components/user-message.js +17 -0
  503. package/dist/tui/gateway-chat.js +140 -0
  504. package/dist/tui/theme/theme.js +80 -0
  505. package/dist/tui/tui.js +708 -0
  506. package/dist/utils/provider-utils.js +28 -0
  507. package/dist/utils.js +158 -0
  508. package/dist/version.js +18 -0
  509. package/dist/web/accounts.js +86 -0
  510. package/dist/web/active-listener.js +25 -0
  511. package/dist/web/auto-reply.js +1256 -0
  512. package/dist/web/inbound.js +649 -0
  513. package/dist/web/login-qr.js +230 -0
  514. package/dist/web/login.js +71 -0
  515. package/dist/web/media.js +175 -0
  516. package/dist/web/outbound.js +102 -0
  517. package/dist/web/qr-image.js +97 -0
  518. package/dist/web/reconnect.js +60 -0
  519. package/dist/web/session.js +370 -0
  520. package/dist/wizard/clack-prompter.js +56 -0
  521. package/dist/wizard/onboarding.js +642 -0
  522. package/dist/wizard/prompts.js +6 -0
  523. package/dist/wizard/session.js +203 -0
  524. package/docs/AGENTS.default.md +116 -0
  525. package/docs/CAPABILITIES.md +444 -0
  526. package/docs/CNAME +1 -0
  527. package/docs/NEXUS_CORE_REWRITE_SPEC.md +226 -0
  528. package/docs/RELEASING.md +69 -0
  529. package/docs/_config.yml +53 -0
  530. package/docs/_layouts/default.html +145 -0
  531. package/docs/agent-assisted-install.md +95 -0
  532. package/docs/agent-loop.md +61 -0
  533. package/docs/agent-send.md +21 -0
  534. package/docs/agent.md +108 -0
  535. package/docs/android.md +133 -0
  536. package/docs/architecture.md +114 -0
  537. package/docs/assets/markdown.css +133 -0
  538. package/docs/assets/pixel-lobster.svg +60 -0
  539. package/docs/assets/terminal.css +470 -0
  540. package/docs/assets/theme.js +55 -0
  541. package/docs/audio.md +48 -0
  542. package/docs/automation/nexus-sync.md +371 -0
  543. package/docs/background-process.md +74 -0
  544. package/docs/bash.md +32 -0
  545. package/docs/bedrock.md +71 -0
  546. package/docs/bonjour.md +159 -0
  547. package/docs/browser-linux-troubleshooting.md +114 -0
  548. package/docs/browser.md +293 -0
  549. package/docs/bun.md +56 -0
  550. package/docs/camera.md +152 -0
  551. package/docs/clawd.md +212 -0
  552. package/docs/concepts/usage-tracking.md +29 -0
  553. package/docs/configuration.md +1666 -0
  554. package/docs/control-ui.md +83 -0
  555. package/docs/cron.md +385 -0
  556. package/docs/dashboard.md +17 -0
  557. package/docs/device-models.md +46 -0
  558. package/docs/discord.md +308 -0
  559. package/docs/discovery.md +112 -0
  560. package/docs/docker.md +258 -0
  561. package/docs/docs.json +105 -0
  562. package/docs/doctor.md +68 -0
  563. package/docs/elevated.md +31 -0
  564. package/docs/faq.md +736 -0
  565. package/docs/feature-inventory/overview.md +141 -0
  566. package/docs/feature-inventory/rollout-checklist.md +53 -0
  567. package/docs/feature-inventory/test-matrix.md +87 -0
  568. package/docs/feature-inventory.md +9 -0
  569. package/docs/gateway/configuration-examples.md +221 -0
  570. package/docs/gateway/configuration.md +172 -0
  571. package/docs/gateway/cron.md +61 -0
  572. package/docs/gateway/heartbeat.md +207 -0
  573. package/docs/gateway/pairing.md +109 -0
  574. package/docs/gateway-lock.md +28 -0
  575. package/docs/gateway.md +227 -0
  576. package/docs/gmail-pubsub.md +191 -0
  577. package/docs/grammy.md +27 -0
  578. package/docs/group-messages.md +73 -0
  579. package/docs/groups.md +130 -0
  580. package/docs/health.md +28 -0
  581. package/docs/heartbeat.md +73 -0
  582. package/docs/home-userspace.md +277 -0
  583. package/docs/hubs.md +148 -0
  584. package/docs/images.md +51 -0
  585. package/docs/imessage.md +94 -0
  586. package/docs/index.md +196 -0
  587. package/docs/ios.md +372 -0
  588. package/docs/linux.md +11 -0
  589. package/docs/location-command.md +95 -0
  590. package/docs/location.md +46 -0
  591. package/docs/logging.md +110 -0
  592. package/docs/lore.md +131 -0
  593. package/docs/mac/bun.md +133 -0
  594. package/docs/mac/canvas.md +161 -0
  595. package/docs/mac/child-process.md +72 -0
  596. package/docs/mac/dev-setup.md +81 -0
  597. package/docs/mac/health.md +28 -0
  598. package/docs/mac/icon.md +26 -0
  599. package/docs/mac/logging.md +51 -0
  600. package/docs/mac/menu-bar.md +69 -0
  601. package/docs/mac/peekaboo.md +170 -0
  602. package/docs/mac/permissions.md +40 -0
  603. package/docs/mac/release.md +76 -0
  604. package/docs/mac/remote.md +57 -0
  605. package/docs/mac/signing.md +41 -0
  606. package/docs/mac/skills.md +27 -0
  607. package/docs/mac/voice-overlay.md +52 -0
  608. package/docs/mac/voicewake.md +56 -0
  609. package/docs/mac/webchat.md +27 -0
  610. package/docs/mac/xpc.md +40 -0
  611. package/docs/macos.md +104 -0
  612. package/docs/model-failover.md +75 -0
  613. package/docs/models.md +91 -0
  614. package/docs/multi-agent.md +74 -0
  615. package/docs/nix.md +95 -0
  616. package/docs/nodes.md +157 -0
  617. package/docs/onboarding-config-protocol.md +34 -0
  618. package/docs/onboarding.md +189 -0
  619. package/docs/pairing.md +85 -0
  620. package/docs/plans/cron-add-hardening.md +72 -0
  621. package/docs/plans/group-policy-hardening.md +121 -0
  622. package/docs/poll.md +52 -0
  623. package/docs/prereqs.md +67 -0
  624. package/docs/presence.md +133 -0
  625. package/docs/proposals/model-config.md +147 -0
  626. package/docs/provider-routing.md +25 -0
  627. package/docs/queue.md +78 -0
  628. package/docs/reference/templates/AGENTS.md +226 -0
  629. package/docs/remote-gateway-readme.md +153 -0
  630. package/docs/remote.md +61 -0
  631. package/docs/research/memory.md +227 -0
  632. package/docs/rpc.md +35 -0
  633. package/docs/security.md +200 -0
  634. package/docs/session-ingestion.md +119 -0
  635. package/docs/session-tool.md +154 -0
  636. package/docs/session.md +85 -0
  637. package/docs/sessions.md +8 -0
  638. package/docs/setup.md +131 -0
  639. package/docs/showcase.md +37 -0
  640. package/docs/signal.md +122 -0
  641. package/docs/skills-config.md +68 -0
  642. package/docs/skills-scan.md +81 -0
  643. package/docs/skills-updates.md +113 -0
  644. package/docs/skills.md +166 -0
  645. package/docs/slack.md +221 -0
  646. package/docs/subagents.md +72 -0
  647. package/docs/tailscale.md +71 -0
  648. package/docs/talk.md +79 -0
  649. package/docs/telegram.md +96 -0
  650. package/docs/templates/AGENTS.md +226 -0
  651. package/docs/templates/BOOTSTRAP.md +55 -0
  652. package/docs/templates/IDENTITY.md +23 -0
  653. package/docs/templates/SOUL.md +41 -0
  654. package/docs/templates/TOOLS.md +41 -0
  655. package/docs/templates/USER.md +28 -0
  656. package/docs/test.md +43 -0
  657. package/docs/testing-onboarding-quickstart.md +76 -0
  658. package/docs/testing-philosophy.md +211 -0
  659. package/docs/thinking.md +46 -0
  660. package/docs/timezone.md +40 -0
  661. package/docs/tools.md +346 -0
  662. package/docs/troubleshooting.md +257 -0
  663. package/docs/tui.md +71 -0
  664. package/docs/typebox.md +42 -0
  665. package/docs/updating.md +138 -0
  666. package/docs/usage-cloud-aggregation-spec.md +133 -0
  667. package/docs/usage-suggestions-pipeline.md +126 -0
  668. package/docs/voicewake.md +61 -0
  669. package/docs/web.md +115 -0
  670. package/docs/webchat.md +34 -0
  671. package/docs/webhook.md +132 -0
  672. package/docs/whatsapp-clawd.jpg +0 -0
  673. package/docs/whatsapp.md +170 -0
  674. package/docs/windows.md +11 -0
  675. package/docs/wizard.md +167 -0
  676. package/package.json +186 -0
  677. package/patches/@mariozechner__pi-ai.patch +215 -0
  678. package/patches/playwright-core@1.57.0.patch +13 -0
  679. package/patches/qrcode-terminal.patch +12 -0
  680. package/scripts/postinstall.js +202 -0
  681. package/skills/connectors/brave-search/SKILL.md +36 -0
  682. package/skills/connectors/brave-search/docs/setup.md +40 -0
  683. package/skills/connectors/brave-search/docs/troubleshooting.md +37 -0
  684. package/skills/connectors/brave-search/docs/usage.md +28 -0
  685. package/skills/connectors/brave-search/scripts/content.mjs +53 -0
  686. package/skills/connectors/brave-search/scripts/search.mjs +79 -0
  687. package/skills/connectors/discord/SKILL.md +370 -0
  688. package/skills/connectors/gemini/SKILL.md +23 -0
  689. package/skills/connectors/github/SKILL.md +26 -0
  690. package/skills/connectors/github/docs/setup.md +21 -0
  691. package/skills/connectors/github/docs/troubleshooting.md +24 -0
  692. package/skills/connectors/google-oauth/SKILL.md +94 -0
  693. package/skills/connectors/notion/SKILL.md +156 -0
  694. package/skills/connectors/slack/SKILL.md +144 -0
  695. package/skills/connectors/telegram/SKILL.md +20 -0
  696. package/skills/connectors/telegram/docs/pairing.md +30 -0
  697. package/skills/connectors/telegram/docs/setup.md +41 -0
  698. package/skills/connectors/telegram/docs/webhook.md +17 -0
  699. package/skills/connectors/wacli/SKILL.md +48 -0
  700. package/skills/connectors/wacli/docs/auth.md +21 -0
  701. package/skills/connectors/wacli/docs/backup.md +9 -0
  702. package/skills/connectors/wacli/docs/troubleshooting.md +21 -0
  703. package/skills/guides/browser-use-agent-sdk/SKILL.md +90 -0
  704. package/skills/guides/filesystem/SKILL.md +217 -0
  705. package/skills/guides/json-render/SKILL.md +154 -0
  706. package/skills/guides/json-render/assets/components/README.md +21 -0
  707. package/skills/guides/json-render/assets/components/catalog.ts +78 -0
  708. package/skills/guides/json-render/assets/components/registry.tsx +172 -0
  709. package/skills/guides/json-render/assets/demo/App.css +397 -0
  710. package/skills/guides/json-render/assets/demo/App.tsx +897 -0
  711. package/skills/guides/json-render/assets/demo/README.md +22 -0
  712. package/skills/guides/json-render/assets/demo/catalog.ts +78 -0
  713. package/skills/guides/json-render/assets/demo/data/nexus-core.json +31 -0
  714. package/skills/guides/json-render/assets/demo/index.css +27 -0
  715. package/skills/guides/json-render/assets/demo/registry.tsx +150 -0
  716. package/skills/guides/json-render/docs/nexus-state-demo.md +84 -0
  717. package/skills/guides/json-render/docs/shadcn-preset.md +33 -0
  718. package/skills/guides/json-render/scripts/create-vite-demo.sh +45 -0
  719. package/skills/guides/json-render/scripts/llm-server/README.md +33 -0
  720. package/skills/guides/json-render/scripts/llm-server/catalog.ts +78 -0
  721. package/skills/guides/json-render/scripts/llm-server/package-lock.json +702 -0
  722. package/skills/guides/json-render/scripts/llm-server/package.json +18 -0
  723. package/skills/guides/json-render/scripts/llm-server/server.ts +285 -0
  724. package/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-311.pyc +0 -0
  725. package/skills/tools/1password/SKILL.md +54 -0
  726. package/skills/tools/1password/docs/setup.md +85 -0
  727. package/skills/tools/1password/docs/troubleshooting.md +63 -0
  728. package/skills/tools/1password/references/cli-examples.md +29 -0
  729. package/skills/tools/1password/references/get-started.md +17 -0
  730. package/skills/tools/agent-browser/SKILL.md +450 -0
  731. package/skills/tools/agent-browser/docs/browser-use-eval.md +95 -0
  732. package/skills/tools/agent-browser/docs/first-tests.md +261 -0
  733. package/skills/tools/agent-browser/docs/wordle-nyt-eval.js +32 -0
  734. package/skills/tools/aix/SKILL.md +93 -0
  735. package/skills/tools/aix/docs/embeddings.md +40 -0
  736. package/skills/tools/aix/docs/setup.md +58 -0
  737. package/skills/tools/aix/docs/troubleshooting.md +41 -0
  738. package/skills/tools/aix/references/sql.md +48 -0
  739. package/skills/tools/apple-notes/SKILL.md +50 -0
  740. package/skills/tools/apple-reminders/SKILL.md +67 -0
  741. package/skills/tools/bear-notes/SKILL.md +79 -0
  742. package/skills/tools/bird/SKILL.md +32 -0
  743. package/skills/tools/bird/docs/auth.md +31 -0
  744. package/skills/tools/bird/docs/troubleshooting.md +31 -0
  745. package/skills/tools/blogwatcher/SKILL.md +46 -0
  746. package/skills/tools/blucli/SKILL.md +27 -0
  747. package/skills/tools/camsnap/SKILL.md +25 -0
  748. package/skills/tools/clawdhub/SKILL.md +53 -0
  749. package/skills/tools/coding-agent/SKILL.md +274 -0
  750. package/skills/tools/comms/SKILL.md +249 -0
  751. package/skills/tools/comms/docs/adapters.md +54 -0
  752. package/skills/tools/comms/docs/setup.md +56 -0
  753. package/skills/tools/comms/docs/troubleshooting.md +44 -0
  754. package/skills/tools/comms/references/schema.md +49 -0
  755. package/skills/tools/computer-use/SKILL.md +204 -0
  756. package/skills/tools/computer-use/docs/open-interpreter.md +26 -0
  757. package/skills/tools/computer-use/docs/peekaboo.md +26 -0
  758. package/skills/tools/computer-use/docs/setup.md +47 -0
  759. package/skills/tools/computer-use/docs/troubleshooting.md +33 -0
  760. package/skills/tools/eightctl/SKILL.md +29 -0
  761. package/skills/tools/eve/SKILL.md +215 -0
  762. package/skills/tools/eve/docs/dual-account.md +84 -0
  763. package/skills/tools/eve/docs/intelligence.md +58 -0
  764. package/skills/tools/eve/docs/setup.md +60 -0
  765. package/skills/tools/eve/docs/troubleshooting.md +54 -0
  766. package/skills/tools/eve/scripts/setup-dual-account.sh +125 -0
  767. package/skills/tools/food-order/SKILL.md +41 -0
  768. package/skills/tools/gh/SKILL.md +22 -0
  769. package/skills/tools/gh/docs/usage.md +41 -0
  770. package/skills/tools/gifgrep/SKILL.md +47 -0
  771. package/skills/tools/gog/SKILL.md +104 -0
  772. package/skills/tools/gog/docs/portability.md +94 -0
  773. package/skills/tools/gog/docs/setup.md +76 -0
  774. package/skills/tools/gog/docs/troubleshooting.md +94 -0
  775. package/skills/tools/gog/scripts/cdp/README.md +90 -0
  776. package/skills/tools/gog/scripts/cdp/add_test_users.py +69 -0
  777. package/skills/tools/gog/scripts/cdp/auth_add_accounts.py +209 -0
  778. package/skills/tools/gog/scripts/cdp/auth_add_accounts_manual.py +206 -0
  779. package/skills/tools/gog/scripts/cdp/create_oauth_client.py +165 -0
  780. package/skills/tools/gog/scripts/cdp/launch_cdp_chrome.sh +58 -0
  781. package/skills/tools/goplaces/SKILL.md +30 -0
  782. package/skills/tools/imsg/SKILL.md +25 -0
  783. package/skills/tools/local-places/SERVER_README.md +101 -0
  784. package/skills/tools/local-places/SKILL.md +91 -0
  785. package/skills/tools/local-places/pyproject.toml +27 -0
  786. package/skills/tools/local-places/src/local_places/__init__.py +2 -0
  787. package/skills/tools/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
  788. package/skills/tools/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
  789. package/skills/tools/local-places/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
  790. package/skills/tools/local-places/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
  791. package/skills/tools/local-places/src/local_places/google_places.py +314 -0
  792. package/skills/tools/local-places/src/local_places/main.py +65 -0
  793. package/skills/tools/local-places/src/local_places/schemas.py +107 -0
  794. package/skills/tools/mcporter/SKILL.md +38 -0
  795. package/skills/tools/model-usage/SKILL.md +45 -0
  796. package/skills/tools/model-usage/references/codexbar-cli.md +28 -0
  797. package/skills/tools/model-usage/scripts/model_usage.py +310 -0
  798. package/skills/tools/nano-banana-pro/SKILL.md +30 -0
  799. package/skills/tools/nano-banana-pro/scripts/generate_image.py +169 -0
  800. package/skills/tools/nano-pdf/SKILL.md +20 -0
  801. package/skills/tools/nexus-cloud/SKILL.md +54 -0
  802. package/skills/tools/nexus-cloud/docs/security.md +24 -0
  803. package/skills/tools/nexus-cloud/docs/setup.md +51 -0
  804. package/skills/tools/nexus-cloud/docs/troubleshooting.md +28 -0
  805. package/skills/tools/obsidian/SKILL.md +55 -0
  806. package/skills/tools/openai-image-gen/SKILL.md +31 -0
  807. package/skills/tools/openai-image-gen/scripts/gen.py +173 -0
  808. package/skills/tools/openai-whisper/SKILL.md +19 -0
  809. package/skills/tools/openai-whisper-api/SKILL.md +43 -0
  810. package/skills/tools/openai-whisper-api/scripts/transcribe.sh +85 -0
  811. package/skills/tools/openhue/SKILL.md +30 -0
  812. package/skills/tools/oracle/SKILL.md +105 -0
  813. package/skills/tools/ordercli/SKILL.md +47 -0
  814. package/skills/tools/peekaboo/SKILL.md +153 -0
  815. package/skills/tools/qmd/SKILL.md +32 -0
  816. package/skills/tools/qmd/docs/mcp.md +30 -0
  817. package/skills/tools/qmd/docs/ollama.md +42 -0
  818. package/skills/tools/qmd/docs/setup.md +44 -0
  819. package/skills/tools/sag/SKILL.md +62 -0
  820. package/skills/tools/skill-cli-template/SKILL.md +109 -0
  821. package/skills/tools/songsee/SKILL.md +29 -0
  822. package/skills/tools/sonoscli/SKILL.md +26 -0
  823. package/skills/tools/spotify-player/SKILL.md +34 -0
  824. package/skills/tools/summarize/SKILL.md +49 -0
  825. package/skills/tools/things-mac/SKILL.md +61 -0
  826. package/skills/tools/tmux/SKILL.md +121 -0
  827. package/skills/tools/tmux/scripts/find-sessions.sh +112 -0
  828. package/skills/tools/tmux/scripts/wait-for-text.sh +83 -0
  829. package/skills/tools/trello/SKILL.md +84 -0
  830. package/skills/tools/upstream-sync/SKILL.md +151 -0
  831. package/skills/tools/upstream-sync/scripts/auto-port.sh +227 -0
  832. package/skills/tools/upstream-sync/scripts/check-all.sh +88 -0
  833. package/skills/tools/upstream-sync/scripts/check-nexus.sh +146 -0
  834. package/skills/tools/upstream-sync/scripts/check-pi-ai.sh +129 -0
  835. package/skills/tools/video-frames/SKILL.md +29 -0
  836. package/skills/tools/video-frames/scripts/frame.sh +81 -0
  837. package/skills/tools/weather/SKILL.md +53 -0
  838. package/skills/tools/weather/docs/usage.md +40 -0
@@ -0,0 +1,1465 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { Readable } from "node:stream";
6
+ import { pipeline } from "node:stream/promises";
7
+ import { fileTypeFromFile } from "file-type";
8
+ import { getSkillMetadata, hasBinary, loadWorkspaceSkillEntries, } from "../agents/skills.js";
9
+ import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
10
+ import { DEFAULT_AGENT_WORKSPACE_DIR } from "../agents/workspace.js";
11
+ import { generateSkillManifest, readSkillManifest, writeSkillManifest, } from "../commands/skills-manifest.js";
12
+ import { loadConfig } from "../config/config.js";
13
+ import { listCredentialEntries, resolveCredentialValue, } from "../credentials/store.js";
14
+ import { runCommandWithTimeout } from "../process/exec.js";
15
+ import { NEXUS_ROOT, resolveUserPath } from "../utils.js";
16
+ function getHubBaseUrl() {
17
+ return (process.env.NEXUS_HUB_URL ||
18
+ process.env.NEXUS_WEBSITE_URL ||
19
+ "https://getnexus.sh");
20
+ }
21
+ function normalizeSkillKey(value) {
22
+ return value.trim().toLowerCase();
23
+ }
24
+ function normalizeQuery(query) {
25
+ return query
26
+ .toLowerCase()
27
+ .split(/\s+/)
28
+ .map((token) => token.trim())
29
+ .filter(Boolean);
30
+ }
31
+ function normalizeStringList(value) {
32
+ if (Array.isArray(value)) {
33
+ return value.map((entry) => String(entry).trim()).filter(Boolean);
34
+ }
35
+ if (typeof value === "string") {
36
+ return value
37
+ .split(",")
38
+ .map((entry) => entry.trim())
39
+ .filter(Boolean);
40
+ }
41
+ return [];
42
+ }
43
+ function normalizeVersion(value) {
44
+ if (typeof value !== "string")
45
+ return null;
46
+ const trimmed = value.trim();
47
+ return trimmed ? trimmed : null;
48
+ }
49
+ function resolveLatestVersionFromPayload(payload) {
50
+ const direct = normalizeVersion(payload.latestVersion) ??
51
+ normalizeVersion(payload.version);
52
+ if (direct)
53
+ return direct;
54
+ const versions = payload.versions;
55
+ if (Array.isArray(versions) && versions.length > 0) {
56
+ const first = versions[0];
57
+ return (normalizeVersion(first?.version) ??
58
+ normalizeVersion(first?.tag) ??
59
+ null);
60
+ }
61
+ return null;
62
+ }
63
+ async function fetchHubSkillUpdateInfo(slug) {
64
+ const baseUrl = getHubBaseUrl();
65
+ const url = new URL(`/api/skills/${encodeURIComponent(slug)}`, baseUrl);
66
+ const res = await fetch(url);
67
+ if (!res.ok) {
68
+ const body = await res.text().catch(() => "");
69
+ throw new Error(`Hub skill lookup failed (${res.status}): ${body}`);
70
+ }
71
+ const data = (await res.json());
72
+ const skill = data.skill && typeof data.skill === "object"
73
+ ? data.skill
74
+ : data;
75
+ return {
76
+ slug,
77
+ name: typeof skill.name === "string" ? skill.name : undefined,
78
+ latestVersion: resolveLatestVersionFromPayload(skill),
79
+ releasedAt: typeof skill.releasedAt === "string"
80
+ ? skill.releasedAt
81
+ : typeof skill.updatedAt === "string"
82
+ ? skill.updatedAt
83
+ : undefined,
84
+ };
85
+ }
86
+ function resolveManagedSkillUpdateTargets(manifest, opts) {
87
+ const targets = [];
88
+ const only = opts.only;
89
+ for (const entry of Object.values(manifest.managed.skills)) {
90
+ const hubSlug = entry.hub?.slug;
91
+ const name = entry.name;
92
+ const candidates = [
93
+ hubSlug ? normalizeSkillKey(hubSlug) : null,
94
+ name ? normalizeSkillKey(name) : null,
95
+ ].filter(Boolean);
96
+ if (only && candidates.length > 0) {
97
+ const matches = candidates.some((candidate) => only.has(candidate));
98
+ if (!matches)
99
+ continue;
100
+ }
101
+ else if (only && candidates.length === 0) {
102
+ continue;
103
+ }
104
+ let slug = hubSlug;
105
+ if (!slug && opts.assumeName) {
106
+ slug = name;
107
+ }
108
+ if (!slug)
109
+ continue;
110
+ targets.push({ name, slug, entry });
111
+ }
112
+ return targets;
113
+ }
114
+ function normalizeHubDependencies(value) {
115
+ const raw = value && typeof value === "object"
116
+ ? value
117
+ : {};
118
+ return {
119
+ dependencies: normalizeStringList(raw.dependencies),
120
+ tools: normalizeStringList(raw.tools),
121
+ connectors: normalizeStringList(raw.connectors),
122
+ };
123
+ }
124
+ function parseFrontmatter(content) {
125
+ const trimmed = content.trimStart();
126
+ if (!trimmed.startsWith("---")) {
127
+ return { frontmatter: {}, body: content };
128
+ }
129
+ const lines = trimmed.split("\n");
130
+ let endIndex = -1;
131
+ for (let i = 1; i < lines.length; i += 1) {
132
+ if (lines[i].trim() === "---") {
133
+ endIndex = i;
134
+ break;
135
+ }
136
+ }
137
+ if (endIndex === -1) {
138
+ return { frontmatter: {}, body: content };
139
+ }
140
+ const frontLines = lines.slice(1, endIndex);
141
+ const body = lines.slice(endIndex + 1).join("\n");
142
+ const frontmatter = {};
143
+ let currentListKey = null;
144
+ for (const line of frontLines) {
145
+ const trimmedLine = line.trim();
146
+ if (!trimmedLine || trimmedLine.startsWith("#")) {
147
+ continue;
148
+ }
149
+ const listMatch = line.match(/^\s*-\s+(.+)$/);
150
+ if (listMatch && currentListKey) {
151
+ const existing = frontmatter[currentListKey];
152
+ if (!Array.isArray(existing)) {
153
+ frontmatter[currentListKey] = [];
154
+ }
155
+ frontmatter[currentListKey].push(stripQuotes(listMatch[1].trim()));
156
+ continue;
157
+ }
158
+ const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
159
+ if (!match) {
160
+ currentListKey = null;
161
+ continue;
162
+ }
163
+ const key = match[1];
164
+ const rawValue = match[2].trim();
165
+ if (!rawValue) {
166
+ frontmatter[key] = [];
167
+ currentListKey = key;
168
+ continue;
169
+ }
170
+ currentListKey = null;
171
+ frontmatter[key] = parseScalarValue(rawValue);
172
+ }
173
+ return { frontmatter, body };
174
+ }
175
+ function stripQuotes(value) {
176
+ if ((value.startsWith('"') && value.endsWith('"')) ||
177
+ (value.startsWith("'") && value.endsWith("'"))) {
178
+ return value.slice(1, -1);
179
+ }
180
+ return value;
181
+ }
182
+ function parseScalarValue(value) {
183
+ const cleaned = stripQuotes(value);
184
+ if (cleaned === "true")
185
+ return true;
186
+ if (cleaned === "false")
187
+ return false;
188
+ if (cleaned.startsWith("{") || cleaned.startsWith("[")) {
189
+ try {
190
+ return JSON.parse(cleaned);
191
+ }
192
+ catch {
193
+ return cleaned;
194
+ }
195
+ }
196
+ return cleaned;
197
+ }
198
+ function normalizeMetadata(value) {
199
+ if (!value)
200
+ return {};
201
+ if (typeof value === "object") {
202
+ return value;
203
+ }
204
+ if (typeof value === "string") {
205
+ try {
206
+ const parsed = JSON.parse(value);
207
+ if (parsed && typeof parsed === "object") {
208
+ return parsed;
209
+ }
210
+ }
211
+ catch {
212
+ return {};
213
+ }
214
+ }
215
+ return {};
216
+ }
217
+ function resolveCapabilities(entry) {
218
+ const metadata = entry.metadata;
219
+ const metadataNexus = metadata && typeof metadata.nexus === "object"
220
+ ? metadata.nexus
221
+ : undefined;
222
+ const candidates = [
223
+ entry.capabilities,
224
+ entry.provides,
225
+ metadataNexus?.provides,
226
+ metadataNexus?.capabilities,
227
+ metadata?.capabilities,
228
+ ];
229
+ for (const candidate of candidates) {
230
+ const parsed = normalizeStringList(candidate);
231
+ if (parsed.length > 0) {
232
+ return parsed;
233
+ }
234
+ }
235
+ return [];
236
+ }
237
+ function extractExcerpt(body, max = 700) {
238
+ const trimmed = body.trim();
239
+ if (!trimmed)
240
+ return "";
241
+ if (trimmed.length <= max)
242
+ return trimmed;
243
+ return `${trimmed.slice(0, max)}…`;
244
+ }
245
+ function scoreTextMatch(query, name, description) {
246
+ if (!query)
247
+ return 1;
248
+ const q = query.toLowerCase().trim();
249
+ const nameLower = name.toLowerCase();
250
+ const descLower = description.toLowerCase();
251
+ if (nameLower.includes(q))
252
+ return 100;
253
+ if (descLower.includes(q))
254
+ return 40;
255
+ const tokens = normalizeQuery(query);
256
+ let score = 0;
257
+ for (const token of tokens) {
258
+ if (nameLower.includes(token))
259
+ score += 20;
260
+ if (descLower.includes(token))
261
+ score += 8;
262
+ }
263
+ return score;
264
+ }
265
+ function extractDependencies(metadata) {
266
+ const requires = metadata?.requires ?? {};
267
+ return {
268
+ bins: requires.bins ?? [],
269
+ anyBins: requires.anyBins ?? [],
270
+ env: requires.env ?? [],
271
+ config: requires.config ?? [],
272
+ credentials: requires.credentials ?? [],
273
+ install: metadata?.install ?? [],
274
+ };
275
+ }
276
+ function manifestToMetadata(manifest) {
277
+ if (!manifest || typeof manifest !== "object")
278
+ return null;
279
+ const raw = manifest;
280
+ if (raw.nexus && typeof raw.nexus === "object")
281
+ return raw.nexus;
282
+ if (raw.metadata && typeof raw.metadata === "object") {
283
+ const nested = raw.metadata;
284
+ if (nested.nexus && typeof nested.nexus === "object")
285
+ return nested.nexus;
286
+ if (typeof nested.nexus === "string") {
287
+ try {
288
+ return JSON.parse(nested.nexus);
289
+ }
290
+ catch {
291
+ return null;
292
+ }
293
+ }
294
+ }
295
+ return null;
296
+ }
297
+ function summarizeInstallOptions(install) {
298
+ return install.map((entry) => ({
299
+ kind: entry.kind,
300
+ label: entry.label ?? "",
301
+ }));
302
+ }
303
+ async function fetchHubSkills(query, opts) {
304
+ const baseUrl = getHubBaseUrl();
305
+ const url = new URL("/api/skills/search", baseUrl);
306
+ url.searchParams.set("q", query);
307
+ url.searchParams.set("limit", String(opts.limit));
308
+ url.searchParams.set("includeManifest", "true");
309
+ if (opts.type)
310
+ url.searchParams.set("type", opts.type);
311
+ if (opts.capability)
312
+ url.searchParams.set("capability", opts.capability);
313
+ const res = await fetch(url);
314
+ if (!res.ok) {
315
+ const body = await res.text().catch(() => "");
316
+ throw new Error(`Hub search failed (${res.status}): ${body}`);
317
+ }
318
+ const data = (await res.json());
319
+ return data.skills ?? [];
320
+ }
321
+ async function fetchHubSkillDetails(slug) {
322
+ const baseUrl = getHubBaseUrl();
323
+ const url = new URL(`/api/skills/${encodeURIComponent(slug)}`, baseUrl);
324
+ const res = await fetch(url);
325
+ if (!res.ok) {
326
+ const body = await res.text().catch(() => "");
327
+ throw new Error(`Hub skill lookup failed (${res.status}): ${body}`);
328
+ }
329
+ const data = (await res.json());
330
+ if (!data.skill?.slug || !data.skill?.name) {
331
+ throw new Error("Hub skill lookup failed (invalid response)");
332
+ }
333
+ return {
334
+ slug: data.skill.slug,
335
+ name: data.skill.name,
336
+ dependencies: normalizeHubDependencies(data.skill.dependencies),
337
+ };
338
+ }
339
+ async function downloadSkillArtifact(slug) {
340
+ const baseUrl = getHubBaseUrl();
341
+ const url = new URL(`/api/skills/${encodeURIComponent(slug)}/download`, baseUrl);
342
+ const res = await fetch(url, { method: "POST" });
343
+ if (!res.ok) {
344
+ const body = await res.text().catch(() => "");
345
+ throw new Error(`Download request failed (${res.status}): ${body}`);
346
+ }
347
+ return (await res.json());
348
+ }
349
+ function slugToDirName(slug) {
350
+ return slug.replace(/[\\/]/g, "__");
351
+ }
352
+ function dirNameToSlug(dirName) {
353
+ return dirName.split("__").join("/");
354
+ }
355
+ async function ensureDir(dir) {
356
+ await fs.mkdir(dir, { recursive: true });
357
+ }
358
+ async function loadInstalledSkillSlugs(skillsRoot) {
359
+ const slugs = new Set();
360
+ const roots = ["tools", "connectors", "guides"].map((segment) => path.join(skillsRoot, segment));
361
+ for (const root of roots) {
362
+ let entries = [];
363
+ try {
364
+ entries = await fs.readdir(root, { withFileTypes: true });
365
+ }
366
+ catch {
367
+ continue;
368
+ }
369
+ for (const entry of entries) {
370
+ if (!entry.isDirectory())
371
+ continue;
372
+ if (entry.name.startsWith("."))
373
+ continue;
374
+ const slug = dirNameToSlug(entry.name);
375
+ if (!slug)
376
+ continue;
377
+ slugs.add(normalizeSkillKey(slug));
378
+ }
379
+ }
380
+ return slugs;
381
+ }
382
+ function isSkillInstalled(id, installed) {
383
+ const key = normalizeSkillKey(id);
384
+ return installed.names.has(key) || installed.slugs.has(key);
385
+ }
386
+ async function streamToFile(res, outPath) {
387
+ if (!res.body) {
388
+ throw new Error("Download response had no body");
389
+ }
390
+ await ensureDir(path.dirname(outPath));
391
+ const stream = Readable.fromWeb(res.body);
392
+ const handle = await fs.open(outPath, "w");
393
+ try {
394
+ await pipeline(stream, handle.createWriteStream());
395
+ }
396
+ finally {
397
+ await handle.close();
398
+ }
399
+ }
400
+ async function sha256File(filePath) {
401
+ const data = await fs.readFile(filePath);
402
+ return crypto.createHash("sha256").update(data).digest("hex");
403
+ }
404
+ async function extractArchive(artifactPath, destDir) {
405
+ let ext = "";
406
+ try {
407
+ const type = await fileTypeFromFile(artifactPath);
408
+ ext = type?.ext ?? "";
409
+ }
410
+ catch {
411
+ ext = "";
412
+ }
413
+ await ensureDir(destDir);
414
+ if (ext === "zip" || artifactPath.endsWith(".zip")) {
415
+ if (!hasBinary("unzip")) {
416
+ throw new Error("Missing 'unzip' binary. Install unzip or extract manually.");
417
+ }
418
+ const result = await runCommandWithTimeout(["unzip", "-q", artifactPath, "-d", destDir], 300_000);
419
+ if (result.code !== 0) {
420
+ throw new Error(result.stderr || result.stdout || "Unzip failed");
421
+ }
422
+ return;
423
+ }
424
+ if (!hasBinary("tar")) {
425
+ throw new Error("Missing 'tar' binary. Install tar or extract manually.");
426
+ }
427
+ const result = await runCommandWithTimeout(["tar", "-xf", artifactPath, "-C", destDir], 300_000);
428
+ if (result.code !== 0) {
429
+ throw new Error(result.stderr || result.stdout || "Tar extraction failed");
430
+ }
431
+ }
432
+ async function normalizeSkillRoot(destDir) {
433
+ const skillPath = path.join(destDir, "SKILL.md");
434
+ try {
435
+ await fs.access(skillPath);
436
+ return;
437
+ }
438
+ catch {
439
+ // continue
440
+ }
441
+ const entries = await fs.readdir(destDir, { withFileTypes: true });
442
+ if (entries.length !== 1)
443
+ return;
444
+ const only = entries[0];
445
+ if (!only.isDirectory())
446
+ return;
447
+ const nested = path.join(destDir, only.name);
448
+ const nestedSkill = path.join(nested, "SKILL.md");
449
+ try {
450
+ await fs.access(nestedSkill);
451
+ }
452
+ catch {
453
+ return;
454
+ }
455
+ const nestedEntries = await fs.readdir(nested);
456
+ for (const entry of nestedEntries) {
457
+ await fs.rename(path.join(nested, entry), path.join(destDir, entry));
458
+ }
459
+ await fs.rm(nested, { recursive: true, force: true });
460
+ }
461
+ async function writeHubSkillMetadata(destDir, slug) {
462
+ const skillFile = path.join(destDir, "SKILL.md");
463
+ let version;
464
+ try {
465
+ const content = await fs.readFile(skillFile, "utf-8");
466
+ const { frontmatter } = parseFrontmatter(content);
467
+ if (typeof frontmatter.version === "string") {
468
+ version = frontmatter.version.trim();
469
+ }
470
+ }
471
+ catch {
472
+ // ignore
473
+ }
474
+ const metadataPath = path.join(destDir, ".nexus-skill.json");
475
+ let existing = {};
476
+ try {
477
+ const raw = await fs.readFile(metadataPath, "utf-8");
478
+ const parsed = JSON.parse(raw);
479
+ if (parsed && typeof parsed === "object") {
480
+ existing = parsed;
481
+ }
482
+ }
483
+ catch {
484
+ existing = {};
485
+ }
486
+ const existingHub = existing.hub && typeof existing.hub === "object"
487
+ ? existing.hub
488
+ : {};
489
+ const mergedHub = {
490
+ ...existingHub,
491
+ slug,
492
+ installedVersion: version ||
493
+ (typeof existingHub.installedVersion === "string"
494
+ ? existingHub.installedVersion
495
+ : undefined),
496
+ };
497
+ const record = {
498
+ ...existing,
499
+ hub: mergedHub,
500
+ installedAt: typeof existing.installedAt === "string"
501
+ ? existing.installedAt
502
+ : new Date().toISOString(),
503
+ };
504
+ await fs.writeFile(metadataPath, JSON.stringify(record, null, 2), "utf-8");
505
+ }
506
+ async function resolveInstalledSkillType(skillDir) {
507
+ const skillFile = path.join(skillDir, "SKILL.md");
508
+ let content = "";
509
+ try {
510
+ content = await fs.readFile(skillFile, "utf-8");
511
+ }
512
+ catch {
513
+ return "guide";
514
+ }
515
+ const { frontmatter } = parseFrontmatter(content);
516
+ const rawType = typeof frontmatter.type === "string" ? frontmatter.type.trim().toLowerCase() : "";
517
+ if (rawType === "tool" || rawType === "connector" || rawType === "guide") {
518
+ return rawType;
519
+ }
520
+ const metadata = normalizeMetadata(frontmatter.metadata);
521
+ const metaType = metadata.nexus && typeof metadata.nexus === "object"
522
+ ? metadata.nexus.type
523
+ : undefined;
524
+ if (typeof metaType === "string") {
525
+ const normalized = metaType.trim().toLowerCase();
526
+ if (normalized === "tool" || normalized === "connector" || normalized === "guide") {
527
+ return normalized;
528
+ }
529
+ }
530
+ return "guide";
531
+ }
532
+ async function resolveHubDependencyPlan(slug, installed, getDetails, onMissing) {
533
+ const plan = [];
534
+ const visiting = new Set();
535
+ const visited = new Set();
536
+ const addDependency = async (depSlug) => {
537
+ const key = normalizeSkillKey(depSlug);
538
+ if (!key || isSkillInstalled(depSlug, installed) || visited.has(key)) {
539
+ return;
540
+ }
541
+ if (visiting.has(key)) {
542
+ return;
543
+ }
544
+ visiting.add(key);
545
+ let details;
546
+ try {
547
+ details = await getDetails(depSlug);
548
+ }
549
+ catch {
550
+ visiting.delete(key);
551
+ if (onMissing)
552
+ onMissing(depSlug);
553
+ return;
554
+ }
555
+ const deps = [
556
+ ...details.dependencies.tools,
557
+ ...details.dependencies.connectors,
558
+ ];
559
+ for (const dep of deps) {
560
+ await addDependency(dep);
561
+ }
562
+ visiting.delete(key);
563
+ visited.add(key);
564
+ plan.push(details.slug);
565
+ };
566
+ let root;
567
+ try {
568
+ root = await getDetails(slug);
569
+ }
570
+ catch {
571
+ if (onMissing)
572
+ onMissing(slug);
573
+ return plan;
574
+ }
575
+ const rootDeps = [
576
+ ...root.dependencies.tools,
577
+ ...root.dependencies.connectors,
578
+ ];
579
+ for (const dep of rootDeps) {
580
+ await addDependency(dep);
581
+ }
582
+ return plan;
583
+ }
584
+ async function resolveSkillFile(inputPath) {
585
+ const stats = await fs.stat(inputPath);
586
+ if (stats.isFile()) {
587
+ return { skillDir: path.dirname(inputPath), skillFile: inputPath };
588
+ }
589
+ const skillFile = path.join(inputPath, "SKILL.md");
590
+ return { skillDir: inputPath, skillFile };
591
+ }
592
+ async function createTarball(sourceDir, outPath) {
593
+ if (!hasBinary("tar")) {
594
+ throw new Error("Missing 'tar' binary. Install tar to publish skills.");
595
+ }
596
+ const result = await runCommandWithTimeout(["tar", "-czf", outPath, "-C", sourceDir, "."], 300_000);
597
+ if (result.code !== 0) {
598
+ throw new Error(result.stderr || result.stdout || "Tar failed");
599
+ }
600
+ }
601
+ async function computeArtifactInfo(filePath) {
602
+ const hash = await sha256File(filePath);
603
+ const stats = await fs.stat(filePath);
604
+ return { sha256: hash, bytes: stats.size };
605
+ }
606
+ async function resolveHubToken(input) {
607
+ if (input?.trim())
608
+ return input.trim();
609
+ const envToken = process.env.NEXUS_HUB_TOKEN ||
610
+ process.env.NEXUS_WEBSITE_TOKEN ||
611
+ process.env.SKILLS_HUB_API_TOKEN;
612
+ if (envToken?.trim())
613
+ return envToken.trim();
614
+ const entries = await listCredentialEntries();
615
+ const candidates = entries.filter((entry) => entry.service === "nexus-hub" || entry.service === "nexus-cloud");
616
+ for (const entry of candidates) {
617
+ const resolved = await resolveCredentialValue(entry.record);
618
+ if (resolved?.value) {
619
+ return resolved.value;
620
+ }
621
+ }
622
+ return null;
623
+ }
624
+ function buildManifestPayload(input) {
625
+ const { frontmatter, body, overrides } = input;
626
+ const metadata = normalizeMetadata(frontmatter.metadata);
627
+ const nexusMeta = metadata.nexus && typeof metadata.nexus === "object"
628
+ ? metadata.nexus
629
+ : {};
630
+ const name = overrides.name ||
631
+ (typeof frontmatter.name === "string" ? frontmatter.name : "") ||
632
+ "";
633
+ const description = overrides.description ||
634
+ (typeof frontmatter.description === "string"
635
+ ? frontmatter.description
636
+ : "") ||
637
+ "";
638
+ const type = overrides.type ||
639
+ (typeof frontmatter.type === "string" ? frontmatter.type : "") ||
640
+ (typeof nexusMeta.type === "string" ? nexusMeta.type : "") ||
641
+ "";
642
+ const version = overrides.version ||
643
+ (typeof frontmatter.version === "string" ? frontmatter.version : "") ||
644
+ "";
645
+ const license = overrides.license ||
646
+ (typeof frontmatter.license === "string" ? frontmatter.license : "") ||
647
+ "";
648
+ const repository = overrides.repository ||
649
+ (typeof frontmatter.repository === "string"
650
+ ? frontmatter.repository
651
+ : "") ||
652
+ (typeof frontmatter.repo === "string" ? frontmatter.repo : "") ||
653
+ "";
654
+ const homepage = overrides.homepage ||
655
+ (typeof frontmatter.homepage === "string" ? frontmatter.homepage : "") ||
656
+ (typeof frontmatter.website === "string" ? frontmatter.website : "") ||
657
+ "";
658
+ const baseManifest = {
659
+ ...frontmatter,
660
+ name,
661
+ description,
662
+ type,
663
+ version,
664
+ license,
665
+ ...(repository ? { repository } : {}),
666
+ ...(homepage ? { homepage } : {}),
667
+ };
668
+ const manifestEntry = {
669
+ ...baseManifest,
670
+ metadata: {
671
+ ...metadata,
672
+ nexus: {
673
+ ...nexusMeta,
674
+ ...(type ? { type } : {}),
675
+ },
676
+ },
677
+ };
678
+ const capabilityCandidates = {
679
+ ...manifestEntry,
680
+ capabilities: overrides.capabilities ?? manifestEntry.capabilities,
681
+ };
682
+ const capabilities = resolveCapabilities(capabilityCandidates);
683
+ if (capabilities.length > 0) {
684
+ manifestEntry.capabilities = capabilities;
685
+ const metadata = (manifestEntry.metadata ?? {});
686
+ const existingNexus = metadata.nexus && typeof metadata.nexus === "object"
687
+ ? metadata.nexus
688
+ : {};
689
+ metadata.nexus = {
690
+ ...existingNexus,
691
+ provides: capabilities,
692
+ };
693
+ manifestEntry.metadata = metadata;
694
+ }
695
+ const readmeExcerpt = extractExcerpt(body || description);
696
+ return {
697
+ name,
698
+ description,
699
+ type,
700
+ version,
701
+ license,
702
+ repository,
703
+ homepage,
704
+ capabilities,
705
+ manifest: manifestEntry,
706
+ readmeExcerpt,
707
+ };
708
+ }
709
+ async function installHubSkill(params) {
710
+ const dirName = slugToDirName(params.slug);
711
+ const download = await downloadSkillArtifact(params.slug);
712
+ if (!download.downloadUrl || !download.artifactSha256) {
713
+ throw new Error("Download URL missing from hub response");
714
+ }
715
+ const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "nexus-skill-"));
716
+ const artifactPath = path.join(tmpDir, "artifact.bin");
717
+ const extractDir = path.join(tmpDir, "skill");
718
+ const downloadHeaders = {};
719
+ if (download.cloudToken) {
720
+ downloadHeaders.authorization = `Bearer ${download.cloudToken}`;
721
+ }
722
+ const res = await fetch(download.downloadUrl, { headers: downloadHeaders });
723
+ if (!res.ok) {
724
+ const body = await res.text().catch(() => "");
725
+ throw new Error(`Download failed (${res.status}): ${body}`);
726
+ }
727
+ await streamToFile(res, artifactPath);
728
+ const hash = await sha256File(artifactPath);
729
+ if (hash !== download.artifactSha256) {
730
+ throw new Error(`Checksum mismatch (expected ${download.artifactSha256}, got ${hash})`);
731
+ }
732
+ await extractArchive(artifactPath, extractDir);
733
+ await normalizeSkillRoot(extractDir);
734
+ const skillType = await resolveInstalledSkillType(extractDir);
735
+ const targetBase = path.join(params.skillsRoot, `${skillType}s`);
736
+ const destDir = path.join(targetBase, dirName);
737
+ try {
738
+ if (!params.force) {
739
+ await fs.access(destDir);
740
+ if (params.allowSkip) {
741
+ return { installed: false, destDir };
742
+ }
743
+ throw new Error(`Skill already installed at ${destDir}. Use --force to overwrite.`);
744
+ }
745
+ await fs.rm(destDir, { recursive: true, force: true });
746
+ }
747
+ catch (err) {
748
+ if (err.code !== "ENOENT") {
749
+ throw err;
750
+ }
751
+ }
752
+ await ensureDir(targetBase);
753
+ await fs.rename(extractDir, destDir);
754
+ await writeHubSkillMetadata(destDir, params.slug);
755
+ const previous = await readSkillManifest();
756
+ const manifest = await generateSkillManifest(params.skillsRoot, params.userSkillsDir, previous);
757
+ await writeSkillManifest(manifest);
758
+ return { installed: true, destDir };
759
+ }
760
+ export function registerSkillsHubCommand(program) {
761
+ const skills = program
762
+ .command("skills")
763
+ .description("Search and install skills from the Nexus Hub");
764
+ skills
765
+ .command("search <query>")
766
+ .description("Search local skills and the Nexus Hub")
767
+ .option("--type <type>", "Filter by type (guide|tool|connector)")
768
+ .option("--capability <cap>", "Filter by capability")
769
+ .option("--limit <n>", "Hub results to return", (value) => Number(value))
770
+ .option("--local-only", "Only search local skills")
771
+ .option("--hub-only", "Only search the hub")
772
+ .option("--suggest", "Suggest up to 3 uninstalled hub skills")
773
+ .option("--json", "Output JSON")
774
+ .action(async (query, opts) => {
775
+ const suggestMode = Boolean(opts.suggest);
776
+ const limitRaw = Number(opts.limit);
777
+ const hubLimit = Number.isFinite(limitRaw) && limitRaw > 0
778
+ ? limitRaw
779
+ : suggestMode
780
+ ? 3
781
+ : 10;
782
+ const cfg = loadConfig();
783
+ const workspaceDir = resolveUserPath(cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
784
+ const skillsRoot = path.join(NEXUS_ROOT, "skills");
785
+ const status = buildWorkspaceSkillStatus(workspaceDir, {
786
+ config: cfg,
787
+ });
788
+ const metadataEntries = loadWorkspaceSkillEntries(workspaceDir, {
789
+ config: cfg,
790
+ });
791
+ const metadataByName = new Map(metadataEntries.map((entry) => [
792
+ entry.skill.name,
793
+ getSkillMetadata(entry),
794
+ ]));
795
+ const installedNames = new Set(metadataEntries.map((entry) => normalizeSkillKey(entry.skill.name)));
796
+ const installedSlugs = await loadInstalledSkillSlugs(skillsRoot);
797
+ const installedIndex = {
798
+ names: installedNames,
799
+ slugs: installedSlugs,
800
+ };
801
+ const localMatches = status.skills
802
+ .map((skill) => {
803
+ const metadata = metadataByName.get(skill.name);
804
+ let score = scoreTextMatch(query, skill.name, skill.description);
805
+ if (opts.type && metadata?.type && metadata.type !== opts.type) {
806
+ score = 0;
807
+ }
808
+ if (opts.capability) {
809
+ const provides = metadata?.provides ?? [];
810
+ if (!provides.includes(String(opts.capability))) {
811
+ score = 0;
812
+ }
813
+ }
814
+ const deps = extractDependencies(metadata ?? undefined);
815
+ return {
816
+ name: skill.name,
817
+ description: skill.description,
818
+ type: metadata?.type,
819
+ installed: true,
820
+ eligible: skill.eligible,
821
+ missing: {
822
+ bins: skill.missing.bins,
823
+ env: skill.missing.env,
824
+ config: skill.missing.config,
825
+ os: skill.missing.os,
826
+ credentials: deps.credentials,
827
+ },
828
+ install: summarizeInstallOptions(skill.install),
829
+ provides: metadata?.provides ?? [],
830
+ score,
831
+ };
832
+ })
833
+ .filter((skill) => skill.score > 0)
834
+ .sort((a, b) => b.score - a.score)
835
+ .map(({ score: _score, ...rest }) => rest);
836
+ let hubMatches = [];
837
+ if (!opts.localOnly) {
838
+ try {
839
+ const hubSkills = await fetchHubSkills(query, {
840
+ limit: Math.max(1, hubLimit),
841
+ type: opts.type,
842
+ capability: opts.capability,
843
+ });
844
+ hubMatches = hubSkills.map((skill) => {
845
+ const metadata = manifestToMetadata(skill.manifest);
846
+ const deps = extractDependencies(metadata ?? undefined);
847
+ return {
848
+ slug: skill.slug,
849
+ name: skill.name,
850
+ description: skill.description,
851
+ type: skill.type,
852
+ version: skill.version ?? null,
853
+ capabilities: skill.capabilities ?? [],
854
+ installed: installedIndex.names.has(normalizeSkillKey(skill.name)) ||
855
+ installedIndex.slugs.has(normalizeSkillKey(skill.slug)),
856
+ verified: Boolean(skill.verified),
857
+ dependencies: deps,
858
+ };
859
+ });
860
+ }
861
+ catch (err) {
862
+ if (opts.json) {
863
+ console.log(JSON.stringify({
864
+ query,
865
+ local: localMatches,
866
+ hub: [],
867
+ error: err instanceof Error ? err.message : String(err),
868
+ }, null, 2));
869
+ return;
870
+ }
871
+ console.error(`Hub search failed: ${err instanceof Error ? err.message : String(err)}`);
872
+ }
873
+ }
874
+ if (suggestMode) {
875
+ const maxSuggestions = Math.min(3, hubLimit);
876
+ const suggestions = hubMatches
877
+ .filter((skill) => !skill.installed)
878
+ .slice(0, maxSuggestions);
879
+ const suggestionDetails = await Promise.all(suggestions.map(async (skill) => {
880
+ try {
881
+ const details = await fetchHubSkillDetails(skill.slug);
882
+ return { skill, dependencies: details.dependencies };
883
+ }
884
+ catch {
885
+ return {
886
+ skill,
887
+ dependencies: { dependencies: [], tools: [], connectors: [] },
888
+ };
889
+ }
890
+ }));
891
+ if (opts.json) {
892
+ console.log(JSON.stringify({
893
+ query,
894
+ suggestions: suggestionDetails.map(({ skill, dependencies }) => ({
895
+ slug: skill.slug,
896
+ name: skill.name,
897
+ description: skill.description,
898
+ type: skill.type,
899
+ version: skill.version ?? null,
900
+ verified: Boolean(skill.verified),
901
+ dependencies,
902
+ installCommand: `nexus skills install ${skill.slug}`,
903
+ installWithDepsCommand: `nexus skills install ${skill.slug} --with-deps`,
904
+ })),
905
+ hubUrl: getHubBaseUrl(),
906
+ }, null, 2));
907
+ return;
908
+ }
909
+ console.log(`\nSuggested hub skills (${suggestionDetails.length})\n`);
910
+ if (suggestionDetails.length === 0) {
911
+ console.log(" (none)\n");
912
+ return;
913
+ }
914
+ for (const { skill, dependencies } of suggestionDetails) {
915
+ const verified = skill.verified ? "verified" : "unverified";
916
+ console.log(` 🌐 ${skill.slug} — ${skill.description} (${verified})`);
917
+ console.log(` Install → nexus skills install ${skill.slug}`);
918
+ console.log(` Install chain → nexus skills install ${skill.slug} --with-deps`);
919
+ const deps = [
920
+ dependencies.tools.length > 0
921
+ ? `Tools: ${dependencies.tools.join(", ")}`
922
+ : null,
923
+ dependencies.connectors.length > 0
924
+ ? `Connectors: ${dependencies.connectors.join(", ")}`
925
+ : null,
926
+ ].filter(Boolean);
927
+ if (deps.length > 0) {
928
+ console.log(` Requires → ${deps.join(" | ")}`);
929
+ }
930
+ }
931
+ console.log("");
932
+ return;
933
+ }
934
+ if (opts.json) {
935
+ console.log(JSON.stringify({
936
+ query,
937
+ local: opts.hubOnly ? [] : localMatches,
938
+ hub: opts.localOnly ? [] : hubMatches,
939
+ hubUrl: getHubBaseUrl(),
940
+ }, null, 2));
941
+ return;
942
+ }
943
+ if (!opts.hubOnly) {
944
+ console.log(`\nLocal matches (${localMatches.length})\n`);
945
+ if (localMatches.length === 0) {
946
+ console.log(" (none)\n");
947
+ }
948
+ else {
949
+ for (const skill of localMatches) {
950
+ const status = skill.eligible ? "✅" : "🔧";
951
+ console.log(` ${status} ${skill.name} — ${skill.description}`);
952
+ const deps = [
953
+ skill.missing.credentials.length > 0
954
+ ? `Connectors: ${skill.missing.credentials.join(", ")}`
955
+ : null,
956
+ skill.missing.bins.length > 0
957
+ ? `Bins: ${skill.missing.bins.join(", ")}`
958
+ : null,
959
+ skill.missing.env.length > 0
960
+ ? `Env: ${skill.missing.env.join(", ")}`
961
+ : null,
962
+ skill.missing.config.length > 0
963
+ ? `Config: ${skill.missing.config.join(", ")}`
964
+ : null,
965
+ ].filter(Boolean);
966
+ if (deps.length > 0) {
967
+ console.log(` Requires → ${deps.join(" | ")}`);
968
+ }
969
+ if (skill.install.length > 0) {
970
+ console.log(` Install → ${skill.install
971
+ .map((i) => i.label)
972
+ .filter(Boolean)
973
+ .join(", ")}`);
974
+ }
975
+ }
976
+ console.log("");
977
+ }
978
+ }
979
+ if (!opts.localOnly) {
980
+ console.log(`Hub matches (${hubMatches.length})\n`);
981
+ if (hubMatches.length === 0) {
982
+ console.log(" (none)\n");
983
+ }
984
+ else {
985
+ for (const skill of hubMatches) {
986
+ const status = skill.installed ? "✅" : "🌐";
987
+ const verified = skill.verified ? "verified" : "unverified";
988
+ console.log(` ${status} ${skill.slug} — ${skill.description} (${verified})`);
989
+ if (!skill.installed) {
990
+ console.log(` Install → nexus skills install ${skill.slug}`);
991
+ }
992
+ const deps = [
993
+ skill.dependencies.credentials.length > 0
994
+ ? `Connectors: ${skill.dependencies.credentials.join(", ")}`
995
+ : null,
996
+ skill.dependencies.bins.length > 0
997
+ ? `Bins: ${skill.dependencies.bins.join(", ")}`
998
+ : null,
999
+ skill.dependencies.env.length > 0
1000
+ ? `Env: ${skill.dependencies.env.join(", ")}`
1001
+ : null,
1002
+ skill.dependencies.config.length > 0
1003
+ ? `Config: ${skill.dependencies.config.join(", ")}`
1004
+ : null,
1005
+ ].filter(Boolean);
1006
+ if (deps.length > 0) {
1007
+ console.log(` Requires → ${deps.join(" | ")}`);
1008
+ }
1009
+ }
1010
+ console.log("");
1011
+ }
1012
+ }
1013
+ });
1014
+ skills
1015
+ .command("publish [skillPath]")
1016
+ .description("Publish a skill to the Nexus Hub")
1017
+ .option("--slug <slug>", "Publish a new version for an existing skill")
1018
+ .option("--name <name>", "Override skill name")
1019
+ .option("--description <description>", "Override skill description")
1020
+ .option("--type <type>", "Override skill type (guide|tool|connector)")
1021
+ .option("--version <version>", "Override skill version")
1022
+ .option("--license <license>", "Override license")
1023
+ .option("--repository <url>", "Override repository URL")
1024
+ .option("--homepage <url>", "Override homepage URL")
1025
+ .option("--visibility <value>", "public or unlisted", "public")
1026
+ .option("--capability <cap>", "Add capability", (value, prev) => {
1027
+ const list = Array.isArray(prev) ? prev : [];
1028
+ list.push(value);
1029
+ return list;
1030
+ })
1031
+ .option("--capabilities <list>", "Comma-separated capabilities")
1032
+ .option("--source <path>", "Optional source archive or directory")
1033
+ .option("--source-commit <sha>", "Optional source commit SHA")
1034
+ .option("--token <token>", "Hub API token (or NEXUS_HUB_TOKEN)")
1035
+ .option("--base <url>", "Hub base URL (default getnexus.sh)")
1036
+ .action(async (skillPath, opts) => {
1037
+ try {
1038
+ const inputPath = resolveUserPath(skillPath ?? process.cwd());
1039
+ const { skillDir, skillFile } = await resolveSkillFile(inputPath);
1040
+ const content = await fs.readFile(skillFile, "utf-8");
1041
+ const { frontmatter, body } = parseFrontmatter(content);
1042
+ const capOverrides = [
1043
+ ...(Array.isArray(opts.capability) ? opts.capability : []),
1044
+ ...normalizeStringList(opts.capabilities),
1045
+ ]
1046
+ .map((cap) => cap.trim())
1047
+ .filter(Boolean);
1048
+ const overrides = {
1049
+ path: skillDir,
1050
+ slug: typeof opts.slug === "string" ? opts.slug.trim() : undefined,
1051
+ name: typeof opts.name === "string" ? opts.name.trim() : undefined,
1052
+ description: typeof opts.description === "string"
1053
+ ? opts.description.trim()
1054
+ : undefined,
1055
+ type: typeof opts.type === "string" ? opts.type.trim() : undefined,
1056
+ version: typeof opts.version === "string" ? opts.version.trim() : undefined,
1057
+ license: typeof opts.license === "string" ? opts.license.trim() : undefined,
1058
+ repository: typeof opts.repository === "string"
1059
+ ? opts.repository.trim()
1060
+ : undefined,
1061
+ homepage: typeof opts.homepage === "string"
1062
+ ? opts.homepage.trim()
1063
+ : undefined,
1064
+ visibility: typeof opts.visibility === "string"
1065
+ ? opts.visibility.trim()
1066
+ : "public",
1067
+ capabilities: capOverrides.length > 0 ? capOverrides : undefined,
1068
+ sourcePath: typeof opts.source === "string"
1069
+ ? resolveUserPath(opts.source)
1070
+ : undefined,
1071
+ sourceCommit: typeof opts.sourceCommit === "string"
1072
+ ? opts.sourceCommit.trim()
1073
+ : undefined,
1074
+ token: typeof opts.token === "string" ? opts.token.trim() : undefined,
1075
+ baseUrl: typeof opts.base === "string" ? opts.base.trim() : undefined,
1076
+ };
1077
+ const token = await resolveHubToken(overrides.token);
1078
+ if (!token) {
1079
+ throw new Error("Missing hub token. Run `nexus cloud login` or set NEXUS_HUB_TOKEN.");
1080
+ }
1081
+ const payload = buildManifestPayload({
1082
+ frontmatter,
1083
+ body,
1084
+ overrides,
1085
+ });
1086
+ const missing = [];
1087
+ if (!payload.name)
1088
+ missing.push("name");
1089
+ if (!payload.description)
1090
+ missing.push("description");
1091
+ if (!payload.type)
1092
+ missing.push("type");
1093
+ if (!payload.version)
1094
+ missing.push("version");
1095
+ if (!payload.license)
1096
+ missing.push("license");
1097
+ if (missing.length > 0) {
1098
+ throw new Error(`Missing required fields: ${missing.join(", ")} (use flags or frontmatter)`);
1099
+ }
1100
+ const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "nexus-skill-publish-"));
1101
+ const artifactPath = path.join(tmpDir, "artifact.tgz");
1102
+ await createTarball(skillDir, artifactPath);
1103
+ const artifact = await computeArtifactInfo(artifactPath);
1104
+ let source = null;
1105
+ let sourcePath = null;
1106
+ if (overrides.sourcePath) {
1107
+ const sourceStats = await fs.stat(overrides.sourcePath);
1108
+ if (sourceStats.isDirectory()) {
1109
+ sourcePath = path.join(tmpDir, "source.tgz");
1110
+ await createTarball(overrides.sourcePath, sourcePath);
1111
+ }
1112
+ else {
1113
+ sourcePath = overrides.sourcePath;
1114
+ }
1115
+ source = await computeArtifactInfo(sourcePath);
1116
+ }
1117
+ const baseUrl = overrides.baseUrl || getHubBaseUrl();
1118
+ const endpoint = overrides.slug
1119
+ ? `/api/skills/${encodeURIComponent(overrides.slug)}/versions`
1120
+ : "/api/skills";
1121
+ const response = await fetch(new URL(endpoint, baseUrl), {
1122
+ method: "POST",
1123
+ headers: {
1124
+ "content-type": "application/json",
1125
+ authorization: `Bearer ${token}`,
1126
+ },
1127
+ body: JSON.stringify({
1128
+ name: payload.name,
1129
+ description: payload.description,
1130
+ type: payload.type,
1131
+ version: payload.version,
1132
+ license: payload.license,
1133
+ repository: payload.repository || "",
1134
+ homepage: payload.homepage || "",
1135
+ visibility: overrides.visibility || "public",
1136
+ sourceCommit: overrides.sourceCommit || "",
1137
+ capabilities: payload.capabilities,
1138
+ readmeExcerpt: payload.readmeExcerpt,
1139
+ manifest: payload.manifest,
1140
+ artifact: { sha256: artifact.sha256, bytes: artifact.bytes },
1141
+ ...(source
1142
+ ? { source: { sha256: source.sha256, bytes: source.bytes } }
1143
+ : {}),
1144
+ }),
1145
+ });
1146
+ const data = await response.json().catch(() => ({}));
1147
+ if (!response.ok) {
1148
+ if (response.status === 409 && !overrides.slug) {
1149
+ throw new Error("Skill already exists. Re-run with --slug <owner/name> to publish a new version.");
1150
+ }
1151
+ throw new Error(data?.error || `Publish failed (${response.status})`);
1152
+ }
1153
+ const upload = data?.upload;
1154
+ const needed = Array.isArray(upload?.needed) ? upload.needed : [];
1155
+ const fileMap = new Map([
1156
+ [artifact.sha256, artifactPath],
1157
+ ]);
1158
+ if (source && sourcePath) {
1159
+ fileMap.set(source.sha256, sourcePath);
1160
+ }
1161
+ for (const item of needed) {
1162
+ if (!item?.id || !item?.url)
1163
+ continue;
1164
+ const filePath = fileMap.get(item.id);
1165
+ if (!filePath)
1166
+ continue;
1167
+ const blob = await fs.readFile(filePath);
1168
+ const headers = {};
1169
+ if (upload?.cloudToken && item.url.includes("/api/v1/blobs/")) {
1170
+ headers.authorization = `Bearer ${upload.cloudToken}`;
1171
+ }
1172
+ const uploadResp = await fetch(item.url, {
1173
+ method: "PUT",
1174
+ headers,
1175
+ body: blob,
1176
+ });
1177
+ if (!uploadResp.ok) {
1178
+ const bodyText = await uploadResp.text().catch(() => "");
1179
+ throw new Error(`Upload failed (${uploadResp.status}): ${bodyText || "unknown error"}`);
1180
+ }
1181
+ }
1182
+ console.log(`✅ Published ${payload.name} (${payload.version})` +
1183
+ (data?.skill?.slug ? ` as ${data.skill.slug}` : ""));
1184
+ if (needed.length > 0) {
1185
+ console.log(` Uploaded ${needed.length} artifact(s)`);
1186
+ }
1187
+ }
1188
+ catch (err) {
1189
+ console.error(err instanceof Error ? err.message : `Publish failed: ${String(err)}`);
1190
+ process.exit(1);
1191
+ }
1192
+ });
1193
+ skills
1194
+ .command("install <slug>")
1195
+ .description("Install a skill from the Nexus Hub")
1196
+ .option("--force", "Overwrite if destination exists")
1197
+ .option("--with-deps", "Install tool/connector dependencies first")
1198
+ .action(async (slug, opts) => {
1199
+ try {
1200
+ const cfg = loadConfig();
1201
+ const workspaceDir = resolveUserPath(cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
1202
+ const userSkillsDir = path.join(workspaceDir, "skills");
1203
+ const skillsRoot = path.join(NEXUS_ROOT, "skills");
1204
+ const metadataEntries = loadWorkspaceSkillEntries(workspaceDir, {
1205
+ config: cfg,
1206
+ });
1207
+ const installedNames = new Set(metadataEntries.map((entry) => normalizeSkillKey(entry.skill.name)));
1208
+ const installedSlugs = await loadInstalledSkillSlugs(skillsRoot);
1209
+ const installedIndex = {
1210
+ names: installedNames,
1211
+ slugs: installedSlugs,
1212
+ };
1213
+ const detailsCache = new Map();
1214
+ const getDetails = async (detailSlug) => {
1215
+ const key = normalizeSkillKey(detailSlug);
1216
+ const cached = detailsCache.get(key);
1217
+ if (cached)
1218
+ return cached;
1219
+ const details = await fetchHubSkillDetails(detailSlug);
1220
+ detailsCache.set(key, details);
1221
+ return details;
1222
+ };
1223
+ if (opts.withDeps) {
1224
+ const missingDeps = [];
1225
+ const plan = await resolveHubDependencyPlan(slug, installedIndex, getDetails, (missing) => {
1226
+ missingDeps.push(missing);
1227
+ });
1228
+ if (plan.length > 0) {
1229
+ console.log(`\nInstalling dependencies (${plan.length})...\n`);
1230
+ }
1231
+ for (const dep of plan) {
1232
+ const result = await installHubSkill({
1233
+ slug: dep,
1234
+ skillsRoot,
1235
+ userSkillsDir,
1236
+ allowSkip: true,
1237
+ });
1238
+ if (result.installed) {
1239
+ installedIndex.slugs.add(normalizeSkillKey(dep));
1240
+ const detail = detailsCache.get(normalizeSkillKey(dep));
1241
+ if (detail?.name) {
1242
+ installedIndex.names.add(normalizeSkillKey(detail.name));
1243
+ }
1244
+ console.log(`✅ Installed dependency ${dep}`);
1245
+ }
1246
+ else {
1247
+ console.log(`⏭️ Dependency already installed: ${dep}`);
1248
+ }
1249
+ }
1250
+ if (plan.length > 0) {
1251
+ console.log("");
1252
+ }
1253
+ if (missingDeps.length > 0) {
1254
+ console.log(`⚠️ Missing dependencies in hub: ${missingDeps.join(", ")}`);
1255
+ }
1256
+ }
1257
+ const result = await installHubSkill({
1258
+ slug,
1259
+ skillsRoot,
1260
+ userSkillsDir,
1261
+ force: Boolean(opts.force),
1262
+ });
1263
+ console.log(`✅ Installed ${slug} to ${result.destDir}`);
1264
+ console.log(` Run: nexus skill use ${path.basename(slug)}`);
1265
+ }
1266
+ catch (err) {
1267
+ console.error(err instanceof Error ? err.message : `Install failed: ${String(err)}`);
1268
+ process.exit(1);
1269
+ }
1270
+ });
1271
+ skills
1272
+ .command("updates")
1273
+ .description("Check for updates to managed skills")
1274
+ .option("--json", "Output JSON")
1275
+ .option("--only <list>", "Comma-separated skill slugs or names")
1276
+ .option("--assume-name", "Use the skill name as a hub slug when missing")
1277
+ .action(async (opts) => {
1278
+ const cfg = loadConfig();
1279
+ const workspaceDir = resolveUserPath(cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
1280
+ const skillsRoot = path.join(NEXUS_ROOT, "skills");
1281
+ const userSkillsDir = path.join(workspaceDir, "skills");
1282
+ const previous = await readSkillManifest();
1283
+ const manifest = previous ??
1284
+ (await generateSkillManifest(skillsRoot, userSkillsDir, previous));
1285
+ const onlyList = normalizeStringList(opts.only);
1286
+ const only = onlyList.length > 0
1287
+ ? new Set(onlyList.map((value) => normalizeSkillKey(value)))
1288
+ : undefined;
1289
+ const targets = resolveManagedSkillUpdateTargets(manifest, {
1290
+ only,
1291
+ assumeName: Boolean(opts.assumeName),
1292
+ });
1293
+ if (targets.length === 0) {
1294
+ const message = "No managed skills matched for update checks.";
1295
+ if (opts.json) {
1296
+ console.log(JSON.stringify({ checkedAt: new Date().toISOString(), results: [], message }, null, 2));
1297
+ }
1298
+ else {
1299
+ console.log(message);
1300
+ }
1301
+ return;
1302
+ }
1303
+ const checkedAt = new Date().toISOString();
1304
+ const results = [];
1305
+ for (const target of targets) {
1306
+ const entry = target.entry;
1307
+ const hub = entry.hub ?? {};
1308
+ hub.slug = hub.slug ?? target.slug;
1309
+ const installedVersion = hub.installedVersion ?? entry.version ?? null;
1310
+ if (!hub.installedVersion && installedVersion) {
1311
+ hub.installedVersion = installedVersion;
1312
+ }
1313
+ try {
1314
+ const info = await fetchHubSkillUpdateInfo(target.slug);
1315
+ const latestVersion = info.latestVersion ?? null;
1316
+ hub.latestVersion = latestVersion ?? undefined;
1317
+ hub.lastCheckedAt = checkedAt;
1318
+ hub.lastError = undefined;
1319
+ entry.hub = hub;
1320
+ let status = "unknown";
1321
+ if (latestVersion && installedVersion) {
1322
+ status = latestVersion === installedVersion ? "up-to-date" : "update";
1323
+ }
1324
+ else if (latestVersion && !installedVersion) {
1325
+ status = "unknown";
1326
+ }
1327
+ results.push({
1328
+ name: target.name,
1329
+ slug: target.slug,
1330
+ installedVersion,
1331
+ latestVersion,
1332
+ managedModified: Boolean(entry.managedModified),
1333
+ status,
1334
+ });
1335
+ }
1336
+ catch (err) {
1337
+ const message = err instanceof Error ? err.message : String(err);
1338
+ hub.lastCheckedAt = checkedAt;
1339
+ hub.lastError = message;
1340
+ entry.hub = hub;
1341
+ results.push({
1342
+ name: target.name,
1343
+ slug: target.slug,
1344
+ installedVersion,
1345
+ latestVersion: null,
1346
+ managedModified: Boolean(entry.managedModified),
1347
+ status: "error",
1348
+ error: message,
1349
+ });
1350
+ }
1351
+ }
1352
+ await writeSkillManifest(manifest);
1353
+ if (opts.json) {
1354
+ console.log(JSON.stringify({
1355
+ checkedAt,
1356
+ total: results.length,
1357
+ updates: results.filter((r) => r.status === "update"),
1358
+ results,
1359
+ }, null, 2));
1360
+ return;
1361
+ }
1362
+ const updates = results.filter((r) => r.status === "update");
1363
+ const upToDate = results.filter((r) => r.status === "up-to-date");
1364
+ const errors = results.filter((r) => r.status === "error");
1365
+ const unknown = results.filter((r) => r.status === "unknown");
1366
+ console.log(`\nSkill updates (${updates.length})\n`);
1367
+ if (updates.length === 0) {
1368
+ console.log(" (none)\n");
1369
+ }
1370
+ else {
1371
+ for (const item of updates) {
1372
+ const flag = item.managedModified ? " (modified)" : "";
1373
+ console.log(` ⬆️ ${item.slug} ${item.installedVersion ?? "?"} → ${item.latestVersion ?? "?"}${flag}`);
1374
+ }
1375
+ console.log("");
1376
+ }
1377
+ if (upToDate.length > 0) {
1378
+ console.log(`Up to date (${upToDate.length})`);
1379
+ }
1380
+ if (unknown.length > 0) {
1381
+ console.log(`Unknown version (${unknown.length})`);
1382
+ }
1383
+ if (errors.length > 0) {
1384
+ console.log(`Errors (${errors.length})`);
1385
+ for (const item of errors) {
1386
+ console.log(` ⚠️ ${item.slug}: ${item.error}`);
1387
+ }
1388
+ }
1389
+ console.log("");
1390
+ });
1391
+ skills
1392
+ .command("update <slug>")
1393
+ .description("Update a managed skill from the Nexus Hub")
1394
+ .option("--force", "Overwrite local edits if present")
1395
+ .action(async (slug, opts) => {
1396
+ try {
1397
+ const cfg = loadConfig();
1398
+ const workspaceDir = resolveUserPath(cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
1399
+ const skillsRoot = path.join(NEXUS_ROOT, "skills");
1400
+ const userSkillsDir = path.join(workspaceDir, "skills");
1401
+ const previous = await readSkillManifest();
1402
+ const manifest = previous ??
1403
+ (await generateSkillManifest(skillsRoot, userSkillsDir, previous));
1404
+ const normalized = normalizeSkillKey(slug);
1405
+ const managedEntries = Object.values(manifest.managed.skills);
1406
+ const entry = managedEntries.find((item) => {
1407
+ const hubSlug = item.hub?.slug ? normalizeSkillKey(item.hub.slug) : null;
1408
+ const nameKey = normalizeSkillKey(item.name);
1409
+ return hubSlug === normalized || nameKey === normalized;
1410
+ });
1411
+ if (!entry) {
1412
+ throw new Error(`Managed skill not found: ${slug}`);
1413
+ }
1414
+ if (entry.managedModified && !opts.force) {
1415
+ console.error(`Update available for ${slug}, but local edits were detected.\n` +
1416
+ `Update will overwrite local changes.\n` +
1417
+ `Use --force to overwrite, or keep your local version.`);
1418
+ process.exit(2);
1419
+ }
1420
+ const hubSlug = entry.hub?.slug ?? slug;
1421
+ const installedVersion = entry.hub?.installedVersion ?? entry.version ?? null;
1422
+ try {
1423
+ const info = await fetchHubSkillUpdateInfo(hubSlug);
1424
+ const latestVersion = info.latestVersion ?? null;
1425
+ const hub = entry.hub ?? {};
1426
+ hub.slug = hub.slug ?? hubSlug;
1427
+ hub.installedVersion =
1428
+ hub.installedVersion ?? installedVersion ?? undefined;
1429
+ hub.latestVersion = latestVersion ?? undefined;
1430
+ hub.lastCheckedAt = new Date().toISOString();
1431
+ hub.lastError = undefined;
1432
+ entry.hub = hub;
1433
+ if (latestVersion &&
1434
+ installedVersion &&
1435
+ latestVersion === installedVersion &&
1436
+ !opts.force) {
1437
+ await writeSkillManifest(manifest);
1438
+ console.log(`✅ ${hubSlug} is already up to date (${latestVersion}).`);
1439
+ return;
1440
+ }
1441
+ }
1442
+ catch (err) {
1443
+ const message = err instanceof Error ? err.message : String(err);
1444
+ const hub = entry.hub ?? {};
1445
+ hub.slug = hub.slug ?? hubSlug;
1446
+ hub.lastCheckedAt = new Date().toISOString();
1447
+ hub.lastError = message;
1448
+ entry.hub = hub;
1449
+ await writeSkillManifest(manifest);
1450
+ }
1451
+ const result = await installHubSkill({
1452
+ slug: hubSlug,
1453
+ skillsRoot,
1454
+ userSkillsDir,
1455
+ force: true,
1456
+ });
1457
+ console.log(`✅ Updated ${hubSlug} at ${result.destDir}`);
1458
+ }
1459
+ catch (err) {
1460
+ console.error(err instanceof Error ? err.message : `Update failed: ${String(err)}`);
1461
+ process.exit(1);
1462
+ }
1463
+ });
1464
+ }
1465
+ // Cloud login moved to cloud-cli.