@jackwener/opencli 1.7.13 → 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.
- package/cli-manifest.json +326 -44
- package/clis/bilibili/subtitle.js +1 -1
- package/clis/dianping/cityResolver.js +185 -0
- package/clis/dianping/dianping.test.js +154 -0
- package/clis/dianping/search.js +6 -3
- package/clis/douyin/_shared/browser-fetch.js +14 -2
- package/clis/douyin/_shared/browser-fetch.test.js +13 -0
- package/clis/douyin/stats.js +1 -1
- package/clis/douyin/update.js +1 -1
- package/clis/jike/search.js +1 -1
- package/clis/reddit/search.js +1 -1
- package/clis/reddit/subreddit.js +1 -1
- package/clis/reddit/user-comments.js +1 -1
- package/clis/reddit/user-posts.js +1 -1
- package/clis/reddit/user.js +1 -1
- package/clis/twitter/article.js +2 -1
- package/clis/twitter/bookmark-folder.js +189 -0
- package/clis/twitter/bookmark-folder.test.js +334 -0
- package/clis/twitter/bookmark-folders.js +117 -0
- package/clis/twitter/bookmark-folders.test.js +150 -0
- package/clis/twitter/bookmark.js +15 -6
- package/clis/twitter/bookmark.test.js +74 -0
- package/clis/twitter/bookmarks.js +7 -5
- package/clis/twitter/delete.js +11 -35
- package/clis/twitter/delete.test.js +21 -9
- package/clis/twitter/download.js +5 -5
- package/clis/twitter/followers.js +9 -3
- package/clis/twitter/following.js +11 -5
- package/clis/twitter/hide-reply.js +24 -5
- package/clis/twitter/hide-reply.test.js +76 -0
- package/clis/twitter/like.js +21 -11
- package/clis/twitter/like.test.js +73 -0
- package/clis/twitter/likes.js +8 -6
- package/clis/twitter/list-add.js +4 -4
- package/clis/twitter/list-remove.js +4 -4
- package/clis/twitter/list-tweets.js +6 -4
- package/clis/twitter/lists.js +3 -3
- package/clis/twitter/notifications.js +2 -2
- package/clis/twitter/profile.js +4 -3
- package/clis/twitter/quote.js +167 -0
- package/clis/twitter/quote.test.js +194 -0
- package/clis/twitter/reply.js +24 -178
- package/clis/twitter/reply.test.js +29 -11
- package/clis/twitter/retweet.js +94 -0
- package/clis/twitter/retweet.test.js +73 -0
- package/clis/twitter/search.js +175 -23
- package/clis/twitter/search.test.js +266 -1
- package/clis/twitter/shared.js +81 -0
- package/clis/twitter/shared.test.js +134 -1
- package/clis/twitter/thread.js +6 -4
- package/clis/twitter/timeline.js +8 -6
- package/clis/twitter/tweets.js +5 -3
- package/clis/twitter/unbookmark.js +13 -6
- package/clis/twitter/unbookmark.test.js +73 -0
- package/clis/twitter/unlike.js +80 -0
- package/clis/twitter/unlike.test.js +75 -0
- package/clis/twitter/unretweet.js +94 -0
- package/clis/twitter/unretweet.test.js +73 -0
- package/clis/twitter/utils.js +286 -0
- package/clis/twitter/utils.test.js +169 -0
- package/dist/src/browser/ax-snapshot.d.ts +37 -0
- package/dist/src/browser/ax-snapshot.js +217 -0
- package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
- package/dist/src/browser/ax-snapshot.test.js +91 -0
- package/dist/src/browser/base-page.d.ts +51 -0
- package/dist/src/browser/base-page.js +545 -2
- package/dist/src/browser/base-page.test.js +520 -4
- package/dist/src/browser/bridge.js +47 -45
- package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
- package/dist/src/browser/cdp-click-fixture.test.js +87 -0
- package/dist/src/browser/cdp.js +5 -0
- package/dist/src/browser/cdp.test.js +1 -0
- package/dist/src/browser/daemon-client.d.ts +3 -1
- package/dist/src/browser/find.d.ts +9 -1
- package/dist/src/browser/find.js +219 -0
- package/dist/src/browser/find.test.js +61 -1
- package/dist/src/browser/page.d.ts +2 -1
- package/dist/src/browser/page.js +13 -0
- package/dist/src/browser/page.test.js +28 -0
- package/dist/src/browser/target-errors.d.ts +3 -1
- package/dist/src/browser/target-errors.js +2 -0
- package/dist/src/browser/target-resolver.d.ts +14 -0
- package/dist/src/browser/target-resolver.js +28 -0
- package/dist/src/browser/visual-refs.d.ts +11 -0
- package/dist/src/browser/visual-refs.js +108 -0
- package/dist/src/browser.test.js +18 -0
- package/dist/src/build-manifest.d.ts +23 -0
- package/dist/src/build-manifest.js +34 -0
- package/dist/src/build-manifest.test.js +108 -1
- package/dist/src/cli.js +560 -58
- package/dist/src/cli.test.js +689 -1
- package/dist/src/commanderAdapter.js +23 -4
- package/dist/src/help.d.ts +36 -0
- package/dist/src/help.js +301 -5
- package/dist/src/types.d.ts +82 -0
- package/package.json +1 -1
- package/scripts/typed-error-lint-baseline.json +18 -18
|
@@ -12,10 +12,9 @@
|
|
|
12
12
|
import { log } from './logger.js';
|
|
13
13
|
import yaml from 'js-yaml';
|
|
14
14
|
import { fullName, getRegistry } from './registry.js';
|
|
15
|
-
import { formatRegistryHelpText } from './serialization.js';
|
|
16
15
|
import { render as renderOutput } from './output.js';
|
|
17
16
|
import { executeCommand, prepareCommandArgs } from './execution.js';
|
|
18
|
-
import { commandHelpData, formatSiteCommandDescription,
|
|
17
|
+
import { commandHelpData, formatCommandHelpText, formatCommandListTerm, formatSiteCommandDescription, formatSiteHelpText, getRequestedHelpFormat, renderStructuredHelp, siteHelpData, } from './help.js';
|
|
19
18
|
import { CliError, EXIT_CODES, toEnvelope, } from './errors.js';
|
|
20
19
|
/**
|
|
21
20
|
* Register a single CliCommand as a Commander subcommand.
|
|
@@ -49,7 +48,16 @@ export function registerCommandToProgram(siteCmd, cmd) {
|
|
|
49
48
|
.option('-f, --format <fmt>', 'Output format: table, plain, json, yaml, md, csv', 'table')
|
|
50
49
|
.option('--trace <mode>', 'Trace capture: off, on, retain-on-failure', 'off')
|
|
51
50
|
.option('-v, --verbose', 'Debug output', false);
|
|
52
|
-
|
|
51
|
+
const originalHelpInformation = subCmd.helpInformation.bind(subCmd);
|
|
52
|
+
subCmd.helpInformation = ((contextOptions) => {
|
|
53
|
+
const format = getRequestedHelpFormat();
|
|
54
|
+
if (format)
|
|
55
|
+
return renderStructuredHelp(commandHelpData(cmd), format);
|
|
56
|
+
// Keep a fallback reference so future Commander upgrades still initialize
|
|
57
|
+
// internal help state before we render the cleaner grouped command help.
|
|
58
|
+
void originalHelpInformation(contextOptions);
|
|
59
|
+
return formatCommandHelpText(cmd);
|
|
60
|
+
});
|
|
53
61
|
subCmd.action(async (...actionArgs) => {
|
|
54
62
|
const actionOpts = actionArgs[positionalArgs.length] ?? {};
|
|
55
63
|
const optionsRecord = typeof actionOpts === 'object' && actionOpts !== null ? actionOpts : {};
|
|
@@ -174,7 +182,18 @@ export function registerAllCommands(program, siteGroups) {
|
|
|
174
182
|
for (const cmd of commands) {
|
|
175
183
|
registerCommandToProgram(siteCmd, cmd);
|
|
176
184
|
}
|
|
177
|
-
|
|
185
|
+
const commandTerms = new Map(commands.map(cmd => [cmd.name, formatCommandListTerm(cmd)]));
|
|
186
|
+
siteCmd.configureHelp({
|
|
187
|
+
subcommandTerm: command => commandTerms.get(command.name()) ?? command.name(),
|
|
188
|
+
});
|
|
189
|
+
const originalSiteHelpInformation = siteCmd.helpInformation.bind(siteCmd);
|
|
190
|
+
siteCmd.helpInformation = ((contextOptions) => {
|
|
191
|
+
const format = getRequestedHelpFormat();
|
|
192
|
+
if (format)
|
|
193
|
+
return renderStructuredHelp(siteHelpData(site, commands), format);
|
|
194
|
+
void originalSiteHelpInformation(contextOptions);
|
|
195
|
+
return formatSiteHelpText(site, commands);
|
|
196
|
+
});
|
|
178
197
|
}
|
|
179
198
|
return [...commandsBySite.keys()].sort((a, b) => a.localeCompare(b));
|
|
180
199
|
}
|
package/dist/src/help.d.ts
CHANGED
|
@@ -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,8 +47,26 @@ 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;
|
|
64
|
+
export declare function formatCommandListTerm(cmd: CliCommand): string;
|
|
32
65
|
export declare function rootHelpData(program: Command, groups: RootAdapterGroups): Record<string, unknown>;
|
|
33
66
|
export declare function siteHelpData(site: string, commands: readonly CliCommand[]): Record<string, unknown>;
|
|
34
67
|
export declare function commandHelpData(cmd: CliCommand): Record<string, unknown>;
|
|
68
|
+
export declare function formatCommonOptionsHelpText(): string;
|
|
69
|
+
export declare function formatSiteHelpText(site: string, commands: readonly CliCommand[]): string;
|
|
70
|
+
export declare function formatCommandHelpText(cmd: CliCommand): string;
|
|
35
71
|
export declare function installStructuredHelp(command: Command, data: () => unknown, textSuffix?: string | (() => string)): void;
|
|
36
72
|
export declare function formatSiteCommandDescription(cmd: CliCommand): string;
|
package/dist/src/help.js
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import yaml from 'js-yaml';
|
|
2
2
|
import { fullName } from './registry.js';
|
|
3
3
|
import { formatCommandExample } from './serialization.js';
|
|
4
|
+
const COMMON_OPTIONS = [
|
|
5
|
+
{
|
|
6
|
+
flags: '-f, --format <fmt>',
|
|
7
|
+
name: 'format',
|
|
8
|
+
help: 'Output format: table, plain, json, yaml, md, csv',
|
|
9
|
+
default: 'table',
|
|
10
|
+
choices: ['table', 'plain', 'json', 'yaml', 'md', 'csv'],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
flags: '--trace <mode>',
|
|
14
|
+
name: 'trace',
|
|
15
|
+
help: 'Trace capture: off, on, retain-on-failure',
|
|
16
|
+
default: 'off',
|
|
17
|
+
choices: ['off', 'on', 'retain-on-failure'],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
flags: '-v, --verbose',
|
|
21
|
+
name: 'verbose',
|
|
22
|
+
help: 'Debug output',
|
|
23
|
+
default: false,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
flags: '-h, --help',
|
|
27
|
+
name: 'help',
|
|
28
|
+
help: 'display help for command',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
4
31
|
function normalizeStructuredHelpFormat(value) {
|
|
5
32
|
const normalized = value?.toLowerCase();
|
|
6
33
|
if (normalized === 'yaml' || normalized === 'yml')
|
|
@@ -73,7 +100,7 @@ export function formatRootAdapterHelpText(groups) {
|
|
|
73
100
|
lines.push(...formatGroupSection('App adapters', groups.apps));
|
|
74
101
|
lines.push(...formatGroupSection('Site adapters', groups.sites));
|
|
75
102
|
lines.push("Run 'opencli list' for full command details, or 'opencli <site> --help' to inspect one site.");
|
|
76
|
-
lines.push("Agent tip: use 'opencli <site> --help -f yaml' for
|
|
103
|
+
lines.push("Agent tip: use 'opencli <site> --help -f yaml' for all command args/options in one structured response.");
|
|
77
104
|
lines.push('');
|
|
78
105
|
return lines.join('\n');
|
|
79
106
|
}
|
|
@@ -89,18 +116,201 @@ function compactArg(arg) {
|
|
|
89
116
|
...(arg.help ? { help: arg.help } : {}),
|
|
90
117
|
};
|
|
91
118
|
}
|
|
92
|
-
function
|
|
119
|
+
function compactCommonOption(option) {
|
|
120
|
+
return {
|
|
121
|
+
name: option.name,
|
|
122
|
+
flags: option.flags,
|
|
123
|
+
help: option.help,
|
|
124
|
+
...('default' in option ? { default: option.default } : {}),
|
|
125
|
+
...('choices' in option ? { choices: option.choices } : {}),
|
|
126
|
+
};
|
|
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
|
+
}
|
|
273
|
+
function positionals(cmd) {
|
|
274
|
+
return cmd.args.filter(arg => arg.positional);
|
|
275
|
+
}
|
|
276
|
+
function commandOptions(cmd) {
|
|
277
|
+
return cmd.args.filter(arg => !arg.positional);
|
|
278
|
+
}
|
|
279
|
+
function formatPositionals(args) {
|
|
280
|
+
return args
|
|
281
|
+
.map(arg => arg.required ? `<${arg.name}>` : `[${arg.name}]`)
|
|
282
|
+
.join(' ');
|
|
283
|
+
}
|
|
284
|
+
function formatCommandOptionTerm(arg) {
|
|
285
|
+
if (arg.required || arg.valueRequired)
|
|
286
|
+
return `--${arg.name} <value>`;
|
|
287
|
+
return `--${arg.name} [value]`;
|
|
288
|
+
}
|
|
289
|
+
export function formatCommandListTerm(cmd) {
|
|
290
|
+
const positionalText = formatPositionals(positionals(cmd));
|
|
291
|
+
const optionText = commandOptions(cmd).length > 0 ? ' [options]' : '';
|
|
292
|
+
return `${cmd.name}${positionalText ? ` ${positionalText}` : ''}${optionText}`;
|
|
293
|
+
}
|
|
294
|
+
function formatUsage(cmd) {
|
|
295
|
+
const positionalText = formatPositionals(positionals(cmd));
|
|
296
|
+
return `opencli ${cmd.site} ${cmd.name}${positionalText ? ` ${positionalText}` : ''} [options]`;
|
|
297
|
+
}
|
|
298
|
+
function compactCommand(cmd) {
|
|
93
299
|
return {
|
|
94
300
|
name: cmd.name,
|
|
95
301
|
command: `opencli ${cmd.site} ${cmd.name}`,
|
|
302
|
+
usage: formatUsage(cmd),
|
|
96
303
|
access: cmd.access,
|
|
97
304
|
description: cmd.description,
|
|
305
|
+
browser: !!cmd.browser,
|
|
306
|
+
...(cmd.domain ? { domain: cmd.domain } : {}),
|
|
98
307
|
...(cmd.aliases?.length ? { aliases: cmd.aliases } : {}),
|
|
99
|
-
|
|
308
|
+
positionals: positionals(cmd).map(compactArg),
|
|
309
|
+
command_options: commandOptions(cmd).map(compactArg),
|
|
100
310
|
example: formatCommandExample(cmd),
|
|
101
311
|
...(cmd.browserSession ? { browserSession: cmd.browserSession } : {}),
|
|
102
312
|
...(cmd.defaultFormat ? { defaultFormat: cmd.defaultFormat } : {}),
|
|
103
|
-
...(
|
|
313
|
+
...(cmd.columns?.length ? { columns: cmd.columns } : {}),
|
|
104
314
|
};
|
|
105
315
|
}
|
|
106
316
|
export function rootHelpData(program, groups) {
|
|
@@ -142,6 +352,7 @@ export function siteHelpData(site, commands) {
|
|
|
142
352
|
site,
|
|
143
353
|
command_count: unique.length,
|
|
144
354
|
commands: unique.map(cmd => compactCommand(cmd)),
|
|
355
|
+
common_options: COMMON_OPTIONS.map(compactCommonOption),
|
|
145
356
|
next: [
|
|
146
357
|
`opencli ${site} <command> --help -f yaml`,
|
|
147
358
|
`opencli ${site} <command> -f yaml`,
|
|
@@ -151,10 +362,95 @@ export function siteHelpData(site, commands) {
|
|
|
151
362
|
export function commandHelpData(cmd) {
|
|
152
363
|
return {
|
|
153
364
|
site: cmd.site,
|
|
154
|
-
...compactCommand(cmd
|
|
365
|
+
...compactCommand(cmd),
|
|
366
|
+
common_options: COMMON_OPTIONS.map(compactCommonOption),
|
|
155
367
|
output_formats: ['table', 'plain', 'yaml', 'json', 'md', 'csv'],
|
|
156
368
|
};
|
|
157
369
|
}
|
|
370
|
+
function formatRows(rows) {
|
|
371
|
+
if (rows.length === 0)
|
|
372
|
+
return [];
|
|
373
|
+
const width = Math.min(Math.max(...rows.map(([left]) => left.length)), 34);
|
|
374
|
+
return rows.map(([left, right]) => ` ${left.padEnd(width + 2)}${right}`);
|
|
375
|
+
}
|
|
376
|
+
function formatArgHelp(arg) {
|
|
377
|
+
const parts = [];
|
|
378
|
+
if (arg.help)
|
|
379
|
+
parts.push(arg.help);
|
|
380
|
+
if (arg.default !== undefined)
|
|
381
|
+
parts.push(`default: ${arg.default}`);
|
|
382
|
+
if (arg.choices?.length)
|
|
383
|
+
parts.push(`choices: ${arg.choices.join(', ')}`);
|
|
384
|
+
return parts.join(' ');
|
|
385
|
+
}
|
|
386
|
+
export function formatCommonOptionsHelpText() {
|
|
387
|
+
const rows = COMMON_OPTIONS.map(option => {
|
|
388
|
+
const details = [option.help];
|
|
389
|
+
if ('default' in option)
|
|
390
|
+
details.push(`default: ${option.default}`);
|
|
391
|
+
if ('choices' in option)
|
|
392
|
+
details.push(`choices: ${option.choices.join(', ')}`);
|
|
393
|
+
return [option.flags, details.join(' ')];
|
|
394
|
+
});
|
|
395
|
+
return ['Common options:', ...formatRows(rows)].join('\n');
|
|
396
|
+
}
|
|
397
|
+
export function formatSiteHelpText(site, commands) {
|
|
398
|
+
const unique = [...new Map(commands.map(cmd => [fullName(cmd), cmd])).values()]
|
|
399
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
400
|
+
const lines = [
|
|
401
|
+
`Usage: opencli ${site} <command> [args] [options]`,
|
|
402
|
+
'',
|
|
403
|
+
wrapCommaList(unique.map(cmd => cmd.name), { indent: '' }),
|
|
404
|
+
'',
|
|
405
|
+
'Commands:',
|
|
406
|
+
...formatRows(unique.map(cmd => [formatCommandListTerm(cmd), formatSiteCommandDescription(cmd)])),
|
|
407
|
+
'',
|
|
408
|
+
formatCommonOptionsHelpText(),
|
|
409
|
+
'',
|
|
410
|
+
`Agent tip: use 'opencli ${site} --help -f yaml' to get all command args/options in one structured response.`,
|
|
411
|
+
'',
|
|
412
|
+
];
|
|
413
|
+
return lines.join('\n');
|
|
414
|
+
}
|
|
415
|
+
export function formatCommandHelpText(cmd) {
|
|
416
|
+
const lines = [
|
|
417
|
+
`Usage: ${formatUsage(cmd)}`,
|
|
418
|
+
'',
|
|
419
|
+
cmd.description,
|
|
420
|
+
'',
|
|
421
|
+
];
|
|
422
|
+
const positionalRows = positionals(cmd).map(arg => [
|
|
423
|
+
arg.name,
|
|
424
|
+
formatArgHelp(arg),
|
|
425
|
+
]);
|
|
426
|
+
if (positionalRows.length) {
|
|
427
|
+
lines.push('Arguments:', ...formatRows(positionalRows), '');
|
|
428
|
+
}
|
|
429
|
+
const optionRows = commandOptions(cmd).map(arg => [
|
|
430
|
+
formatCommandOptionTerm(arg),
|
|
431
|
+
formatArgHelp(arg),
|
|
432
|
+
]);
|
|
433
|
+
if (optionRows.length) {
|
|
434
|
+
lines.push('Command options:', ...formatRows(optionRows), '');
|
|
435
|
+
}
|
|
436
|
+
lines.push(formatCommonOptionsHelpText(), '');
|
|
437
|
+
const meta = [];
|
|
438
|
+
meta.push(`Access: ${cmd.access}`);
|
|
439
|
+
meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
|
|
440
|
+
if (cmd.domain)
|
|
441
|
+
meta.push(`Domain: ${cmd.domain}`);
|
|
442
|
+
if (cmd.defaultFormat)
|
|
443
|
+
meta.push(`Default format: ${cmd.defaultFormat}`);
|
|
444
|
+
if (cmd.aliases?.length)
|
|
445
|
+
meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
|
|
446
|
+
lines.push(meta.join(' | '));
|
|
447
|
+
lines.push(`Example: ${formatCommandExample(cmd)}`);
|
|
448
|
+
if (cmd.columns?.length)
|
|
449
|
+
lines.push(`Output columns: ${cmd.columns.join(', ')}`);
|
|
450
|
+
lines.push("Agent tip: use '--help -f yaml' for structured args/options.");
|
|
451
|
+
lines.push('');
|
|
452
|
+
return lines.join('\n');
|
|
453
|
+
}
|
|
158
454
|
export function installStructuredHelp(command, data, textSuffix) {
|
|
159
455
|
const original = command.helpInformation.bind(command);
|
|
160
456
|
command.helpInformation = ((contextOptions) => {
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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
|
/**
|