publishport-opencli 1.8.4-pp.5 → 1.8.5-pp.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 (51) hide show
  1. package/README.md +1 -2
  2. package/README.zh-CN.md +1 -1
  3. package/cli-manifest.json +218 -6
  4. package/clis/_shared/article/auth.js +29 -0
  5. package/clis/_shared/article/auth.test.js +28 -1
  6. package/clis/baijiahao/login.js +15 -0
  7. package/clis/baijiahao/whoami.js +6 -1
  8. package/clis/cnblogs/login.js +15 -0
  9. package/clis/cnblogs/whoami.js +6 -1
  10. package/clis/csdn/whoami.js +6 -1
  11. package/clis/imooc/login.js +15 -0
  12. package/clis/imooc/whoami.js +6 -1
  13. package/clis/juejin/whoami.js +6 -1
  14. package/clis/oschina/whoami.js +6 -1
  15. package/clis/segmentfault/login.js +15 -0
  16. package/clis/segmentfault/whoami.js +6 -1
  17. package/clis/sohu/login.js +15 -0
  18. package/clis/sohu/whoami.js +6 -1
  19. package/clis/twitter/tweets.js +36 -3
  20. package/clis/twitter/tweets.test.js +125 -0
  21. package/clis/woshipm/login.js +15 -0
  22. package/clis/woshipm/whoami.js +6 -1
  23. package/clis/xianyu/search.js +206 -79
  24. package/clis/xianyu/search.test.js +92 -5
  25. package/dist/src/browser/bridge-readiness.d.ts +14 -0
  26. package/dist/src/browser/bridge-readiness.js +24 -0
  27. package/dist/src/browser/bridge-readiness.test.d.ts +1 -0
  28. package/dist/src/browser/bridge-readiness.test.js +57 -0
  29. package/dist/src/browser/bridge.d.ts +0 -2
  30. package/dist/src/browser/bridge.js +6 -120
  31. package/dist/src/browser/config.d.ts +2 -0
  32. package/dist/src/browser/config.js +14 -0
  33. package/dist/src/browser/daemon-client.d.ts +2 -56
  34. package/dist/src/browser/daemon-client.js +64 -103
  35. package/dist/src/browser/daemon-client.test.js +105 -39
  36. package/dist/src/browser/daemon-lifecycle.d.ts +15 -1
  37. package/dist/src/browser/daemon-lifecycle.js +84 -1
  38. package/dist/src/browser/daemon-transport.d.ts +55 -0
  39. package/dist/src/browser/daemon-transport.js +68 -0
  40. package/dist/src/browser.test.js +22 -18
  41. package/dist/src/cli.js +4 -3
  42. package/dist/src/cli.test.js +4 -4
  43. package/dist/src/constants.d.ts +1 -0
  44. package/dist/src/constants.js +6 -0
  45. package/dist/src/daemon.js +6 -2
  46. package/dist/src/main.js +5 -0
  47. package/dist/src/runtime.d.ts +2 -2
  48. package/dist/src/runtime.js +2 -14
  49. package/package.json +3 -3
  50. package/scripts/typed-error-lint-baseline.json +16 -80
  51. package/skills/opencli-usage/SKILL.md +1 -2
package/README.md CHANGED
@@ -169,10 +169,9 @@ When the site you need is not yet covered, use the `opencli-adapter-author` skil
169
169
 
170
170
  | Variable | Default | Description |
171
171
  |----------|---------|-------------|
172
- | `OPENCLI_DAEMON_PORT` | `19825` | HTTP port for the daemon-extension bridge |
173
172
  | `OPENCLI_PROFILE` | — | Browser Bridge profile alias/contextId to use when multiple Chrome profiles are connected |
174
173
  | `OPENCLI_WINDOW` | command default | Set to `foreground` or `background` to override Browser Bridge window placement. Browser-backed commands also accept `--window <foreground\|background>`. |
175
- | `OPENCLI_BROWSER_CONNECT_TIMEOUT` | `30` | Seconds to wait for browser connection |
174
+ | `OPENCLI_BROWSER_CONNECT_TIMEOUT` | `45` | Seconds to wait for browser connection |
176
175
  | `OPENCLI_BROWSER_COMMAND_TIMEOUT` | `60` | Seconds to wait for a single browser command |
177
176
  | `OPENCLI_CDP_ENDPOINT` | — | Chrome DevTools Protocol endpoint for remote browser or Electron apps |
178
177
  | `OPENCLI_CDP_TARGET` | — | Filter CDP targets by URL substring (e.g. `detail.1688.com`) |
package/README.zh-CN.md CHANGED
@@ -157,7 +157,7 @@ Agent 在内部自动处理所有 `opencli browser` 命令——你只需用自
157
157
  |------|--------|------|
158
158
  | `OPENCLI_DAEMON_PORT` | `19825` | daemon-extension 通信端口 |
159
159
  | `OPENCLI_WINDOW` | 命令默认值 | 设为 `foreground` 或 `background` 来覆盖 Browser Bridge 窗口位置。浏览器型命令也支持 `--window <foreground\|background>` |
160
- | `OPENCLI_BROWSER_CONNECT_TIMEOUT` | `30` | 浏览器连接超时(秒) |
160
+ | `OPENCLI_BROWSER_CONNECT_TIMEOUT` | `45` | 浏览器连接超时(秒) |
161
161
  | `OPENCLI_BROWSER_COMMAND_TIMEOUT` | `60` | 单个浏览器命令超时(秒) |
162
162
  | `OPENCLI_CDP_ENDPOINT` | — | Chrome DevTools Protocol 端点,用于远程浏览器或 Electron 应用 |
163
163
  | `OPENCLI_CDP_TARGET` | — | 按 URL 子串过滤 CDP target(如 `detail.1688.com`) |
package/cli-manifest.json CHANGED
@@ -3149,6 +3149,36 @@
3149
3149
  "sourceFile": "baijiahao/lists.js",
3150
3150
  "navigateBefore": "https://baijiahao.baidu.com"
3151
3151
  },
3152
+ {
3153
+ "site": "baijiahao",
3154
+ "name": "login",
3155
+ "description": "打开百家号登录页并等待浏览器完成登录(供桌面客户端引导登录)。",
3156
+ "access": "write",
3157
+ "domain": "baijiahao.baidu.com",
3158
+ "strategy": "cookie",
3159
+ "browser": true,
3160
+ "args": [
3161
+ {
3162
+ "name": "timeout",
3163
+ "type": "int",
3164
+ "default": 300,
3165
+ "required": false,
3166
+ "help": "等待用户完成登录的最长秒数"
3167
+ }
3168
+ ],
3169
+ "columns": [
3170
+ "status",
3171
+ "logged_in",
3172
+ "user_id",
3173
+ "username"
3174
+ ],
3175
+ "type": "js",
3176
+ "modulePath": "baijiahao/login.js",
3177
+ "sourceFile": "baijiahao/login.js",
3178
+ "navigateBefore": false,
3179
+ "siteSession": "persistent",
3180
+ "defaultWindowMode": "foreground"
3181
+ },
3152
3182
  {
3153
3183
  "site": "baijiahao",
3154
3184
  "name": "whoami",
@@ -7873,6 +7903,36 @@
7873
7903
  "sourceFile": "cnblogs/article.js",
7874
7904
  "navigateBefore": "https://cnblogs.com"
7875
7905
  },
7906
+ {
7907
+ "site": "cnblogs",
7908
+ "name": "login",
7909
+ "description": "打开博客园登录页并等待浏览器完成登录(供桌面客户端引导登录)。",
7910
+ "access": "write",
7911
+ "domain": "cnblogs.com",
7912
+ "strategy": "cookie",
7913
+ "browser": true,
7914
+ "args": [
7915
+ {
7916
+ "name": "timeout",
7917
+ "type": "int",
7918
+ "default": 300,
7919
+ "required": false,
7920
+ "help": "等待用户完成登录的最长秒数"
7921
+ }
7922
+ ],
7923
+ "columns": [
7924
+ "status",
7925
+ "logged_in",
7926
+ "user_id",
7927
+ "username"
7928
+ ],
7929
+ "type": "js",
7930
+ "modulePath": "cnblogs/login.js",
7931
+ "sourceFile": "cnblogs/login.js",
7932
+ "navigateBefore": false,
7933
+ "siteSession": "persistent",
7934
+ "defaultWindowMode": "foreground"
7935
+ },
7876
7936
  {
7877
7937
  "site": "cnblogs",
7878
7938
  "name": "whoami",
@@ -17763,6 +17823,36 @@
17763
17823
  "sourceFile": "imooc/article.js",
17764
17824
  "navigateBefore": "https://www.imooc.com"
17765
17825
  },
17826
+ {
17827
+ "site": "imooc",
17828
+ "name": "login",
17829
+ "description": "打开慕课网登录页并等待浏览器完成登录(供桌面客户端引导登录)。",
17830
+ "access": "write",
17831
+ "domain": "imooc.com",
17832
+ "strategy": "cookie",
17833
+ "browser": true,
17834
+ "args": [
17835
+ {
17836
+ "name": "timeout",
17837
+ "type": "int",
17838
+ "default": 300,
17839
+ "required": false,
17840
+ "help": "等待用户完成登录的最长秒数"
17841
+ }
17842
+ ],
17843
+ "columns": [
17844
+ "status",
17845
+ "logged_in",
17846
+ "user_id",
17847
+ "username"
17848
+ ],
17849
+ "type": "js",
17850
+ "modulePath": "imooc/login.js",
17851
+ "sourceFile": "imooc/login.js",
17852
+ "navigateBefore": false,
17853
+ "siteSession": "persistent",
17854
+ "defaultWindowMode": "foreground"
17855
+ },
17766
17856
  {
17767
17857
  "site": "imooc",
17768
17858
  "name": "whoami",
@@ -30914,6 +31004,36 @@
30914
31004
  "sourceFile": "segmentfault/channels.js",
30915
31005
  "navigateBefore": "https://segmentfault.com"
30916
31006
  },
31007
+ {
31008
+ "site": "segmentfault",
31009
+ "name": "login",
31010
+ "description": "打开思否(SegmentFault)登录页并等待浏览器完成登录(供桌面客户端引导登录)。",
31011
+ "access": "write",
31012
+ "domain": "segmentfault.com",
31013
+ "strategy": "cookie",
31014
+ "browser": true,
31015
+ "args": [
31016
+ {
31017
+ "name": "timeout",
31018
+ "type": "int",
31019
+ "default": 300,
31020
+ "required": false,
31021
+ "help": "等待用户完成登录的最长秒数"
31022
+ }
31023
+ ],
31024
+ "columns": [
31025
+ "status",
31026
+ "logged_in",
31027
+ "user_id",
31028
+ "username"
31029
+ ],
31030
+ "type": "js",
31031
+ "modulePath": "segmentfault/login.js",
31032
+ "sourceFile": "segmentfault/login.js",
31033
+ "navigateBefore": false,
31034
+ "siteSession": "persistent",
31035
+ "defaultWindowMode": "foreground"
31036
+ },
30917
31037
  {
30918
31038
  "site": "segmentfault",
30919
31039
  "name": "tags",
@@ -30956,8 +31076,8 @@
30956
31076
  "username"
30957
31077
  ],
30958
31078
  "type": "js",
30959
- "modulePath": "segmentfault/whoami.js",
30960
- "sourceFile": "segmentfault/whoami.js",
31079
+ "modulePath": "segmentfault/login.js",
31080
+ "sourceFile": "segmentfault/login.js",
30961
31081
  "navigateBefore": "https://segmentfault.com"
30962
31082
  },
30963
31083
  {
@@ -33251,6 +33371,36 @@
33251
33371
  "sourceFile": "sohu/columns.js",
33252
33372
  "navigateBefore": "https://mp.sohu.com"
33253
33373
  },
33374
+ {
33375
+ "site": "sohu",
33376
+ "name": "login",
33377
+ "description": "打开搜狐号登录页并等待浏览器完成登录(供桌面客户端引导登录)。",
33378
+ "access": "write",
33379
+ "domain": "mp.sohu.com",
33380
+ "strategy": "cookie",
33381
+ "browser": true,
33382
+ "args": [
33383
+ {
33384
+ "name": "timeout",
33385
+ "type": "int",
33386
+ "default": 300,
33387
+ "required": false,
33388
+ "help": "等待用户完成登录的最长秒数"
33389
+ }
33390
+ ],
33391
+ "columns": [
33392
+ "status",
33393
+ "logged_in",
33394
+ "user_id",
33395
+ "username"
33396
+ ],
33397
+ "type": "js",
33398
+ "modulePath": "sohu/login.js",
33399
+ "sourceFile": "sohu/login.js",
33400
+ "navigateBefore": false,
33401
+ "siteSession": "persistent",
33402
+ "defaultWindowMode": "foreground"
33403
+ },
33254
33404
  {
33255
33405
  "site": "sohu",
33256
33406
  "name": "topics",
@@ -38511,7 +38661,14 @@
38511
38661
  "type": "int",
38512
38662
  "default": 20,
38513
38663
  "required": false,
38514
- "help": "Max tweets to return"
38664
+ "help": "Max tweets to return (1-10000; fetched across cursor pages)"
38665
+ },
38666
+ {
38667
+ "name": "page-delay",
38668
+ "type": "int",
38669
+ "default": 2,
38670
+ "required": false,
38671
+ "help": "Seconds to wait between paginated timeline requests to reduce rate-limit risk. Use 0 to disable."
38515
38672
  },
38516
38673
  {
38517
38674
  "name": "top-by-engagement",
@@ -41390,6 +41547,36 @@
41390
41547
  "sourceFile": "woshipm/article.js",
41391
41548
  "navigateBefore": "https://www.woshipm.com"
41392
41549
  },
41550
+ {
41551
+ "site": "woshipm",
41552
+ "name": "login",
41553
+ "description": "打开人人都是产品经理登录页并等待浏览器完成登录(供桌面客户端引导登录)。",
41554
+ "access": "write",
41555
+ "domain": "woshipm.com",
41556
+ "strategy": "cookie",
41557
+ "browser": true,
41558
+ "args": [
41559
+ {
41560
+ "name": "timeout",
41561
+ "type": "int",
41562
+ "default": 300,
41563
+ "required": false,
41564
+ "help": "等待用户完成登录的最长秒数"
41565
+ }
41566
+ ],
41567
+ "columns": [
41568
+ "status",
41569
+ "logged_in",
41570
+ "user_id",
41571
+ "username"
41572
+ ],
41573
+ "type": "js",
41574
+ "modulePath": "woshipm/login.js",
41575
+ "sourceFile": "woshipm/login.js",
41576
+ "navigateBefore": false,
41577
+ "siteSession": "persistent",
41578
+ "defaultWindowMode": "foreground"
41579
+ },
41393
41580
  {
41394
41581
  "site": "woshipm",
41395
41582
  "name": "whoami",
@@ -41832,7 +42019,7 @@
41832
42019
  {
41833
42020
  "site": "xianyu",
41834
42021
  "name": "search",
41835
- "description": "搜索闲鱼商品",
42022
+ "description": "搜索闲鱼商品(支持服务端价格区间 / 地区筛选)",
41836
42023
  "access": "read",
41837
42024
  "domain": "www.goofish.com",
41838
42025
  "strategy": "cookie",
@@ -41843,14 +42030,38 @@
41843
42030
  "type": "str",
41844
42031
  "required": true,
41845
42032
  "positional": true,
41846
- "help": "Search keyword"
42033
+ "help": "搜索关键词"
41847
42034
  },
41848
42035
  {
41849
42036
  "name": "limit",
41850
42037
  "type": "int",
41851
42038
  "default": 20,
41852
42039
  "required": false,
41853
- "help": "Number of results to return"
42040
+ "help": "返回结果数(最多 60,自动翻页)"
42041
+ },
42042
+ {
42043
+ "name": "min-price",
42044
+ "type": "float",
42045
+ "required": false,
42046
+ "help": "最低价格(元),服务端筛选"
42047
+ },
42048
+ {
42049
+ "name": "max-price",
42050
+ "type": "float",
42051
+ "required": false,
42052
+ "help": "最高价格(元),服务端筛选"
42053
+ },
42054
+ {
42055
+ "name": "province",
42056
+ "type": "string",
42057
+ "required": false,
42058
+ "help": "省份名(如 广东),服务端按地区筛选"
42059
+ },
42060
+ {
42061
+ "name": "city",
42062
+ "type": "string",
42063
+ "required": false,
42064
+ "help": "城市名(如 深圳 / 湛江),可单独使用,服务端按地区筛选"
41854
42065
  }
41855
42066
  ],
41856
42067
  "columns": [
@@ -41862,6 +42073,7 @@
41862
42073
  "brand",
41863
42074
  "location",
41864
42075
  "badge",
42076
+ "want",
41865
42077
  "url"
41866
42078
  ],
41867
42079
  "type": "js",
@@ -88,8 +88,37 @@ export async function requireLogin(page, profile, siteLabel) {
88
88
  return r;
89
89
  }
90
90
 
91
+ /**
92
+ * 构造「快速登录检测」(quickCheck):只读 cookie、不导航,开销极小。
93
+ *
94
+ * 供 `auth status` 的 quick 模式用——桌面 GUI 正是靠它判断登录状态(基于 getCookies,
95
+ * 能读到 HttpOnly,且不会驱动浏览器窗口、不和正在进行的登录抢自动化窗口)。
96
+ * 文章平台原本只有 whoami(full probe,会导航+调接口),没有 quickCheck,于是
97
+ * `auth status` 一律返回「quickCheck not implemented」,GUI 表现为「检测不到登录状态」。
98
+ *
99
+ * 命中任一登录态 cookie 即视为已登录。cookie 名必须实测确认(去掉它接口翻匿名),
100
+ * 不能凭记忆猜。
101
+ *
102
+ * @param {string} url 读 cookie 的目标 URL(决定带哪些域的 cookie)
103
+ * @param {string[]} names 登录态 cookie 名(精确匹配,命中任一且有值即已登录)
104
+ * @param {string[]} [prefixes] 登录态 cookie 名前缀(如 WordPress 的
105
+ * `wordpress_logged_in_<hash>`,hash 随站固定,只能按前缀匹配)
106
+ * @returns {(page: { getCookies: Function }) => Promise<{ logged_in: boolean }>}
107
+ */
108
+ export function cookieQuickCheck(url, names, prefixes = []) {
109
+ const want = new Set(names);
110
+ return async (page) => {
111
+ const cookies = await page.getCookies({ url });
112
+ const logged_in = cookies.some(
113
+ (c) => c.value && (want.has(c.name) || prefixes.some((p) => c.name.startsWith(p))),
114
+ );
115
+ return { logged_in };
116
+ };
117
+ }
118
+
91
119
  export const __test__ = {
92
120
  buildCheckAuthJs,
93
121
  checkLogin,
94
122
  requireLogin,
123
+ cookieQuickCheck,
95
124
  };
@@ -1,6 +1,33 @@
1
1
  // @vitest-environment jsdom
2
2
  import { describe, expect, it, vi } from 'vitest';
3
- import { buildCheckAuthJs, checkLogin, requireLogin } from './auth.js';
3
+ import { buildCheckAuthJs, checkLogin, cookieQuickCheck, requireLogin } from './auth.js';
4
+
5
+ describe('cookieQuickCheck', () => {
6
+ const cookiePage = (cookies) => ({ getCookies: vi.fn().mockResolvedValue(cookies) });
7
+
8
+ it('命中精确 cookie 名(有值)即判已登录', async () => {
9
+ const qc = cookieQuickCheck('https://x.test', ['sessionid']);
10
+ const r = await qc(cookiePage([{ name: 'sessionid', value: 'abc' }]));
11
+ expect(r).toEqual({ logged_in: true });
12
+ });
13
+
14
+ it('cookie 缺失或空值 → 未登录', async () => {
15
+ const qc = cookieQuickCheck('https://x.test', ['sessionid']);
16
+ expect(await qc(cookiePage([{ name: 'other', value: 'x' }]))).toEqual({ logged_in: false });
17
+ expect(await qc(cookiePage([{ name: 'sessionid', value: '' }]))).toEqual({ logged_in: false });
18
+ });
19
+
20
+ it('按前缀匹配(WordPress wordpress_logged_in_<hash>)', async () => {
21
+ const qc = cookieQuickCheck('https://x.test', [], ['wordpress_logged_in_']);
22
+ const r = await qc(cookiePage([{ name: 'wordpress_logged_in_deadbeef', value: 'v' }]));
23
+ expect(r).toEqual({ logged_in: true });
24
+ });
25
+
26
+ it('命中任一名即可(多 cookie 家族)', async () => {
27
+ const qc = cookieQuickCheck('https://x.test', ['BDUSS', 'BDUSS_BFESS']);
28
+ expect(await qc(cookiePage([{ name: 'BDUSS_BFESS', value: 'v' }]))).toEqual({ logged_in: true });
29
+ });
30
+ });
4
31
 
5
32
  describe('buildCheckAuthJs', () => {
6
33
  it('内联 PAGE_RUNTIME + checkAuth 源码并归一返回字段', () => {
@@ -0,0 +1,15 @@
1
+ import { registerArticleLogin } from '../_shared/article/login.js';
2
+ import { baijiahaoProfile } from './article.js';
3
+
4
+ // 百家号 login 命令:补桌面客户端「登录」按钮所需的 `baijiahao login`。
5
+ // 登录态判定复用 baijiahaoProfile.checkAuth(与 whoami 同源),打开百家号首页让用户
6
+ // 完成(百度统一)登录。
7
+ registerArticleLogin({
8
+ site: 'baijiahao',
9
+ domain: 'baijiahao.baidu.com',
10
+ profile: {
11
+ home: baijiahaoProfile.home,
12
+ checkAuth: baijiahaoProfile.checkAuth,
13
+ },
14
+ loginDescription: '打开百家号登录页并等待浏览器完成登录(供桌面客户端引导登录)。',
15
+ });
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { baijiahaoProfile } from './article.js';
4
4
 
5
5
  // 构建 auth profile:只需 home + checkAuth,直接复用 article.js 导出的 profile。
@@ -17,6 +17,11 @@ cli({
17
17
  strategy: Strategy.COOKIE,
18
18
  browser: true,
19
19
  columns: ['logged_in', 'user_id', 'username'],
20
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):百家号走百度统一登录,登录态由
21
+ // BDUSS / BDUSS_BFESS 承载(实测:仅留任一即仍登录),命中任一即已登录。
22
+ authStatus: {
23
+ quickCheck: cookieQuickCheck('https://baijiahao.baidu.com', ['BDUSS', 'BDUSS_BFESS']),
24
+ },
20
25
  func: async (page) => {
21
26
  const r = await checkLogin(page, authProfile);
22
27
  return [{
@@ -0,0 +1,15 @@
1
+ import { registerArticleLogin } from '../_shared/article/login.js';
2
+ import { cnblogsAuthProfile } from './article.js';
3
+
4
+ // 博客园 login 命令:补桌面客户端「登录」按钮所需的 `cnblogs login`。
5
+ // 登录态判定复用 cnblogsAuthProfile.checkAuth(与 whoami 同源),打开「当前用户」页
6
+ // (未登录会被重定向到登录页)让用户完成登录。
7
+ registerArticleLogin({
8
+ site: 'cnblogs',
9
+ domain: 'cnblogs.com',
10
+ profile: {
11
+ home: cnblogsAuthProfile.home,
12
+ checkAuth: cnblogsAuthProfile.checkAuth,
13
+ },
14
+ loginDescription: '打开博客园登录页并等待浏览器完成登录(供桌面客户端引导登录)。',
15
+ });
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { cnblogsAuthProfile } from './article.js';
4
4
 
5
5
  cli({
@@ -11,6 +11,11 @@ cli({
11
11
  strategy: Strategy.COOKIE,
12
12
  browser: true,
13
13
  columns: ['logged_in', 'user_id', 'username'],
14
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):博客园登录态由
15
+ // .Cnblogs.AspNetCore.Cookies 承载(实测:去掉它鉴权接口翻匿名)。
16
+ authStatus: {
17
+ quickCheck: cookieQuickCheck('https://home.cnblogs.com', ['.Cnblogs.AspNetCore.Cookies']),
18
+ },
14
19
  func: async (page) => {
15
20
  const r = await checkLogin(page, cnblogsAuthProfile);
16
21
  return [{
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { csdnProfile } from './article.js';
4
4
 
5
5
  // checkAuth 与 home 从 article.js 的 csdnProfile 复用,保持单一来源
@@ -19,6 +19,11 @@ cli({
19
19
  browser: true,
20
20
  args: [],
21
21
  columns: ['logged_in', 'user_id', 'username'],
22
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):CSDN 登录态由 UserToken
23
+ // 承载(实测:去掉它鉴权接口翻匿名),cookie 写在 .csdn.net 顶域。
24
+ authStatus: {
25
+ quickCheck: cookieQuickCheck('https://www.csdn.net', ['UserToken']),
26
+ },
22
27
  func: async (page) => {
23
28
  const r = await checkLogin(page, authProfile);
24
29
  return [
@@ -0,0 +1,15 @@
1
+ import { registerArticleLogin } from '../_shared/article/login.js';
2
+ import { imoocProfile } from './article.js';
3
+
4
+ // 慕课网 login 命令:补桌面客户端「登录」按钮所需的 `imooc login`。
5
+ // 登录态判定复用 imoocProfile.checkAuth(与 whoami 同源),打开手记发布页(未登录会被
6
+ // 重定向到登录页)让用户完成登录。
7
+ registerArticleLogin({
8
+ site: 'imooc',
9
+ domain: 'imooc.com',
10
+ profile: {
11
+ home: imoocProfile.home,
12
+ checkAuth: imoocProfile.checkAuth,
13
+ },
14
+ loginDescription: '打开慕课网登录页并等待浏览器完成登录(供桌面客户端引导登录)。',
15
+ });
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { imoocProfile } from './article.js';
4
4
 
5
5
  // 从 article profile 提取 authProfile(home + checkAuth)
@@ -17,6 +17,11 @@ cli({
17
17
  strategy: Strategy.COOKIE,
18
18
  browser: true,
19
19
  columns: ['logged_in', 'user_id', 'username'],
20
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):慕课网登录态由 apsid
21
+ // 承载(实测:去掉它鉴权接口翻匿名,仅留它也仍登录)。
22
+ authStatus: {
23
+ quickCheck: cookieQuickCheck('https://www.imooc.com', ['apsid']),
24
+ },
20
25
  func: async (page) => {
21
26
  const r = await checkLogin(page, authProfile);
22
27
  return [{
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { juejinProfile } from './article.js';
4
4
 
5
5
  // ── 掘金登录状态检测(whoami)──────────────────────────────────────────────
@@ -18,6 +18,11 @@ cli({
18
18
  strategy: Strategy.COOKIE,
19
19
  browser: true,
20
20
  columns: ['logged_in', 'user_id', 'username'],
21
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):掘金登录态由字节跳动 session
22
+ // cookie 承载(实测:去掉 sessionid 系列即翻匿名),命中任一即已登录。
23
+ authStatus: {
24
+ quickCheck: cookieQuickCheck('https://juejin.cn', ['sessionid', 'sessionid_ss', 'sid_tt']),
25
+ },
21
26
  func: async (page) => {
22
27
  const r = await checkLogin(page, authProfile);
23
28
  return [{
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { oschinaProfile } from './article.js';
4
4
 
5
5
  // 取当前开源中国登录账号(共用 article.js 导出的 oschinaProfile.home + oschinaProfile.checkAuth)。
@@ -17,6 +17,11 @@ cli({
17
17
  strategy: Strategy.COOKIE,
18
18
  browser: true,
19
19
  columns: ['logged_in', 'user_id', 'username'],
20
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):开源中国登录态由 oscid
21
+ // 承载(实测:去掉它鉴权接口翻匿名),cookie 写在 .oschina.net 顶域。
22
+ authStatus: {
23
+ quickCheck: cookieQuickCheck('https://my.oschina.net', ['oscid']),
24
+ },
20
25
  func: async (page) => {
21
26
  const r = await checkLogin(page, authProfile);
22
27
  return [
@@ -0,0 +1,15 @@
1
+ import { registerArticleLogin } from '../_shared/article/login.js';
2
+ import { authProfile } from './whoami.js';
3
+
4
+ // 思否 login 命令:补桌面客户端「登录」按钮所需的 `segmentfault login`。
5
+ // 思否的 checkAuth 写在 whoami.js(已 export authProfile),这里复用同一来源,避免
6
+ // 重复定义。打开 /user/settings(未登录会被重定向到登录页)让用户完成登录。
7
+ registerArticleLogin({
8
+ site: 'segmentfault',
9
+ domain: 'segmentfault.com',
10
+ profile: {
11
+ home: authProfile.home,
12
+ checkAuth: authProfile.checkAuth,
13
+ },
14
+ loginDescription: '打开思否(SegmentFault)登录页并等待浏览器完成登录(供桌面客户端引导登录)。',
15
+ });
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { segmentfaultProfile } from './article.js';
4
4
 
5
5
  // 思否 checkAuth:移植自 Wechatsync SegmentfaultAdapter.checkAuth()。
@@ -41,6 +41,11 @@ cli({
41
41
  strategy: Strategy.COOKIE,
42
42
  browser: true,
43
43
  columns: ['logged_in', 'user_id', 'username'],
44
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):思否登录态由 PHPSESSID
45
+ // 承载(实测:去掉它鉴权接口翻匿名,仅留它也仍登录)。
46
+ authStatus: {
47
+ quickCheck: cookieQuickCheck('https://segmentfault.com', ['PHPSESSID']),
48
+ },
44
49
  func: async (page) => {
45
50
  const r = await checkLogin(page, authProfile);
46
51
  return [{ logged_in: r.isAuthenticated, user_id: r.userId, username: r.username }];
@@ -0,0 +1,15 @@
1
+ import { registerArticleLogin } from '../_shared/article/login.js';
2
+ import { sohuAuthProfile } from './article.js';
3
+
4
+ // 搜狐号 login 命令:补桌面客户端「登录」按钮所需的 `sohu login`。
5
+ // 登录态判定复用 sohuAuthProfile.checkAuth(与 whoami 同源),打开搜狐号后台首页
6
+ // (未登录会被重定向到登录页)让用户完成登录。
7
+ registerArticleLogin({
8
+ site: 'sohu',
9
+ domain: 'mp.sohu.com',
10
+ profile: {
11
+ home: sohuAuthProfile.home,
12
+ checkAuth: sohuAuthProfile.checkAuth,
13
+ },
14
+ loginDescription: '打开搜狐号登录页并等待浏览器完成登录(供桌面客户端引导登录)。',
15
+ });
@@ -1,5 +1,5 @@
1
1
  import { cli, Strategy } from '@jackwener/opencli/registry';
2
- import { checkLogin } from '../_shared/article/auth.js';
2
+ import { checkLogin, cookieQuickCheck } from '../_shared/article/auth.js';
3
3
  import { sohuAuthProfile } from './article.js';
4
4
 
5
5
  cli({
@@ -11,6 +11,11 @@ cli({
11
11
  strategy: Strategy.COOKIE,
12
12
  browser: true,
13
13
  columns: ['logged_in', 'user_id', 'username'],
14
+ // 快速登录检测(`auth status` quick / 桌面 GUI 用):搜狐号登录态由 pprdig
15
+ // 承载(实测:去掉它鉴权接口翻匿名,仅留它也仍登录)。
16
+ authStatus: {
17
+ quickCheck: cookieQuickCheck('https://mp.sohu.com', ['pprdig']),
18
+ },
14
19
  func: async (page) => {
15
20
  const r = await checkLogin(page, sohuAuthProfile);
16
21
  return [{