@jackwener/opencli 1.7.14 → 1.7.15

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 (94) hide show
  1. package/cli-manifest.json +215 -45
  2. package/clis/bilibili/subtitle.js +1 -1
  3. package/clis/dianping/cityResolver.js +185 -0
  4. package/clis/dianping/dianping.test.js +154 -0
  5. package/clis/dianping/search.js +6 -3
  6. package/clis/douyin/_shared/browser-fetch.js +14 -2
  7. package/clis/douyin/_shared/browser-fetch.test.js +13 -0
  8. package/clis/douyin/stats.js +1 -1
  9. package/clis/douyin/update.js +1 -1
  10. package/clis/jike/search.js +1 -1
  11. package/clis/reddit/search.js +1 -1
  12. package/clis/reddit/subreddit.js +1 -1
  13. package/clis/reddit/user-comments.js +1 -1
  14. package/clis/reddit/user-posts.js +1 -1
  15. package/clis/reddit/user.js +1 -1
  16. package/clis/twitter/article.js +2 -1
  17. package/clis/twitter/bookmark-folder.js +189 -0
  18. package/clis/twitter/bookmark-folder.test.js +334 -0
  19. package/clis/twitter/bookmark-folders.js +117 -0
  20. package/clis/twitter/bookmark-folders.test.js +150 -0
  21. package/clis/twitter/bookmark.js +15 -6
  22. package/clis/twitter/bookmark.test.js +74 -0
  23. package/clis/twitter/bookmarks.js +7 -5
  24. package/clis/twitter/delete.js +11 -35
  25. package/clis/twitter/delete.test.js +21 -9
  26. package/clis/twitter/download.js +5 -5
  27. package/clis/twitter/followers.js +9 -3
  28. package/clis/twitter/following.js +11 -5
  29. package/clis/twitter/hide-reply.js +24 -5
  30. package/clis/twitter/hide-reply.test.js +76 -0
  31. package/clis/twitter/like.js +21 -11
  32. package/clis/twitter/like.test.js +73 -0
  33. package/clis/twitter/likes.js +8 -6
  34. package/clis/twitter/list-add.js +4 -4
  35. package/clis/twitter/list-remove.js +4 -4
  36. package/clis/twitter/list-tweets.js +6 -4
  37. package/clis/twitter/lists.js +3 -3
  38. package/clis/twitter/notifications.js +2 -2
  39. package/clis/twitter/profile.js +4 -3
  40. package/clis/twitter/quote.js +60 -32
  41. package/clis/twitter/quote.test.js +96 -8
  42. package/clis/twitter/reply.js +24 -178
  43. package/clis/twitter/reply.test.js +29 -11
  44. package/clis/twitter/retweet.js +9 -14
  45. package/clis/twitter/retweet.test.js +5 -1
  46. package/clis/twitter/search.js +175 -23
  47. package/clis/twitter/search.test.js +266 -1
  48. package/clis/twitter/shared.js +43 -0
  49. package/clis/twitter/shared.test.js +107 -1
  50. package/clis/twitter/thread.js +6 -4
  51. package/clis/twitter/timeline.js +8 -6
  52. package/clis/twitter/tweets.js +5 -3
  53. package/clis/twitter/unbookmark.js +13 -6
  54. package/clis/twitter/unbookmark.test.js +73 -0
  55. package/clis/twitter/unlike.js +6 -13
  56. package/clis/twitter/unlike.test.js +5 -2
  57. package/clis/twitter/unretweet.js +9 -14
  58. package/clis/twitter/unretweet.test.js +5 -1
  59. package/clis/twitter/utils.js +286 -0
  60. package/clis/twitter/utils.test.js +169 -0
  61. package/dist/src/browser/ax-snapshot.d.ts +37 -0
  62. package/dist/src/browser/ax-snapshot.js +217 -0
  63. package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
  64. package/dist/src/browser/ax-snapshot.test.js +91 -0
  65. package/dist/src/browser/base-page.d.ts +51 -0
  66. package/dist/src/browser/base-page.js +545 -2
  67. package/dist/src/browser/base-page.test.js +520 -4
  68. package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
  69. package/dist/src/browser/cdp-click-fixture.test.js +87 -0
  70. package/dist/src/browser/cdp.js +5 -0
  71. package/dist/src/browser/cdp.test.js +1 -0
  72. package/dist/src/browser/daemon-client.d.ts +3 -1
  73. package/dist/src/browser/find.d.ts +9 -1
  74. package/dist/src/browser/find.js +219 -0
  75. package/dist/src/browser/find.test.js +61 -1
  76. package/dist/src/browser/page.d.ts +2 -1
  77. package/dist/src/browser/page.js +13 -0
  78. package/dist/src/browser/page.test.js +28 -0
  79. package/dist/src/browser/target-errors.d.ts +3 -1
  80. package/dist/src/browser/target-errors.js +2 -0
  81. package/dist/src/browser/target-resolver.d.ts +14 -0
  82. package/dist/src/browser/target-resolver.js +28 -0
  83. package/dist/src/browser/visual-refs.d.ts +11 -0
  84. package/dist/src/browser/visual-refs.js +108 -0
  85. package/dist/src/build-manifest.d.ts +23 -0
  86. package/dist/src/build-manifest.js +34 -0
  87. package/dist/src/build-manifest.test.js +108 -1
  88. package/dist/src/cli.js +560 -58
  89. package/dist/src/cli.test.js +598 -0
  90. package/dist/src/help.d.ts +32 -0
  91. package/dist/src/help.js +145 -0
  92. package/dist/src/types.d.ts +82 -0
  93. package/package.json +1 -1
  94. package/scripts/typed-error-lint-baseline.json +18 -18
@@ -1,6 +1,24 @@
1
1
  import { Command } from 'commander';
2
2
  import type { CliCommand } from './registry.js';
3
3
  export type StructuredHelpFormat = 'yaml' | 'json';
4
+ export interface ArgSpec {
5
+ name: string;
6
+ required?: true;
7
+ variadic?: true;
8
+ help?: string;
9
+ default?: unknown;
10
+ choices?: string[];
11
+ }
12
+ export interface OptionSpec {
13
+ name: string;
14
+ flags: string;
15
+ help?: string;
16
+ takes_value?: 'required' | 'optional';
17
+ required?: true;
18
+ default?: unknown;
19
+ choices?: string[];
20
+ negate?: true;
21
+ }
4
22
  export declare function getRequestedHelpFormat(argv?: readonly string[]): StructuredHelpFormat | undefined;
5
23
  export declare function renderStructuredHelp(data: unknown, format: StructuredHelpFormat): string;
6
24
  export declare function wrapCommaList(items: readonly string[], opts?: {
@@ -29,6 +47,20 @@ export interface RootAdapterGroups {
29
47
  sites: readonly string[];
30
48
  }
31
49
  export declare function formatRootAdapterHelpText(groups: RootAdapterGroups): string;
50
+ export declare function commanderNamespaceHelpData(namespaceRoot: Command, opts?: {
51
+ globalCommand?: Command;
52
+ description?: string;
53
+ }): Record<string, unknown>;
54
+ export declare function commanderCommandHelpData(namespaceRoot: Command, command: Command, opts?: {
55
+ globalCommand?: Command;
56
+ }): Record<string, unknown>;
57
+ export declare function commanderGroupHelpData(namespaceRoot: Command, groupCommand: Command, opts?: {
58
+ globalCommand?: Command;
59
+ }): Record<string, unknown>;
60
+ export declare function installCommanderNamespaceStructuredHelp(namespaceRoot: Command, opts?: {
61
+ globalCommand?: Command;
62
+ description?: string;
63
+ }): void;
32
64
  export declare function formatCommandListTerm(cmd: CliCommand): string;
33
65
  export declare function rootHelpData(program: Command, groups: RootAdapterGroups): Record<string, unknown>;
34
66
  export declare function siteHelpData(site: string, commands: readonly CliCommand[]): Record<string, unknown>;
package/dist/src/help.js CHANGED
@@ -125,6 +125,151 @@ function compactCommonOption(option) {
125
125
  ...('choices' in option ? { choices: option.choices } : {}),
126
126
  };
127
127
  }
128
+ function compactCommanderArgument(arg) {
129
+ return {
130
+ name: arg.name(),
131
+ ...(arg.required ? { required: true } : {}),
132
+ ...(arg.variadic ? { variadic: true } : {}),
133
+ ...(arg.description ? { help: arg.description } : {}),
134
+ ...(arg.defaultValue !== undefined ? { default: arg.defaultValue } : {}),
135
+ ...(arg.argChoices?.length ? { choices: [...arg.argChoices] } : {}),
136
+ };
137
+ }
138
+ function compactCommanderOption(option) {
139
+ if (option.hidden)
140
+ return null;
141
+ return {
142
+ name: option.attributeName(),
143
+ flags: option.flags,
144
+ ...(option.description ? { help: option.description } : {}),
145
+ ...(option.required ? { takes_value: 'required' } : {}),
146
+ ...(option.optional ? { takes_value: 'optional' } : {}),
147
+ ...(option.mandatory ? { required: true } : {}),
148
+ ...(option.defaultValue !== undefined ? { default: option.defaultValue } : {}),
149
+ ...(option.argChoices?.length ? { choices: [...option.argChoices] } : {}),
150
+ ...(option.negate ? { negate: true } : {}),
151
+ };
152
+ }
153
+ function compactCommanderOptions(options) {
154
+ return options
155
+ .map(compactCommanderOption)
156
+ .filter((option) => option !== null);
157
+ }
158
+ function commanderPath(command) {
159
+ const parts = [];
160
+ let current = command;
161
+ while (current) {
162
+ const name = current.name();
163
+ if (name)
164
+ parts.push(name);
165
+ current = current.parent;
166
+ }
167
+ return parts.reverse();
168
+ }
169
+ function commandPathFromRoot(namespaceRoot, command) {
170
+ const rootPath = commanderPath(namespaceRoot);
171
+ const commandPath = commanderPath(command);
172
+ return commandPath.slice(rootPath.length);
173
+ }
174
+ function collectLeafCommands(command) {
175
+ if (command.commands.length === 0)
176
+ return [command];
177
+ return command.commands.flatMap(child => collectLeafCommands(child));
178
+ }
179
+ function collectDescendantCommands(command) {
180
+ return command.commands.flatMap(child => [child, ...collectDescendantCommands(child)]);
181
+ }
182
+ function formatCommanderPositionals(args) {
183
+ return args
184
+ .map(arg => {
185
+ const name = `${arg.name()}${arg.variadic ? '...' : ''}`;
186
+ return arg.required ? `<${name}>` : `[${name}]`;
187
+ })
188
+ .join(' ');
189
+ }
190
+ function formatCommanderUsage(command, opts = {}) {
191
+ const path = commanderPath(command).join(' ');
192
+ const positionalText = formatCommanderPositionals(command.registeredArguments);
193
+ const hasOptions = compactCommanderOptions(command.options).length > 0
194
+ || (opts.namespaceRoot ? compactCommanderOptions(opts.namespaceRoot.options).length > 0 : false)
195
+ || (opts.globalCommand ? compactCommanderOptions(opts.globalCommand.options).length > 0 : false);
196
+ const optionText = hasOptions ? ' [options]' : '';
197
+ return `${path}${positionalText ? ` ${positionalText}` : ''}${optionText}`;
198
+ }
199
+ function compactCommanderCommand(namespaceRoot, command, opts = {}) {
200
+ const relativePath = commandPathFromRoot(namespaceRoot, command);
201
+ return {
202
+ name: relativePath.join(' '),
203
+ command: commanderPath(command).join(' '),
204
+ usage: formatCommanderUsage(command, { namespaceRoot, globalCommand: opts.globalCommand }),
205
+ description: command.description(),
206
+ ...(command.aliases().length ? { aliases: command.aliases() } : {}),
207
+ positionals: command.registeredArguments.map(compactCommanderArgument),
208
+ command_options: compactCommanderOptions(command.options),
209
+ };
210
+ }
211
+ export function commanderNamespaceHelpData(namespaceRoot, opts = {}) {
212
+ const leaves = collectLeafCommands(namespaceRoot)
213
+ .filter(command => command !== namespaceRoot)
214
+ .sort((a, b) => commandPathFromRoot(namespaceRoot, a).join(' ').localeCompare(commandPathFromRoot(namespaceRoot, b).join(' ')));
215
+ return {
216
+ namespace: namespaceRoot.name(),
217
+ command: commanderPath(namespaceRoot).join(' '),
218
+ usage: `${commanderPath(namespaceRoot).join(' ')} <command> [args] [options]`,
219
+ description: opts.description ?? namespaceRoot.description(),
220
+ command_count: leaves.length,
221
+ commands: leaves.map(command => compactCommanderCommand(namespaceRoot, command, opts)),
222
+ namespace_options: compactCommanderOptions(namespaceRoot.options),
223
+ ...(opts.globalCommand ? { global_options: compactCommanderOptions(opts.globalCommand.options) } : {}),
224
+ structured_help: {
225
+ formats: ['yaml', 'json'],
226
+ usage: `${commanderPath(namespaceRoot).join(' ')} --help -f yaml`,
227
+ },
228
+ };
229
+ }
230
+ export function commanderCommandHelpData(namespaceRoot, command, opts = {}) {
231
+ return {
232
+ namespace: namespaceRoot.name(),
233
+ ...compactCommanderCommand(namespaceRoot, command, opts),
234
+ namespace_options: compactCommanderOptions(namespaceRoot.options),
235
+ ...(opts.globalCommand ? { global_options: compactCommanderOptions(opts.globalCommand.options) } : {}),
236
+ structured_help: {
237
+ formats: ['yaml', 'json'],
238
+ usage: `${commanderPath(command).join(' ')} --help -f yaml`,
239
+ },
240
+ };
241
+ }
242
+ export function commanderGroupHelpData(namespaceRoot, groupCommand, opts = {}) {
243
+ const leaves = collectLeafCommands(groupCommand)
244
+ .filter(command => command !== groupCommand)
245
+ .sort((a, b) => commandPathFromRoot(namespaceRoot, a).join(' ').localeCompare(commandPathFromRoot(namespaceRoot, b).join(' ')));
246
+ return {
247
+ namespace: namespaceRoot.name(),
248
+ group: commandPathFromRoot(namespaceRoot, groupCommand).join(' '),
249
+ command: commanderPath(groupCommand).join(' '),
250
+ usage: `${commanderPath(groupCommand).join(' ')} <command> [args] [options]`,
251
+ description: groupCommand.description(),
252
+ command_count: leaves.length,
253
+ commands: leaves.map(command => compactCommanderCommand(namespaceRoot, command, opts)),
254
+ namespace_options: compactCommanderOptions(namespaceRoot.options),
255
+ ...(opts.globalCommand ? { global_options: compactCommanderOptions(opts.globalCommand.options) } : {}),
256
+ structured_help: {
257
+ formats: ['yaml', 'json'],
258
+ usage: `${commanderPath(groupCommand).join(' ')} --help -f yaml`,
259
+ },
260
+ };
261
+ }
262
+ export function installCommanderNamespaceStructuredHelp(namespaceRoot, opts = {}) {
263
+ installStructuredHelp(namespaceRoot, () => commanderNamespaceHelpData(namespaceRoot, opts));
264
+ for (const command of collectDescendantCommands(namespaceRoot)) {
265
+ if (command.commands.length > 0) {
266
+ installStructuredHelp(command, () => commanderGroupHelpData(namespaceRoot, command, opts));
267
+ }
268
+ else {
269
+ installStructuredHelp(command, () => commanderCommandHelpData(namespaceRoot, command, opts));
270
+ }
271
+ }
272
+ }
128
273
  function positionals(cmd) {
129
274
  return cmd.args.filter(arg => arg.positional);
130
275
  }
@@ -20,6 +20,8 @@ export interface SnapshotOptions {
20
20
  raw?: boolean;
21
21
  viewportExpand?: number;
22
22
  maxTextLength?: number;
23
+ /** Observation backend. `dom` is the stable default; `ax` is an opt-in prototype. */
24
+ source?: 'dom' | 'ax';
23
25
  }
24
26
  export interface WaitOptions {
25
27
  text?: string;
@@ -27,10 +29,25 @@ export interface WaitOptions {
27
29
  time?: number;
28
30
  timeout?: number;
29
31
  }
32
+ export interface BrowserDownloadWaitResult {
33
+ downloaded: boolean;
34
+ id?: number;
35
+ filename?: string;
36
+ url?: string;
37
+ finalUrl?: string;
38
+ mime?: string;
39
+ totalBytes?: number;
40
+ state?: string;
41
+ danger?: string;
42
+ error?: string;
43
+ elapsedMs: number;
44
+ }
30
45
  export interface ScreenshotOptions {
31
46
  format?: 'png' | 'jpeg';
32
47
  quality?: number;
33
48
  fullPage?: boolean;
49
+ /** Overlay current browser-state refs on visible interactive elements. */
50
+ annotate?: boolean;
34
51
  /** Override viewport width in CSS pixels for the screenshot only (cleared after). */
35
52
  width?: number;
36
53
  /** Override viewport height in CSS pixels for the screenshot only (ignored when fullPage). */
@@ -84,6 +101,69 @@ export interface IPage {
84
101
  matches_n: number;
85
102
  match_level: 'exact' | 'stable' | 'reidentified';
86
103
  }>;
104
+ dblClick?(ref: string, opts?: {
105
+ nth?: number;
106
+ firstOnMulti?: boolean;
107
+ }): Promise<{
108
+ matches_n: number;
109
+ match_level: 'exact' | 'stable' | 'reidentified';
110
+ }>;
111
+ hover?(ref: string, opts?: {
112
+ nth?: number;
113
+ firstOnMulti?: boolean;
114
+ }): Promise<{
115
+ matches_n: number;
116
+ match_level: 'exact' | 'stable' | 'reidentified';
117
+ }>;
118
+ focus?(ref: string, opts?: {
119
+ nth?: number;
120
+ firstOnMulti?: boolean;
121
+ }): Promise<{
122
+ focused: boolean;
123
+ matches_n: number;
124
+ match_level: 'exact' | 'stable' | 'reidentified';
125
+ }>;
126
+ setChecked?(ref: string, checked: boolean, opts?: {
127
+ nth?: number;
128
+ firstOnMulti?: boolean;
129
+ }): Promise<{
130
+ checked: boolean;
131
+ changed: boolean;
132
+ matches_n: number;
133
+ match_level: 'exact' | 'stable' | 'reidentified';
134
+ kind?: string;
135
+ }>;
136
+ uploadFiles?(ref: string, files: string[], opts?: {
137
+ nth?: number;
138
+ firstOnMulti?: boolean;
139
+ }): Promise<{
140
+ uploaded: boolean;
141
+ files: number;
142
+ file_names: string[];
143
+ target: string;
144
+ matches_n: number;
145
+ match_level: 'exact' | 'stable' | 'reidentified';
146
+ multiple?: boolean;
147
+ accept?: string;
148
+ }>;
149
+ drag?(source: string, target: string, opts?: {
150
+ from?: {
151
+ nth?: number;
152
+ firstOnMulti?: boolean;
153
+ };
154
+ to?: {
155
+ nth?: number;
156
+ firstOnMulti?: boolean;
157
+ };
158
+ }): Promise<{
159
+ dragged: boolean;
160
+ source: string;
161
+ target: string;
162
+ source_matches_n: number;
163
+ target_matches_n: number;
164
+ source_match_level: 'exact' | 'stable' | 'reidentified';
165
+ target_match_level: 'exact' | 'stable' | 'reidentified';
166
+ }>;
87
167
  typeText(ref: string, text: string, opts?: {
88
168
  nth?: number;
89
169
  firstOnMulti?: boolean;
@@ -111,6 +191,7 @@ export interface IPage {
111
191
  }): Promise<any>;
112
192
  getFormState(): Promise<any>;
113
193
  wait(options: number | WaitOptions): Promise<void>;
194
+ waitForDownload?(pattern?: string, timeoutMs?: number): Promise<BrowserDownloadWaitResult>;
114
195
  tabs(): Promise<any>;
115
196
  closeTab?(target?: number | string): Promise<void>;
116
197
  newTab?(url?: string): Promise<string | undefined>;
@@ -126,6 +207,7 @@ export interface IPage {
126
207
  getInterceptedRequests(): Promise<any[]>;
127
208
  waitForCapture(timeout?: number): Promise<void>;
128
209
  screenshot(options?: ScreenshotOptions): Promise<string>;
210
+ annotatedScreenshot?(options?: ScreenshotOptions): Promise<string>;
129
211
  startNetworkCapture?(pattern?: string): Promise<boolean>;
130
212
  readNetworkCapture?(): Promise<unknown[]>;
131
213
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackwener/opencli",
3
- "version": "1.7.14",
3
+ "version": "1.7.15",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -615,11 +615,19 @@
615
615
  "text": "rn_need: String(Math.min(Math.max(limit + 10, 10), 30)),",
616
616
  "occurrence": 0
617
617
  },
618
+ {
619
+ "rule": "silent-clamp",
620
+ "command": "twitter/bookmark-folder",
621
+ "file": "clis/twitter/bookmark-folder.js",
622
+ "line": 161,
623
+ "text": "const fetchCount = Math.min(100, limit - allTweets.length + 10);",
624
+ "occurrence": 0
625
+ },
618
626
  {
619
627
  "rule": "silent-clamp",
620
628
  "command": "twitter/bookmarks",
621
629
  "file": "clis/twitter/bookmarks.js",
622
- "line": 155,
630
+ "line": 156,
623
631
  "text": "const fetchCount = Math.min(100, limit - allTweets.length + 10);",
624
632
  "occurrence": 0
625
633
  },
@@ -627,7 +635,7 @@
627
635
  "rule": "silent-clamp",
628
636
  "command": "twitter/following",
629
637
  "file": "clis/twitter/following.js",
630
- "line": 209,
638
+ "line": 215,
631
639
  "text": "const fetchCount = Math.min(50, limit - allUsers.length + 10);",
632
640
  "occurrence": 0
633
641
  },
@@ -635,7 +643,7 @@
635
643
  "rule": "silent-clamp",
636
644
  "command": "twitter/likes",
637
645
  "file": "clis/twitter/likes.js",
638
- "line": 194,
646
+ "line": 195,
639
647
  "text": "const fetchCount = Math.min(100, limit - allTweets.length + 10);",
640
648
  "occurrence": 0
641
649
  },
@@ -643,7 +651,7 @@
643
651
  "rule": "silent-clamp",
644
652
  "command": "twitter/list-tweets",
645
653
  "file": "clis/twitter/list-tweets.js",
646
- "line": 167,
654
+ "line": 168,
647
655
  "text": "const fetchCount = Math.min(100, limit - allTweets.length + 10);",
648
656
  "occurrence": 0
649
657
  },
@@ -651,7 +659,7 @@
651
659
  "rule": "silent-clamp",
652
660
  "command": "twitter/timeline",
653
661
  "file": "clis/twitter/timeline.js",
654
- "line": 181,
662
+ "line": 182,
655
663
  "text": "const fetchCount = Math.min(40, limit - allTweets.length + 5); // over-fetch slightly for promoted filtering",
656
664
  "occurrence": 0
657
665
  },
@@ -659,7 +667,7 @@
659
667
  "rule": "silent-clamp",
660
668
  "command": "twitter/tweets",
661
669
  "file": "clis/twitter/tweets.js",
662
- "line": 193,
670
+ "line": 194,
663
671
  "text": "const fetchCount = Math.min(100, limit - all.length + 10);",
664
672
  "occurrence": 0
665
673
  },
@@ -667,7 +675,7 @@
667
675
  "rule": "silent-clamp",
668
676
  "command": "twitter/tweets",
669
677
  "file": "clis/twitter/tweets.js",
670
- "line": 158,
678
+ "line": 159,
671
679
  "text": "const limit = Math.max(1, Math.min(200, kwargs.limit || 20));",
672
680
  "occurrence": 0
673
681
  },
@@ -1203,7 +1211,7 @@
1203
1211
  "rule": "silent-sentinel",
1204
1212
  "command": "twitter/article",
1205
1213
  "file": "clis/twitter/article.js",
1206
- "line": 104,
1214
+ "line": 105,
1207
1215
  "text": "const screenName = user?.legacy?.screen_name || user?.core?.screen_name || 'unknown';",
1208
1216
  "occurrence": 0
1209
1217
  },
@@ -1279,19 +1287,11 @@
1279
1287
  "text": "const user = lines[0] || 'Unknown';",
1280
1288
  "occurrence": 0
1281
1289
  },
1282
- {
1283
- "rule": "silent-sentinel",
1284
- "command": "twitter/reply",
1285
- "file": "clis/twitter/reply.js",
1286
- "line": 68,
1287
- "text": "throw new Error(`Unsupported remote image format \"${normalizedContentType || 'unknown'}\". ` +",
1288
- "occurrence": 0
1289
- },
1290
1290
  {
1291
1291
  "rule": "silent-sentinel",
1292
1292
  "command": "twitter/search",
1293
1293
  "file": "clis/twitter/search.js",
1294
- "line": 156,
1294
+ "line": 296,
1295
1295
  "text": "author: tweetUser?.core?.screen_name || tweetUser?.legacy?.screen_name || 'unknown',",
1296
1296
  "occurrence": 0
1297
1297
  },
@@ -1411,7 +1411,7 @@
1411
1411
  "rule": "silent-sentinel",
1412
1412
  "command": "xiaohongshu/publish",
1413
1413
  "file": "clis/xiaohongshu/publish.js",
1414
- "line": 516,
1414
+ "line": 529,
1415
1415
  "text": "throw new Error(`Image injection failed: ${upload.error ?? 'unknown'}. ` +",
1416
1416
  "occurrence": 0
1417
1417
  },