@zenalexa/unicli 0.207.1 → 0.209.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.
Files changed (155) hide show
  1. package/AGENTS.md +4 -4
  2. package/README.md +30 -17
  3. package/dist/browser/observe.d.ts +80 -0
  4. package/dist/browser/observe.d.ts.map +1 -0
  5. package/dist/browser/observe.js +144 -0
  6. package/dist/browser/observe.js.map +1 -0
  7. package/dist/browser/snapshot.d.ts.map +1 -1
  8. package/dist/browser/snapshot.js +29 -9
  9. package/dist/browser/snapshot.js.map +1 -1
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +59 -2
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/agents.d.ts.map +1 -1
  14. package/dist/commands/agents.js +82 -2
  15. package/dist/commands/agents.js.map +1 -1
  16. package/dist/commands/eval.d.ts +112 -0
  17. package/dist/commands/eval.d.ts.map +1 -0
  18. package/dist/commands/eval.js +485 -0
  19. package/dist/commands/eval.js.map +1 -0
  20. package/dist/commands/generate.d.ts.map +1 -1
  21. package/dist/commands/generate.js +20 -1
  22. package/dist/commands/generate.js.map +1 -1
  23. package/dist/commands/hub.d.ts +13 -0
  24. package/dist/commands/hub.d.ts.map +1 -0
  25. package/dist/commands/hub.js +232 -0
  26. package/dist/commands/hub.js.map +1 -0
  27. package/dist/commands/mcp.d.ts +16 -0
  28. package/dist/commands/mcp.d.ts.map +1 -0
  29. package/dist/commands/mcp.js +135 -0
  30. package/dist/commands/mcp.js.map +1 -0
  31. package/dist/commands/operate.d.ts.map +1 -1
  32. package/dist/commands/operate.js +66 -1
  33. package/dist/commands/operate.js.map +1 -1
  34. package/dist/commands/research.d.ts +17 -0
  35. package/dist/commands/research.d.ts.map +1 -0
  36. package/dist/commands/research.js +257 -0
  37. package/dist/commands/research.js.map +1 -0
  38. package/dist/commands/skills.d.ts +91 -0
  39. package/dist/commands/skills.d.ts.map +1 -0
  40. package/dist/commands/skills.js +266 -0
  41. package/dist/commands/skills.js.map +1 -0
  42. package/dist/commands/test-gen.d.ts +10 -0
  43. package/dist/commands/test-gen.d.ts.map +1 -0
  44. package/dist/commands/test-gen.js +124 -0
  45. package/dist/commands/test-gen.js.map +1 -0
  46. package/dist/commands/usage.d.ts +17 -0
  47. package/dist/commands/usage.d.ts.map +1 -0
  48. package/dist/commands/usage.js +87 -0
  49. package/dist/commands/usage.js.map +1 -0
  50. package/dist/discovery/loader.d.ts +8 -1
  51. package/dist/discovery/loader.d.ts.map +1 -1
  52. package/dist/discovery/loader.js +103 -6
  53. package/dist/discovery/loader.js.map +1 -1
  54. package/dist/engine/capability.d.ts +40 -0
  55. package/dist/engine/capability.d.ts.map +1 -0
  56. package/dist/engine/capability.js +191 -0
  57. package/dist/engine/capability.js.map +1 -0
  58. package/dist/engine/endpoint.d.ts +47 -0
  59. package/dist/engine/endpoint.d.ts.map +1 -0
  60. package/dist/engine/endpoint.js +295 -0
  61. package/dist/engine/endpoint.js.map +1 -0
  62. package/dist/engine/framework.d.ts +28 -0
  63. package/dist/engine/framework.d.ts.map +1 -0
  64. package/dist/engine/framework.js +66 -0
  65. package/dist/engine/framework.js.map +1 -0
  66. package/dist/engine/probe.d.ts +19 -0
  67. package/dist/engine/probe.d.ts.map +1 -0
  68. package/dist/engine/probe.js +85 -0
  69. package/dist/engine/probe.js.map +1 -0
  70. package/dist/engine/research.d.ts +38 -0
  71. package/dist/engine/research.d.ts.map +1 -0
  72. package/dist/engine/research.js +414 -0
  73. package/dist/engine/research.js.map +1 -0
  74. package/dist/engine/update-check.js +1 -1
  75. package/dist/engine/update-check.js.map +1 -1
  76. package/dist/engine/yaml-runner.d.ts.map +1 -1
  77. package/dist/engine/yaml-runner.js +115 -6
  78. package/dist/engine/yaml-runner.js.map +1 -1
  79. package/dist/main.d.ts +1 -4
  80. package/dist/main.d.ts.map +1 -1
  81. package/dist/main.js +1 -4
  82. package/dist/main.js.map +1 -1
  83. package/dist/manifest.json +519 -1
  84. package/dist/mcp/server.d.ts +19 -6
  85. package/dist/mcp/server.d.ts.map +1 -1
  86. package/dist/mcp/server.js +459 -115
  87. package/dist/mcp/server.js.map +1 -1
  88. package/dist/permissions/sensitive-paths.d.ts +92 -0
  89. package/dist/permissions/sensitive-paths.d.ts.map +1 -0
  90. package/dist/permissions/sensitive-paths.js +174 -0
  91. package/dist/permissions/sensitive-paths.js.map +1 -0
  92. package/dist/runtime/usage-ledger.d.ts +86 -0
  93. package/dist/runtime/usage-ledger.d.ts.map +1 -0
  94. package/dist/runtime/usage-ledger.js +173 -0
  95. package/dist/runtime/usage-ledger.js.map +1 -0
  96. package/package.json +8 -7
  97. package/src/adapters/autoagent/eval-run.yaml +36 -0
  98. package/src/adapters/cnn/top.yaml +21 -0
  99. package/src/adapters/cocoapods/search.yaml +16 -0
  100. package/src/adapters/crates-io/search.yaml +27 -0
  101. package/src/adapters/cua/bench-list.yaml +20 -0
  102. package/src/adapters/cua/bench-run.yaml +32 -0
  103. package/src/adapters/docker-hub/search.yaml +26 -0
  104. package/src/adapters/eastmoney/hot.yaml +23 -0
  105. package/src/adapters/eastmoney/search.yaml +25 -0
  106. package/src/adapters/exchangerate/convert.yaml +19 -0
  107. package/src/adapters/feishu/calendar.yaml +24 -0
  108. package/src/adapters/feishu/docs.yaml +17 -0
  109. package/src/adapters/feishu/send.yaml +29 -0
  110. package/src/adapters/feishu/tasks.yaml +24 -0
  111. package/src/adapters/gitee/search.yaml +25 -0
  112. package/src/adapters/gitee/trending.yaml +22 -0
  113. package/src/adapters/gitlab/search.yaml +24 -0
  114. package/src/adapters/gitlab/trending.yaml +22 -0
  115. package/src/adapters/godot/project-run.yaml +31 -0
  116. package/src/adapters/godot/scene-export.yaml +39 -0
  117. package/src/adapters/hermes/sessions-search.yaml +61 -0
  118. package/src/adapters/hermes/skills-list.yaml +30 -0
  119. package/src/adapters/hermes/skills-read.yaml +46 -0
  120. package/src/adapters/homebrew/info.yaml +15 -0
  121. package/src/adapters/huggingface-papers/daily.yaml +21 -0
  122. package/src/adapters/infoq/articles.yaml +29 -0
  123. package/src/adapters/ip-info/lookup.yaml +15 -0
  124. package/src/adapters/itch-io/popular.yaml +22 -0
  125. package/src/adapters/ithome/news.yaml +21 -0
  126. package/src/adapters/mastodon/search.yaml +29 -0
  127. package/src/adapters/mastodon/trending.yaml +27 -0
  128. package/src/adapters/meituan/search.yaml +30 -0
  129. package/src/adapters/minimax/chat.yaml +33 -0
  130. package/src/adapters/minimax/models.yaml +18 -0
  131. package/src/adapters/minimax/tts.yaml +33 -0
  132. package/src/adapters/motion-studio/component-get.yaml +35 -0
  133. package/src/adapters/netease-music/hot.yaml +24 -0
  134. package/src/adapters/netease-music/search.yaml +29 -0
  135. package/src/adapters/npm-trends/compare.yaml +19 -0
  136. package/src/adapters/nytimes/top.yaml +26 -0
  137. package/src/adapters/openharness/memory-read.yaml +51 -0
  138. package/src/adapters/openharness/skills-list.yaml +28 -0
  139. package/src/adapters/openrouter/models.yaml +22 -0
  140. package/src/adapters/pexels/search.yaml +28 -0
  141. package/src/adapters/pinduoduo/hot.yaml +20 -0
  142. package/src/adapters/pypi/info.yaml +16 -0
  143. package/src/adapters/qweather/now.yaml +16 -0
  144. package/src/adapters/renderdoc/capture-list.yaml +42 -0
  145. package/src/adapters/renderdoc/frame-export.yaml +32 -0
  146. package/src/adapters/replicate/search.yaml +25 -0
  147. package/src/adapters/replicate/trending.yaml +22 -0
  148. package/src/adapters/sspai/hot.yaml +21 -0
  149. package/src/adapters/sspai/latest.yaml +22 -0
  150. package/src/adapters/stagehand/wrap-observe.yaml +42 -0
  151. package/src/adapters/techcrunch/latest.yaml +22 -0
  152. package/src/adapters/theverge/latest.yaml +21 -0
  153. package/src/adapters/twitch/top.yaml +26 -0
  154. package/src/adapters/unsplash/search.yaml +28 -0
  155. package/src/adapters/ycombinator/launches.yaml +20 -0
@@ -0,0 +1,46 @@
1
+ # NousResearch/hermes-agent skills/read — read one skill file by name.
2
+ #
3
+ # Security: `args.name` is passed via environment variable UNICLI_NAME, not
4
+ # template-interpolated into the shell script. Bash expands "$UNICLI_NAME"
5
+ # inside double quotes as a literal string, so command injection is not
6
+ # possible. Path traversal (`name=../../etc/passwd`) is blocked by the
7
+ # case check that rejects slashes and `..` in the name.
8
+ site: hermes
9
+ name: skills/read
10
+ description: Read a Hermes skill file by name (without .md extension)
11
+ type: desktop
12
+ strategy: public
13
+ binary: sh
14
+ detect: test -d ~/.hermes/skills
15
+
16
+ args:
17
+ name:
18
+ type: str
19
+ required: true
20
+ positional: true
21
+ description: Skill name (filename without .md)
22
+
23
+ pipeline:
24
+ - exec:
25
+ command: sh
26
+ args:
27
+ - -c
28
+ - |
29
+ # Reject path traversal and anything with a slash or ".."
30
+ case "$UNICLI_NAME" in
31
+ */*|*..*|"")
32
+ echo '{"error":"invalid skill name"}'
33
+ exit 1
34
+ ;;
35
+ esac
36
+ file="$HOME/.hermes/skills/${UNICLI_NAME}.md"
37
+ if [ ! -f "$file" ]; then
38
+ printf '%s' "$file" | jq -Rs '{error:"not found",path:.}'
39
+ exit 1
40
+ fi
41
+ jq -Rs --arg name "$UNICLI_NAME" '{name:$name,content:.}' < "$file"
42
+ env:
43
+ UNICLI_NAME: "${{ args.name }}"
44
+ parse: json
45
+
46
+ columns: [name, content]
@@ -0,0 +1,15 @@
1
+ site: homebrew
2
+ name: info
3
+ description: Get Homebrew formula details
4
+ type: web-api
5
+ domain: formulae.brew.sh
6
+ strategy: public
7
+ args:
8
+ formula:
9
+ required: true
10
+ positional: true
11
+ description: Formula name (e.g. "ffmpeg", "node", "python")
12
+ pipeline:
13
+ - fetch:
14
+ url: "https://formulae.brew.sh/api/formula/${{ args.formula }}.json"
15
+ columns: [name, desc, homepage, versions]
@@ -0,0 +1,21 @@
1
+ site: huggingface-papers
2
+ name: daily
3
+ description: Daily trending papers on Hugging Face
4
+ type: web-api
5
+ domain: huggingface.co
6
+ strategy: public
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 20
11
+ pipeline:
12
+ - fetch:
13
+ url: "https://huggingface.co/api/daily_papers"
14
+ - map:
15
+ title: "${{ item.paper.title }}"
16
+ authors: "${{ item.paper.authors[0].name }}"
17
+ upvotes: "${{ item.paper.upvotes }}"
18
+ url: "${{ 'https://huggingface.co/papers/' + item.paper.id }}"
19
+ date: "${{ item.publishedAt }}"
20
+ - limit: "${{ args.limit | default(20) }}"
21
+ columns: [title, authors, upvotes, url]
@@ -0,0 +1,29 @@
1
+ site: infoq
2
+ name: articles
3
+ description: Latest InfoQ articles (Chinese edition)
4
+ type: web-api
5
+ domain: infoq.cn
6
+ strategy: public
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 20
11
+ pipeline:
12
+ - fetch:
13
+ url: "https://www.infoq.cn/public/v1/article/getList"
14
+ method: POST
15
+ headers:
16
+ Content-Type: application/json
17
+ Referer: "https://www.infoq.cn"
18
+ body:
19
+ type: 1
20
+ size: "${{ args.limit | default(20) }}"
21
+ - select: data
22
+ - map:
23
+ title: "${{ item.article_title }}"
24
+ author: "${{ item.author[0].nickname }}"
25
+ views: "${{ item.views }}"
26
+ url: "${{ 'https://www.infoq.cn/article/' + item.uuid }}"
27
+ date: "${{ item.publish_time }}"
28
+ - limit: "${{ args.limit | default(20) }}"
29
+ columns: [title, author, views, url]
@@ -0,0 +1,15 @@
1
+ site: ip-info
2
+ name: lookup
3
+ description: IP geolocation lookup (free, no key)
4
+ type: web-api
5
+ domain: ipapi.co
6
+ strategy: public
7
+ args:
8
+ ip:
9
+ required: false
10
+ positional: true
11
+ description: IP address (omit for your own IP)
12
+ pipeline:
13
+ - fetch:
14
+ url: "https://ipapi.co/${{ args.ip | default('') }}/json/"
15
+ columns: [ip, city, region, country_name, org, timezone, latitude, longitude]
@@ -0,0 +1,22 @@
1
+ site: itch-io
2
+ name: popular
3
+ description: Popular games on itch.io
4
+ type: web-api
5
+ domain: itch.io
6
+ strategy: public
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 20
11
+ pipeline:
12
+ - fetch:
13
+ url: "https://itch.io/games/top-rated.json"
14
+ - select: games
15
+ - map:
16
+ title: "${{ item.title }}"
17
+ url: "${{ item.url }}"
18
+ author: "${{ item.user.display_name }}"
19
+ classification: "${{ item.classification }}"
20
+ price: "${{ item.min_price ? ('$' + (item.min_price / 100).toFixed(2)) : 'Free' }}"
21
+ - limit: "${{ args.limit | default(20) }}"
22
+ columns: [title, author, classification, price, url]
@@ -0,0 +1,21 @@
1
+ site: ithome
2
+ name: news
3
+ description: IT Home (IT之家) latest tech news via RSS
4
+ type: web-api
5
+ domain: ithome.com
6
+ strategy: public
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 20
11
+ pipeline:
12
+ - fetch_text:
13
+ url: "https://www.ithome.com/rss/"
14
+ - parse_rss: ~
15
+ - map:
16
+ title: "${{ item.title }}"
17
+ url: "${{ item.link }}"
18
+ date: "${{ item.pubDate }}"
19
+ description: "${{ item.contentSnippet }}"
20
+ - limit: "${{ args.limit | default(20) }}"
21
+ columns: [title, url, date]
@@ -0,0 +1,29 @@
1
+ site: mastodon
2
+ name: search
3
+ description: Search posts on a Mastodon instance
4
+ type: web-api
5
+ domain: mastodon.social
6
+ strategy: public
7
+ args:
8
+ query:
9
+ required: true
10
+ positional: true
11
+ description: Search query
12
+ instance:
13
+ required: false
14
+ default: mastodon.social
15
+ limit:
16
+ required: false
17
+ default: 20
18
+ pipeline:
19
+ - fetch:
20
+ url: "https://${{ args.instance | default('mastodon.social') }}/api/v2/search?q=${{ args.query }}&type=statuses&limit=${{ args.limit | default(20) }}"
21
+ - select: statuses
22
+ - map:
23
+ author: "${{ item.account.display_name }}"
24
+ handle: "${{ '@' + item.account.acct }}"
25
+ content: "${{ item.content.replace(/<[^>]*>/g, '').slice(0, 120) }}"
26
+ url: "${{ item.url }}"
27
+ date: "${{ item.created_at }}"
28
+ - limit: "${{ args.limit | default(20) }}"
29
+ columns: [author, content, url, date]
@@ -0,0 +1,27 @@
1
+ site: mastodon
2
+ name: trending
3
+ description: Trending posts on a Mastodon instance (default mastodon.social)
4
+ type: web-api
5
+ domain: mastodon.social
6
+ strategy: public
7
+ args:
8
+ instance:
9
+ required: false
10
+ default: mastodon.social
11
+ description: Mastodon instance domain
12
+ limit:
13
+ required: false
14
+ default: 20
15
+ pipeline:
16
+ - fetch:
17
+ url: "https://${{ args.instance | default('mastodon.social') }}/api/v1/trends/statuses?limit=${{ args.limit | default(20) }}"
18
+ - map:
19
+ author: "${{ item.account.display_name }}"
20
+ handle: "${{ '@' + item.account.acct }}"
21
+ content: "${{ item.content.replace(/<[^>]*>/g, '').slice(0, 120) }}"
22
+ reblogs: "${{ item.reblogs_count }}"
23
+ favorites: "${{ item.favourites_count }}"
24
+ url: "${{ item.url }}"
25
+ date: "${{ item.created_at }}"
26
+ - limit: "${{ args.limit | default(20) }}"
27
+ columns: [author, content, reblogs, favorites, url]
@@ -0,0 +1,30 @@
1
+ site: meituan
2
+ name: search
3
+ description: Search restaurants/shops on Meituan
4
+ type: web-api
5
+ domain: apimobile.meituan.com
6
+ strategy: cookie
7
+ args:
8
+ query:
9
+ required: true
10
+ positional: true
11
+ description: Search keyword (e.g. "火锅", "coffee")
12
+ city:
13
+ required: false
14
+ default: "1"
15
+ description: City ID (1=北京, 10=上海, 20=广州)
16
+ limit:
17
+ required: false
18
+ default: 20
19
+ pipeline:
20
+ - fetch:
21
+ url: "https://apimobile.meituan.com/group/v4/poi/pcsearch/${{ args.city | default('1') }}?uuid=auto&limit=${{ args.limit | default(20) }}&q=${{ args.query }}"
22
+ - select: data.searchResult
23
+ - map:
24
+ name: "${{ item.title }}"
25
+ score: "${{ item.avgscore }}"
26
+ price: "${{ item.avgprice }}"
27
+ address: "${{ item.address }}"
28
+ category: "${{ item.catName }}"
29
+ - limit: "${{ args.limit | default(20) }}"
30
+ columns: [name, score, price, address, category]
@@ -0,0 +1,33 @@
1
+ site: minimax
2
+ name: chat
3
+ description: MiniMax M2 chat completion (OpenAI-compatible API)
4
+ type: web-api
5
+ domain: api.minimax.chat
6
+ strategy: header
7
+ args:
8
+ prompt:
9
+ required: true
10
+ positional: true
11
+ description: Chat message
12
+ model:
13
+ required: false
14
+ default: MiniMax-M2.7
15
+ description: Model name (MiniMax-M2.7, MiniMax-M2.5, MiniMax-M1)
16
+ pipeline:
17
+ - fetch:
18
+ url: "https://api.minimax.chat/v1/text/chatcompletion_v2"
19
+ method: POST
20
+ headers:
21
+ Content-Type: application/json
22
+ Authorization: "Bearer ${{ env.MINIMAX_API_KEY }}"
23
+ body:
24
+ model: "${{ args.model | default('MiniMax-M2.7') }}"
25
+ messages:
26
+ - role: user
27
+ content: "${{ args.prompt }}"
28
+ - select: choices
29
+ - map:
30
+ content: "${{ item.message.content }}"
31
+ model: "${{ item.model }}"
32
+ usage: "${{ item.usage }}"
33
+ columns: [content]
@@ -0,0 +1,18 @@
1
+ site: minimax
2
+ name: models
3
+ description: List available MiniMax models
4
+ type: web-api
5
+ domain: api.minimax.chat
6
+ strategy: header
7
+ args: {}
8
+ pipeline:
9
+ - fetch:
10
+ url: "https://api.minimax.chat/v1/models"
11
+ headers:
12
+ Authorization: "Bearer ${{ env.MINIMAX_API_KEY }}"
13
+ - select: data
14
+ - map:
15
+ id: "${{ item.id }}"
16
+ type: "${{ item.type }}"
17
+ created: "${{ item.created }}"
18
+ columns: [id, type, created]
@@ -0,0 +1,33 @@
1
+ site: minimax
2
+ name: tts
3
+ description: MiniMax text-to-speech generation
4
+ type: web-api
5
+ domain: api.minimax.chat
6
+ strategy: header
7
+ args:
8
+ text:
9
+ required: true
10
+ positional: true
11
+ description: Text to convert to speech
12
+ voice:
13
+ required: false
14
+ default: male-qn-qingse
15
+ description: Voice ID
16
+ output:
17
+ required: false
18
+ default: output.mp3
19
+ description: Output file path
20
+ pipeline:
21
+ - fetch:
22
+ url: "https://api.minimax.chat/v1/t2a_v2"
23
+ method: POST
24
+ headers:
25
+ Content-Type: application/json
26
+ Authorization: "Bearer ${{ env.MINIMAX_API_KEY }}"
27
+ body:
28
+ model: speech-02-hd
29
+ text: "${{ args.text }}"
30
+ voice_setting:
31
+ voice_id: "${{ args.voice | default('male-qn-qingse') }}"
32
+ - select: data
33
+ columns: [audio_url, duration]
@@ -0,0 +1,35 @@
1
+ # Motion Studio (motion.dev) — fetch one example component as paste-ready code.
2
+ # motion.dev/examples/<id> serves a Next.js page; we hit the underlying
3
+ # data endpoint and surface the source body.
4
+ site: motion-studio
5
+ name: component/get
6
+ description: Fetch a Motion (motion.dev) example component as paste-ready code
7
+ domain: motion.dev
8
+ type: web-api
9
+ strategy: public
10
+ browser: false
11
+
12
+ args:
13
+ id:
14
+ type: str
15
+ required: true
16
+ positional: true
17
+ description: Example slug from motion.dev/examples/<id> (e.g. react-command-palette)
18
+
19
+ pipeline:
20
+ - fetch_text:
21
+ url: "https://motion.dev/examples/${{ args.id }}"
22
+ headers:
23
+ Accept: text/html
24
+ User-Agent: Uni-CLI/0.208
25
+
26
+ - set:
27
+ html: ${{ ctx.data }}
28
+
29
+ - map:
30
+ id: ${{ args.id }}
31
+ url: "https://motion.dev/examples/${{ args.id }}"
32
+ length: ${{ vars.html.length }}
33
+ preview: ${{ vars.html.slice(0, 1200) }}
34
+
35
+ columns: [id, url, length, preview]
@@ -0,0 +1,24 @@
1
+ site: netease-music
2
+ name: hot
3
+ description: NetEase Cloud Music hot/trending songs
4
+ type: web-api
5
+ domain: music.163.com
6
+ strategy: public
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 20
11
+ pipeline:
12
+ - fetch:
13
+ url: "https://music.163.com/api/playlist/detail?id=3778678"
14
+ headers:
15
+ Referer: "https://music.163.com"
16
+ - select: result.tracks
17
+ - map:
18
+ rank: "${{ index + 1 }}"
19
+ name: "${{ item.name }}"
20
+ artist: "${{ item.artists[0].name }}"
21
+ album: "${{ item.album.name }}"
22
+ duration: "${{ Math.floor(item.duration / 60000) }}:${{ String(Math.floor((item.duration % 60000) / 1000)).padStart(2, '0') }}"
23
+ - limit: "${{ args.limit | default(20) }}"
24
+ columns: [rank, name, artist, album]
@@ -0,0 +1,29 @@
1
+ site: netease-music
2
+ name: search
3
+ description: Search songs on NetEase Cloud Music
4
+ type: web-api
5
+ domain: music.163.com
6
+ strategy: public
7
+ args:
8
+ query:
9
+ required: true
10
+ positional: true
11
+ description: Search keyword
12
+ limit:
13
+ required: false
14
+ default: 20
15
+ pipeline:
16
+ - fetch:
17
+ url: "https://music.163.com/api/search/get/web?s=${{ args.query }}&type=1&offset=0&limit=${{ args.limit | default(20) }}"
18
+ method: POST
19
+ headers:
20
+ Referer: "https://music.163.com"
21
+ Content-Type: application/x-www-form-urlencoded
22
+ - select: result.songs
23
+ - map:
24
+ name: "${{ item.name }}"
25
+ artist: "${{ item.artists[0].name }}"
26
+ album: "${{ item.album.name }}"
27
+ id: "${{ item.id }}"
28
+ - limit: "${{ args.limit | default(20) }}"
29
+ columns: [name, artist, album, id]
@@ -0,0 +1,19 @@
1
+ site: npm-trends
2
+ name: compare
3
+ description: Compare npm package download counts
4
+ type: web-api
5
+ domain: api.npmjs.org
6
+ strategy: public
7
+ args:
8
+ packages:
9
+ required: true
10
+ positional: true
11
+ description: Comma-separated package names (e.g. "react,vue,svelte")
12
+ period:
13
+ required: false
14
+ default: last-month
15
+ description: Time period (last-week, last-month, last-year)
16
+ pipeline:
17
+ - fetch:
18
+ url: "https://api.npmjs.org/downloads/point/${{ args.period | default('last-month') }}/${{ args.packages }}"
19
+ columns: [package, downloads, start, end]
@@ -0,0 +1,26 @@
1
+ site: nytimes
2
+ name: top
3
+ description: New York Times top stories via RSS
4
+ type: web-api
5
+ domain: rss.nytimes.com
6
+ strategy: public
7
+ args:
8
+ section:
9
+ required: false
10
+ default: HomePage
11
+ description: Section (HomePage, World, Business, Technology, Science, Arts)
12
+ limit:
13
+ required: false
14
+ default: 20
15
+ pipeline:
16
+ - fetch_text:
17
+ url: "https://rss.nytimes.com/services/xml/rss/nyt/${{ args.section | default('HomePage') }}.xml"
18
+ - parse_rss: ~
19
+ - map:
20
+ title: "${{ item.title }}"
21
+ url: "${{ item.link }}"
22
+ author: "${{ item.creator }}"
23
+ date: "${{ item.pubDate }}"
24
+ description: "${{ item.contentSnippet }}"
25
+ - limit: "${{ args.limit | default(20) }}"
26
+ columns: [title, url, author, date]
@@ -0,0 +1,51 @@
1
+ # HKUDS/OpenHarness memory/read — read MEMORY.md and per-topic memory files
2
+ # from a local OpenHarness install.
3
+ #
4
+ # Security: `args.topic` is passed via UNICLI_TOPIC env var (literal in bash).
5
+ # Path traversal is blocked by the case check rejecting slashes and `..`.
6
+ site: openharness
7
+ name: memory/read
8
+ description: Read OpenHarness MEMORY.md and per-topic memory files (~/.openharness/memory/)
9
+ type: desktop
10
+ strategy: public
11
+ binary: sh
12
+ detect: test -d ~/.openharness
13
+
14
+ args:
15
+ topic:
16
+ type: str
17
+ required: false
18
+ description: Optional topic file (without .md). When omitted, returns MEMORY.md.
19
+
20
+ pipeline:
21
+ - exec:
22
+ command: sh
23
+ args:
24
+ - -c
25
+ - |
26
+ base="$HOME/.openharness"
27
+ if [ ! -d "$base" ]; then
28
+ echo '{"error":"openharness not installed","hint":"~/.openharness not found"}'
29
+ exit 1
30
+ fi
31
+ if [ -n "$UNICLI_TOPIC" ]; then
32
+ case "$UNICLI_TOPIC" in
33
+ */*|*..*)
34
+ echo '{"error":"invalid topic name"}'
35
+ exit 1
36
+ ;;
37
+ esac
38
+ file="$base/memory/${UNICLI_TOPIC}.md"
39
+ else
40
+ file="$base/MEMORY.md"
41
+ fi
42
+ if [ ! -f "$file" ]; then
43
+ printf '%s' "$file" | jq -Rs '{error:"not found",path:.}'
44
+ exit 1
45
+ fi
46
+ jq -Rs --arg path "$file" '{path:$path,content:.}' < "$file"
47
+ env:
48
+ UNICLI_TOPIC: "${{ args.topic }}"
49
+ parse: json
50
+
51
+ columns: [path, content]
@@ -0,0 +1,28 @@
1
+ # HKUDS/OpenHarness skills/list — list installed OpenHarness skills.
2
+ #
3
+ # Security: no user input; safe argv-only call.
4
+ site: openharness
5
+ name: skills/list
6
+ description: List skills installed in the local OpenHarness (~/.openharness/skills/)
7
+ type: desktop
8
+ strategy: public
9
+ binary: sh
10
+ detect: test -d ~/.openharness/skills
11
+
12
+ pipeline:
13
+ - exec:
14
+ command: sh
15
+ args:
16
+ - -c
17
+ - |
18
+ dir="$HOME/.openharness/skills"
19
+ if [ ! -d "$dir" ]; then
20
+ echo "[]"
21
+ exit 0
22
+ fi
23
+ find "$dir" -maxdepth 2 -name '*.md' -type f 2>/dev/null \
24
+ | sed "s|$dir/||" \
25
+ | jq -R -s 'split("\n") | map(select(length > 0)) | map({name: .})'
26
+ parse: json
27
+
28
+ columns: [name]
@@ -0,0 +1,22 @@
1
+ site: openrouter
2
+ name: models
3
+ description: List all available AI models on OpenRouter
4
+ type: web-api
5
+ domain: openrouter.ai
6
+ strategy: public
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 30
11
+ pipeline:
12
+ - fetch:
13
+ url: "https://openrouter.ai/api/v1/models"
14
+ - select: data
15
+ - map:
16
+ id: "${{ item.id }}"
17
+ name: "${{ item.name }}"
18
+ context_length: "${{ item.context_length }}"
19
+ pricing_prompt: "${{ item.pricing.prompt }}"
20
+ pricing_completion: "${{ item.pricing.completion }}"
21
+ - limit: "${{ args.limit | default(30) }}"
22
+ columns: [id, name, context_length, pricing_prompt]
@@ -0,0 +1,28 @@
1
+ site: pexels
2
+ name: search
3
+ description: Search free stock photos on Pexels
4
+ type: web-api
5
+ domain: api.pexels.com
6
+ strategy: header
7
+ args:
8
+ query:
9
+ required: true
10
+ positional: true
11
+ description: Photo search query
12
+ limit:
13
+ required: false
14
+ default: 20
15
+ pipeline:
16
+ - fetch:
17
+ url: "https://api.pexels.com/v1/search?query=${{ args.query }}&per_page=${{ args.limit | default(20) }}"
18
+ headers:
19
+ Authorization: "${{ env.PEXELS_API_KEY }}"
20
+ - select: photos
21
+ - map:
22
+ photographer: "${{ item.photographer }}"
23
+ url: "${{ item.src.large }}"
24
+ alt: "${{ item.alt }}"
25
+ width: "${{ item.width }}"
26
+ height: "${{ item.height }}"
27
+ - limit: "${{ args.limit | default(20) }}"
28
+ columns: [photographer, alt, url, width, height]
@@ -0,0 +1,20 @@
1
+ site: pinduoduo
2
+ name: hot
3
+ description: Pinduoduo hot/trending products
4
+ type: web-api
5
+ domain: mobile.yangkeduo.com
6
+ strategy: cookie
7
+ args:
8
+ limit:
9
+ required: false
10
+ default: 20
11
+ pipeline:
12
+ - fetch:
13
+ url: "https://mobile.yangkeduo.com/proxy/api/api/darwin/hot_search/list"
14
+ - select: data.list
15
+ - map:
16
+ rank: "${{ index + 1 }}"
17
+ keyword: "${{ item.keyword }}"
18
+ heat: "${{ item.heat }}"
19
+ - limit: "${{ args.limit | default(20) }}"
20
+ columns: [rank, keyword, heat]
@@ -0,0 +1,16 @@
1
+ site: pypi
2
+ name: info
3
+ description: Get PyPI package details
4
+ type: web-api
5
+ domain: pypi.org
6
+ strategy: public
7
+ args:
8
+ package:
9
+ required: true
10
+ positional: true
11
+ description: Package name (e.g. "requests", "flask")
12
+ pipeline:
13
+ - fetch:
14
+ url: "https://pypi.org/pypi/${{ args.package }}/json"
15
+ - select: info
16
+ columns: [name, version, summary, author, license]