publishport-opencli 1.0.0 → 1.0.2

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 (333) hide show
  1. package/README.md +61 -61
  2. package/README.zh-CN.md +68 -68
  3. package/cli-manifest.json +954 -61
  4. package/clis/1688/shared.js +2 -2
  5. package/clis/36kr/news.js +1 -1
  6. package/clis/_atlassian/shared.js +1 -1
  7. package/clis/_shared/article/auth.js +1 -1
  8. package/clis/_shared/article/publish.js +1 -1
  9. package/clis/_shared/content-guard.js +1 -1
  10. package/clis/_shared/self-hosted-sites.js +2 -0
  11. package/clis/_shared/site-auth.js +1 -1
  12. package/clis/_shared/token-auth.js +2 -2
  13. package/clis/_shared/video-publish.js +1 -1
  14. package/clis/aibase/news.js +1 -1
  15. package/clis/amazon/shared.js +2 -2
  16. package/clis/antigravity/SKILL.md +12 -12
  17. package/clis/antigravity/storage.js +1 -1
  18. package/clis/apple-podcasts/episodes.js +1 -1
  19. package/clis/archive/item.js +1 -1
  20. package/clis/archive/search.js +1 -1
  21. package/clis/archive/snapshots.js +1 -1
  22. package/clis/archive/wayback.js +1 -1
  23. package/clis/arxiv/author.js +1 -1
  24. package/clis/baijiahao/publish.js +1 -1
  25. package/clis/bbc/utils.js +1 -1
  26. package/clis/bloomberg/businessweek.js +1 -1
  27. package/clis/bloomberg/utils.js +1 -1
  28. package/clis/booking/search.js +1 -1
  29. package/clis/boss/utils.js +1 -1
  30. package/clis/chatgpt/ask.js +1 -1
  31. package/clis/chatgpt/detail.js +1 -1
  32. package/clis/chatgpt/history.js +1 -1
  33. package/clis/chatgpt/project-file-add.js +1 -1
  34. package/clis/chatgpt/project-list.js +1 -1
  35. package/clis/chatgpt/utils.js +2 -2
  36. package/clis/chess/utils.js +1 -1
  37. package/clis/claude/ask.js +1 -1
  38. package/clis/claude/history.js +1 -1
  39. package/clis/claude/utils.js +1 -1
  40. package/clis/codex/extract-diff.js +1 -1
  41. package/clis/coingecko/coin.js +1 -1
  42. package/clis/crates/utils.js +1 -1
  43. package/clis/csdn/stats.js +1 -1
  44. package/clis/dblp/utils.js +1 -1
  45. package/clis/defillama/utils.js +1 -1
  46. package/clis/devto/publish.js +1 -1
  47. package/clis/discord-app/utils.js +1 -1
  48. package/clis/dockerhub/utils.js +1 -1
  49. package/clis/douban/utils.js +1 -1
  50. package/clis/douyin/_shared/tos-upload.js +1 -1
  51. package/clis/douyin/hashtag.js +1 -1
  52. package/clis/douyin/publish-image.js +1 -1
  53. package/clis/douyin/publish.js +1 -1
  54. package/clis/eastmoney/announcement.js +1 -1
  55. package/clis/eastmoney/rank.js +1 -1
  56. package/clis/eastmoney/sectors.js +1 -1
  57. package/clis/endoflife/utils.js +1 -1
  58. package/clis/flathub/utils.js +1 -1
  59. package/clis/gemini/detail.js +1 -1
  60. package/clis/gemini/read.js +1 -1
  61. package/clis/geogebra/add-circle.js +1 -1
  62. package/clis/geogebra/add-line.js +1 -1
  63. package/clis/geogebra/add-point.js +1 -1
  64. package/clis/geogebra/add-polygon.js +1 -1
  65. package/clis/geogebra/eval.js +1 -1
  66. package/clis/geogebra/hexagon.js +1 -1
  67. package/clis/geogebra/info.js +1 -1
  68. package/clis/geogebra/triangle.js +1 -1
  69. package/clis/ghost/login.js +1 -0
  70. package/clis/ghost/publish.js +1 -1
  71. package/clis/ghost/shared.js +24 -1
  72. package/clis/ghost/sites.js +1 -0
  73. package/clis/ghost/whoami.js +1 -1
  74. package/clis/gitee/user.js +2 -2
  75. package/clis/github-trending/repos.js +1 -1
  76. package/clis/goproxy/utils.js +1 -1
  77. package/clis/grok/export-all.js +1 -1
  78. package/clis/grok/export.js +1 -1
  79. package/clis/hashnode/publish.js +1 -1
  80. package/clis/hf/datasets.js +1 -1
  81. package/clis/hf/models.js +1 -1
  82. package/clis/hf/paper.js +1 -1
  83. package/clis/hf/spaces.js +1 -1
  84. package/clis/homebrew/utils.js +1 -1
  85. package/clis/instagram/note.js +1 -1
  86. package/clis/jimeng/generate.js +1 -1
  87. package/clis/juejin/utils.js +1 -1
  88. package/clis/kuaishou/publish.js +1 -1
  89. package/clis/lesswrong/tag.js +1 -1
  90. package/clis/lichess/utils.js +1 -1
  91. package/clis/linkedin/search.js +2 -2
  92. package/clis/linux-do/feed.js +2 -2
  93. package/clis/lobsters/domain.js +1 -1
  94. package/clis/mastodon/login.js +1 -0
  95. package/clis/mastodon/post.js +1 -1
  96. package/clis/mastodon/shared.js +10 -10
  97. package/clis/mastodon/sites.js +1 -0
  98. package/clis/mastodon/whoami.js +1 -1
  99. package/clis/maven/utils.js +1 -1
  100. package/clis/mdn/search.js +1 -1
  101. package/clis/medium/tag.js +1 -1
  102. package/clis/notebooklm/current.js +1 -1
  103. package/clis/notebooklm/get.js +1 -1
  104. package/clis/notebooklm/history.js +1 -1
  105. package/clis/notebooklm/note-list.js +1 -1
  106. package/clis/notebooklm/notes-get.js +1 -1
  107. package/clis/notebooklm/open.js +1 -1
  108. package/clis/notebooklm/source-fulltext.js +1 -1
  109. package/clis/notebooklm/source-get.js +1 -1
  110. package/clis/notebooklm/source-guide.js +1 -1
  111. package/clis/notebooklm/source-list.js +1 -1
  112. package/clis/notebooklm/summary.js +1 -1
  113. package/clis/notebooklm/utils.js +1 -1
  114. package/clis/npm/utils.js +1 -1
  115. package/clis/nuget/utils.js +1 -1
  116. package/clis/nvd/cve.js +1 -1
  117. package/clis/oeis/utils.js +1 -1
  118. package/clis/ones/common.js +2 -2
  119. package/clis/ones/me.js +1 -1
  120. package/clis/ones/tasks.js +1 -1
  121. package/clis/ones/token-info.js +1 -1
  122. package/clis/ones/worklog.js +1 -1
  123. package/clis/openalex/utils.js +1 -1
  124. package/clis/oschina/stats.js +1 -1
  125. package/clis/osv/utils.js +1 -1
  126. package/clis/packagist/utils.js +1 -1
  127. package/clis/pixiv/detail.js +1 -1
  128. package/clis/pixiv/user.js +1 -1
  129. package/clis/producthunt/utils.js +1 -1
  130. package/clis/pypi/utils.js +1 -1
  131. package/clis/qiita/gql.js +2 -2
  132. package/clis/quora/__fixtures__/dom.html +39 -0
  133. package/clis/quora/answer-comments.js +9 -0
  134. package/clis/quora/answer-detail.js +1 -0
  135. package/clis/quora/answer-queue.js +1 -0
  136. package/clis/quora/comment.js +23 -0
  137. package/clis/quora/create-answer.js +4 -4
  138. package/clis/quora/create-question.js +3 -3
  139. package/clis/quora/follow.js +15 -0
  140. package/clis/quora/followers.js +1 -0
  141. package/clis/quora/question.js +1 -0
  142. package/clis/quora/search.js +1 -0
  143. package/clis/quora/shared.js +26 -11
  144. package/clis/quora/stats.js +1 -0
  145. package/clis/quora/upvote.js +14 -0
  146. package/clis/quora/user-answers.js +1 -0
  147. package/clis/quora/user.js +1 -0
  148. package/clis/rest-countries/utils.js +1 -1
  149. package/clis/rfc/utils.js +1 -1
  150. package/clis/rubygems/utils.js +1 -1
  151. package/clis/semanticscholar/utils.js +1 -1
  152. package/clis/slock/errors.js +1 -1
  153. package/clis/spotify/spotify.js +1 -1
  154. package/clis/spotify/utils.js +1 -1
  155. package/clis/stackoverflow/utils.js +1 -1
  156. package/clis/steam/utils.js +1 -1
  157. package/clis/substack/auth.js +2 -2
  158. package/clis/suno/generate.js +2 -2
  159. package/clis/suno/list.js +3 -3
  160. package/clis/telegram/send.js +1 -1
  161. package/clis/tiktok/creator-videos.js +1 -1
  162. package/clis/tiktok/publish.js +1 -1
  163. package/clis/tiktok/utils.js +1 -1
  164. package/clis/trae-cn/activity.js +1 -1
  165. package/clis/trae-cn/approve.js +1 -1
  166. package/clis/trae-cn/ask.js +1 -1
  167. package/clis/trae-cn/dump.js +1 -1
  168. package/clis/trae-cn/export.js +1 -1
  169. package/clis/trae-cn/model.js +1 -1
  170. package/clis/trae-cn/new.js +1 -1
  171. package/clis/trae-cn/read.js +1 -1
  172. package/clis/trae-cn/screenshot.js +1 -1
  173. package/clis/trae-cn/select-model.js +1 -1
  174. package/clis/trae-cn/send.js +1 -1
  175. package/clis/trae-cn/setup.js +1 -1
  176. package/clis/trae-cn/status.js +1 -1
  177. package/clis/trae-cn/targets.js +1 -1
  178. package/clis/trae-cn/watch.js +1 -1
  179. package/clis/trae-solo/state-fs.js +1 -1
  180. package/clis/tumblr/publish.js +1 -1
  181. package/clis/tvmaze/utils.js +1 -1
  182. package/clis/twitter/bookmark-folder.js +1 -1
  183. package/clis/twitter/download.js +1 -1
  184. package/clis/twitter/followers.js +2 -2
  185. package/clis/twitter/following.js +2 -2
  186. package/clis/twitter/likes.js +1 -1
  187. package/clis/twitter/list-add-batch.js +1 -1
  188. package/clis/twitter/list-add-core.js +1 -1
  189. package/clis/twitter/list-add.js +1 -1
  190. package/clis/twitter/list-create.js +1 -1
  191. package/clis/twitter/list-delete.js +3 -3
  192. package/clis/twitter/list-remove-batch.js +1 -1
  193. package/clis/twitter/list-remove.js +1 -1
  194. package/clis/twitter/list-tweets.js +1 -1
  195. package/clis/twitter/profile.js +1 -1
  196. package/clis/twitter/search.js +1 -1
  197. package/clis/twitter/shared.js +1 -1
  198. package/clis/twitter/tweets.js +1 -1
  199. package/clis/uisdc/news.js +1 -1
  200. package/clis/v2ex/daily.js +2 -2
  201. package/clis/v2ex/me.js +2 -2
  202. package/clis/v2ex/notifications.js +1 -1
  203. package/clis/wikidata/utils.js +1 -1
  204. package/clis/wikipedia/page.js +2 -2
  205. package/clis/wikipedia/summary.js +1 -1
  206. package/clis/wikipedia/utils.js +1 -1
  207. package/clis/wordpress/login.js +1 -1
  208. package/clis/wordpress/publish.js +1 -1
  209. package/clis/wordpress/shared.js +3 -3
  210. package/clis/wordpress/sites.js +1 -0
  211. package/clis/wordpress/whoami.js +1 -1
  212. package/clis/woshipm/stats.js +1 -1
  213. package/clis/xiaoe/content.js +1 -1
  214. package/clis/xiaohongshu/draft-delete.js +1 -1
  215. package/clis/xiaohongshu/draft-open.js +1 -1
  216. package/clis/xiaohongshu/draft-utils.js +2 -2
  217. package/clis/xiaohongshu/publish-video.js +1 -1
  218. package/clis/xiaohongshu/publish.js +1 -1
  219. package/clis/xiaoyuzhou/auth.js +1 -1
  220. package/clis/xiaoyuzhou/transcript.js +1 -1
  221. package/clis/yollomi/background.js +1 -1
  222. package/clis/yollomi/edit.js +1 -1
  223. package/clis/yollomi/generate.js +1 -1
  224. package/clis/yollomi/try-on.js +1 -1
  225. package/clis/youtube/publish.js +1 -1
  226. package/clis/zhihu/answer-comments.js +1 -1
  227. package/clis/zhihu/answer-detail.js +1 -1
  228. package/clis/zhihu/collection.js +2 -2
  229. package/clis/zhihu/collections.js +1 -1
  230. package/clis/zhihu/question.js +1 -1
  231. package/clis/zhihu/search.js +1 -1
  232. package/clis/zhihu/target.js +1 -1
  233. package/clis/zhihu/user-arg.js +1 -1
  234. package/dist/src/adapter-shadow.js +1 -1
  235. package/dist/src/browser/analyze.js +1 -1
  236. package/dist/src/browser/article-extract.d.ts +1 -1
  237. package/dist/src/browser/base-page.js +3 -3
  238. package/dist/src/browser/cdp.js +1 -1
  239. package/dist/src/browser/daemon-client.d.ts +1 -1
  240. package/dist/src/browser/daemon-lifecycle.js +6 -6
  241. package/dist/src/browser/daemon-version.js +1 -1
  242. package/dist/src/browser/dom-snapshot.d.ts +1 -1
  243. package/dist/src/browser/dom-snapshot.js +2 -2
  244. package/dist/src/browser/errors.js +2 -2
  245. package/dist/src/browser/network-cache.js +1 -1
  246. package/dist/src/browser/profile.js +1 -1
  247. package/dist/src/browser/target-resolver.js +4 -4
  248. package/dist/src/browser/verify-fixture.js +1 -1
  249. package/dist/src/browser-session-lock.js +1 -1
  250. package/dist/src/build-manifest.d.ts +1 -1
  251. package/dist/src/build-manifest.js +1 -1
  252. package/dist/src/cli-argv-preprocess.d.ts +4 -4
  253. package/dist/src/cli-argv-preprocess.js +1 -1
  254. package/dist/src/cli.d.ts +1 -1
  255. package/dist/src/cli.js +19 -19
  256. package/dist/src/commanderAdapter.js +1 -1
  257. package/dist/src/commands/auth.js +2 -2
  258. package/dist/src/commands/daemon.d.ts +4 -4
  259. package/dist/src/commands/daemon.js +1 -1
  260. package/dist/src/completion-shared.js +12 -12
  261. package/dist/src/completion.d.ts +2 -2
  262. package/dist/src/constants.d.ts +1 -1
  263. package/dist/src/constants.js +1 -1
  264. package/dist/src/daemon-utils.d.ts +1 -1
  265. package/dist/src/daemon-utils.js +1 -1
  266. package/dist/src/daemon.d.ts +2 -2
  267. package/dist/src/daemon.js +1 -1
  268. package/dist/src/discovery.d.ts +7 -7
  269. package/dist/src/discovery.js +2 -2
  270. package/dist/src/doctor.d.ts +1 -1
  271. package/dist/src/doctor.js +6 -6
  272. package/dist/src/electron-apps.d.ts +1 -1
  273. package/dist/src/electron-apps.js +1 -1
  274. package/dist/src/errors.d.ts +2 -2
  275. package/dist/src/errors.js +1 -1
  276. package/dist/src/execution.js +1 -1
  277. package/dist/src/external.d.ts +1 -1
  278. package/dist/src/external.js +1 -1
  279. package/dist/src/help.d.ts +1 -1
  280. package/dist/src/help.js +3 -3
  281. package/dist/src/hooks.d.ts +1 -1
  282. package/dist/src/launcher.js +2 -2
  283. package/dist/src/logger.d.ts +1 -1
  284. package/dist/src/main.d.ts +1 -1
  285. package/dist/src/main.js +1 -1
  286. package/dist/src/observation/artifact.js +2 -2
  287. package/dist/src/package-paths.js +1 -1
  288. package/dist/src/package-paths.test.d.ts +1 -0
  289. package/dist/src/plugin-manifest.d.ts +12 -3
  290. package/dist/src/plugin-manifest.js +1 -1
  291. package/dist/src/plugin-scaffold.d.ts +2 -2
  292. package/dist/src/plugin-scaffold.js +9 -9
  293. package/dist/src/plugin.d.ts +4 -4
  294. package/dist/src/plugin.js +10 -10
  295. package/dist/src/rate-limit.js +1 -1
  296. package/dist/src/registry-api.d.ts +1 -1
  297. package/dist/src/runtime-detect.d.ts +1 -1
  298. package/dist/src/serialization.js +1 -1
  299. package/dist/src/skills.js +6 -6
  300. package/dist/src/user-runtime.d.ts +8 -0
  301. package/dist/src/user-runtime.js +1 -0
  302. package/dist/src/user-runtime.test.d.ts +1 -0
  303. package/dist/src/validate.js +1 -1
  304. package/dist/src/validate.test.d.ts +1 -1
  305. package/docs/guide/browser-bridge.md +23 -23
  306. package/docs/guide/electron-app-cli.md +3 -3
  307. package/docs/guide/exit-codes.md +3 -3
  308. package/docs/guide/extending-opencli.md +37 -37
  309. package/docs/guide/getting-started.md +19 -19
  310. package/docs/guide/installation.md +6 -6
  311. package/docs/guide/plugins.md +32 -32
  312. package/docs/guide/remote-orchestration.md +5 -5
  313. package/docs/guide/troubleshooting.md +9 -9
  314. package/package.json +3 -2
  315. package/scripts/fetch-adapters.js +6 -6
  316. package/scripts/postinstall.js +14 -14
  317. package/skills/opencli-adapter-author/SKILL.md +24 -24
  318. package/skills/opencli-adapter-author/references/adapter-template.md +13 -13
  319. package/skills/opencli-adapter-author/references/api-discovery.md +25 -25
  320. package/skills/opencli-adapter-author/references/coverage-matrix.md +3 -3
  321. package/skills/opencli-adapter-author/references/field-decode-playbook.md +10 -10
  322. package/skills/opencli-adapter-author/references/jsdom-fixture-pattern.md +2 -2
  323. package/skills/opencli-adapter-author/references/site-memory.md +11 -11
  324. package/skills/opencli-adapter-author/references/site-recon.md +7 -7
  325. package/skills/opencli-adapter-author/references/strategy-selection.md +3 -3
  326. package/skills/opencli-adapter-author/references/success-rate-pitfalls.md +4 -4
  327. package/skills/opencli-adapter-author/references/typed-errors.md +2 -2
  328. package/skills/opencli-autofix/SKILL.md +29 -29
  329. package/skills/opencli-browser/SKILL.md +55 -55
  330. package/skills/opencli-browser-sitemap/SKILL.md +7 -7
  331. package/skills/opencli-sitemap-author/SKILL.md +11 -11
  332. package/skills/opencli-sitemap-author/references/sitemap-schema.md +19 -19
  333. package/skills/opencli-usage/SKILL.md +43 -43
@@ -4,8 +4,8 @@
4
4
 
5
5
  ### "Extension not connected"
6
6
 
7
- - Ensure the opencli Browser Bridge extension is installed and **enabled** in `chrome://extensions`.
8
- - Run `opencli doctor` to diagnose connectivity.
7
+ - Ensure the ppcli Browser Bridge extension is installed and **enabled** in `chrome://extensions`.
8
+ - Run `ppcli doctor` to diagnose connectivity.
9
9
 
10
10
  ### Empty data or 'Unauthorized' error
11
11
 
@@ -16,11 +16,11 @@
16
16
 
17
17
  - A healthy Browser Bridge connection does not guarantee that the current page target exposes the data your adapter expects.
18
18
  - Some browser adapters are sensitive to the active host or page context.
19
- - Example: `opencli 1688 item` may fail with `did not expose product context` if the target is too broad.
19
+ - Example: `ppcli 1688 item` may fail with `did not expose product context` if the target is too broad.
20
20
  - Retry on a real item page, refresh the page in Chrome, and if needed narrow the target, for example:
21
21
 
22
22
  ```bash
23
- OPENCLI_CDP_TARGET=detail.1688.com opencli 1688 item 841141931191 -f json
23
+ OPENCLI_CDP_TARGET=detail.1688.com ppcli 1688 item 841141931191 -f json
24
24
  ```
25
25
 
26
26
  ### Node API errors
@@ -34,15 +34,15 @@ OPENCLI_CDP_TARGET=detail.1688.com opencli 1688 item 841141931191 -f json
34
34
  curl localhost:19825/logs
35
35
 
36
36
  # Stop the daemon
37
- opencli daemon stop
37
+ ppcli daemon stop
38
38
 
39
39
  # Full diagnostics
40
- opencli doctor
40
+ ppcli doctor
41
41
  ```
42
42
 
43
- > The daemon is persistent and stays alive until explicitly stopped (`opencli daemon stop`) or the package is uninstalled.
43
+ > The daemon is persistent and stays alive until explicitly stopped (`ppcli daemon stop`) or the package is uninstalled.
44
44
 
45
- > When the CLI detects a stale daemon (version mismatch after `npm install -g @jackwener/opencli@latest`), it first asks the daemon to shut down via `/shutdown`, then falls back to `SIGKILL` if the daemon does not release the port within 3 seconds. Manual `opencli daemon stop` is only needed if SIGKILL itself is rejected (cross-user owner / cross-machine PID file).
45
+ > When the CLI detects a stale daemon (version mismatch after `npm install -g @jackwener/opencli@latest`), it first asks the daemon to shut down via `/shutdown`, then falls back to `SIGKILL` if the daemon does not release the port within 3 seconds. Manual `ppcli daemon stop` is only needed if SIGKILL itself is rejected (cross-user owner / cross-machine PID file).
46
46
 
47
47
  ### Desktop adapter connection issues
48
48
 
@@ -66,4 +66,4 @@ npx tsc --noEmit
66
66
  ## Getting Help
67
67
 
68
68
  - [GitHub Issues](https://github.com/jackwener/opencli/issues) — Bug reports and feature requests
69
- - Run `opencli doctor` for comprehensive diagnostics
69
+ - Run `ppcli doctor` for comprehensive diagnostics
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "publishport-opencli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": false
@@ -12,6 +12,7 @@
12
12
  "type": "module",
13
13
  "main": "dist/src/main.js",
14
14
  "bin": {
15
+ "ppcli": "dist/src/main.js",
15
16
  "opencli": "dist/src/main.js"
16
17
  },
17
18
  "exports": {
@@ -96,8 +97,8 @@
96
97
  "ws": "^8.18.0"
97
98
  },
98
99
  "devDependencies": {
99
- "@types/jsdom": "^27.0.0",
100
100
  "@types/js-yaml": "^4.0.9",
101
+ "@types/jsdom": "^27.0.0",
101
102
  "@types/node": "^25.5.2",
102
103
  "@types/turndown": "^5.0.6",
103
104
  "@types/ws": "^8.5.13",
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Sparse adapter sync: keeps ~/.opencli/clis/ clean by removing stale overrides.
4
+ * Sparse adapter sync: keeps ~/.ppcli/clis/ clean by removing stale overrides.
5
5
  *
6
6
  * Strategy (hash-based, site-level granularity):
7
7
  * - When an official site has upstream changes: DELETE the local override
@@ -10,7 +10,7 @@
10
10
  * - User-created custom sites (not in package): always preserved
11
11
  * - Skips entirely if already synced at the same version
12
12
  *
13
- * ~/.opencli/clis/ is a sparse override layer, not a full copy.
13
+ * ~/.ppcli/clis/ is a sparse override layer, not a full copy.
14
14
  * Only eject-ed or user-modified sites appear here.
15
15
  *
16
16
  * Only runs on global install (npm install -g) or explicit OPENCLI_FETCH=1.
@@ -24,7 +24,7 @@ import { createHash } from 'node:crypto';
24
24
  import { join, resolve, dirname, relative } from 'node:path';
25
25
  import { homedir } from 'node:os';
26
26
 
27
- const OPENCLI_DIR = join(homedir(), '.opencli');
27
+ const OPENCLI_DIR = join(homedir(), '.ppcli');
28
28
  const USER_CLIS_DIR = join(OPENCLI_DIR, 'clis');
29
29
  const MANIFEST_PATH = join(OPENCLI_DIR, 'adapter-manifest.json');
30
30
  const PACKAGE_ROOT = resolve(import.meta.dirname, '..');
@@ -159,7 +159,7 @@ export function fetchAdapters() {
159
159
 
160
160
  // 2. Sparse cleanup: for changed/removed official sites, delete local overrides.
161
161
  // Do NOT copy new versions — runtime falls back to package baseline.
162
- // Only eject-ed sites live in ~/.opencli/clis/.
162
+ // Only eject-ed sites live in ~/.ppcli/clis/.
163
163
  let cleared = 0;
164
164
  for (const site of changedSites) {
165
165
  const siteDir = join(USER_CLIS_DIR, site);
@@ -204,9 +204,9 @@ export function fetchAdapters() {
204
204
  }
205
205
  if (yamlCleaned > 0) log(`Cleaned up ${yamlCleaned} stale .yaml adapter files`);
206
206
 
207
- // 4. Clean up legacy compat shim files from ~/.opencli/
207
+ // 4. Clean up legacy compat shim files from ~/.ppcli/
208
208
  // These were created by an older approach that placed re-export shims directly
209
- // in ~/.opencli/ (e.g., registry.js, errors.js, browser/). The current approach
209
+ // in ~/.ppcli/ (e.g., registry.js, errors.js, browser/). The current approach
210
210
  // uses a node_modules/@jackwener/opencli symlink instead.
211
211
  const LEGACY_SHIM_FILES = [
212
212
  'registry.js', 'errors.js', 'utils.js', 'launcher.js', 'logger.js', 'types.js',
@@ -22,36 +22,36 @@ import { homedir } from 'node:os';
22
22
 
23
23
  // ── Completion script content ──────────────────────────────────────────────
24
24
 
25
- const BASH_COMPLETION = `# Bash completion for opencli (auto-installed)
25
+ const BASH_COMPLETION = `# Bash completion for ppcli (auto-installed)
26
26
  _opencli_completions() {
27
27
  local cur words cword
28
28
  _get_comp_words_by_ref -n : cur words cword
29
29
 
30
30
  local completions
31
- completions=$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)
31
+ completions=$(ppcli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)
32
32
 
33
33
  COMPREPLY=( $(compgen -W "$completions" -- "$cur") )
34
34
  __ltrim_colon_completions "$cur"
35
35
  }
36
- complete -F _opencli_completions opencli
36
+ complete -F _opencli_completions ppcli
37
37
  `;
38
38
 
39
- const ZSH_COMPLETION = `#compdef opencli
40
- # Zsh completion for opencli (auto-installed)
39
+ const ZSH_COMPLETION = `#compdef ppcli
40
+ # Zsh completion for ppcli (auto-installed)
41
41
  _opencli() {
42
42
  local -a completions
43
43
  local cword=$((CURRENT - 1))
44
- completions=(\${(f)"$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)"})
44
+ completions=(\${(f)"$(ppcli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)"})
45
45
  compadd -a completions
46
46
  }
47
47
  _opencli
48
48
  `;
49
49
 
50
- const FISH_COMPLETION = `# Fish completion for opencli (auto-installed)
51
- complete -c opencli -f -a '(
50
+ const FISH_COMPLETION = `# Fish completion for ppcli (auto-installed)
51
+ complete -c ppcli -f -a '(
52
52
  set -l tokens (commandline -cop)
53
53
  set -l cursor (count (commandline -cop))
54
- opencli --get-completions --cursor $cursor $tokens[2..] 2>/dev/null
54
+ ppcli --get-completions --cursor $cursor $tokens[2..] 2>/dev/null
55
55
  )'
56
56
  `;
57
57
 
@@ -113,7 +113,7 @@ function main() {
113
113
  }
114
114
  case 'bash': {
115
115
  const userCompDir = join(home, '.bash_completion.d');
116
- const completionFile = join(userCompDir, 'opencli');
116
+ const completionFile = join(userCompDir, 'ppcli');
117
117
  ensureDir(userCompDir);
118
118
  writeFileSync(completionFile, BASH_COMPLETION, 'utf8');
119
119
 
@@ -127,7 +127,7 @@ function main() {
127
127
  }
128
128
  case 'fish': {
129
129
  const completionsDir = join(home, '.config', 'fish', 'completions');
130
- const completionFile = join(completionsDir, 'opencli.fish');
130
+ const completionFile = join(completionsDir, 'ppcli.fish');
131
131
  ensureDir(completionsDir);
132
132
  writeFileSync(completionFile, FISH_COMPLETION, 'utf8');
133
133
 
@@ -144,7 +144,7 @@ function main() {
144
144
  }
145
145
 
146
146
  // ── Spotify credentials template ────────────────────────────────────
147
- const opencliDir = join(home, '.opencli');
147
+ const opencliDir = join(home, '.ppcli');
148
148
  const spotifyEnvFile = join(opencliDir, 'spotify.env');
149
149
  ensureDir(opencliDir);
150
150
  if (!existsSync(spotifyEnvFile)) {
@@ -156,7 +156,7 @@ function main() {
156
156
  'utf8'
157
157
  );
158
158
  console.log(`✓ Spotify credentials template created at ${spotifyEnvFile}`);
159
- console.log(` Edit the file and add your Client ID and Secret, then run: opencli spotify auth`);
159
+ console.log(` Edit the file and add your Client ID and Secret, then run: ppcli spotify auth`);
160
160
  }
161
161
 
162
162
  // ── Browser Bridge setup hint ───────────────────────────────────────
@@ -166,7 +166,7 @@ function main() {
166
166
  console.log(' 1. Download: https://github.com/jackwener/opencli/releases');
167
167
  console.log(' 2. In Chrome or Chromium, open chrome://extensions → enable Developer Mode → Load unpacked');
168
168
  console.log('');
169
- console.log(' Then run \x1b[36mopencli doctor\x1b[0m to verify.');
169
+ console.log(' Then run \x1b[36mppcli doctor\x1b[0m to verify.');
170
170
  console.log('');
171
171
 
172
172
  }
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  name: opencli-adapter-author
3
- description: Use when writing an OpenCLI adapter for a new site or adding a new command to an existing site. Guides end-to-end from first recon through field decoding, adapter coding, and verify. Replaces opencli-oneshot / opencli-explorer. For ad-hoc browser driving (no adapter), see opencli-browser instead; for a top-level orientation to opencli, see opencli-usage.
4
- allowed-tools: Bash(opencli:*), Read, Edit, Write, Grep
3
+ description: Use when writing an ppcli adapter for a new site or adding a new command to an existing site. Guides end-to-end from first recon through field decoding, adapter coding, and verify. Replaces opencli-oneshot / opencli-explorer. For ad-hoc browser driving (no adapter), see opencli-browser instead; for a top-level orientation to ppcli, see opencli-usage.
4
+ allowed-tools: Bash(ppcli:*), Read, Edit, Write, Grep
5
5
  ---
6
6
 
7
7
  # opencli-adapter-author
8
8
 
9
- 你是要给一个站点写 adapter 的 agent。这份 skill 目标:**从零到通过 `opencli browser verify` 的 30 分钟内闭环**。
9
+ 你是要给一个站点写 adapter 的 agent。这份 skill 目标:**从零到通过 `ppcli browser verify` 的 30 分钟内闭环**。
10
10
 
11
- 全程用现有工具:`opencli browser *` / `opencli doctor` / `opencli browser init` / `opencli browser verify`。没有新命令。
11
+ 全程用现有工具:`ppcli browser *` / `ppcli doctor` / `ppcli browser init` / `ppcli browser verify`。没有新命令。
12
12
 
13
13
  调试浏览器型 adapter 时,优先直接带上 `--trace on --keep-tab true --window foreground`。`--trace on` 每轮都落 trace artifact,`summary.md` 是失败/成功复盘入口;`--keep-tab true --window foreground` 让 tab lease 保留且浏览器窗口在前台,方便核对最终页面状态。
14
14
 
@@ -54,7 +54,7 @@ Strategy classes:
54
54
  | `COOKIE_API` | stable | Node-side `fetch` + `page.getCookies()` / header helper 能拿数据 | cookie/CSRF 来源清楚,replay 非空 |
55
55
  | `UI_SELECTOR` | visible-ui | publish/upload/click/表单,或页面语义比内部接口更稳 | selector 有语义锚点;错误路径是 typed error |
56
56
  | `DOM_STATE` | visible-ui | 数据在 hydration state / bootstrap JSON / SSR HTML 里 | state key / script JSON / HTML 结构明确 |
57
- | `PAGE_FETCH` | internal-unstable | 只能在页面上下文 `fetch` 才能复用 same-origin/session/runtime | `opencli browser eval fetch(...)` 非空;必须解释为什么避不开内部接口 |
57
+ | `PAGE_FETCH` | internal-unstable | 只能在页面上下文 `fetch` 才能复用 same-origin/session/runtime | `ppcli browser eval fetch(...)` 非空;必须解释为什么避不开内部接口 |
58
58
  | `INTERCEPT` | internal-unstable | 请求签名复杂,但页面自己能自然发出请求 | 触发 UI 后能截到目标 response;必须解释为什么 UI/DOM 不够 |
59
59
 
60
60
  选择规则:优先 `PUBLIC_API` / `COOKIE_API`。如果 UI/DOM 语义稳定,不要强行升级到 `PAGE_FETCH` / `INTERCEPT`。只有公开/官方接口不可用、UI/DOM 无法表达目标数据或操作时,才承担无契约内部接口的维护成本。
@@ -68,14 +68,14 @@ START
68
68
 
69
69
 
70
70
  ┌──────────────────────────┐
71
- opencli doctor 通? │── no ──→ 修桥接(doctor 输出里的提示)
71
+ ppcli doctor 通? │── no ──→ 修桥接(doctor 输出里的提示)
72
72
  └──────────────────────────┘
73
73
  │ yes
74
74
 
75
75
  ┌────────────────────────────────────────────────────┐
76
76
  │ 读站点记忆: │
77
- │ 1. ~/.opencli/sites/<site>/endpoints.json │
78
- │ 2. ~/.opencli/sites/<site>/notes.md │
77
+ │ 1. ~/.ppcli/sites/<site>/endpoints.json │
78
+ │ 2. ~/.ppcli/sites/<site>/notes.md │
79
79
  │ 3. references/site-memory/<site>.md │
80
80
  └────────────────────────────────────────────────────┘
81
81
  │ 命中 endpoint + 字段 → 直接跳到【endpoint 验证】(不跳写 adapter!memory 可能过期)
@@ -110,14 +110,14 @@ START
110
110
 
111
111
 
112
112
  ┌──────────────────────────┐
113
- opencli browser init │ 生成 ~/.opencli/clis/<site>/<name>.js 骨架
113
+ ppcli browser init │ 生成 ~/.ppcli/clis/<site>/<name>.js 骨架
114
114
  │ 复制最像的邻居 adapter │
115
115
  │ 改 name / URL / 映射三处 │
116
116
  └──────────────────────────┘
117
117
 
118
118
 
119
119
  ┌──────────────────────────┐
120
- opencli browser verify │── 失败 ──→ autofix skill,用 --trace retain-on-failure 回对应步骤
120
+ ppcli browser verify │── 失败 ──→ autofix skill,用 --trace retain-on-failure 回对应步骤
121
121
  └──────────────────────────┘
122
122
  │ 成功
123
123
 
@@ -127,7 +127,7 @@ START
127
127
  │ 对得上
128
128
 
129
129
  ┌──────────────────────────┐
130
- │ 回写 ~/.opencli/sites/ │ endpoints / field-map / notes / fixtures
130
+ │ 回写 ~/.ppcli/sites/ │ endpoints / field-map / notes / fixtures
131
131
  └──────────────────────────┘
132
132
 
133
133
 
@@ -139,14 +139,14 @@ DONE
139
139
  ## Runbook(一步一步勾选)
140
140
 
141
141
  ```
142
- [ ] 1. opencli doctor 返回 "Everything looks good"
142
+ [ ] 1. ppcli doctor 返回 "Everything looks good"
143
143
  [ ] 2. 读站点记忆:
144
- [ ] ~/.opencli/sites/<site>/endpoints.json 存在?里面有想要的 endpoint?
144
+ [ ] ~/.ppcli/sites/<site>/endpoints.json 存在?里面有想要的 endpoint?
145
145
  [ ] references/site-memory/<site>.md 存在?看"已知 endpoint"节
146
146
  [ ] 命中后:**跳到第 5(endpoint 验证) + 第 7(字段核对)**,不能直接跳第 9 写 adapter
147
147
  [ ] memory 写入超过 30 天(看 `verified_at`)→ 当作过期,按冷启动走 Step 3 → 4
148
148
  [ ] 3. 侦察(site-recon.md):
149
- [ ] **首选**:`opencli browser analyze <url>` 一步拿 pattern + 反爬 + 最近 adapter + next step
149
+ [ ] **首选**:`ppcli browser analyze <url>` 一步拿 pattern + 反爬 + 最近 adapter + next step
150
150
  [ ] `analyze` 结论模糊时再手跑:`open` → `wait time 2` (或 `wait xhr <regex>`) → `network`
151
151
  [ ] 定 Pattern(A / B / C / D / E)
152
152
  [ ] 4. API 发现(api-discovery.md)按 Pattern 选 §:
@@ -173,21 +173,21 @@ DONE
173
173
  [ ] 类型 / 单位 / 百分比格式清楚
174
174
  [ ] 顺序:识别列 → 业务数字 → metadata
175
175
  [ ] 9. 写 adapter(adapter-template.md):
176
- [ ] opencli browser init <site>/<name>
176
+ [ ] ppcli browser init <site>/<name>
177
177
  [ ] 找同站点或同类型最像的 adapter,cp 过来
178
178
  [ ] 改 name / URL / 字段映射
179
- [ ] 10. opencli browser verify <site>/<name>
180
- [ ] 首轮通过后立刻 `--write-fixture` 生成 `~/.opencli/sites/<site>/verify/<cmd>.json` 种子
179
+ [ ] 10. ppcli browser verify <site>/<name>
180
+ [ ] 首轮通过后立刻 `--write-fixture` 生成 `~/.ppcli/sites/<site>/verify/<cmd>.json` 种子
181
181
  [ ] 手改种子:加 `patterns`(URL / 日期 / ID 格式)+ `notEmpty`(核心字段)+ 收紧 `rowCount`
182
- [ ] 再跑一次 `opencli browser verify <site>/<name>`,确认 ✓ matches fixture
182
+ [ ] 再跑一次 `ppcli browser verify <site>/<name>`,确认 ✓ matches fixture
183
183
  [ ] 11. 字段值 vs 网页肉眼比对(别只看 "Adapter works!")
184
184
  [ ] 12. 回写站点记忆(**verify 通过 + 肉眼比对对得上之后**,schema 见 `references/site-memory.md`):
185
185
  [ ] `endpoints.json`:以 endpoint 的短名为 key,value = `{url, method, params.{required,optional}, response, verified_at: YYYY-MM-DD, notes}`
186
186
  [ ] `field-map.json`:只追加新代号。key = 字段代号,value = `{meaning, verified_at: YYYY-MM-DD, source}`;**已存在的 key 不要覆盖**,有冲突先和网页肉眼值对齐再写
187
187
  [ ] `notes.md`:顶部追加一段 `## YYYY-MM-DD by <agent/user>`,写本次写 adapter 时遇到的新坑 / 新结论
188
- [ ] `verify/<cmd>.json`:**必填。** `opencli browser verify` 的期望值(args / rowCount / columns / types / patterns / notEmpty),Step 10 已经让你生成了,这里只是 checklist
188
+ [ ] `verify/<cmd>.json`:**必填。** `ppcli browser verify` 的期望值(args / rowCount / columns / types / patterns / notEmpty),Step 10 已经让你生成了,这里只是 checklist
189
189
  [ ] `fixtures/<cmd>-<YYYYMMDDHHMM>.json`:存一份该 endpoint 的完整响应样本(去掉 cookie / token / 用户私有字段再存),给后续字段对比 / 离线 replay 用
190
- [ ] 调试过程中如果在 repo / adapter 目录 dump 过临时文件(`.dbg-*.html` / `raw-*.json` / 等),**在 commit 前清干净**——这些本来就该落在 `~/.opencli/sites/<site>/fixtures/` 或 `/tmp/`
190
+ [ ] 调试过程中如果在 repo / adapter 目录 dump 过临时文件(`.dbg-*.html` / `raw-*.json` / 等),**在 commit 前清干净**——这些本来就该落在 `~/.ppcli/sites/<site>/fixtures/` 或 `/tmp/`
191
191
  ```
192
192
 
193
193
  ---
@@ -225,7 +225,7 @@ DONE
225
225
  | `references/field-decode-playbook.md` | Step 7 字段不在词典时 |
226
226
  | `references/output-design.md` | Step 8 命名 / 类型 / 顺序 |
227
227
  | `references/adapter-template.md` | Step 9 文件结构 + 活例子 `convertible.js` |
228
- | `references/site-memory.md` | 总览:in-repo 种子 + 本地 `~/.opencli/sites/` 的两层结构 |
228
+ | `references/site-memory.md` | 总览:in-repo 种子 + 本地 `~/.ppcli/sites/` 的两层结构 |
229
229
  | `references/site-memory/<site>.md` | Step 2 读站点公共知识(eastmoney / xueqiu / bilibili / tonghuashun 已铺) |
230
230
  | `references/success-rate-pitfalls.md` | Step 7 / 11 踩坑前翻:11 种"verify 能过但数据是错的"静默失败(含 aria-label locale-dependence) |
231
231
  | `references/jsdom-fixture-pattern.md` | 当 adapter 走 `page.evaluate` 内 DOM 抽取、且 mocked-evaluate 单测漏 silent bug 时——把 HTML 冻进 `clis/<site>/__fixtures__/` 用 JSDOM 跑(含 fixture 创建 mandatory `awk 'NF>0'` 收紧 + reverse-validate 纪律) |
@@ -240,16 +240,16 @@ DONE
240
240
  - **中间解析对象 key 不能跟 `columns` 任一项重叠**(否则 silent-column-drop audit 误判,PR #1329 R1 真踩过;改成专属命名 + push row 时 destructure aliasing)
241
241
  - **`browser:` field 决定 func 签名**:`browser:false → (args)`,`browser:true → (page, args)`。搞反时 `args` 实际是 debug flag,所有外部参数 silent fallback 到 default(PR #1329 upstream 之前 8 个 non-browser adapter 全踩过这个)
242
242
  - 已知失败按 [`references/typed-errors.md`](./references/typed-errors.md) 5-classification 抛对应 typed error;**不要** silent `return []`,**不要** silent `return [{sentinel}]`,**不要** `Math.max/min` silent clamp 外部参数
243
- - 写私人 adapter 用 `~/.opencli/clis/<site>/<name>.js`(免 build);要提 PR 才 copy 到 `clis/<site>/<name>.js`
243
+ - 写私人 adapter 用 `~/.ppcli/clis/<site>/<name>.js`(免 build);要提 PR 才 copy 到 `clis/<site>/<name>.js`
244
244
  - 站点记忆每轮回写:没记忆 → 用 skill → 产生记忆 → 下次变 5 分钟
245
- - **调试过程中的原始 dump / 抓包 / HTML 样本只能落在 `~/.opencli/sites/<site>/fixtures/` 或 `/tmp/`。严禁在 repo 根目录、`clis/<site>/` 或当前工作目录留 `.dbg-*.html / raw-*.json / sample.*` 这类临时文件**(PR diff 会带上去,别人 review 时很烦)。
245
+ - **调试过程中的原始 dump / 抓包 / HTML 样本只能落在 `~/.ppcli/sites/<site>/fixtures/` 或 `/tmp/`。严禁在 repo 根目录、`clis/<site>/` 或当前工作目录留 `.dbg-*.html / raw-*.json / sample.*` 这类临时文件**(PR diff 会带上去,别人 review 时很烦)。
246
246
  - **JSDOM unit-test fixture(`clis/<site>/__fixtures__/<command>.html`)是上面那条的例外**——它是有意 commit 进 repo 的 review artifact,不是临时 dump。但因此 quality bar 要更高:必须按 `references/jsdom-fixture-pattern.md` 的 5 步做完(含 mandatory `awk 'NF>0'` 空白行收紧),并 reverse-validate 一道证明 regression guard 真能挂。
247
247
 
248
248
  ---
249
249
 
250
250
  ## 卡住了
251
251
 
252
- - 诊断类:`opencli doctor` → 看 `notes.md` → 搜 autofix skill
252
+ - 诊断类:`ppcli doctor` → 看 `notes.md` → 搜 autofix skill
253
253
  - 字段解码类:`field-decode-playbook.md` 全三节走完 → 先输出 raw 迭代
254
254
  - endpoint 找不到:api-discovery §5 intercept 兜底
255
255
 
@@ -94,7 +94,7 @@ cli({
94
94
  cli({
95
95
  site: 'eastmoney', // 第一级命名空间,目录名一致
96
96
  name: 'convertible', // 第二级,CLI 上的子命令
97
- description: '...', // 一句话,出现在 `opencli list` 和 `opencli <site> -h`
97
+ description: '...', // 一句话,出现在 `ppcli list` 和 `ppcli <site> -h`
98
98
  domain: 'push2.eastmoney.com', // 主要请求域名(诊断面板用)
99
99
  strategy: Strategy.PUBLIC, // PUBLIC / COOKIE / INTERCEPT / UI
100
100
  browser: false, // PUBLIC 几乎总是 false;COOKIE/INTERCEPT/UI 一律 true
@@ -327,7 +327,7 @@ const SEND_BUTTON_SELECTORS = [
327
327
  5. **失败要 typed fail-fast**:找不到 control 应该 `CommandExecutionError` / send-failed,不要返回空 rows 或假成功
328
328
  6. **不要给 framework 加 `--i18n "zh:提交,ja:送信"` 这种 flag** —— 等于把 fallback list 从 adapter 挪到 CLI,多一层 indirection 还要维护翻译字典。这是 over-engineering,已经在评审时被否
329
329
 
330
- 为什么不在 daemon 端固定 Chrome locale?因为 opencli **不启动 Chrome**——daemon 是连用户已经在跑的 Chrome(CDP via extension),用户可能就是中文 UI / 中文资料检索需求。强制 en-US 会破坏用户的正当工作流。
330
+ 为什么不在 daemon 端固定 Chrome locale?因为 ppcli **不启动 Chrome**——daemon 是连用户已经在跑的 Chrome(CDP via extension),用户可能就是中文 UI / 中文资料检索需求。强制 en-US 会破坏用户的正当工作流。
331
331
 
332
332
  ### Cookie 域的双查
333
333
 
@@ -383,9 +383,9 @@ if (/暂时没有提醒内容/.test(html)) {
383
383
 
384
384
  ---
385
385
 
386
- ## Verify fixture(每个 adapter 配一份 `~/.opencli/sites/<site>/verify/<name>.json`)
386
+ ## Verify fixture(每个 adapter 配一份 `~/.ppcli/sites/<site>/verify/<name>.json`)
387
387
 
388
- verify fixture 是"adapter 产出长什么样"的结构锚点。没有它,`opencli browser verify` 只能证"adapter 能跑完不抛",证不出数据没错位。**必写**。
388
+ verify fixture 是"adapter 产出长什么样"的结构锚点。没有它,`ppcli browser verify` 只能证"adapter 能跑完不抛",证不出数据没错位。**必写**。
389
389
 
390
390
  详细 schema 见 `site-memory.md` 的 `verify/<cmd>.json` 节。这里只讲两个容易踩的地方:
391
391
 
@@ -428,28 +428,28 @@ named-flag adapter(`hot` / `latest` 类)可以直接让工具生成种子:
428
428
 
429
429
  ```bash
430
430
  # 1. 让 verify 先跑一遍,--write-fixture 生成种子(默认追加 --limit 3)
431
- opencli browser verify 1point3acres/hot --write-fixture
431
+ ppcli browser verify 1point3acres/hot --write-fixture
432
432
 
433
- # 2. 手改 ~/.opencli/sites/1point3acres/verify/hot.json
433
+ # 2. 手改 ~/.ppcli/sites/1point3acres/verify/hot.json
434
434
  # - patterns: 加 URL / 日期 / ID 正则
435
435
  # - notEmpty: 加核心字段(title / author / url)
436
436
  # - rowCount: 收紧到业务合理区间
437
437
 
438
438
  # 3. 再跑 verify,fixture 吃得动就 OK
439
- opencli browser verify 1point3acres/hot
439
+ ppcli browser verify 1point3acres/hot
440
440
  ```
441
441
 
442
442
  positional adapter 目前 `--write-fixture` 没法表达主语,**首份 fixture 要手写**:
443
443
 
444
444
  ```bash
445
445
  # 1. 先直跑 adapter 看输出长啥样
446
- opencli 1point3acres thread 1173710 --limit 2 --format json | head
446
+ ppcli 1point3acres thread 1173710 --limit 2 --format json | head
447
447
 
448
- # 2. 照着响应手写 ~/.opencli/sites/1point3acres/verify/thread.json
448
+ # 2. 照着响应手写 ~/.ppcli/sites/1point3acres/verify/thread.json
449
449
  # (args 一定用数组: ["1173710", "--limit", "2"])
450
450
 
451
451
  # 3. 跑 verify 核对
452
- opencli browser verify 1point3acres/thread
452
+ ppcli browser verify 1point3acres/thread
453
453
  ```
454
454
 
455
455
  机器生成的种子只有 rowCount.min=1 / columns / types,挡不住字段值错位。**patterns + notEmpty 无论哪种情形都是肉写的**。
@@ -459,13 +459,13 @@ opencli browser verify 1point3acres/thread
459
459
  ## 私人 adapter vs repo 贡献
460
460
 
461
461
  ```
462
- ~/.opencli/clis/<site>/<name>.js # 私人
462
+ ~/.ppcli/clis/<site>/<name>.js # 私人
463
463
  clis/<site>/<name>.js # repo 贡献
464
464
  ```
465
465
 
466
466
  **两者在 `cli({...})` 层面完全一样**。差别只在运行入口:
467
467
 
468
- - 私人:写完立即可跑(`opencli <site> <name>`)
468
+ - 私人:写完立即可跑(`ppcli <site> <name>`)
469
469
  - repo:要 `npm run build` 才被注册
470
470
 
471
- 先在 `~/.opencli/clis/` 调通再拷贝到 `clis/`。
471
+ 先在 `~/.ppcli/clis/` 调通再拷贝到 `clis/`。
@@ -12,7 +12,7 @@
12
12
 
13
13
  ### 0.1 反爬厂商 → 决定 fetch 能不能从 Node 走
14
14
 
15
- `opencli browser analyze <url>` 的 `anti_bot` 字段给答案;手查看 cookies 也行:
15
+ `ppcli browser analyze <url>` 的 `anti_bot` 字段给答案;手查看 cookies 也行:
16
16
 
17
17
  | cookie / body 信号 | 厂商 | 裸 Node fetch / curl 结果 | 策略 |
18
18
  |------------------|------|-----|-----|
@@ -30,7 +30,7 @@
30
30
  判断:
31
31
 
32
32
  ```bash
33
- opencli browser eval "fetch('https://<target-subdomain>/api/...', {credentials:'include'}).then(r=>r.status).catch(e=>'cors:'+e.message)"
33
+ ppcli browser eval "fetch('https://<target-subdomain>/api/...', {credentials:'include'}).then(r=>r.status).catch(e=>'cors:'+e.message)"
34
34
  ```
35
35
 
36
36
  - 返回 status 数字 → CORS 通,继续
@@ -39,7 +39,7 @@ opencli browser eval "fetch('https://<target-subdomain>/api/...', {credentials:'
39
39
  **挡住时**:不要把 `credentials:'include'` 当万能药——这只解决"带 cookie",不解决"跨 origin"。降级路径:
40
40
 
41
41
  1. 换同 origin 的 endpoint(同一个 subdomain 下的 API 往往更宽松)
42
- 2. 用 `opencli browser open https://<target-subdomain>/`,让页面在目标 subdomain 本身打开,再 fetch 相对路径
42
+ 2. 用 `ppcli browser open https://<target-subdomain>/`,让页面在目标 subdomain 本身打开,再 fetch 相对路径
43
43
  3. 真跨域且无替代 → 走 `§5 intercept`,从页面自身发的请求里抓响应
44
44
 
45
45
  ---
@@ -49,7 +49,7 @@ opencli browser eval "fetch('https://<target-subdomain>/api/...', {credentials:'
49
49
  ### 拿候选
50
50
 
51
51
  ```bash
52
- opencli browser network
52
+ ppcli browser network
53
53
  ```
54
54
 
55
55
  默认输出是 JSON,每个候选都带:
@@ -59,7 +59,7 @@ opencli browser network
59
59
 
60
60
  静态资源 / 埋点 / 追踪默认已过滤。默认会保留 JSON / XML / plain text / `text/javascript` 这类 API 响应;如果你确定浏览器 DevTools 里有目标请求但这里缺失,用 `--all` 查一遍是否被 content-type 或 URL 噪音过滤挡掉。
61
61
 
62
- 如果是冷启动,先看 `opencli browser analyze <url>` 里的 `api_candidates`:
62
+ 如果是冷启动,先看 `ppcli browser analyze <url>` 里的 `api_candidates`:
63
63
 
64
64
  - `verdict: "likely_data"`:优先 replay 这条,拿 status / content-type / sample shape 填 strategy note
65
65
  - `verdict: "maybe_data"`:可以试,但必须人工核对字段是否是目标业务数据
@@ -81,7 +81,7 @@ opencli browser network
81
81
  已经知道目标 body 该含哪些字段就直接让 CLI 把列表筛到只剩候选,不用自己 scroll 翻 shape:
82
82
 
83
83
  ```bash
84
- opencli browser network --filter author,text,likes
84
+ ppcli browser network --filter author,text,likes
85
85
  ```
86
86
 
87
87
  - 字段以英文逗号分隔;AND 语义,必须每个字段都作为 shape 路径的**任意一段**出现才保留(`$.data.items[0].author` 命中 `author`、`items`、`data` 都算)
@@ -97,10 +97,10 @@ opencli browser network --filter author,text,likes
97
97
  候选定了再拉完整 body(by key,不是 index — 数组顺序会随每次 capture 变):
98
98
 
99
99
  ```bash
100
- opencli browser network --detail <key>
100
+ ppcli browser network --detail <key>
101
101
  ```
102
102
 
103
- capture 会持久化到 `~/.opencli/cache/browser-network/<session>.json`(默认 TTL 24h),所以 `--detail` 即使跨多条其他命令也还在。
103
+ capture 会持久化到 `~/.ppcli/cache/browser-network/<session>.json`(默认 TTL 24h),所以 `--detail` 即使跨多条其他命令也还在。
104
104
 
105
105
  ### 关键 request headers
106
106
 
@@ -120,14 +120,14 @@ capture 会持久化到 `~/.opencli/cache/browser-network/<session>.json`(默
120
120
 
121
121
  ```bash
122
122
  # 滚到底(虚拟列表)
123
- opencli browser eval "window.scrollTo(0, document.body.scrollHeight)"
124
- opencli browser wait time 2
125
- opencli browser network
123
+ ppcli browser eval "window.scrollTo(0, document.body.scrollHeight)"
124
+ ppcli browser wait time 2
125
+ ppcli browser network
126
126
 
127
127
  # 点某个按钮
128
- opencli browser click <N>
129
- opencli browser wait time 2
130
- opencli browser network
128
+ ppcli browser click <N>
129
+ ppcli browser wait time 2
130
+ ppcli browser network
131
131
  ```
132
132
 
133
133
  ---
@@ -137,7 +137,7 @@ opencli browser network
137
137
  首屏数据常挂在这几个全局变量上:
138
138
 
139
139
  ```bash
140
- opencli browser eval "Object.keys(window).filter(k=>k.startsWith('__'))"
140
+ ppcli browser eval "Object.keys(window).filter(k=>k.startsWith('__'))"
141
141
  ```
142
142
 
143
143
  命中的常见名:
@@ -153,7 +153,7 @@ opencli browser eval "Object.keys(window).filter(k=>k.startsWith('__'))"
153
153
  取数据:
154
154
 
155
155
  ```bash
156
- opencli browser eval "JSON.stringify(window.__NEXT_DATA__).slice(0, 3000)"
156
+ ppcli browser eval "JSON.stringify(window.__NEXT_DATA__).slice(0, 3000)"
157
157
  ```
158
158
 
159
159
  **关键**:inline state 只覆盖首屏的一部分(通常是 SEO 相关字段)。分页 / 评论 / 懒加载还是得回 §1 抓 API。
@@ -167,7 +167,7 @@ opencli browser eval "JSON.stringify(window.__NEXT_DATA__).slice(0, 3000)"
167
167
  ### 扫 script src
168
168
 
169
169
  ```bash
170
- opencli browser eval "[...document.querySelectorAll('script[src]')].map(s=>s.src).filter(s=>!/\\.(css|png|jpg|svg|woff|mp4)$/.test(s)&&!/googletagmanager|crazyegg|sentry|doubleclick|amazon-adsystem|cloudflare/.test(s))"
170
+ ppcli browser eval "[...document.querySelectorAll('script[src]')].map(s=>s.src).filter(s=>!/\\.(css|png|jpg|svg|woff|mp4)$/.test(s)&&!/googletagmanager|crazyegg|sentry|doubleclick|amazon-adsystem|cloudflare/.test(s))"
171
171
  ```
172
172
 
173
173
  看结果里的 hostname:
@@ -178,7 +178,7 @@ opencli browser eval "[...document.querySelectorAll('script[src]')].map(s=>s.src
178
178
  ### 搜 bundle 里的 baseURL
179
179
 
180
180
  ```bash
181
- opencli browser eval "(async()=>{const s=[...document.querySelectorAll('script[src]')].map(e=>e.src).find(s=>/main|app|index|bundle|chunk/.test(s));if(!s)return'no bundle';const t=await fetch(s).then(r=>r.text());const patterns=['baseURL','baseUrl','BASE_URL','apiHost','apiBase','API_HOST','API_BASE'];const hits=[];for(const p of patterns){let i=-1;while((i=t.indexOf(p,i+1))>-1&&hits.length<5)hits.push(t.slice(Math.max(0,i-5),i+80));}return hits})()"
181
+ ppcli browser eval "(async()=>{const s=[...document.querySelectorAll('script[src]')].map(e=>e.src).find(s=>/main|app|index|bundle|chunk/.test(s));if(!s)return'no bundle';const t=await fetch(s).then(r=>r.text());const patterns=['baseURL','baseUrl','BASE_URL','apiHost','apiBase','API_HOST','API_BASE'];const hits=[];for(const p of patterns){let i=-1;while((i=t.indexOf(p,i+1))>-1&&hits.length<5)hits.push(t.slice(Math.max(0,i-5),i+80));}return hits})()"
182
182
  ```
183
183
 
184
184
  命中 `baseURL:"https://api.foo.com"` 直接拿 host 拼 endpoint。
@@ -188,7 +188,7 @@ opencli browser eval "(async()=>{const s=[...document.querySelectorAll('script[s
188
188
  像 eastmoney 这种经验 endpoint 可以直接喂:
189
189
 
190
190
  ```bash
191
- opencli browser eval "fetch('https://push2.eastmoney.com/api/qt/clist/get?fs=m:1+t:2&pn=1&pz=5&fltt=2&fid=f3&po=1&fields=f2,f3,f12,f14').then(r=>r.json())"
191
+ ppcli browser eval "fetch('https://push2.eastmoney.com/api/qt/clist/get?fs=m:1+t:2&pn=1&pz=5&fltt=2&fid=f3&po=1&fields=f2,f3,f12,f14').then(r=>r.json())"
192
192
  ```
193
193
 
194
194
  200 且数据对得上就认。
@@ -202,7 +202,7 @@ opencli browser eval "fetch('https://push2.eastmoney.com/api/qt/clist/get?fs=m:1
202
202
 
203
203
  ```bash
204
204
  # 当前页加 .json 试
205
- opencli browser eval "fetch(location.pathname.replace(/\\/$/,'')+'.json').then(r=>r.ok?r.json():'no')"
205
+ ppcli browser eval "fetch(location.pathname.replace(/\\/$/,'')+'.json').then(r=>r.ok?r.json():'no')"
206
206
  ```
207
207
 
208
208
  ---
@@ -214,7 +214,7 @@ opencli browser eval "fetch(location.pathname.replace(/\\/$/,'')+'.json').then(r
214
214
  ### Cookie 里
215
215
 
216
216
  ```bash
217
- opencli browser eval "document.cookie.split('; ').reduce((o,x)=>{const[k,v]=x.split('=');o[k]=v;return o},{})"
217
+ ppcli browser eval "document.cookie.split('; ').reduce((o,x)=>{const[k,v]=x.split('=');o[k]=v;return o},{})"
218
218
  ```
219
219
 
220
220
  常见 token cookie 名:`ct0`(Twitter CSRF)、`xq_a_token`(雪球)、`SESSDATA`(B 站)、`_csrf / csrfToken`(通用)。
@@ -226,7 +226,7 @@ opencli browser eval "document.cookie.split('; ').reduce((o,x)=>{const[k,v]=x.sp
226
226
  ### localStorage / sessionStorage 里
227
227
 
228
228
  ```bash
229
- opencli browser eval "Object.keys(localStorage).map(k=>k+' => '+localStorage.getItem(k).slice(0,50))"
229
+ ppcli browser eval "Object.keys(localStorage).map(k=>k+' => '+localStorage.getItem(k).slice(0,50))"
230
230
  ```
231
231
 
232
232
  找 `token / auth / jwt / bearer` 关键字。
@@ -236,7 +236,7 @@ opencli browser eval "Object.keys(localStorage).map(k=>k+' => '+localStorage.get
236
236
  有些站的 Bearer 是全站一个常量(Twitter 的匿名 Bearer)。在 bundle 里搜:
237
237
 
238
238
  ```bash
239
- opencli browser eval "(async()=>{const s=[...document.querySelectorAll('script[src]')].map(e=>e.src).find(s=>/main|app|bundle/.test(s));const t=await fetch(s).then(r=>r.text());const m=t.match(/Bearer\\s+[\\w-]{20,}/g);return m?.slice(0,3)||'not found'})()"
239
+ ppcli browser eval "(async()=>{const s=[...document.querySelectorAll('script[src]')].map(e=>e.src).find(s=>/main|app|bundle/.test(s));const t=await fetch(s).then(r=>r.text());const m=t.match(/Bearer\\s+[\\w-]{20,}/g);return m?.slice(0,3)||'not found'})()"
240
240
  ```
241
241
 
242
242
  ### Store action 绕签名
@@ -245,10 +245,10 @@ Vue + Pinia / Redux / React Context 有时直接调 store method 能绕过签名
245
245
 
246
246
  ```bash
247
247
  # Pinia
248
- opencli browser eval "typeof __pinia !== 'undefined' ? Object.keys(__pinia.state.value) : 'no pinia'"
248
+ ppcli browser eval "typeof __pinia !== 'undefined' ? Object.keys(__pinia.state.value) : 'no pinia'"
249
249
 
250
250
  # 直接调 store action(每个站点具体 action 名要查)
251
- opencli browser eval "window.__pinia.state.value.someStore.someMethod({...})"
251
+ ppcli browser eval "window.__pinia.state.value.someStore.someMethod({...})"
252
252
  ```
253
253
 
254
254
  ---