@sovovs/bycli 2.1.40 → 2.1.41

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 (42) hide show
  1. package/cli-manifest.json +10 -2
  2. package/clis/weixin/_wechat/article-artifact.js +55 -0
  3. package/clis/weixin/_wechat/article-identity.js +27 -0
  4. package/clis/weixin/_wechat/publish-analysis.js +8 -4
  5. package/clis/weixin/_wechat/publish-download.js +3 -1
  6. package/clis/weixin/download-publish-data.js +20 -0
  7. package/clis/weixin/download.js +15 -2
  8. package/dist/src/adapter-coordination.d.ts +26 -0
  9. package/dist/src/adapter-coordination.js +183 -0
  10. package/dist/src/adapter-coordination.test.d.ts +1 -0
  11. package/dist/src/adapter-execution-context.d.ts +6 -0
  12. package/dist/src/adapter-execution-context.js +8 -0
  13. package/dist/src/adapter-scheduler.d.ts +86 -0
  14. package/dist/src/adapter-scheduler.js +349 -0
  15. package/dist/src/adapter-scheduler.test.d.ts +1 -0
  16. package/dist/src/browser/daemon-client.d.ts +11 -0
  17. package/dist/src/browser/daemon-client.js +53 -1
  18. package/dist/src/browser/extension-capabilities.d.ts +1 -0
  19. package/dist/src/browser/extension-capabilities.js +18 -5
  20. package/dist/src/browser/page.d.ts +2 -1
  21. package/dist/src/browser/page.js +3 -0
  22. package/dist/src/build-manifest.js +1 -0
  23. package/dist/src/cli-argv-preprocess.d.ts +3 -0
  24. package/dist/src/cli-argv-preprocess.js +4 -0
  25. package/dist/src/commanderAdapter.js +11 -0
  26. package/dist/src/daemon.js +118 -0
  27. package/dist/src/discovery.js +1 -0
  28. package/dist/src/download/article-download.d.ts +2 -0
  29. package/dist/src/download/article-download.js +30 -4
  30. package/dist/src/errors.d.ts +3 -0
  31. package/dist/src/errors.js +5 -0
  32. package/dist/src/execution.d.ts +2 -0
  33. package/dist/src/execution.js +168 -105
  34. package/dist/src/help.d.ts +1 -0
  35. package/dist/src/help.js +40 -0
  36. package/dist/src/manifest-types.d.ts +4 -0
  37. package/dist/src/registry.d.ts +6 -0
  38. package/dist/src/registry.js +23 -0
  39. package/dist/src/serialization.d.ts +1 -0
  40. package/dist/src/serialization.js +1 -0
  41. package/dist/src/types.d.ts +2 -0
  42. package/package.json +3 -2
package/dist/src/help.js CHANGED
@@ -48,6 +48,19 @@ const BROWSER_COMMON_OPTIONS = [
48
48
  choices: ['true', 'false'],
49
49
  },
50
50
  ];
51
+ const ADAPTER_SESSION_OPTIONS = [
52
+ {
53
+ flags: '--adapter-session <name>',
54
+ name: 'adapter-session',
55
+ help: 'Named persistent Adapter tab session',
56
+ },
57
+ {
58
+ flags: '--adapter-queue-timeout <seconds>',
59
+ name: 'adapter-queue-timeout',
60
+ help: 'Seconds to wait for an Adapter command lease',
61
+ default: 300,
62
+ },
63
+ ];
51
64
  function normalizeStructuredHelpFormat(value) {
52
65
  const normalized = value?.toLowerCase();
53
66
  if (normalized === 'yaml' || normalized === 'yml')
@@ -369,6 +382,12 @@ function compactCommand(cmd) {
369
382
  positionals: positionals(cmd).map(compactArg),
370
383
  command_options: commandOptions(cmd).map(compactArg),
371
384
  ...(hasBrowserCapability(cmd) ? { browser_common_options: BROWSER_COMMON_OPTIONS.map(compactCommonOption) } : {}),
385
+ ...(cmd.adapterConcurrency?.isolatedTabs === true
386
+ ? {
387
+ adapterConcurrency: cmd.adapterConcurrency,
388
+ adapter_common_options: ADAPTER_SESSION_OPTIONS.map(compactCommonOption),
389
+ }
390
+ : {}),
372
391
  example: formatCommandExample(cmd),
373
392
  ...(cmd.siteSession ? { siteSession: cmd.siteSession } : {}),
374
393
  ...(cmd.defaultFormat ? { defaultFormat: cmd.defaultFormat } : {}),
@@ -417,6 +436,9 @@ export function siteHelpData(site, commands) {
417
436
  commands: unique.map(cmd => compactCommand(cmd)),
418
437
  common_options: COMMON_OPTIONS.map(compactCommonOption),
419
438
  ...(unique.some(hasBrowserCapability) ? { browser_common_options: BROWSER_COMMON_OPTIONS.map(compactCommonOption) } : {}),
439
+ ...(unique.some(cmd => cmd.adapterConcurrency?.isolatedTabs === true)
440
+ ? { adapter_common_options: ADAPTER_SESSION_OPTIONS.map(compactCommonOption) }
441
+ : {}),
420
442
  next: [
421
443
  `bycli ${site} <command> --help -f yaml`,
422
444
  `bycli ${site} <command> -f yaml`,
@@ -429,6 +451,12 @@ export function commandHelpData(cmd) {
429
451
  ...compactCommand(cmd),
430
452
  common_options: COMMON_OPTIONS.map(compactCommonOption),
431
453
  ...(hasBrowserCapability(cmd) ? { browser_common_options: BROWSER_COMMON_OPTIONS.map(compactCommonOption) } : {}),
454
+ ...(cmd.adapterConcurrency?.isolatedTabs === true
455
+ ? {
456
+ adapterConcurrency: cmd.adapterConcurrency,
457
+ adapter_common_options: ADAPTER_SESSION_OPTIONS.map(compactCommonOption),
458
+ }
459
+ : {}),
432
460
  output_formats: ['table', 'plain', 'yaml', 'json', 'md', 'csv'],
433
461
  };
434
462
  }
@@ -468,6 +496,15 @@ export function formatBrowserCommonOptionsHelpText() {
468
496
  });
469
497
  return ['Browser common options:', ...formatRows(rows)].join('\n');
470
498
  }
499
+ export function formatAdapterSessionOptionsHelpText() {
500
+ const rows = ADAPTER_SESSION_OPTIONS.map(option => {
501
+ const details = [option.help];
502
+ if ('default' in option)
503
+ details.push(`default: ${option.default}`);
504
+ return [option.flags, details.join(' ')];
505
+ });
506
+ return ['Adapter session options:', ...formatRows(rows)].join('\n');
507
+ }
471
508
  export function formatSiteHelpText(site, commands) {
472
509
  const unique = [...new Map(commands.map(cmd => [fullName(cmd), cmd])).values()]
473
510
  .sort((a, b) => a.name.localeCompare(b.name));
@@ -481,6 +518,7 @@ export function formatSiteHelpText(site, commands) {
481
518
  '',
482
519
  formatCommonOptionsHelpText(),
483
520
  ...(unique.some(hasBrowserCapability) ? ['', formatBrowserCommonOptionsHelpText()] : []),
521
+ ...(unique.some(cmd => cmd.adapterConcurrency?.isolatedTabs === true) ? ['', formatAdapterSessionOptionsHelpText()] : []),
484
522
  '',
485
523
  `Agent tip: use 'bycli ${site} --help -f yaml' to get all command args/options in one structured response.`,
486
524
  '',
@@ -511,6 +549,8 @@ export function formatCommandHelpText(cmd) {
511
549
  lines.push(formatCommonOptionsHelpText(), '');
512
550
  if (hasBrowserCapability(cmd))
513
551
  lines.push(formatBrowserCommonOptionsHelpText(), '');
552
+ if (cmd.adapterConcurrency?.isolatedTabs === true)
553
+ lines.push(formatAdapterSessionOptionsHelpText(), '');
514
554
  const meta = [];
515
555
  meta.push(`Access: ${cmd.access}`);
516
556
  meta.push(`Browser: ${browserRequirementLabel(cmd)}`);
@@ -38,4 +38,8 @@ export interface ManifestEntry {
38
38
  navigateBefore?: boolean | string;
39
39
  /** Site session lifecycle defaults — see CliCommand.siteSession */
40
40
  siteSession?: 'ephemeral' | 'persistent';
41
+ adapterConcurrency?: {
42
+ isolatedTabs: true;
43
+ maxParallel: number;
44
+ };
41
45
  }
@@ -28,6 +28,10 @@ export type ConditionalBrowserCommandFunc = (page: IPage | null, kwargs: Command
28
28
  export type NonBrowserCommandFunc = (kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
29
29
  export type CommandAccess = 'read' | 'write';
30
30
  export type SiteSessionMode = 'ephemeral' | 'persistent';
31
+ export interface AdapterConcurrency {
32
+ isolatedTabs: true;
33
+ maxParallel: number;
34
+ }
31
35
  /**
32
36
  * 所有已注册 adapter command 的共享元数据和运行选项。
33
37
  *
@@ -82,6 +86,8 @@ interface BaseCliCommand {
82
86
  navigateBefore?: boolean | string;
83
87
  /** adapter 浏览器站点 session 生命周期:临时 session 或持久 session。 */
84
88
  siteSession?: SiteSessionMode;
89
+ /** Opt-in authorization for isolated persistent Adapter tabs. */
90
+ adapterConcurrency?: AdapterConcurrency;
85
91
  /** 用户没有传 `-f/--format` 时使用的默认输出格式。 */
86
92
  defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'yml' | 'md' | 'markdown' | 'csv';
87
93
  }
@@ -95,6 +95,7 @@ function rawCommandBase(opts) {
95
95
  validateArgs: opts.validateArgs,
96
96
  navigateBefore: opts.navigateBefore,
97
97
  siteSession: opts.siteSession,
98
+ adapterConcurrency: opts.adapterConcurrency,
98
99
  defaultFormat: opts.defaultFormat,
99
100
  };
100
101
  }
@@ -190,6 +191,27 @@ function assertSiteSession(cmd) {
190
191
  throw new Error(`Command ${key} siteSession must be one of: ephemeral, persistent`);
191
192
  }
192
193
  }
194
+ function assertAdapterConcurrency(cmd) {
195
+ if (cmd.adapterConcurrency === undefined)
196
+ return;
197
+ const key = `${cmd.site}/${cmd.name}`;
198
+ if (!cmd.adapterConcurrency || typeof cmd.adapterConcurrency !== 'object') {
199
+ throw new Error(`Command ${key} adapterConcurrency must be an object`);
200
+ }
201
+ const metadata = cmd.adapterConcurrency;
202
+ if (metadata.isolatedTabs !== true) {
203
+ throw new Error(`Command ${key} adapterConcurrency.isolatedTabs must be true`);
204
+ }
205
+ if (!Number.isInteger(metadata.maxParallel)
206
+ || metadata.maxParallel < 1
207
+ || metadata.maxParallel > 3) {
208
+ throw new Error(`Command ${key} adapterConcurrency.maxParallel must be an integer between 1 and 3`);
209
+ }
210
+ if (cmd.browser === false
211
+ || (cmd.browser === undefined && (cmd.strategy === Strategy.PUBLIC || cmd.strategy === Strategy.LOCAL))) {
212
+ throw new Error(`Command ${key} adapterConcurrency requires browser capability`);
213
+ }
214
+ }
193
215
  export function registerCommand(cmd) {
194
216
  registerCommandInput(cmd);
195
217
  }
@@ -197,6 +219,7 @@ function registerCommandInput(cmd) {
197
219
  withRegistryMutationGroup(() => {
198
220
  assertCommandAccess(cmd);
199
221
  assertSiteSession(cmd);
222
+ assertAdapterConcurrency(cmd);
200
223
  if (cmd.browser === 'conditional') {
201
224
  if (typeof cmd.requiresBrowser !== 'function') {
202
225
  const key = `${cmd.site}/${cmd.name}`;
@@ -33,6 +33,7 @@ export declare function serializeCommand(cmd: CliCommand): {
33
33
  example: string;
34
34
  defaultFormat: "table" | "plain" | "json" | "yaml" | "yml" | "md" | "markdown" | "csv" | null;
35
35
  siteSession: import("./registry.js").SiteSessionMode | null;
36
+ adapterConcurrency: import("./registry.js").AdapterConcurrency | null;
36
37
  };
37
38
  /** Human-readable arg summary: `<required> [optional]` style. */
38
39
  export declare function formatArgSummary(args: Arg[]): string;
@@ -35,6 +35,7 @@ export function serializeCommand(cmd) {
35
35
  example: formatCommandExample(cmd),
36
36
  defaultFormat: cmd.defaultFormat ?? null,
37
37
  siteSession: cmd.siteSession ?? null,
38
+ adapterConcurrency: cmd.adapterConcurrency ?? null,
38
39
  };
39
40
  }
40
41
  // ── Formatting ──────────────────────────────────────────────────────────────
@@ -222,6 +222,8 @@ export interface IPage {
222
222
  /** Focus the browser window containing the active page for interactive login. */
223
223
  focusWindow?(): Promise<void>;
224
224
  closeWindow?(): Promise<void>;
225
+ /** Pin subsequent commands to the daemon profile selected for this operation. */
226
+ setContextId?(contextId: string): void;
225
227
  /** Returns the current page URL, or null if unavailable. */
226
228
  getCurrentUrl?(): Promise<string | null>;
227
229
  /** Returns the active page identity (targetId), or undefined if not yet resolved. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sovovs/bycli",
3
- "version": "2.1.40",
3
+ "version": "2.1.41",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -33,7 +33,8 @@
33
33
  "./download/media-download": "./dist/src/download/media-download.js",
34
34
  "./download/progress": "./dist/src/download/progress.js",
35
35
  "./download/wechat-article": "./dist/src/download/wechat-article.js",
36
- "./pipeline": "./dist/src/pipeline/index.js"
36
+ "./pipeline": "./dist/src/pipeline/index.js",
37
+ "./adapter-coordination": "./dist/src/adapter-coordination.js"
37
38
  },
38
39
  "files": [
39
40
  "dist/src/",