@jackwener/opencli 1.1.1 → 1.2.1

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 (523) hide show
  1. package/.github/workflows/build-extension.yml +3 -3
  2. package/.github/workflows/ci.yml +6 -6
  3. package/.github/workflows/doc-check.yml +3 -3
  4. package/.github/workflows/e2e-headed.yml +2 -2
  5. package/.github/workflows/pkg-pr-new.yml +2 -2
  6. package/.github/workflows/release.yml +3 -3
  7. package/.github/workflows/security.yml +2 -2
  8. package/CONTRIBUTING.md +39 -1
  9. package/README.md +13 -10
  10. package/README.zh-CN.md +43 -17
  11. package/SKILL.md +10 -5
  12. package/dist/browser/cdp.d.ts +4 -4
  13. package/dist/browser/cdp.js +39 -16
  14. package/dist/browser/daemon-client.d.ts +4 -2
  15. package/dist/browser/daemon-client.js +17 -4
  16. package/dist/browser/dom-helpers.js +38 -7
  17. package/dist/browser/dom-snapshot.d.ts +86 -0
  18. package/dist/browser/dom-snapshot.js +729 -0
  19. package/dist/browser/dom-snapshot.test.d.ts +11 -0
  20. package/dist/browser/dom-snapshot.test.js +212 -0
  21. package/dist/browser/index.d.ts +2 -0
  22. package/dist/browser/index.js +1 -0
  23. package/dist/browser/mcp.js +3 -1
  24. package/dist/browser/page.d.ts +14 -24
  25. package/dist/browser/page.js +46 -6
  26. package/dist/build-manifest.d.ts +11 -4
  27. package/dist/build-manifest.js +59 -21
  28. package/dist/build-manifest.test.js +58 -2
  29. package/dist/cli-manifest.json +3856 -1509
  30. package/dist/cli.js +66 -0
  31. package/dist/clis/barchart/greeks.js +1 -1
  32. package/dist/clis/barchart/options.js +1 -1
  33. package/dist/clis/barchart/quote.js +1 -1
  34. package/dist/clis/bilibili/download.js +1 -1
  35. package/dist/clis/bilibili/following.js +1 -1
  36. package/dist/clis/bilibili/subtitle.js +1 -1
  37. package/dist/clis/bilibili/user-videos.js +1 -1
  38. package/dist/clis/boss/batchgreet.js +10 -97
  39. package/dist/clis/boss/chatlist.js +8 -25
  40. package/dist/clis/boss/chatmsg.js +11 -42
  41. package/dist/clis/boss/common.d.ts +92 -0
  42. package/dist/clis/boss/common.js +223 -0
  43. package/dist/clis/boss/detail.js +7 -49
  44. package/dist/clis/boss/exchange.js +13 -79
  45. package/dist/clis/boss/greet.js +18 -145
  46. package/dist/clis/boss/invite.js +26 -121
  47. package/dist/clis/boss/joblist.js +6 -31
  48. package/dist/clis/boss/mark.js +12 -85
  49. package/dist/clis/boss/recommend.js +10 -49
  50. package/dist/clis/boss/resume.js +18 -118
  51. package/dist/clis/boss/search.js +12 -60
  52. package/dist/clis/boss/send.js +17 -151
  53. package/dist/clis/boss/stats.js +18 -69
  54. package/dist/clis/coupang/add-to-cart.js +1 -1
  55. package/dist/clis/devto/tag.yaml +34 -0
  56. package/dist/clis/devto/top.yaml +29 -0
  57. package/dist/clis/devto/user.yaml +33 -0
  58. package/dist/clis/douban/book-hot.d.ts +1 -0
  59. package/dist/clis/douban/book-hot.js +14 -0
  60. package/dist/clis/douban/marks.d.ts +1 -0
  61. package/dist/clis/douban/marks.js +115 -0
  62. package/dist/clis/douban/movie-hot.d.ts +1 -0
  63. package/dist/clis/douban/movie-hot.js +14 -0
  64. package/dist/clis/douban/reviews.d.ts +1 -0
  65. package/dist/clis/douban/reviews.js +106 -0
  66. package/dist/clis/douban/search.d.ts +1 -0
  67. package/dist/clis/douban/search.js +16 -0
  68. package/dist/clis/douban/shared.d.ts +4 -0
  69. package/dist/clis/douban/shared.js +155 -0
  70. package/dist/clis/douban/subject.yaml +76 -0
  71. package/dist/clis/douban/top250.yaml +70 -0
  72. package/dist/clis/douban/utils.d.ts +35 -0
  73. package/dist/clis/douban/utils.js +48 -0
  74. package/dist/clis/facebook/add-friend.yaml +43 -0
  75. package/dist/clis/facebook/events.yaml +44 -0
  76. package/dist/clis/facebook/feed.yaml +63 -0
  77. package/dist/clis/facebook/friends.yaml +42 -0
  78. package/dist/clis/facebook/groups.yaml +50 -0
  79. package/dist/clis/facebook/join-group.yaml +44 -0
  80. package/dist/clis/facebook/memories.yaml +39 -0
  81. package/dist/clis/facebook/notifications.yaml +40 -0
  82. package/dist/clis/facebook/profile.yaml +37 -0
  83. package/dist/clis/facebook/search.yaml +46 -0
  84. package/dist/clis/google/news.d.ts +5 -0
  85. package/dist/clis/google/news.js +58 -0
  86. package/dist/clis/google/search.d.ts +10 -0
  87. package/dist/clis/google/search.js +127 -0
  88. package/dist/clis/google/suggest.d.ts +5 -0
  89. package/dist/clis/google/suggest.js +34 -0
  90. package/dist/clis/google/trends.d.ts +5 -0
  91. package/dist/clis/google/trends.js +38 -0
  92. package/dist/clis/google/utils.d.ts +9 -0
  93. package/dist/clis/google/utils.js +23 -0
  94. package/dist/clis/google/utils.test.d.ts +1 -0
  95. package/dist/clis/google/utils.test.js +75 -0
  96. package/dist/clis/grok/ask.d.ts +14 -0
  97. package/dist/clis/grok/ask.js +257 -65
  98. package/dist/clis/grok/ask.test.d.ts +1 -0
  99. package/dist/clis/grok/ask.test.js +36 -0
  100. package/dist/clis/instagram/comment.yaml +52 -0
  101. package/dist/clis/instagram/explore.yaml +43 -0
  102. package/dist/clis/instagram/follow.yaml +41 -0
  103. package/dist/clis/instagram/followers.yaml +51 -0
  104. package/dist/clis/instagram/following.yaml +51 -0
  105. package/dist/clis/instagram/like.yaml +46 -0
  106. package/dist/clis/instagram/profile.yaml +42 -0
  107. package/dist/clis/instagram/save.yaml +46 -0
  108. package/dist/clis/instagram/saved.yaml +40 -0
  109. package/dist/clis/instagram/search.yaml +43 -0
  110. package/dist/clis/instagram/unfollow.yaml +38 -0
  111. package/dist/clis/instagram/unlike.yaml +46 -0
  112. package/dist/clis/instagram/unsave.yaml +46 -0
  113. package/dist/clis/instagram/user.yaml +54 -0
  114. package/dist/clis/jike/repost.js +1 -1
  115. package/dist/clis/jimeng/generate.yaml +1 -0
  116. package/dist/clis/linux-do/category.yaml +1 -0
  117. package/dist/clis/lobsters/active.yaml +29 -0
  118. package/dist/clis/lobsters/hot.yaml +29 -0
  119. package/dist/clis/lobsters/newest.yaml +29 -0
  120. package/dist/clis/lobsters/tag.yaml +34 -0
  121. package/dist/clis/medium/feed.d.ts +1 -0
  122. package/dist/clis/medium/feed.js +15 -0
  123. package/dist/clis/medium/search.d.ts +1 -0
  124. package/dist/clis/medium/search.js +15 -0
  125. package/dist/clis/medium/shared.d.ts +5 -0
  126. package/dist/clis/medium/shared.js +78 -0
  127. package/dist/clis/medium/user.d.ts +1 -0
  128. package/dist/clis/medium/user.js +15 -0
  129. package/dist/clis/reddit/comment.js +1 -1
  130. package/dist/clis/reddit/read.js +1 -1
  131. package/dist/clis/reddit/save.js +1 -1
  132. package/dist/clis/reddit/subreddit.yaml +1 -0
  133. package/dist/clis/reddit/subscribe.js +1 -1
  134. package/dist/clis/reddit/upvote.js +1 -1
  135. package/dist/clis/sinablog/article.d.ts +1 -0
  136. package/dist/clis/sinablog/article.js +14 -0
  137. package/dist/clis/sinablog/hot.d.ts +1 -0
  138. package/dist/clis/sinablog/hot.js +14 -0
  139. package/dist/clis/sinablog/search.d.ts +1 -0
  140. package/dist/clis/sinablog/search.js +51 -0
  141. package/dist/clis/sinablog/shared.d.ts +7 -0
  142. package/dist/clis/sinablog/shared.js +187 -0
  143. package/dist/clis/sinablog/user.d.ts +1 -0
  144. package/dist/clis/sinablog/user.js +15 -0
  145. package/dist/clis/substack/feed.d.ts +1 -0
  146. package/dist/clis/substack/feed.js +15 -0
  147. package/dist/clis/substack/publication.d.ts +1 -0
  148. package/dist/clis/substack/publication.js +15 -0
  149. package/dist/clis/substack/search.d.ts +1 -0
  150. package/dist/clis/substack/search.js +77 -0
  151. package/dist/clis/substack/shared.d.ts +4 -0
  152. package/dist/clis/substack/shared.js +129 -0
  153. package/dist/clis/tiktok/comment.yaml +66 -0
  154. package/dist/clis/tiktok/explore.yaml +39 -0
  155. package/dist/clis/tiktok/follow.yaml +39 -0
  156. package/dist/clis/tiktok/following.yaml +46 -0
  157. package/dist/clis/tiktok/friends.yaml +47 -0
  158. package/dist/clis/tiktok/like.yaml +38 -0
  159. package/dist/clis/tiktok/live.yaml +51 -0
  160. package/dist/clis/tiktok/notifications.yaml +52 -0
  161. package/dist/clis/tiktok/profile.yaml +45 -0
  162. package/dist/clis/tiktok/save.yaml +34 -0
  163. package/dist/clis/tiktok/search.yaml +46 -0
  164. package/dist/clis/tiktok/unfollow.yaml +44 -0
  165. package/dist/clis/tiktok/unlike.yaml +38 -0
  166. package/dist/clis/tiktok/unsave.yaml +36 -0
  167. package/dist/clis/tiktok/user.yaml +44 -0
  168. package/dist/clis/twitter/download.d.ts +1 -1
  169. package/dist/clis/twitter/download.js +3 -3
  170. package/dist/clis/twitter/followers.js +1 -1
  171. package/dist/clis/twitter/following.js +1 -1
  172. package/dist/clis/twitter/thread.js +1 -1
  173. package/dist/clis/twitter/timeline.d.ts +23 -0
  174. package/dist/clis/twitter/timeline.js +42 -14
  175. package/dist/clis/twitter/timeline.test.d.ts +1 -0
  176. package/dist/clis/twitter/timeline.test.js +102 -0
  177. package/dist/clis/wikipedia/random.d.ts +1 -0
  178. package/dist/clis/wikipedia/random.js +19 -0
  179. package/dist/clis/wikipedia/search.js +3 -3
  180. package/dist/clis/wikipedia/summary.js +4 -9
  181. package/dist/clis/wikipedia/trending.d.ts +1 -0
  182. package/dist/clis/wikipedia/trending.js +35 -0
  183. package/dist/clis/wikipedia/utils.d.ts +28 -0
  184. package/dist/clis/wikipedia/utils.js +13 -0
  185. package/dist/clis/xiaohongshu/creator-note-detail.js +1 -1
  186. package/dist/clis/xiaohongshu/creator-note-detail.test.js +2 -0
  187. package/dist/clis/xiaohongshu/creator-notes.test.js +2 -0
  188. package/dist/clis/xiaohongshu/download.js +1 -1
  189. package/dist/clis/xueqiu/earnings-date.yaml +69 -0
  190. package/dist/clis/xueqiu/search.yaml +2 -1
  191. package/dist/clis/xueqiu/stock.yaml +2 -0
  192. package/dist/clis/yahoo-finance/quote.js +1 -1
  193. package/dist/commanderAdapter.js +13 -7
  194. package/dist/daemon.js +21 -0
  195. package/dist/discovery.d.ts +8 -0
  196. package/dist/discovery.js +105 -19
  197. package/dist/doctor.js +3 -1
  198. package/dist/doctor.test.js +46 -2
  199. package/dist/engine.test.d.ts +0 -3
  200. package/dist/engine.test.js +74 -6
  201. package/dist/execution.d.ts +4 -2
  202. package/dist/execution.js +31 -7
  203. package/dist/explore.d.ts +76 -3
  204. package/dist/explore.js +11 -4
  205. package/dist/generate.d.ts +41 -2
  206. package/dist/generate.js +5 -4
  207. package/dist/main.js +2 -1
  208. package/dist/pipeline/executor.d.ts +4 -2
  209. package/dist/pipeline/executor.js +54 -15
  210. package/dist/pipeline/executor.test.js +33 -6
  211. package/dist/pipeline/registry.d.ts +1 -1
  212. package/dist/pipeline/steps/browser.d.ts +7 -7
  213. package/dist/pipeline/steps/browser.js +15 -7
  214. package/dist/pipeline/steps/fetch.d.ts +1 -1
  215. package/dist/pipeline/steps/fetch.js +11 -7
  216. package/dist/pipeline/steps/transform.d.ts +6 -5
  217. package/dist/pipeline/steps/transform.js +30 -9
  218. package/dist/pipeline/template.d.ts +6 -6
  219. package/dist/pipeline/template.js +43 -5
  220. package/dist/pipeline/template.test.js +18 -0
  221. package/dist/pipeline/transform.test.js +11 -0
  222. package/dist/plugin.d.ts +31 -0
  223. package/dist/plugin.js +216 -0
  224. package/dist/plugin.test.d.ts +4 -0
  225. package/dist/plugin.test.js +76 -0
  226. package/dist/registry-api.d.ts +11 -0
  227. package/dist/registry-api.js +9 -0
  228. package/dist/registry.d.ts +11 -0
  229. package/dist/registry.js +6 -1
  230. package/dist/synthesize.d.ts +94 -4
  231. package/dist/synthesize.js +5 -4
  232. package/dist/types.d.ts +39 -26
  233. package/dist/validate.js +8 -2
  234. package/docs/.vitepress/config.mts +6 -4
  235. package/docs/adapters/browser/barchart.md +6 -5
  236. package/docs/adapters/browser/bilibili.md +9 -0
  237. package/docs/adapters/browser/devto.md +35 -0
  238. package/docs/adapters/browser/douban.md +38 -0
  239. package/docs/adapters/browser/facebook.md +36 -0
  240. package/docs/adapters/browser/google.md +62 -0
  241. package/docs/adapters/browser/grok.md +26 -8
  242. package/docs/adapters/browser/instagram.md +46 -0
  243. package/docs/adapters/browser/lobsters.md +32 -0
  244. package/docs/adapters/browser/medium.md +32 -0
  245. package/docs/adapters/browser/reddit.md +9 -0
  246. package/docs/adapters/browser/sinablog.md +36 -0
  247. package/docs/adapters/browser/substack.md +38 -0
  248. package/docs/adapters/browser/tiktok.md +68 -0
  249. package/docs/adapters/browser/wikipedia.md +11 -2
  250. package/docs/adapters/browser/xueqiu.md +10 -0
  251. package/docs/adapters/browser/yahoo-finance.md +6 -5
  252. package/docs/adapters/desktop/antigravity.md +6 -0
  253. package/docs/adapters/desktop/chatgpt.md +2 -1
  254. package/docs/adapters/desktop/codex.md +5 -1
  255. package/docs/adapters/desktop/cursor.md +4 -0
  256. package/docs/adapters/desktop/discord.md +7 -7
  257. package/docs/adapters/index.md +1 -4
  258. package/docs/guide/getting-started.md +1 -0
  259. package/docs/guide/plugins.md +153 -0
  260. package/docs/zh/guide/plugins.md +107 -0
  261. package/extension/dist/background.js +91 -23
  262. package/extension/src/background.ts +82 -29
  263. package/extension/src/cdp.ts +42 -1
  264. package/package.json +10 -5
  265. package/scripts/clean-dist.cjs +13 -0
  266. package/src/browser/cdp.ts +71 -31
  267. package/src/browser/daemon-client.ts +21 -5
  268. package/src/browser/dom-helpers.ts +38 -7
  269. package/src/browser/dom-snapshot.test.ts +249 -0
  270. package/src/browser/dom-snapshot.ts +770 -0
  271. package/src/browser/index.ts +2 -0
  272. package/src/browser/mcp.ts +3 -1
  273. package/src/browser/page.ts +57 -21
  274. package/src/build-manifest.test.ts +70 -2
  275. package/src/build-manifest.ts +94 -26
  276. package/src/cli.ts +71 -2
  277. package/src/clis/barchart/greeks.ts +1 -1
  278. package/src/clis/barchart/options.ts +1 -1
  279. package/src/clis/barchart/quote.ts +1 -1
  280. package/src/clis/bilibili/download.ts +1 -1
  281. package/src/clis/bilibili/following.ts +1 -1
  282. package/src/clis/bilibili/subtitle.ts +1 -1
  283. package/src/clis/bilibili/user-videos.ts +1 -1
  284. package/src/clis/boss/batchgreet.ts +14 -106
  285. package/src/clis/boss/chatlist.ts +12 -26
  286. package/src/clis/boss/chatmsg.ts +16 -40
  287. package/src/clis/boss/common.ts +287 -0
  288. package/src/clis/boss/detail.ts +8 -54
  289. package/src/clis/boss/exchange.ts +15 -89
  290. package/src/clis/boss/greet.ts +23 -160
  291. package/src/clis/boss/invite.ts +36 -133
  292. package/src/clis/boss/joblist.ts +7 -36
  293. package/src/clis/boss/mark.ts +13 -94
  294. package/src/clis/boss/recommend.ts +12 -57
  295. package/src/clis/boss/resume.ts +19 -124
  296. package/src/clis/boss/search.ts +13 -66
  297. package/src/clis/boss/send.ts +21 -161
  298. package/src/clis/boss/stats.ts +19 -74
  299. package/src/clis/coupang/add-to-cart.ts +1 -1
  300. package/src/clis/devto/tag.yaml +34 -0
  301. package/src/clis/devto/top.yaml +29 -0
  302. package/src/clis/devto/user.yaml +33 -0
  303. package/src/clis/douban/book-hot.ts +15 -0
  304. package/src/clis/douban/marks.ts +135 -0
  305. package/src/clis/douban/movie-hot.ts +15 -0
  306. package/src/clis/douban/reviews.ts +127 -0
  307. package/src/clis/douban/search.ts +17 -0
  308. package/src/clis/douban/shared.ts +165 -0
  309. package/src/clis/douban/subject.yaml +76 -0
  310. package/src/clis/douban/top250.yaml +70 -0
  311. package/src/clis/douban/utils.ts +81 -0
  312. package/src/clis/facebook/add-friend.yaml +43 -0
  313. package/src/clis/facebook/events.yaml +44 -0
  314. package/src/clis/facebook/feed.yaml +63 -0
  315. package/src/clis/facebook/friends.yaml +42 -0
  316. package/src/clis/facebook/groups.yaml +50 -0
  317. package/src/clis/facebook/join-group.yaml +44 -0
  318. package/src/clis/facebook/memories.yaml +39 -0
  319. package/src/clis/facebook/notifications.yaml +40 -0
  320. package/src/clis/facebook/profile.yaml +37 -0
  321. package/src/clis/facebook/search.yaml +46 -0
  322. package/src/clis/google/news.ts +66 -0
  323. package/src/clis/google/search.ts +133 -0
  324. package/src/clis/google/suggest.ts +40 -0
  325. package/src/clis/google/trends.ts +44 -0
  326. package/src/clis/google/utils.test.ts +82 -0
  327. package/src/clis/google/utils.ts +24 -0
  328. package/src/clis/grok/ask.test.ts +53 -0
  329. package/src/clis/grok/ask.ts +300 -69
  330. package/src/clis/instagram/comment.yaml +52 -0
  331. package/src/clis/instagram/explore.yaml +43 -0
  332. package/src/clis/instagram/follow.yaml +41 -0
  333. package/src/clis/instagram/followers.yaml +51 -0
  334. package/src/clis/instagram/following.yaml +51 -0
  335. package/src/clis/instagram/like.yaml +46 -0
  336. package/src/clis/instagram/profile.yaml +42 -0
  337. package/src/clis/instagram/save.yaml +46 -0
  338. package/src/clis/instagram/saved.yaml +40 -0
  339. package/src/clis/instagram/search.yaml +43 -0
  340. package/src/clis/instagram/unfollow.yaml +38 -0
  341. package/src/clis/instagram/unlike.yaml +46 -0
  342. package/src/clis/instagram/unsave.yaml +46 -0
  343. package/src/clis/instagram/user.yaml +54 -0
  344. package/src/clis/jike/repost.ts +1 -1
  345. package/src/clis/jimeng/generate.yaml +1 -0
  346. package/src/clis/linux-do/category.yaml +1 -0
  347. package/src/clis/lobsters/active.yaml +29 -0
  348. package/src/clis/lobsters/hot.yaml +29 -0
  349. package/src/clis/lobsters/newest.yaml +29 -0
  350. package/src/clis/lobsters/tag.yaml +34 -0
  351. package/src/clis/medium/feed.ts +16 -0
  352. package/src/clis/medium/search.ts +16 -0
  353. package/src/clis/medium/shared.ts +83 -0
  354. package/src/clis/medium/user.ts +16 -0
  355. package/src/clis/reddit/comment.ts +1 -1
  356. package/src/clis/reddit/read.ts +1 -1
  357. package/src/clis/reddit/save.ts +1 -1
  358. package/src/clis/reddit/subreddit.yaml +1 -0
  359. package/src/clis/reddit/subscribe.ts +1 -1
  360. package/src/clis/reddit/upvote.ts +1 -1
  361. package/src/clis/sinablog/article.ts +15 -0
  362. package/src/clis/sinablog/hot.ts +15 -0
  363. package/src/clis/sinablog/search.ts +56 -0
  364. package/src/clis/sinablog/shared.ts +198 -0
  365. package/src/clis/sinablog/user.ts +16 -0
  366. package/src/clis/substack/feed.ts +16 -0
  367. package/src/clis/substack/publication.ts +16 -0
  368. package/src/clis/substack/search.ts +91 -0
  369. package/src/clis/substack/shared.ts +132 -0
  370. package/src/clis/tiktok/comment.yaml +66 -0
  371. package/src/clis/tiktok/explore.yaml +39 -0
  372. package/src/clis/tiktok/follow.yaml +39 -0
  373. package/src/clis/tiktok/following.yaml +46 -0
  374. package/src/clis/tiktok/friends.yaml +47 -0
  375. package/src/clis/tiktok/like.yaml +38 -0
  376. package/src/clis/tiktok/live.yaml +51 -0
  377. package/src/clis/tiktok/notifications.yaml +52 -0
  378. package/src/clis/tiktok/profile.yaml +45 -0
  379. package/src/clis/tiktok/save.yaml +34 -0
  380. package/src/clis/tiktok/search.yaml +46 -0
  381. package/src/clis/tiktok/unfollow.yaml +44 -0
  382. package/src/clis/tiktok/unlike.yaml +38 -0
  383. package/src/clis/tiktok/unsave.yaml +36 -0
  384. package/src/clis/tiktok/user.yaml +44 -0
  385. package/src/clis/twitter/download.ts +3 -3
  386. package/src/clis/twitter/followers.ts +1 -1
  387. package/src/clis/twitter/following.ts +1 -1
  388. package/src/clis/twitter/thread.ts +1 -1
  389. package/src/clis/twitter/timeline.test.ts +109 -0
  390. package/src/clis/twitter/timeline.ts +59 -19
  391. package/src/clis/wikipedia/random.ts +19 -0
  392. package/src/clis/wikipedia/search.ts +10 -4
  393. package/src/clis/wikipedia/summary.ts +4 -9
  394. package/src/clis/wikipedia/trending.ts +41 -0
  395. package/src/clis/wikipedia/utils.ts +31 -0
  396. package/src/clis/xiaohongshu/creator-note-detail.test.ts +2 -0
  397. package/src/clis/xiaohongshu/creator-note-detail.ts +1 -1
  398. package/src/clis/xiaohongshu/creator-notes.test.ts +2 -0
  399. package/src/clis/xiaohongshu/download.ts +1 -1
  400. package/src/clis/xueqiu/earnings-date.yaml +69 -0
  401. package/src/clis/xueqiu/search.yaml +2 -1
  402. package/src/clis/xueqiu/stock.yaml +2 -0
  403. package/src/clis/yahoo-finance/quote.ts +1 -1
  404. package/src/commanderAdapter.ts +17 -10
  405. package/src/daemon.ts +23 -0
  406. package/src/discovery.ts +134 -24
  407. package/src/doctor.test.ts +59 -2
  408. package/src/doctor.ts +4 -2
  409. package/src/engine.test.ts +79 -6
  410. package/src/execution.ts +42 -16
  411. package/src/explore.ts +77 -9
  412. package/src/generate.ts +58 -9
  413. package/src/main.ts +2 -1
  414. package/src/pipeline/executor.test.ts +35 -6
  415. package/src/pipeline/executor.ts +68 -19
  416. package/src/pipeline/registry.ts +3 -3
  417. package/src/pipeline/steps/browser.ts +24 -15
  418. package/src/pipeline/steps/fetch.ts +18 -13
  419. package/src/pipeline/steps/transform.ts +40 -15
  420. package/src/pipeline/template.test.ts +18 -0
  421. package/src/pipeline/template.ts +86 -13
  422. package/src/pipeline/transform.test.ts +15 -2
  423. package/src/plugin.test.ts +86 -0
  424. package/src/plugin.ts +254 -0
  425. package/src/registry-api.ts +12 -0
  426. package/src/registry.ts +19 -1
  427. package/src/synthesize.ts +102 -21
  428. package/src/types.ts +44 -12
  429. package/src/validate.ts +19 -4
  430. package/tests/e2e/browser-public.test.ts +11 -0
  431. package/tests/e2e/public-commands.test.ts +64 -0
  432. package/dist/clis/feishu/new.d.ts +0 -1
  433. package/dist/clis/feishu/new.js +0 -27
  434. package/dist/clis/feishu/read.d.ts +0 -1
  435. package/dist/clis/feishu/read.js +0 -40
  436. package/dist/clis/feishu/search.d.ts +0 -1
  437. package/dist/clis/feishu/search.js +0 -30
  438. package/dist/clis/feishu/send.d.ts +0 -1
  439. package/dist/clis/feishu/send.js +0 -39
  440. package/dist/clis/feishu/status.d.ts +0 -1
  441. package/dist/clis/feishu/status.js +0 -28
  442. package/dist/clis/neteasemusic/like.d.ts +0 -1
  443. package/dist/clis/neteasemusic/like.js +0 -25
  444. package/dist/clis/neteasemusic/lyrics.d.ts +0 -1
  445. package/dist/clis/neteasemusic/lyrics.js +0 -47
  446. package/dist/clis/neteasemusic/next.d.ts +0 -1
  447. package/dist/clis/neteasemusic/next.js +0 -26
  448. package/dist/clis/neteasemusic/play.d.ts +0 -1
  449. package/dist/clis/neteasemusic/play.js +0 -26
  450. package/dist/clis/neteasemusic/playing.d.ts +0 -1
  451. package/dist/clis/neteasemusic/playing.js +0 -59
  452. package/dist/clis/neteasemusic/playlist.d.ts +0 -1
  453. package/dist/clis/neteasemusic/playlist.js +0 -46
  454. package/dist/clis/neteasemusic/prev.d.ts +0 -1
  455. package/dist/clis/neteasemusic/prev.js +0 -25
  456. package/dist/clis/neteasemusic/search.d.ts +0 -1
  457. package/dist/clis/neteasemusic/search.js +0 -52
  458. package/dist/clis/neteasemusic/status.d.ts +0 -1
  459. package/dist/clis/neteasemusic/status.js +0 -16
  460. package/dist/clis/neteasemusic/volume.d.ts +0 -1
  461. package/dist/clis/neteasemusic/volume.js +0 -54
  462. package/dist/clis/wechat/chats.d.ts +0 -1
  463. package/dist/clis/wechat/chats.js +0 -28
  464. package/dist/clis/wechat/contacts.d.ts +0 -1
  465. package/dist/clis/wechat/contacts.js +0 -28
  466. package/dist/clis/wechat/read.d.ts +0 -1
  467. package/dist/clis/wechat/read.js +0 -58
  468. package/dist/clis/wechat/search.d.ts +0 -1
  469. package/dist/clis/wechat/search.js +0 -31
  470. package/dist/clis/wechat/send.d.ts +0 -1
  471. package/dist/clis/wechat/send.js +0 -42
  472. package/dist/clis/wechat/status.d.ts +0 -1
  473. package/dist/clis/wechat/status.js +0 -29
  474. package/dist/pipeline.d.ts +0 -7
  475. package/dist/pipeline.js +0 -7
  476. package/docs/adapters/browser/github.md +0 -26
  477. package/docs/adapters/desktop/feishu.md +0 -20
  478. package/docs/adapters/desktop/neteasemusic.md +0 -31
  479. package/docs/adapters/desktop/wechat.md +0 -28
  480. package/src/clis/antigravity/README.md +0 -5
  481. package/src/clis/antigravity/README.zh-CN.md +0 -51
  482. package/src/clis/chaoxing/README.md +0 -14
  483. package/src/clis/chaoxing/README.zh-CN.md +0 -35
  484. package/src/clis/chatgpt/README.md +0 -5
  485. package/src/clis/chatgpt/README.zh-CN.md +0 -44
  486. package/src/clis/chatwise/README.md +0 -5
  487. package/src/clis/chatwise/README.zh-CN.md +0 -38
  488. package/src/clis/codex/README.md +0 -5
  489. package/src/clis/codex/README.zh-CN.md +0 -33
  490. package/src/clis/cursor/README.md +0 -5
  491. package/src/clis/cursor/README.zh-CN.md +0 -33
  492. package/src/clis/discord-app/README.md +0 -5
  493. package/src/clis/discord-app/README.zh-CN.md +0 -28
  494. package/src/clis/feishu/README.md +0 -5
  495. package/src/clis/feishu/README.zh-CN.md +0 -20
  496. package/src/clis/feishu/new.ts +0 -32
  497. package/src/clis/feishu/read.ts +0 -48
  498. package/src/clis/feishu/search.ts +0 -35
  499. package/src/clis/feishu/send.ts +0 -46
  500. package/src/clis/feishu/status.ts +0 -34
  501. package/src/clis/neteasemusic/README.md +0 -5
  502. package/src/clis/neteasemusic/README.zh-CN.md +0 -31
  503. package/src/clis/neteasemusic/like.ts +0 -28
  504. package/src/clis/neteasemusic/lyrics.ts +0 -53
  505. package/src/clis/neteasemusic/next.ts +0 -30
  506. package/src/clis/neteasemusic/play.ts +0 -30
  507. package/src/clis/neteasemusic/playing.ts +0 -62
  508. package/src/clis/neteasemusic/playlist.ts +0 -51
  509. package/src/clis/neteasemusic/prev.ts +0 -29
  510. package/src/clis/neteasemusic/search.ts +0 -58
  511. package/src/clis/neteasemusic/status.ts +0 -18
  512. package/src/clis/neteasemusic/volume.ts +0 -61
  513. package/src/clis/notion/README.md +0 -5
  514. package/src/clis/notion/README.zh-CN.md +0 -29
  515. package/src/clis/wechat/README.md +0 -5
  516. package/src/clis/wechat/README.zh-CN.md +0 -28
  517. package/src/clis/wechat/chats.ts +0 -33
  518. package/src/clis/wechat/contacts.ts +0 -33
  519. package/src/clis/wechat/read.ts +0 -72
  520. package/src/clis/wechat/search.ts +0 -36
  521. package/src/clis/wechat/send.ts +0 -49
  522. package/src/clis/wechat/status.ts +0 -35
  523. package/src/pipeline.ts +0 -8
@@ -5,8 +5,33 @@ const WS_RECONNECT_BASE_DELAY = 2e3;
5
5
  const WS_RECONNECT_MAX_DELAY = 6e4;
6
6
 
7
7
  const attached = /* @__PURE__ */ new Set();
8
+ function isDebuggableUrl$1(url) {
9
+ if (!url) return false;
10
+ return !url.startsWith("chrome://") && !url.startsWith("chrome-extension://");
11
+ }
8
12
  async function ensureAttached(tabId) {
9
- if (attached.has(tabId)) return;
13
+ try {
14
+ const tab = await chrome.tabs.get(tabId);
15
+ if (!isDebuggableUrl$1(tab.url)) {
16
+ attached.delete(tabId);
17
+ throw new Error(`Cannot debug tab ${tabId}: URL is ${tab.url ?? "unknown"}`);
18
+ }
19
+ } catch (e) {
20
+ if (e instanceof Error && e.message.startsWith("Cannot debug tab")) throw e;
21
+ attached.delete(tabId);
22
+ throw new Error(`Tab ${tabId} no longer exists`);
23
+ }
24
+ if (attached.has(tabId)) {
25
+ try {
26
+ await chrome.debugger.sendCommand({ tabId }, "Runtime.evaluate", {
27
+ expression: "1",
28
+ returnByValue: true
29
+ });
30
+ return;
31
+ } catch {
32
+ attached.delete(tabId);
33
+ }
34
+ }
10
35
  try {
11
36
  await chrome.debugger.attach({ tabId }, "1.3");
12
37
  } catch (e) {
@@ -89,6 +114,17 @@ function registerListeners() {
89
114
  chrome.debugger.onDetach.addListener((source) => {
90
115
  if (source.tabId) attached.delete(source.tabId);
91
116
  });
117
+ chrome.tabs.onUpdated.addListener((tabId, info) => {
118
+ if (info.url && !isDebuggableUrl$1(info.url)) {
119
+ if (attached.has(tabId)) {
120
+ attached.delete(tabId);
121
+ try {
122
+ chrome.debugger.detach({ tabId });
123
+ } catch {
124
+ }
125
+ }
126
+ }
127
+ });
92
128
  }
93
129
 
94
130
  let ws = null;
@@ -161,7 +197,7 @@ function scheduleReconnect() {
161
197
  }, delay);
162
198
  }
163
199
  const automationSessions = /* @__PURE__ */ new Map();
164
- const WINDOW_IDLE_TIMEOUT = 3e4;
200
+ const WINDOW_IDLE_TIMEOUT = 12e4;
165
201
  function getWorkspaceKey(workspace) {
166
202
  return workspace?.trim() || "default";
167
203
  }
@@ -265,17 +301,30 @@ async function handleCommand(cmd) {
265
301
  };
266
302
  }
267
303
  }
268
- function isWebUrl(url) {
304
+ function isDebuggableUrl(url) {
269
305
  if (!url) return false;
270
306
  return !url.startsWith("chrome://") && !url.startsWith("chrome-extension://");
271
307
  }
272
308
  async function resolveTabId(tabId, workspace) {
273
- if (tabId !== void 0) return tabId;
309
+ if (tabId !== void 0) {
310
+ try {
311
+ const tab = await chrome.tabs.get(tabId);
312
+ if (isDebuggableUrl(tab.url)) return tabId;
313
+ console.warn(`[opencli] Tab ${tabId} URL is not debuggable (${tab.url}), re-resolving`);
314
+ } catch {
315
+ console.warn(`[opencli] Tab ${tabId} no longer exists, re-resolving`);
316
+ }
317
+ }
274
318
  const windowId = await getAutomationWindow(workspace);
275
319
  const tabs = await chrome.tabs.query({ windowId });
276
- const webTab = tabs.find((t) => t.id && isWebUrl(t.url));
277
- if (webTab?.id) return webTab.id;
278
- if (tabs.length > 0 && tabs[0]?.id) return tabs[0].id;
320
+ const debuggableTab = tabs.find((t) => t.id && isDebuggableUrl(t.url));
321
+ if (debuggableTab?.id) return debuggableTab.id;
322
+ const reuseTab = tabs.find((t) => t.id);
323
+ if (reuseTab?.id) {
324
+ await chrome.tabs.update(reuseTab.id, { url: "about:blank" });
325
+ await new Promise((resolve) => setTimeout(resolve, 200));
326
+ return reuseTab.id;
327
+ }
279
328
  const newTab = await chrome.tabs.create({ windowId, url: "about:blank", active: true });
280
329
  if (!newTab.id) throw new Error("Failed to create tab in automation window");
281
330
  return newTab.id;
@@ -292,7 +341,7 @@ async function listAutomationTabs(workspace) {
292
341
  }
293
342
  async function listAutomationWebTabs(workspace) {
294
343
  const tabs = await listAutomationTabs(workspace);
295
- return tabs.filter((tab) => isWebUrl(tab.url));
344
+ return tabs.filter((tab) => isDebuggableUrl(tab.url));
296
345
  }
297
346
  async function handleExec(cmd, workspace) {
298
347
  if (!cmd.code) return { id: cmd.id, ok: false, error: "Missing code" };
@@ -307,28 +356,47 @@ async function handleExec(cmd, workspace) {
307
356
  async function handleNavigate(cmd, workspace) {
308
357
  if (!cmd.url) return { id: cmd.id, ok: false, error: "Missing url" };
309
358
  const tabId = await resolveTabId(cmd.tabId, workspace);
310
- await chrome.tabs.update(tabId, { url: cmd.url });
359
+ const beforeTab = await chrome.tabs.get(tabId);
360
+ const beforeUrl = beforeTab.url ?? "";
361
+ const targetUrl = cmd.url;
362
+ await chrome.tabs.update(tabId, { url: targetUrl });
363
+ let timedOut = false;
311
364
  await new Promise((resolve) => {
312
- chrome.tabs.get(tabId).then((tab2) => {
313
- if (tab2.status === "complete") {
365
+ let urlChanged = false;
366
+ const listener = (id, info, tab2) => {
367
+ if (id !== tabId) return;
368
+ if (info.url && info.url !== beforeUrl) {
369
+ urlChanged = true;
370
+ }
371
+ if (urlChanged && info.status === "complete") {
372
+ chrome.tabs.onUpdated.removeListener(listener);
314
373
  resolve();
315
- return;
316
374
  }
317
- const listener = (id, info) => {
318
- if (id === tabId && info.status === "complete") {
375
+ };
376
+ chrome.tabs.onUpdated.addListener(listener);
377
+ setTimeout(async () => {
378
+ try {
379
+ const currentTab = await chrome.tabs.get(tabId);
380
+ if (currentTab.url !== beforeUrl && currentTab.status === "complete") {
319
381
  chrome.tabs.onUpdated.removeListener(listener);
320
382
  resolve();
321
383
  }
322
- };
323
- chrome.tabs.onUpdated.addListener(listener);
324
- setTimeout(() => {
325
- chrome.tabs.onUpdated.removeListener(listener);
326
- resolve();
327
- }, 15e3);
328
- });
384
+ } catch {
385
+ }
386
+ }, 100);
387
+ setTimeout(() => {
388
+ chrome.tabs.onUpdated.removeListener(listener);
389
+ timedOut = true;
390
+ console.warn(`[opencli] Navigate to ${targetUrl} timed out after 15s`);
391
+ resolve();
392
+ }, 15e3);
329
393
  });
330
394
  const tab = await chrome.tabs.get(tabId);
331
- return { id: cmd.id, ok: true, data: { title: tab.title, url: tab.url, tabId } };
395
+ return {
396
+ id: cmd.id,
397
+ ok: true,
398
+ data: { title: tab.title, url: tab.url, tabId, timedOut }
399
+ };
332
400
  }
333
401
  async function handleTabs(cmd, workspace) {
334
402
  switch (cmd.op) {
@@ -425,7 +493,7 @@ async function handleSessions(cmd) {
425
493
  const data = await Promise.all([...automationSessions.entries()].map(async ([workspace, session]) => ({
426
494
  workspace,
427
495
  windowId: session.windowId,
428
- tabCount: (await chrome.tabs.query({ windowId: session.windowId })).filter((tab) => isWebUrl(tab.url)).length,
496
+ tabCount: (await chrome.tabs.query({ windowId: session.windowId })).filter((tab) => isDebuggableUrl(tab.url)).length,
429
497
  idleMsRemaining: Math.max(0, session.idleDeadlineAt - now)
430
498
  })));
431
499
  return { id: cmd.id, ok: true, data };
@@ -97,7 +97,7 @@ type AutomationSession = {
97
97
  };
98
98
 
99
99
  const automationSessions = new Map<string, AutomationSession>();
100
- const WINDOW_IDLE_TIMEOUT = 30000; // 30s
100
+ const WINDOW_IDLE_TIMEOUT = 120000; // 120s — longer to survive slow pipelines
101
101
 
102
102
  function getWorkspaceKey(workspace?: string): string {
103
103
  return workspace?.trim() || 'default';
@@ -226,8 +226,8 @@ async function handleCommand(cmd: Command): Promise<Result> {
226
226
 
227
227
  // ─── Action handlers ─────────────────────────────────────────────────
228
228
 
229
- /** Check if a URL is a debuggable web page (not chrome:// or extension page) */
230
- function isWebUrl(url?: string): boolean {
229
+ /** Check if a URL can be attached via CDP (not chrome:// or chrome-extension://) */
230
+ function isDebuggableUrl(url?: string): boolean {
231
231
  if (!url) return false;
232
232
  return !url.startsWith('chrome://') && !url.startsWith('chrome-extension://');
233
233
  }
@@ -238,20 +238,42 @@ function isWebUrl(url?: string): boolean {
238
238
  * Otherwise, find or create a tab in the dedicated automation window.
239
239
  */
240
240
  async function resolveTabId(tabId: number | undefined, workspace: string): Promise<number> {
241
- if (tabId !== undefined) return tabId;
241
+ // Even when an explicit tabId is provided, validate it is still debuggable.
242
+ // This prevents issues when extensions hijack the tab URL to chrome-extension://
243
+ // or when the tab has been closed by the user.
244
+ if (tabId !== undefined) {
245
+ try {
246
+ const tab = await chrome.tabs.get(tabId);
247
+ if (isDebuggableUrl(tab.url)) return tabId;
248
+ // Tab exists but URL is not debuggable — fall through to auto-resolve
249
+ console.warn(`[opencli] Tab ${tabId} URL is not debuggable (${tab.url}), re-resolving`);
250
+ } catch {
251
+ // Tab was closed — fall through to auto-resolve
252
+ console.warn(`[opencli] Tab ${tabId} no longer exists, re-resolving`);
253
+ }
254
+ }
242
255
 
243
256
  // Get (or create) the automation window
244
257
  const windowId = await getAutomationWindow(workspace);
245
258
 
246
- // Find the active tab in our automation window
259
+ // Prefer an existing debuggable tab (about:blank, http://, https://, etc.)
247
260
  const tabs = await chrome.tabs.query({ windowId });
248
- const webTab = tabs.find(t => t.id && isWebUrl(t.url));
249
- if (webTab?.id) return webTab.id;
250
-
251
- // Use the first tab if it's a blank/new tab page
252
- if (tabs.length > 0 && tabs[0]?.id) return tabs[0].id;
261
+ const debuggableTab = tabs.find(t => t.id && isDebuggableUrl(t.url));
262
+ if (debuggableTab?.id) return debuggableTab.id;
263
+
264
+ // No debuggable tab found this typically happens when a "New Tab Override"
265
+ // extension replaces about:blank with a chrome-extension:// page.
266
+ // Reuse the first existing tab by navigating it to about:blank (avoids
267
+ // accumulating orphan tabs if chrome.tabs.create is also intercepted).
268
+ const reuseTab = tabs.find(t => t.id);
269
+ if (reuseTab?.id) {
270
+ await chrome.tabs.update(reuseTab.id, { url: 'about:blank' });
271
+ // Wait briefly for the navigation to take effect
272
+ await new Promise(resolve => setTimeout(resolve, 200));
273
+ return reuseTab.id;
274
+ }
253
275
 
254
- // No suitable tab — create one
276
+ // Window has no tabs at all — create one
255
277
  const newTab = await chrome.tabs.create({ windowId, url: 'about:blank', active: true });
256
278
  if (!newTab.id) throw new Error('Failed to create tab in automation window');
257
279
  return newTab.id;
@@ -270,7 +292,7 @@ async function listAutomationTabs(workspace: string): Promise<chrome.tabs.Tab[]>
270
292
 
271
293
  async function listAutomationWebTabs(workspace: string): Promise<chrome.tabs.Tab[]> {
272
294
  const tabs = await listAutomationTabs(workspace);
273
- return tabs.filter((tab) => isWebUrl(tab.url));
295
+ return tabs.filter((tab) => isDebuggableUrl(tab.url));
274
296
  }
275
297
 
276
298
  async function handleExec(cmd: Command, workspace: string): Promise<Result> {
@@ -287,31 +309,62 @@ async function handleExec(cmd: Command, workspace: string): Promise<Result> {
287
309
  async function handleNavigate(cmd: Command, workspace: string): Promise<Result> {
288
310
  if (!cmd.url) return { id: cmd.id, ok: false, error: 'Missing url' };
289
311
  const tabId = await resolveTabId(cmd.tabId, workspace);
290
- await chrome.tabs.update(tabId, { url: cmd.url });
291
312
 
292
- // Wait for page to finish loading, checking current status first to avoid race
313
+ // Capture the current URL before navigation to detect actual URL change
314
+ const beforeTab = await chrome.tabs.get(tabId);
315
+ const beforeUrl = beforeTab.url ?? '';
316
+ const targetUrl = cmd.url;
317
+
318
+ await chrome.tabs.update(tabId, { url: targetUrl });
319
+
320
+ // Wait for: 1) URL to change from the old URL, 2) tab.status === 'complete'
321
+ // This avoids the race where 'complete' fires for the OLD URL (e.g. about:blank)
322
+ let timedOut = false;
293
323
  await new Promise<void>((resolve) => {
294
- // Check if already complete (e.g. cached pages)
295
- chrome.tabs.get(tabId).then(tab => {
296
- if (tab.status === 'complete') { resolve(); return; }
324
+ let urlChanged = false;
325
+
326
+ const listener = (id: number, info: chrome.tabs.TabChangeInfo, tab: chrome.tabs.Tab) => {
327
+ if (id !== tabId) return;
328
+
329
+ // Track URL change (new URL differs from the one before navigation)
330
+ if (info.url && info.url !== beforeUrl) {
331
+ urlChanged = true;
332
+ }
333
+
334
+ // Only resolve when both URL has changed AND status is complete
335
+ if (urlChanged && info.status === 'complete') {
336
+ chrome.tabs.onUpdated.removeListener(listener);
337
+ resolve();
338
+ }
339
+ };
340
+ chrome.tabs.onUpdated.addListener(listener);
297
341
 
298
- const listener = (id: number, info: chrome.tabs.TabChangeInfo) => {
299
- if (id === tabId && info.status === 'complete') {
342
+ // Also check if the tab already navigated (e.g. instant cache hit)
343
+ setTimeout(async () => {
344
+ try {
345
+ const currentTab = await chrome.tabs.get(tabId);
346
+ if (currentTab.url !== beforeUrl && currentTab.status === 'complete') {
300
347
  chrome.tabs.onUpdated.removeListener(listener);
301
348
  resolve();
302
349
  }
303
- };
304
- chrome.tabs.onUpdated.addListener(listener);
305
- // Timeout fallback
306
- setTimeout(() => {
307
- chrome.tabs.onUpdated.removeListener(listener);
308
- resolve();
309
- }, 15000);
310
- });
350
+ } catch { /* tab gone */ }
351
+ }, 100);
352
+
353
+ // Timeout fallback with warning
354
+ setTimeout(() => {
355
+ chrome.tabs.onUpdated.removeListener(listener);
356
+ timedOut = true;
357
+ console.warn(`[opencli] Navigate to ${targetUrl} timed out after 15s`);
358
+ resolve();
359
+ }, 15000);
311
360
  });
312
361
 
313
362
  const tab = await chrome.tabs.get(tabId);
314
- return { id: cmd.id, ok: true, data: { title: tab.title, url: tab.url, tabId } };
363
+ return {
364
+ id: cmd.id,
365
+ ok: true,
366
+ data: { title: tab.title, url: tab.url, tabId, timedOut },
367
+ };
315
368
  }
316
369
 
317
370
  async function handleTabs(cmd: Command, workspace: string): Promise<Result> {
@@ -415,7 +468,7 @@ async function handleSessions(cmd: Command): Promise<Result> {
415
468
  const data = await Promise.all([...automationSessions.entries()].map(async ([workspace, session]) => ({
416
469
  workspace,
417
470
  windowId: session.windowId,
418
- tabCount: (await chrome.tabs.query({ windowId: session.windowId })).filter((tab) => isWebUrl(tab.url)).length,
471
+ tabCount: (await chrome.tabs.query({ windowId: session.windowId })).filter((tab) => isDebuggableUrl(tab.url)).length,
419
472
  idleMsRemaining: Math.max(0, session.idleDeadlineAt - now),
420
473
  })));
421
474
  return { id: cmd.id, ok: true, data };
@@ -8,8 +8,40 @@
8
8
 
9
9
  const attached = new Set<number>();
10
10
 
11
+ /** Check if a URL can be attached via CDP */
12
+ function isDebuggableUrl(url?: string): boolean {
13
+ if (!url) return false;
14
+ return !url.startsWith('chrome://') && !url.startsWith('chrome-extension://');
15
+ }
16
+
11
17
  async function ensureAttached(tabId: number): Promise<void> {
12
- if (attached.has(tabId)) return;
18
+ // Verify the tab URL is debuggable before attempting attach
19
+ try {
20
+ const tab = await chrome.tabs.get(tabId);
21
+ if (!isDebuggableUrl(tab.url)) {
22
+ // Invalidate cache if previously attached
23
+ attached.delete(tabId);
24
+ throw new Error(`Cannot debug tab ${tabId}: URL is ${tab.url ?? 'unknown'}`);
25
+ }
26
+ } catch (e) {
27
+ // Re-throw our own error, catch only chrome.tabs.get failures
28
+ if (e instanceof Error && e.message.startsWith('Cannot debug tab')) throw e;
29
+ attached.delete(tabId);
30
+ throw new Error(`Tab ${tabId} no longer exists`);
31
+ }
32
+
33
+ if (attached.has(tabId)) {
34
+ // Verify the debugger is still actually attached by sending a harmless command
35
+ try {
36
+ await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {
37
+ expression: '1', returnByValue: true,
38
+ });
39
+ return; // Still attached and working
40
+ } catch {
41
+ // Stale cache entry — need to re-attach
42
+ attached.delete(tabId);
43
+ }
44
+ }
13
45
 
14
46
  try {
15
47
  await chrome.debugger.attach({ tabId }, '1.3');
@@ -122,4 +154,13 @@ export function registerListeners(): void {
122
154
  chrome.debugger.onDetach.addListener((source) => {
123
155
  if (source.tabId) attached.delete(source.tabId);
124
156
  });
157
+ // Invalidate attached cache when tab URL changes to non-debuggable
158
+ chrome.tabs.onUpdated.addListener((tabId, info) => {
159
+ if (info.url && !isDebuggableUrl(info.url)) {
160
+ if (attached.has(tabId)) {
161
+ attached.delete(tabId);
162
+ try { chrome.debugger.detach({ tabId }); } catch { /* ignore */ }
163
+ }
164
+ }
165
+ });
125
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackwener/opencli",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -13,10 +13,15 @@
13
13
  "bin": {
14
14
  "opencli": "dist/main.js"
15
15
  },
16
+ "exports": {
17
+ ".": "./dist/main.js",
18
+ "./registry": "./dist/registry-api.js"
19
+ },
16
20
  "scripts": {
17
21
  "dev": "tsx src/main.ts",
18
- "build": "tsc && npm run clean-yaml && npm run copy-yaml && npm run build-manifest",
22
+ "build": "npm run clean-dist && tsc && npm run clean-yaml && npm run copy-yaml && npm run build-manifest",
19
23
  "build-manifest": "node dist/build-manifest.js",
24
+ "clean-dist": "node scripts/clean-dist.cjs",
20
25
  "clean-yaml": "node scripts/clean-yaml.cjs",
21
26
  "copy-yaml": "node scripts/copy-yaml.cjs",
22
27
  "start": "node dist/main.js",
@@ -24,9 +29,9 @@
24
29
  "typecheck": "tsc --noEmit",
25
30
  "lint": "tsc --noEmit",
26
31
  "prepublishOnly": "npm run build",
27
- "test": "vitest run",
28
- "test:site": "node scripts/test-site.mjs",
29
- "test:watch": "vitest",
32
+ "test": "vitest run --project unit",
33
+ "test:all": "vitest run",
34
+ "test:e2e": "vitest run --project e2e",
30
35
  "docs:dev": "vitepress dev docs",
31
36
  "docs:build": "vitepress build docs",
32
37
  "docs:preview": "vitepress preview docs"
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Remove dist/ before a fresh build so deleted adapters do not leave stale
3
+ * compiled files behind in dist/clis/.
4
+ */
5
+ const { existsSync, rmSync } = require('fs');
6
+
7
+ if (existsSync('dist')) {
8
+ rmSync('dist', { recursive: true, force: true });
9
+ }
10
+
11
+ if (existsSync('tsconfig.tsbuildinfo')) {
12
+ rmSync('tsconfig.tsbuildinfo', { force: true });
13
+ }