@zenalexa/unicli 0.208.0 → 0.210.0
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.
- package/AGENTS.md +56 -15
- package/README.md +228 -278
- package/dist/adapters/cursor/cursor.d.ts +2 -1
- package/dist/adapters/cursor/cursor.d.ts.map +1 -1
- package/dist/adapters/cursor/cursor.js +87 -1
- package/dist/adapters/cursor/cursor.js.map +1 -1
- package/dist/adapters/discord-app/discord-app.d.ts +1 -1
- package/dist/adapters/discord-app/discord-app.js +94 -1
- package/dist/adapters/discord-app/discord-app.js.map +1 -1
- package/dist/browser/bridge.d.ts +45 -0
- package/dist/browser/bridge.d.ts.map +1 -1
- package/dist/browser/bridge.js +94 -1
- package/dist/browser/bridge.js.map +1 -1
- package/dist/browser/cdp-client.d.ts +24 -1
- package/dist/browser/cdp-client.d.ts.map +1 -1
- package/dist/browser/cdp-client.js +56 -2
- package/dist/browser/cdp-client.js.map +1 -1
- package/dist/browser/launcher.d.ts +5 -0
- package/dist/browser/launcher.d.ts.map +1 -1
- package/dist/browser/launcher.js +7 -0
- package/dist/browser/launcher.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +73 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +82 -2
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/browser.d.ts.map +1 -1
- package/dist/commands/browser.js +79 -1
- package/dist/commands/browser.js.map +1 -1
- package/dist/commands/ext.d.ts +11 -0
- package/dist/commands/ext.d.ts.map +1 -0
- package/dist/commands/ext.js +122 -0
- package/dist/commands/ext.js.map +1 -0
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +20 -1
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/hub.d.ts +13 -0
- package/dist/commands/hub.d.ts.map +1 -0
- package/dist/commands/hub.js +232 -0
- package/dist/commands/hub.js.map +1 -0
- package/dist/commands/research.d.ts +17 -0
- package/dist/commands/research.d.ts.map +1 -0
- package/dist/commands/research.js +257 -0
- package/dist/commands/research.js.map +1 -0
- package/dist/commands/skills.d.ts +2 -3
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +2 -3
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +137 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/test-gen.d.ts +10 -0
- package/dist/commands/test-gen.d.ts.map +1 -0
- package/dist/commands/test-gen.js +124 -0
- package/dist/commands/test-gen.js.map +1 -0
- package/dist/discovery/loader.d.ts.map +1 -1
- package/dist/discovery/loader.js +3 -0
- package/dist/discovery/loader.js.map +1 -1
- package/dist/engine/capability.d.ts +40 -0
- package/dist/engine/capability.d.ts.map +1 -0
- package/dist/engine/capability.js +191 -0
- package/dist/engine/capability.js.map +1 -0
- package/dist/engine/endpoint.d.ts +47 -0
- package/dist/engine/endpoint.d.ts.map +1 -0
- package/dist/engine/endpoint.js +295 -0
- package/dist/engine/endpoint.js.map +1 -0
- package/dist/engine/framework.d.ts +28 -0
- package/dist/engine/framework.d.ts.map +1 -0
- package/dist/engine/framework.js +66 -0
- package/dist/engine/framework.js.map +1 -0
- package/dist/engine/probe.d.ts +19 -0
- package/dist/engine/probe.d.ts.map +1 -0
- package/dist/engine/probe.js +85 -0
- package/dist/engine/probe.js.map +1 -0
- package/dist/engine/research.d.ts +38 -0
- package/dist/engine/research.d.ts.map +1 -0
- package/dist/engine/research.js +414 -0
- package/dist/engine/research.js.map +1 -0
- package/dist/engine/yaml-runner.d.ts +10 -0
- package/dist/engine/yaml-runner.d.ts.map +1 -1
- package/dist/engine/yaml-runner.js +131 -8
- package/dist/engine/yaml-runner.js.map +1 -1
- package/dist/hub/index.d.ts +37 -0
- package/dist/hub/index.d.ts.map +1 -0
- package/dist/hub/index.js +98 -0
- package/dist/hub/index.js.map +1 -0
- package/dist/hub/passthrough.d.ts +21 -0
- package/dist/hub/passthrough.d.ts.map +1 -0
- package/dist/hub/passthrough.js +71 -0
- package/dist/hub/passthrough.js.map +1 -0
- package/dist/manifest.json +2242 -134
- package/dist/mcp/server.js +59 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -1
- package/src/adapters/36kr/latest.yaml +36 -0
- package/src/adapters/arxiv/trending.yaml +37 -0
- package/src/adapters/baidu/hot.yaml +37 -0
- package/src/adapters/baidu/search.yaml +41 -0
- package/src/adapters/bbc/technology.yaml +26 -0
- package/src/adapters/bbc/top.yaml +26 -0
- package/src/adapters/bbc/world.yaml +26 -0
- package/src/adapters/bilibili/coin.yaml +33 -0
- package/src/adapters/bilibili/later.yaml +31 -0
- package/src/adapters/bilibili/live.yaml +41 -0
- package/src/adapters/bilibili/trending.yaml +29 -0
- package/src/adapters/binance/hot.yaml +39 -0
- package/src/adapters/binance/kline.yaml +35 -0
- package/src/adapters/binance/ticker.yaml +33 -0
- package/src/adapters/bluesky/likes.yaml +35 -0
- package/src/adapters/bluesky/notifications.yaml +30 -0
- package/src/adapters/bluesky/post.yaml +25 -0
- package/src/adapters/chrome/bookmarks.yaml +26 -0
- package/src/adapters/chrome/tabs.yaml +25 -0
- package/src/adapters/cnki/search.yaml +40 -0
- package/src/adapters/cnn/technology.yaml +26 -0
- package/src/adapters/cnn/top.yaml +21 -0
- package/src/adapters/cocoapods/info.yaml +33 -0
- package/src/adapters/cocoapods/search.yaml +16 -0
- package/src/adapters/coinbase/prices.yaml +27 -0
- package/src/adapters/coinbase/rates.yaml +24 -0
- package/src/adapters/coupang/hot.yaml +29 -0
- package/src/adapters/crates-io/info.yaml +29 -0
- package/src/adapters/crates-io/search.yaml +27 -0
- package/src/adapters/crates-io/versions.yaml +33 -0
- package/src/adapters/ctrip/hot.yaml +28 -0
- package/src/adapters/cursor/cursor.ts +91 -1
- package/src/adapters/dangdang/hot.yaml +38 -0
- package/src/adapters/dangdang/search.yaml +43 -0
- package/src/adapters/deepseek/chat.yaml +33 -0
- package/src/adapters/deepseek/models.yaml +18 -0
- package/src/adapters/devto/latest.yaml +29 -0
- package/src/adapters/devto/search.yaml +34 -0
- package/src/adapters/dianping/hot.yaml +43 -0
- package/src/adapters/dianping/search.yaml +48 -0
- package/src/adapters/discord-app/discord-app.ts +99 -1
- package/src/adapters/docker/networks.yaml +20 -0
- package/src/adapters/docker/volumes.yaml +19 -0
- package/src/adapters/docker-hub/info.yaml +26 -0
- package/src/adapters/docker-hub/search.yaml +26 -0
- package/src/adapters/docker-hub/tags.yaml +34 -0
- package/src/adapters/douban/group-hot.yaml +29 -0
- package/src/adapters/douban/new-movies.yaml +32 -0
- package/src/adapters/douban/tv-hot.yaml +32 -0
- package/src/adapters/doubao/ask.yaml +64 -0
- package/src/adapters/doubao/new.yaml +18 -0
- package/src/adapters/doubao/status.yaml +21 -0
- package/src/adapters/douyu/hot.yaml +34 -0
- package/src/adapters/douyu/search.yaml +42 -0
- package/src/adapters/eastmoney/fund.yaml +36 -0
- package/src/adapters/eastmoney/hot.yaml +23 -0
- package/src/adapters/eastmoney/market.yaml +26 -0
- package/src/adapters/eastmoney/search.yaml +25 -0
- package/src/adapters/ele/hot.yaml +40 -0
- package/src/adapters/ele/search.yaml +47 -0
- package/src/adapters/exchangerate/convert.yaml +19 -0
- package/src/adapters/exchangerate/list.yaml +25 -0
- package/src/adapters/facebook/marketplace.yaml +43 -0
- package/src/adapters/facebook/post.yaml +29 -0
- package/src/adapters/feishu/calendar.yaml +24 -0
- package/src/adapters/feishu/docs.yaml +17 -0
- package/src/adapters/feishu/send.yaml +29 -0
- package/src/adapters/feishu/tasks.yaml +24 -0
- package/src/adapters/futu/hot.yaml +49 -0
- package/src/adapters/futu/quote.yaml +46 -0
- package/src/adapters/gitee/repos.yaml +34 -0
- package/src/adapters/gitee/search.yaml +25 -0
- package/src/adapters/gitee/trending.yaml +22 -0
- package/src/adapters/github-trending/developers.yaml +33 -0
- package/src/adapters/github-trending/weekly.yaml +34 -0
- package/src/adapters/gitlab/projects.yaml +34 -0
- package/src/adapters/gitlab/search.yaml +24 -0
- package/src/adapters/gitlab/trending.yaml +22 -0
- package/src/adapters/godot/scene-export.yaml +1 -1
- package/src/adapters/hackernews/comments.yaml +36 -0
- package/src/adapters/hackernews/item.yaml +28 -0
- package/src/adapters/hf/datasets.yaml +34 -0
- package/src/adapters/hf/spaces.yaml +34 -0
- package/src/adapters/homebrew/info.yaml +15 -0
- package/src/adapters/homebrew/search.yaml +27 -0
- package/src/adapters/huggingface-papers/daily.yaml +21 -0
- package/src/adapters/huggingface-papers/search.yaml +33 -0
- package/src/adapters/imdb/box-office.yaml +28 -0
- package/src/adapters/infoq/articles.yaml +29 -0
- package/src/adapters/infoq/latest.yaml +26 -0
- package/src/adapters/instagram/activity.yaml +45 -0
- package/src/adapters/instagram/highlights.yaml +48 -0
- package/src/adapters/instagram/reels-trending.yaml +51 -0
- package/src/adapters/instagram/reels.yaml +34 -0
- package/src/adapters/instagram/stories.yaml +29 -0
- package/src/adapters/instagram/suggested.yaml +40 -0
- package/src/adapters/instagram/tags.yaml +52 -0
- package/src/adapters/ip-info/lookup.yaml +15 -0
- package/src/adapters/itch-io/popular.yaml +22 -0
- package/src/adapters/itch-io/search.yaml +35 -0
- package/src/adapters/itch-io/top.yaml +31 -0
- package/src/adapters/ithome/hot.yaml +27 -0
- package/src/adapters/ithome/latest.yaml +26 -0
- package/src/adapters/ithome/news.yaml +21 -0
- package/src/adapters/jianyu/search.yaml +42 -0
- package/src/adapters/ke/ershoufang.yaml +75 -0
- package/src/adapters/ke/xiaoqu.yaml +73 -0
- package/src/adapters/kuaishou/hot.yaml +39 -0
- package/src/adapters/kuaishou/search.yaml +44 -0
- package/src/adapters/linkedin/jobs.yaml +47 -0
- package/src/adapters/lobsters/search.yaml +35 -0
- package/src/adapters/macos/active-app.yaml +16 -0
- package/src/adapters/macos/apps-list.yaml +14 -0
- package/src/adapters/macos/apps.yaml +31 -0
- package/src/adapters/macos/battery.yaml +26 -0
- package/src/adapters/macos/bluetooth.yaml +14 -0
- package/src/adapters/macos/brightness.yaml +22 -0
- package/src/adapters/macos/caffeinate.yaml +25 -0
- package/src/adapters/macos/calendar-create.yaml +81 -0
- package/src/adapters/macos/calendar-list.yaml +53 -0
- package/src/adapters/macos/calendar-today.yaml +30 -0
- package/src/adapters/macos/clipboard.yaml +23 -0
- package/src/adapters/macos/contacts-search.yaml +59 -0
- package/src/adapters/macos/dark-mode.yaml +19 -0
- package/src/adapters/macos/disk-info.yaml +31 -0
- package/src/adapters/macos/disk-usage.yaml +14 -0
- package/src/adapters/macos/do-not-disturb.yaml +21 -0
- package/src/adapters/macos/empty-trash.yaml +16 -0
- package/src/adapters/macos/finder-recent.yaml +24 -0
- package/src/adapters/macos/finder-selection.yaml +22 -0
- package/src/adapters/macos/finder-tags.yaml +40 -0
- package/src/adapters/macos/lock-screen.yaml +16 -0
- package/src/adapters/macos/mail-send.yaml +54 -0
- package/src/adapters/macos/mail-status.yaml +38 -0
- package/src/adapters/macos/messages-send.yaml +42 -0
- package/src/adapters/macos/music-control.yaml +43 -0
- package/src/adapters/macos/music-now.yaml +34 -0
- package/src/adapters/macos/notes-list.yaml +30 -0
- package/src/adapters/macos/notes-search.yaml +45 -0
- package/src/adapters/macos/notification.yaml +27 -0
- package/src/adapters/macos/notify.yaml +46 -0
- package/src/adapters/macos/open-app.yaml +21 -0
- package/src/adapters/macos/open.yaml +24 -0
- package/src/adapters/macos/photos-search.yaml +44 -0
- package/src/adapters/macos/processes.yaml +14 -0
- package/src/adapters/macos/reminder-create.yaml +75 -0
- package/src/adapters/macos/reminders-complete.yaml +33 -0
- package/src/adapters/macos/reminders-list.yaml +28 -0
- package/src/adapters/macos/safari-tabs.yaml +26 -0
- package/src/adapters/macos/say.yaml +36 -0
- package/src/adapters/macos/screen-lock.yaml +16 -0
- package/src/adapters/macos/screenshot.yaml +34 -0
- package/src/adapters/macos/shortcuts-list.yaml +14 -0
- package/src/adapters/macos/shortcuts-run.yaml +28 -0
- package/src/adapters/macos/sleep.yaml +14 -0
- package/src/adapters/macos/spotlight.yaml +43 -0
- package/src/adapters/macos/system-info.yaml +32 -0
- package/src/adapters/macos/trash.yaml +32 -0
- package/src/adapters/macos/uptime.yaml +14 -0
- package/src/adapters/macos/volume.yaml +19 -0
- package/src/adapters/macos/wifi-info.yaml +14 -0
- package/src/adapters/macos/wifi.yaml +63 -0
- package/src/adapters/maimai/search.yaml +62 -0
- package/src/adapters/maoyan/hot.yaml +33 -0
- package/src/adapters/maoyan/search.yaml +40 -0
- package/src/adapters/mastodon/search.yaml +29 -0
- package/src/adapters/mastodon/timeline.yaml +33 -0
- package/src/adapters/mastodon/trending.yaml +27 -0
- package/src/adapters/mastodon/user.yaml +32 -0
- package/src/adapters/medium/article.yaml +22 -0
- package/src/adapters/medium/trending.yaml +30 -0
- package/src/adapters/meituan/hot.yaml +26 -0
- package/src/adapters/meituan/search.yaml +30 -0
- package/src/adapters/minimax/chat.yaml +33 -0
- package/src/adapters/minimax/models.yaml +18 -0
- package/src/adapters/minimax/tts.yaml +33 -0
- package/src/adapters/mubu/list.yaml +36 -0
- package/src/adapters/mubu/search.yaml +54 -0
- package/src/adapters/netease-music/hot.yaml +24 -0
- package/src/adapters/netease-music/playlist.yaml +34 -0
- package/src/adapters/netease-music/search.yaml +29 -0
- package/src/adapters/netease-music/top.yaml +33 -0
- package/src/adapters/notion/databases.yaml +41 -0
- package/src/adapters/notion/pages.yaml +44 -0
- package/src/adapters/notion/search.yaml +41 -0
- package/src/adapters/npm/downloads.yaml +28 -0
- package/src/adapters/npm/info.yaml +25 -0
- package/src/adapters/npm/search.yaml +35 -0
- package/src/adapters/npm/versions.yaml +33 -0
- package/src/adapters/npm-trends/compare.yaml +19 -0
- package/src/adapters/npm-trends/trending.yaml +17 -0
- package/src/adapters/nytimes/search.yaml +35 -0
- package/src/adapters/nytimes/top.yaml +26 -0
- package/src/adapters/obsidian/daily.yaml +23 -0
- package/src/adapters/obsidian/open.yaml +26 -0
- package/src/adapters/obsidian/search.yaml +28 -0
- package/src/adapters/ollama/generate.yaml +33 -0
- package/src/adapters/ollama/models.yaml +29 -0
- package/src/adapters/ollama/ps.yaml +20 -0
- package/src/adapters/openrouter/models.yaml +22 -0
- package/src/adapters/openrouter/search.yaml +31 -0
- package/src/adapters/perplexity/ask.yaml +33 -0
- package/src/adapters/pexels/curated.yaml +31 -0
- package/src/adapters/pexels/search.yaml +28 -0
- package/src/adapters/pinduoduo/hot.yaml +20 -0
- package/src/adapters/pinduoduo/search.yaml +36 -0
- package/src/adapters/producthunt/search.yaml +41 -0
- package/src/adapters/pypi/info.yaml +16 -0
- package/src/adapters/pypi/search.yaml +37 -0
- package/src/adapters/pypi/versions.yaml +31 -0
- package/src/adapters/quark/ls.yaml +39 -0
- package/src/adapters/quark/search.yaml +39 -0
- package/src/adapters/qweather/forecast.yaml +37 -0
- package/src/adapters/qweather/now.yaml +16 -0
- package/src/adapters/reddit/new.yaml +34 -0
- package/src/adapters/reddit/rising.yaml +33 -0
- package/src/adapters/reddit/top.yaml +40 -0
- package/src/adapters/reddit/trending.yaml +25 -0
- package/src/adapters/replicate/run.yaml +39 -0
- package/src/adapters/replicate/search.yaml +25 -0
- package/src/adapters/replicate/trending.yaml +22 -0
- package/src/adapters/reuters/latest.yaml +26 -0
- package/src/adapters/sinafinance/market.yaml +21 -0
- package/src/adapters/slack/messages.yaml +41 -0
- package/src/adapters/slack/post.yaml +32 -0
- package/src/adapters/slack/search.yaml +28 -0
- package/src/adapters/slack/send.yaml +35 -0
- package/src/adapters/slack/status.yaml +19 -0
- package/src/adapters/slack/users.yaml +37 -0
- package/src/adapters/slock/servers.yaml +32 -0
- package/src/adapters/spotify/now-playing.yaml +28 -0
- package/src/adapters/spotify/playlists.yaml +37 -0
- package/src/adapters/spotify/top-tracks.yaml +42 -0
- package/src/adapters/sspai/hot.yaml +21 -0
- package/src/adapters/sspai/latest.yaml +22 -0
- package/src/adapters/stackoverflow/question.yaml +34 -0
- package/src/adapters/stackoverflow/tags.yaml +30 -0
- package/src/adapters/steam/app-details.yaml +32 -0
- package/src/adapters/steam/new-releases.yaml +28 -0
- package/src/adapters/steam/search.yaml +36 -0
- package/src/adapters/steam/specials.yaml +29 -0
- package/src/adapters/steam/wishlist.yaml +36 -0
- package/src/adapters/substack/trending.yaml +28 -0
- package/src/adapters/taobao/hot.yaml +31 -0
- package/src/adapters/taobao/search.yaml +44 -0
- package/src/adapters/techcrunch/latest.yaml +22 -0
- package/src/adapters/techcrunch/search.yaml +33 -0
- package/src/adapters/theverge/latest.yaml +21 -0
- package/src/adapters/theverge/search.yaml +33 -0
- package/src/adapters/threads/hot.yaml +44 -0
- package/src/adapters/threads/search.yaml +47 -0
- package/src/adapters/tiktok/trending.yaml +28 -0
- package/src/adapters/toutiao/hot.yaml +31 -0
- package/src/adapters/toutiao/search.yaml +47 -0
- package/src/adapters/twitch/games.yaml +31 -0
- package/src/adapters/twitch/search.yaml +39 -0
- package/src/adapters/twitch/streams.yaml +38 -0
- package/src/adapters/twitch/top.yaml +26 -0
- package/src/adapters/twitter/lists.yaml +49 -0
- package/src/adapters/twitter/media.yaml +48 -0
- package/src/adapters/twitter/mentions.yaml +38 -0
- package/src/adapters/twitter/mute.yaml +42 -0
- package/src/adapters/twitter/pin.yaml +43 -0
- package/src/adapters/twitter/quotes.yaml +43 -0
- package/src/adapters/twitter/retweets.yaml +44 -0
- package/src/adapters/twitter/spaces.yaml +43 -0
- package/src/adapters/twitter/unmute.yaml +42 -0
- package/src/adapters/unsplash/random.yaml +27 -0
- package/src/adapters/unsplash/search.yaml +28 -0
- package/src/adapters/v2ex/search.yaml +36 -0
- package/src/adapters/vscode/extensions.yaml +23 -0
- package/src/adapters/vscode/install-ext.yaml +26 -0
- package/src/adapters/vscode/open.yaml +25 -0
- package/src/adapters/wechat-channels/hot.yaml +39 -0
- package/src/adapters/wechat-channels/search.yaml +57 -0
- package/src/adapters/weibo/trending.yaml +28 -0
- package/src/adapters/weixin/hot.yaml +22 -0
- package/src/adapters/wikipedia/today.yaml +25 -0
- package/src/adapters/xiaohongshu/follow.yaml +35 -0
- package/src/adapters/xiaohongshu/hashtag.yaml +44 -0
- package/src/adapters/xiaohongshu/hot.yaml +34 -0
- package/src/adapters/xiaohongshu/like.yaml +27 -0
- package/src/adapters/xiaohongshu/profile.yaml +39 -0
- package/src/adapters/xiaohongshu/save.yaml +27 -0
- package/src/adapters/xiaohongshu/suggest.yaml +34 -0
- package/src/adapters/xiaohongshu/trending.yaml +35 -0
- package/src/adapters/xiaohongshu/unfollow.yaml +40 -0
- package/src/adapters/xueqiu/market.yaml +25 -0
- package/src/adapters/yahoo-finance/quote.yaml +35 -0
- package/src/adapters/yahoo-finance/search.yaml +42 -0
- package/src/adapters/yahoo-finance/trending.yaml +30 -0
- package/src/adapters/ycombinator/launches.yaml +20 -0
- package/src/adapters/youtube/playlist.yaml +43 -0
- package/src/adapters/youtube/shorts.yaml +42 -0
- package/src/adapters/youtube/trending.yaml +41 -0
- package/src/adapters/zhihu/answer.yaml +29 -0
- package/src/adapters/zhihu/answers.yaml +38 -0
- package/src/adapters/zhihu/article.yaml +27 -0
- package/src/adapters/zhihu/articles.yaml +38 -0
- package/src/adapters/zhihu/collections.yaml +37 -0
- package/src/adapters/zhihu/columns.yaml +38 -0
- package/src/adapters/zhihu/comment.yaml +42 -0
- package/src/adapters/zhihu/followers.yaml +37 -0
- package/src/adapters/zhihu/following.yaml +37 -0
- package/src/adapters/zhihu/pins.yaml +37 -0
- package/src/adapters/zhihu/topic.yaml +35 -0
- package/src/adapters/zhihu/topics.yaml +37 -0
- package/src/adapters/zhihu/trending.yaml +36 -0
- package/src/adapters/zhihu/user.yaml +30 -0
- package/src/adapters/zoom/join.yaml +24 -0
- package/src/adapters/zoom/start.yaml +17 -0
- package/src/hub/external-clis.yaml +343 -0
- package/src/hub/index.ts +128 -0
- package/src/hub/passthrough.ts +85 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
site: zhihu
|
|
2
|
+
name: trending
|
|
3
|
+
description: Zhihu trending topics by category
|
|
4
|
+
domain: www.zhihu.com
|
|
5
|
+
type: web-api
|
|
6
|
+
strategy: cookie
|
|
7
|
+
auth_cookies: [z_c0]
|
|
8
|
+
|
|
9
|
+
args:
|
|
10
|
+
category:
|
|
11
|
+
type: str
|
|
12
|
+
default: total
|
|
13
|
+
description: "Category: total, science, digital, sport, fashion, film, campus"
|
|
14
|
+
limit:
|
|
15
|
+
type: int
|
|
16
|
+
default: 20
|
|
17
|
+
description: Number of items
|
|
18
|
+
|
|
19
|
+
pipeline:
|
|
20
|
+
- fetch:
|
|
21
|
+
url: https://www.zhihu.com/api/v3/feed/topstory/hot-lists/${{ args.category }}
|
|
22
|
+
params:
|
|
23
|
+
limit: "50"
|
|
24
|
+
|
|
25
|
+
- select: data
|
|
26
|
+
|
|
27
|
+
- map:
|
|
28
|
+
rank: ${{ index + 1 }}
|
|
29
|
+
title: ${{ item.target?.title || '' }}
|
|
30
|
+
heat: ${{ item.detail_text || '' }}
|
|
31
|
+
excerpt: ${{ (item.target?.excerpt || '') | strip_html | slice(0, 100) }}
|
|
32
|
+
url: ${{ 'https://www.zhihu.com/question/' + (item.target?.id || '') }}
|
|
33
|
+
|
|
34
|
+
- limit: ${{ args.limit }}
|
|
35
|
+
|
|
36
|
+
columns: [rank, title, heat, excerpt, url]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
site: zhihu
|
|
2
|
+
name: user
|
|
3
|
+
description: Get a Zhihu user profile by URL name
|
|
4
|
+
domain: www.zhihu.com
|
|
5
|
+
type: web-api
|
|
6
|
+
strategy: cookie
|
|
7
|
+
auth_cookies: [z_c0]
|
|
8
|
+
|
|
9
|
+
args:
|
|
10
|
+
id:
|
|
11
|
+
required: true
|
|
12
|
+
positional: true
|
|
13
|
+
description: User URL token (e.g. zhang-san-12)
|
|
14
|
+
|
|
15
|
+
pipeline:
|
|
16
|
+
- fetch:
|
|
17
|
+
url: https://www.zhihu.com/api/v4/members/${{ args.id }}
|
|
18
|
+
params:
|
|
19
|
+
include: "follower_count,following_count,voteup_count,answer_count,articles_count,headline"
|
|
20
|
+
|
|
21
|
+
- map:
|
|
22
|
+
name: ${{ item.name || '' }}
|
|
23
|
+
headline: ${{ item.headline || '' }}
|
|
24
|
+
followers: ${{ item.follower_count || 0 }}
|
|
25
|
+
following: ${{ item.following_count || 0 }}
|
|
26
|
+
voteup: ${{ item.voteup_count || 0 }}
|
|
27
|
+
answers: ${{ item.answer_count || 0 }}
|
|
28
|
+
articles: ${{ item.articles_count || 0 }}
|
|
29
|
+
|
|
30
|
+
columns: [name, headline, followers, following, voteup, answers, articles]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Desktop adapter — join a Zoom meeting via URL scheme
|
|
2
|
+
site: zoom
|
|
3
|
+
name: join
|
|
4
|
+
description: Join a Zoom meeting by meeting ID
|
|
5
|
+
type: desktop
|
|
6
|
+
binary: open
|
|
7
|
+
detect: Darwin
|
|
8
|
+
strategy: public
|
|
9
|
+
|
|
10
|
+
args:
|
|
11
|
+
id:
|
|
12
|
+
type: str
|
|
13
|
+
required: true
|
|
14
|
+
positional: true
|
|
15
|
+
description: Zoom meeting ID or link
|
|
16
|
+
|
|
17
|
+
pipeline:
|
|
18
|
+
- exec:
|
|
19
|
+
command: open
|
|
20
|
+
args:
|
|
21
|
+
- "zoommtg://zoom.us/join?confno=${{ args.id }}"
|
|
22
|
+
timeout: 5000
|
|
23
|
+
|
|
24
|
+
columns: [output]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Desktop adapter — start a personal Zoom meeting
|
|
2
|
+
site: zoom
|
|
3
|
+
name: start
|
|
4
|
+
description: Start your personal Zoom meeting
|
|
5
|
+
type: desktop
|
|
6
|
+
binary: open
|
|
7
|
+
detect: Darwin
|
|
8
|
+
strategy: public
|
|
9
|
+
|
|
10
|
+
pipeline:
|
|
11
|
+
- exec:
|
|
12
|
+
command: open
|
|
13
|
+
args:
|
|
14
|
+
- "zoommtg://zoom.us/start?confno=personal"
|
|
15
|
+
timeout: 5000
|
|
16
|
+
|
|
17
|
+
columns: [output]
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# External CLI Registry — declarative catalog of passthrough CLI tools.
|
|
2
|
+
#
|
|
3
|
+
# Each entry maps an external CLI binary so agents can discover and invoke
|
|
4
|
+
# it via `unicli ext run <name> <args>`. The registry is read at startup;
|
|
5
|
+
# only CLIs whose binary is found on $PATH are registered as live commands.
|
|
6
|
+
|
|
7
|
+
# ── Tier 0 — Chinese Office (highest value) ─────────────────────────────
|
|
8
|
+
|
|
9
|
+
- name: lark-cli
|
|
10
|
+
binary: lark-cli
|
|
11
|
+
description: "Lark/Feishu — messages, documents, calendar, tasks, 200+ commands"
|
|
12
|
+
homepage: "https://github.com/larksuite/cli"
|
|
13
|
+
tags: [lark, feishu, collaboration, productivity]
|
|
14
|
+
json_flag: "--format json"
|
|
15
|
+
install:
|
|
16
|
+
mac: "npm install -g @larksuite/cli"
|
|
17
|
+
linux: "npm install -g @larksuite/cli"
|
|
18
|
+
default: "npm install -g @larksuite/cli"
|
|
19
|
+
|
|
20
|
+
- name: wecom-cli
|
|
21
|
+
binary: wecom-cli
|
|
22
|
+
description: "WeCom/WeChat Work — contacts, messages, bots, 100+ commands"
|
|
23
|
+
homepage: "https://github.com/WecomTeam/wecom-cli"
|
|
24
|
+
tags: [wecom, wechat-work, enterprise, messaging]
|
|
25
|
+
json_flag: "--json"
|
|
26
|
+
install:
|
|
27
|
+
default: "npm install -g @wecom/cli"
|
|
28
|
+
|
|
29
|
+
- name: dws
|
|
30
|
+
binary: dws
|
|
31
|
+
description: "DingTalk Workspace — messages, docs, calendar, contacts, 86 commands"
|
|
32
|
+
homepage: "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli"
|
|
33
|
+
tags: [dingtalk, workspace, collaboration]
|
|
34
|
+
install:
|
|
35
|
+
mac: "curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh"
|
|
36
|
+
linux: "curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh"
|
|
37
|
+
default: "npm install -g dingtalk-workspace-cli"
|
|
38
|
+
|
|
39
|
+
# ── Tier 1 — AI Agent CLIs ──────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
- name: kimi-cli
|
|
42
|
+
binary: kimi
|
|
43
|
+
description: "Kimi Code — Moonshot AI coding agent CLI, 8K★"
|
|
44
|
+
homepage: "https://github.com/MoonshotAI/kimi-cli"
|
|
45
|
+
tags: [ai, agent, coding, moonshot]
|
|
46
|
+
json_flag: "--json"
|
|
47
|
+
install:
|
|
48
|
+
default: "pip install kimi-cli"
|
|
49
|
+
|
|
50
|
+
- name: deepagents
|
|
51
|
+
binary: deepagents
|
|
52
|
+
description: "DeepAgents — LangChain agent harness CLI, 20K★"
|
|
53
|
+
homepage: "https://github.com/langchain-ai/deepagents"
|
|
54
|
+
tags: [ai, agent, langchain, harness]
|
|
55
|
+
json_flag: "--json"
|
|
56
|
+
install:
|
|
57
|
+
default: "pip install deepagents-cli"
|
|
58
|
+
|
|
59
|
+
# ── Tier 1 — Essential ──────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
- name: vercel
|
|
62
|
+
binary: vercel
|
|
63
|
+
description: "Vercel — deploy, domains, env vars, serverless functions"
|
|
64
|
+
homepage: "https://vercel.com/docs/cli"
|
|
65
|
+
tags: [vercel, deployment, serverless]
|
|
66
|
+
install:
|
|
67
|
+
default: "npm install -g vercel"
|
|
68
|
+
|
|
69
|
+
- name: supabase
|
|
70
|
+
binary: supabase
|
|
71
|
+
description: "Supabase — Postgres, auth, storage, edge functions"
|
|
72
|
+
homepage: "https://supabase.com/docs/reference/cli"
|
|
73
|
+
tags: [supabase, postgres, backend]
|
|
74
|
+
json_flag: "--output json"
|
|
75
|
+
install:
|
|
76
|
+
mac: "brew install supabase/tap/supabase"
|
|
77
|
+
default: "npm install -g supabase"
|
|
78
|
+
|
|
79
|
+
- name: stripe
|
|
80
|
+
binary: stripe
|
|
81
|
+
description: "Stripe — payments, subscriptions, invoices, webhooks"
|
|
82
|
+
homepage: "https://stripe.com/docs/stripe-cli"
|
|
83
|
+
tags: [stripe, payments, billing]
|
|
84
|
+
json_flag: "--json"
|
|
85
|
+
install:
|
|
86
|
+
mac: "brew install stripe/stripe-cli/stripe"
|
|
87
|
+
default: "brew install stripe/stripe-cli/stripe"
|
|
88
|
+
|
|
89
|
+
- name: firebase
|
|
90
|
+
binary: firebase
|
|
91
|
+
description: "Firebase — hosting, firestore, auth, cloud functions"
|
|
92
|
+
homepage: "https://firebase.google.com/docs/cli"
|
|
93
|
+
tags: [firebase, google, backend, hosting]
|
|
94
|
+
json_flag: "--json"
|
|
95
|
+
install:
|
|
96
|
+
default: "npm install -g firebase-tools"
|
|
97
|
+
|
|
98
|
+
- name: gws
|
|
99
|
+
binary: gws
|
|
100
|
+
description: "Google Workspace — Drive, Gmail, Calendar, Sheets, 100+ agent skills"
|
|
101
|
+
homepage: "https://github.com/googleworkspace/cli"
|
|
102
|
+
tags: [google, workspace, gmail, calendar, drive, productivity]
|
|
103
|
+
json_flag: "--format json"
|
|
104
|
+
install:
|
|
105
|
+
default: "npm install -g @googleworkspace/cli"
|
|
106
|
+
|
|
107
|
+
- name: wrangler
|
|
108
|
+
binary: wrangler
|
|
109
|
+
description: "Cloudflare Workers — deploy, KV, R2, D1, queues"
|
|
110
|
+
homepage: "https://developers.cloudflare.com/workers/wrangler"
|
|
111
|
+
tags: [cloudflare, workers, edge, serverless]
|
|
112
|
+
json_flag: "--json"
|
|
113
|
+
install:
|
|
114
|
+
default: "npm install -g wrangler"
|
|
115
|
+
|
|
116
|
+
- name: netlify
|
|
117
|
+
binary: netlify
|
|
118
|
+
description: "Netlify — deploy, functions, forms, identity"
|
|
119
|
+
homepage: "https://docs.netlify.com/cli/get-started"
|
|
120
|
+
tags: [netlify, deployment, jamstack]
|
|
121
|
+
json_flag: "--json"
|
|
122
|
+
install:
|
|
123
|
+
default: "npm install -g netlify-cli"
|
|
124
|
+
|
|
125
|
+
- name: flyctl
|
|
126
|
+
binary: fly
|
|
127
|
+
description: "Fly.io — deploy containers, machines, volumes, secrets"
|
|
128
|
+
homepage: "https://fly.io/docs/flyctl"
|
|
129
|
+
tags: [fly, containers, deployment]
|
|
130
|
+
json_flag: "--json"
|
|
131
|
+
install:
|
|
132
|
+
mac: "brew install flyctl"
|
|
133
|
+
default: "brew install flyctl"
|
|
134
|
+
|
|
135
|
+
- name: sentry-cli
|
|
136
|
+
binary: sentry-cli
|
|
137
|
+
description: "Sentry — releases, source maps, debug symbols"
|
|
138
|
+
homepage: "https://docs.sentry.io/cli"
|
|
139
|
+
tags: [sentry, monitoring, error-tracking]
|
|
140
|
+
install:
|
|
141
|
+
default: "npm install -g @sentry/cli"
|
|
142
|
+
|
|
143
|
+
- name: railway
|
|
144
|
+
binary: railway
|
|
145
|
+
description: "Railway — deploy, databases, variables, logs"
|
|
146
|
+
homepage: "https://docs.railway.app/reference/cli-api"
|
|
147
|
+
tags: [railway, deployment, backend]
|
|
148
|
+
json_flag: "--json"
|
|
149
|
+
install:
|
|
150
|
+
mac: "brew install railway"
|
|
151
|
+
default: "brew install railway"
|
|
152
|
+
|
|
153
|
+
- name: mmx-cli
|
|
154
|
+
binary: mmx
|
|
155
|
+
description: "MiniMax AI — text, vision, speech, video generation"
|
|
156
|
+
homepage: "https://www.minimaxi.com"
|
|
157
|
+
tags: [minimax, ai, generation]
|
|
158
|
+
install:
|
|
159
|
+
default: "npm install -g mmx-cli"
|
|
160
|
+
|
|
161
|
+
# ── Tier 2 — High Value ─────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
- name: aliyun
|
|
164
|
+
binary: aliyun
|
|
165
|
+
description: "Alibaba Cloud — ECS, OSS, RDS, 1000+ commands"
|
|
166
|
+
homepage: "https://github.com/aliyun/aliyun-cli"
|
|
167
|
+
tags: [alibaba, cloud, aliyun]
|
|
168
|
+
json_flag: "--output json"
|
|
169
|
+
install:
|
|
170
|
+
mac: "brew install aliyun-cli"
|
|
171
|
+
default: "brew install aliyun-cli"
|
|
172
|
+
|
|
173
|
+
- name: tccli
|
|
174
|
+
binary: tccli
|
|
175
|
+
description: "Tencent Cloud — CVM, COS, TencentDB, 500+ commands"
|
|
176
|
+
homepage: "https://cloud.tencent.com/document/product/440"
|
|
177
|
+
tags: [tencent, cloud, tccli]
|
|
178
|
+
json_flag: "--output json"
|
|
179
|
+
install:
|
|
180
|
+
default: "pip install tccli"
|
|
181
|
+
|
|
182
|
+
- name: doctl
|
|
183
|
+
binary: doctl
|
|
184
|
+
description: "DigitalOcean — droplets, databases, spaces, apps"
|
|
185
|
+
homepage: "https://docs.digitalocean.com/reference/doctl"
|
|
186
|
+
tags: [digitalocean, cloud, droplets]
|
|
187
|
+
json_flag: "--output json"
|
|
188
|
+
install:
|
|
189
|
+
mac: "brew install doctl"
|
|
190
|
+
default: "brew install doctl"
|
|
191
|
+
|
|
192
|
+
- name: hcloud
|
|
193
|
+
binary: hcloud
|
|
194
|
+
description: "Hetzner Cloud — servers, volumes, networks, firewalls"
|
|
195
|
+
homepage: "https://github.com/hetznercloud/cli"
|
|
196
|
+
tags: [hetzner, cloud, servers]
|
|
197
|
+
json_flag: "--output json"
|
|
198
|
+
install:
|
|
199
|
+
mac: "brew install hcloud"
|
|
200
|
+
default: "brew install hcloud"
|
|
201
|
+
|
|
202
|
+
- name: turso
|
|
203
|
+
binary: turso
|
|
204
|
+
description: "Turso — SQLite edge database, groups, replicas"
|
|
205
|
+
homepage: "https://docs.turso.tech/cli"
|
|
206
|
+
tags: [turso, sqlite, edge, database]
|
|
207
|
+
json_flag: "--json"
|
|
208
|
+
install:
|
|
209
|
+
default: "curl -sSfL https://get.tur.so/install.sh | bash"
|
|
210
|
+
|
|
211
|
+
- name: pscale
|
|
212
|
+
binary: pscale
|
|
213
|
+
description: "PlanetScale — MySQL branches, deploy requests, backups"
|
|
214
|
+
homepage: "https://planetscale.com/docs/reference/planetscale-cli"
|
|
215
|
+
tags: [planetscale, mysql, database]
|
|
216
|
+
json_flag: "--format json"
|
|
217
|
+
install:
|
|
218
|
+
mac: "brew install planetscale/tap/pscale"
|
|
219
|
+
default: "brew install planetscale/tap/pscale"
|
|
220
|
+
|
|
221
|
+
- name: neonctl
|
|
222
|
+
binary: neonctl
|
|
223
|
+
description: "Neon — serverless Postgres branches, endpoints, roles"
|
|
224
|
+
homepage: "https://neon.tech/docs/reference/neon-cli"
|
|
225
|
+
tags: [neon, postgres, serverless, database]
|
|
226
|
+
json_flag: "--output json"
|
|
227
|
+
install:
|
|
228
|
+
default: "npm install -g neonctl"
|
|
229
|
+
|
|
230
|
+
- name: auth0
|
|
231
|
+
binary: auth0
|
|
232
|
+
description: "Auth0 — applications, APIs, users, roles, rules"
|
|
233
|
+
homepage: "https://auth0.github.io/auth0-cli"
|
|
234
|
+
tags: [auth0, authentication, identity]
|
|
235
|
+
json_flag: "--json"
|
|
236
|
+
install:
|
|
237
|
+
mac: "brew install auth0"
|
|
238
|
+
default: "brew install auth0"
|
|
239
|
+
|
|
240
|
+
- name: algolia
|
|
241
|
+
binary: algolia
|
|
242
|
+
description: "Algolia — indices, search rules, API keys, analytics"
|
|
243
|
+
homepage: "https://www.algolia.com/doc/tools/cli"
|
|
244
|
+
tags: [algolia, search, indexing]
|
|
245
|
+
install:
|
|
246
|
+
mac: "brew install algolia/algolia-cli/algolia"
|
|
247
|
+
default: "brew install algolia/algolia-cli/algolia"
|
|
248
|
+
|
|
249
|
+
- name: twilio
|
|
250
|
+
binary: twilio
|
|
251
|
+
description: "Twilio — SMS, voice, video, conversations"
|
|
252
|
+
homepage: "https://www.twilio.com/docs/twilio-cli"
|
|
253
|
+
tags: [twilio, sms, voice, communication]
|
|
254
|
+
json_flag: "--output-format json"
|
|
255
|
+
install:
|
|
256
|
+
default: "npm install -g twilio-cli"
|
|
257
|
+
|
|
258
|
+
- name: resend
|
|
259
|
+
binary: resend
|
|
260
|
+
description: "Resend — transactional email, domains, API keys"
|
|
261
|
+
homepage: "https://resend.com/docs/cli"
|
|
262
|
+
tags: [resend, email, transactional]
|
|
263
|
+
install:
|
|
264
|
+
default: "npm install -g resend"
|
|
265
|
+
|
|
266
|
+
- name: linear
|
|
267
|
+
binary: linear
|
|
268
|
+
description: "Linear — issues, projects, cycles, teams"
|
|
269
|
+
homepage: "https://linear.app/docs"
|
|
270
|
+
tags: [linear, project-management, issues]
|
|
271
|
+
install:
|
|
272
|
+
mac: "brew install linear"
|
|
273
|
+
default: "brew install linear"
|
|
274
|
+
|
|
275
|
+
# ── Already have adapters — full passthrough ─────────────────────────────
|
|
276
|
+
|
|
277
|
+
- name: gh
|
|
278
|
+
binary: gh
|
|
279
|
+
description: "GitHub — repos, PRs, issues, actions, releases"
|
|
280
|
+
homepage: "https://cli.github.com"
|
|
281
|
+
tags: [github, git, devops]
|
|
282
|
+
json_flag: "--json"
|
|
283
|
+
install:
|
|
284
|
+
mac: "brew install gh"
|
|
285
|
+
default: "brew install gh"
|
|
286
|
+
|
|
287
|
+
- name: docker
|
|
288
|
+
binary: docker
|
|
289
|
+
description: "Docker — containers, images, volumes, networks"
|
|
290
|
+
homepage: "https://docs.docker.com/engine/reference/commandline/cli"
|
|
291
|
+
tags: [docker, containers, devops]
|
|
292
|
+
json_flag: "--format json"
|
|
293
|
+
install:
|
|
294
|
+
default: "https://docs.docker.com/get-docker/"
|
|
295
|
+
|
|
296
|
+
- name: kubectl
|
|
297
|
+
binary: kubectl
|
|
298
|
+
description: "Kubernetes — pods, services, deployments, config"
|
|
299
|
+
homepage: "https://kubernetes.io/docs/reference/kubectl"
|
|
300
|
+
tags: [kubernetes, k8s, containers, orchestration]
|
|
301
|
+
json_flag: "-o json"
|
|
302
|
+
install:
|
|
303
|
+
mac: "brew install kubectl"
|
|
304
|
+
default: "brew install kubectl"
|
|
305
|
+
|
|
306
|
+
- name: aws
|
|
307
|
+
binary: aws
|
|
308
|
+
description: "AWS CLI — EC2, S3, Lambda, 300+ services"
|
|
309
|
+
homepage: "https://aws.amazon.com/cli"
|
|
310
|
+
tags: [aws, cloud, amazon]
|
|
311
|
+
json_flag: "--output json"
|
|
312
|
+
install:
|
|
313
|
+
mac: "brew install awscli"
|
|
314
|
+
default: "brew install awscli"
|
|
315
|
+
|
|
316
|
+
- name: gcloud
|
|
317
|
+
binary: gcloud
|
|
318
|
+
description: "Google Cloud — compute, storage, BigQuery, 200+ services"
|
|
319
|
+
homepage: "https://cloud.google.com/sdk/gcloud"
|
|
320
|
+
tags: [gcp, google, cloud]
|
|
321
|
+
json_flag: "--format json"
|
|
322
|
+
install:
|
|
323
|
+
default: "https://cloud.google.com/sdk/docs/install"
|
|
324
|
+
|
|
325
|
+
- name: az
|
|
326
|
+
binary: az
|
|
327
|
+
description: "Azure CLI — VMs, storage, databases, 200+ services"
|
|
328
|
+
homepage: "https://learn.microsoft.com/cli/azure"
|
|
329
|
+
tags: [azure, microsoft, cloud]
|
|
330
|
+
json_flag: "--output json"
|
|
331
|
+
install:
|
|
332
|
+
mac: "brew install azure-cli"
|
|
333
|
+
default: "brew install azure-cli"
|
|
334
|
+
|
|
335
|
+
- name: ollama
|
|
336
|
+
binary: ollama
|
|
337
|
+
description: "Ollama — local LLM runner, model management"
|
|
338
|
+
homepage: "https://ollama.ai"
|
|
339
|
+
tags: [ollama, llm, ai, local]
|
|
340
|
+
json_flag: "--format json"
|
|
341
|
+
install:
|
|
342
|
+
mac: "brew install ollama"
|
|
343
|
+
default: "brew install ollama"
|
package/src/hub/index.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External CLI Hub — registry and auto-discovery for third-party CLIs.
|
|
3
|
+
*
|
|
4
|
+
* Reads `external-clis.yaml` at startup, checks which binaries are
|
|
5
|
+
* installed on $PATH, and exposes lookup helpers for the rest of the
|
|
6
|
+
* system (Commander registration, `unicli ext` subcommands, AGENTS.md).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { execFileSync } from "node:child_process";
|
|
13
|
+
import yaml from "js-yaml";
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
|
|
17
|
+
// ── Types ───────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
export interface ExternalCli {
|
|
20
|
+
name: string;
|
|
21
|
+
binary: string;
|
|
22
|
+
description: string;
|
|
23
|
+
homepage?: string;
|
|
24
|
+
tags?: string[];
|
|
25
|
+
json_flag?: string;
|
|
26
|
+
install?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── Cache ───────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
let _cache: ExternalCli[] | null = null;
|
|
32
|
+
const _installedCache = new Map<string, boolean>();
|
|
33
|
+
|
|
34
|
+
// ── Loader ──────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the YAML registry path.
|
|
38
|
+
*
|
|
39
|
+
* The YAML file ships alongside the TypeScript source in `src/hub/`.
|
|
40
|
+
* At runtime we may be executing from `dist/hub/`, so we try the source
|
|
41
|
+
* sibling first (`../../src/hub/`) then fall back to the co-located path.
|
|
42
|
+
*/
|
|
43
|
+
function resolveYamlPath(): string {
|
|
44
|
+
// Running from dist/hub/index.js → ../../src/hub/external-clis.yaml
|
|
45
|
+
const fromDist = join(
|
|
46
|
+
__dirname,
|
|
47
|
+
"..",
|
|
48
|
+
"..",
|
|
49
|
+
"src",
|
|
50
|
+
"hub",
|
|
51
|
+
"external-clis.yaml",
|
|
52
|
+
);
|
|
53
|
+
// Running from src/hub/index.ts (dev via tsx)
|
|
54
|
+
const fromSrc = join(__dirname, "external-clis.yaml");
|
|
55
|
+
|
|
56
|
+
// Prefer the source copy (always present in both dev & installed package)
|
|
57
|
+
try {
|
|
58
|
+
readFileSync(fromSrc, "utf-8");
|
|
59
|
+
return fromSrc;
|
|
60
|
+
} catch {
|
|
61
|
+
return fromDist;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Load and parse the external CLI registry from YAML.
|
|
67
|
+
* Results are cached after the first call.
|
|
68
|
+
*/
|
|
69
|
+
export function loadExternalClis(): ExternalCli[] {
|
|
70
|
+
if (_cache) return _cache;
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const raw = readFileSync(resolveYamlPath(), "utf-8");
|
|
74
|
+
const parsed = yaml.load(raw);
|
|
75
|
+
if (!Array.isArray(parsed)) {
|
|
76
|
+
_cache = [];
|
|
77
|
+
return _cache;
|
|
78
|
+
}
|
|
79
|
+
_cache = parsed as ExternalCli[];
|
|
80
|
+
return _cache;
|
|
81
|
+
} catch {
|
|
82
|
+
_cache = [];
|
|
83
|
+
return _cache;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Discovery ───────────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check whether a binary is available on $PATH.
|
|
91
|
+
* Uses `which` (macOS/Linux) with a short timeout. Results are cached.
|
|
92
|
+
*/
|
|
93
|
+
export function isInstalled(binary: string): boolean {
|
|
94
|
+
if (_installedCache.has(binary)) {
|
|
95
|
+
return _installedCache.get(binary)!;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
execFileSync("which", [binary], {
|
|
100
|
+
stdio: "pipe",
|
|
101
|
+
timeout: 3_000,
|
|
102
|
+
});
|
|
103
|
+
_installedCache.set(binary, true);
|
|
104
|
+
return true;
|
|
105
|
+
} catch {
|
|
106
|
+
_installedCache.set(binary, false);
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Return every registered external CLI with its install status.
|
|
113
|
+
*/
|
|
114
|
+
export function listExternalClis(): Array<
|
|
115
|
+
ExternalCli & { installed: boolean }
|
|
116
|
+
> {
|
|
117
|
+
return loadExternalClis().map((cli) => ({
|
|
118
|
+
...cli,
|
|
119
|
+
installed: isInstalled(cli.binary),
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Look up a single external CLI by name.
|
|
125
|
+
*/
|
|
126
|
+
export function getExternalCli(name: string): ExternalCli | undefined {
|
|
127
|
+
return loadExternalClis().find((c) => c.name === name);
|
|
128
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External CLI passthrough — execute third-party CLIs with smart output wrapping.
|
|
3
|
+
*
|
|
4
|
+
* Security:
|
|
5
|
+
* - Uses `execFileSync` (no shell) to prevent command injection.
|
|
6
|
+
* - Binary name is looked up from the trusted YAML registry, never from user input.
|
|
7
|
+
*
|
|
8
|
+
* Output behavior:
|
|
9
|
+
* - TTY stdout → raw passthrough (human-readable)
|
|
10
|
+
* - Piped stdout → attempt JSON parse; wrap as `{"text": "..."}` on failure
|
|
11
|
+
* - stderr is always passed through
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { execFileSync } from "node:child_process";
|
|
15
|
+
import type { ExternalCli } from "./index.js";
|
|
16
|
+
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Execute an external CLI command with passthrough.
|
|
21
|
+
*
|
|
22
|
+
* When piped (non-TTY), attempt to parse JSON output or wrap as text.
|
|
23
|
+
* Exits the process with the child's exit code on failure.
|
|
24
|
+
*/
|
|
25
|
+
export function executeExternal(cli: ExternalCli, args: string[]): void {
|
|
26
|
+
const isTTY = process.stdout.isTTY ?? false;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const stdout = execFileSync(cli.binary, args, {
|
|
30
|
+
stdio: isTTY ? "inherit" : ["inherit", "pipe", "inherit"],
|
|
31
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
32
|
+
maxBuffer: 50 * 1024 * 1024, // 50 MB
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// In TTY mode execFileSync with stdio "inherit" returns null
|
|
36
|
+
if (!isTTY && stdout) {
|
|
37
|
+
const output = stdout.toString("utf-8");
|
|
38
|
+
|
|
39
|
+
// Try to parse as JSON and re-emit (validates + normalizes)
|
|
40
|
+
try {
|
|
41
|
+
const parsed: unknown = JSON.parse(output);
|
|
42
|
+
process.stdout.write(JSON.stringify(parsed, null, 2) + "\n");
|
|
43
|
+
} catch {
|
|
44
|
+
// Not JSON — wrap as structured text object
|
|
45
|
+
const trimmed = output.trim();
|
|
46
|
+
if (trimmed.length > 0) {
|
|
47
|
+
process.stdout.write(JSON.stringify({ text: trimmed }) + "\n");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (err: unknown) {
|
|
52
|
+
// execFileSync throws on non-zero exit — extract code and forward
|
|
53
|
+
if (isExecError(err)) {
|
|
54
|
+
// If there was stdout content in piped mode, it's in err.stdout
|
|
55
|
+
if (!isTTY && err.stdout && err.stdout.length > 0) {
|
|
56
|
+
const output = err.stdout.toString("utf-8").trim();
|
|
57
|
+
if (output.length > 0) {
|
|
58
|
+
try {
|
|
59
|
+
const parsed: unknown = JSON.parse(output);
|
|
60
|
+
process.stdout.write(JSON.stringify(parsed, null, 2) + "\n");
|
|
61
|
+
} catch {
|
|
62
|
+
process.stdout.write(JSON.stringify({ text: output }) + "\n");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
process.exit(typeof err.status === "number" ? err.status : 1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Unknown error shape — re-throw
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Type guard ──────────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
interface ExecError {
|
|
78
|
+
status: number | null;
|
|
79
|
+
stdout: Buffer | null;
|
|
80
|
+
stderr: Buffer | null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isExecError(err: unknown): err is ExecError {
|
|
84
|
+
return typeof err === "object" && err !== null && "status" in err;
|
|
85
|
+
}
|