browser-debugger-cli 0.12.0 → 0.14.0
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/.claude/skills/bdg/SKILL.md +100 -186
- package/README.md +5 -4
- package/dist/commands/cdp.d.ts +22 -1
- package/dist/commands/cdp.js +100 -43
- package/dist/commands/console.d.ts +12 -0
- package/dist/commands/console.js +67 -13
- package/dist/commands/dom/DomElementResolver.d.ts +3 -1
- package/dist/commands/dom/DomElementResolver.js +10 -3
- package/dist/commands/dom/a11y.d.ts +1 -1
- package/dist/commands/dom/a11y.js +23 -22
- package/dist/commands/dom/eval.d.ts +4 -2
- package/dist/commands/dom/eval.js +31 -7
- package/dist/commands/dom/form.js +10 -9
- package/dist/commands/dom/formInteraction.js +9 -8
- package/dist/commands/dom/get.js +32 -14
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/query.d.ts +27 -3
- package/dist/commands/dom/helpers/query.js +152 -64
- package/dist/commands/dom/helpers/screenshot.js +13 -13
- package/dist/commands/dom/index.js +10 -3
- package/dist/commands/dom/query.d.ts +20 -2
- package/dist/commands/dom/query.js +39 -6
- package/dist/commands/dom/screenshot.js +3 -1
- package/dist/commands/dom/semanticUtils.d.ts +3 -2
- package/dist/commands/dom/semanticUtils.js +40 -9
- package/dist/commands/helpJson.d.ts +82 -19
- package/dist/commands/helpJson.js +112 -41
- package/dist/commands/helpTopic.d.ts +16 -1
- package/dist/commands/helpTopic.js +59 -1
- package/dist/commands/installSkill.d.ts +15 -5
- package/dist/commands/installSkill.js +86 -16
- package/dist/commands/network/list.js +65 -12
- package/dist/commands/optionBehaviors.d.ts +25 -2
- package/dist/commands/optionBehaviors.js +81 -46
- package/dist/commands/peek.js +3 -0
- package/dist/commands/shared/CommandRunner.js +13 -13
- package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
- package/dist/commands/shared/daemonErrorHandler.js +21 -10
- package/dist/commands/shared/dataFetcher.d.ts +14 -4
- package/dist/commands/shared/dataFetcher.js +20 -4
- package/dist/commands/shared/followMode.d.ts +9 -1
- package/dist/commands/shared/followMode.js +22 -4
- package/dist/commands/shared/handleValidationError.js +3 -3
- package/dist/commands/shared/optionTypes.d.ts +17 -3
- package/dist/commands/shared/outputFile.js +6 -1
- package/dist/commands/shared/startHelpers.js +3 -3
- package/dist/commands/start.d.ts +7 -5
- package/dist/commands/start.js +65 -21
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.js +24 -1
- package/dist/commands.js +1 -1
- package/dist/connection/cdp.d.ts +7 -0
- package/dist/connection/cdp.js +9 -0
- package/dist/connection/chromeIdentity.d.ts +8 -2
- package/dist/connection/chromeIdentity.js +85 -13
- package/dist/connection/launcher.js +3 -2
- package/dist/constants.d.ts +29 -1
- package/dist/constants.js +35 -1
- package/dist/daemon/SessionController.js +8 -1
- package/dist/daemon/launcher.d.ts +3 -2
- package/dist/daemon/launcher.js +47 -3
- package/dist/daemon/session/Session.d.ts +5 -1
- package/dist/daemon/session/Session.js +42 -3
- package/dist/daemon/session/TelemetryStore.d.ts +15 -1
- package/dist/daemon/session/TelemetryStore.js +19 -1
- package/dist/daemon/session/commandRegistry.js +52 -18
- package/dist/daemon/session/interactions.d.ts +2 -1
- package/dist/daemon/session/interactions.js +13 -1
- package/dist/daemon/session/matchedStylesReset.d.ts +26 -0
- package/dist/daemon/session/matchedStylesReset.js +46 -0
- package/dist/daemon/session/plugins.js +17 -2
- package/dist/daemon/session/teardown.js +1 -1
- package/dist/daemon/session/triggeredRequests.d.ts +0 -5
- package/dist/daemon/session/triggeredRequests.js +13 -7
- package/dist/daemon.js +2385 -1229
- package/dist/errors/messages.d.ts +62 -11
- package/dist/errors/messages.js +119 -22
- package/dist/index.js +14995 -9866
- package/dist/ipc/client.d.ts +18 -2
- package/dist/ipc/client.js +26 -5
- package/dist/ipc/protocol/auditTypes.d.ts +8 -2
- package/dist/ipc/protocol/commands.d.ts +16 -0
- package/dist/ipc/protocol/domTypes.d.ts +12 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +7 -2
- package/dist/ipc/session/types.d.ts +7 -1
- package/dist/program.d.ts +14 -0
- package/dist/program.js +53 -0
- package/dist/runtime/dom/actionEffects.d.ts +5 -1
- package/dist/runtime/dom/actionEffects.js +26 -14
- package/dist/runtime/dom/audit.js +3 -2
- package/dist/runtime/dom/auditModel.js +6 -1
- package/dist/runtime/dom/auditScripts.d.ts +9 -3
- package/dist/runtime/dom/auditScripts.js +41 -5
- package/dist/runtime/dom/elementGeometry.d.ts +33 -3
- package/dist/runtime/dom/elementGeometry.js +44 -19
- package/dist/runtime/dom/elementInfo.d.ts +76 -18
- package/dist/runtime/dom/elementInfo.js +190 -40
- package/dist/runtime/dom/evalHelpers.d.ts +12 -2
- package/dist/runtime/dom/evalHelpers.js +67 -7
- package/dist/runtime/dom/formDiscovery.d.ts +6 -2
- package/dist/runtime/dom/formDiscovery.js +20 -3
- package/dist/runtime/dom/formFillHelpers/fill.js +7 -11
- package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
- package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
- package/dist/runtime/dom/formSubmitHelpers.js +4 -3
- package/dist/runtime/dom/frameLayout.js +1 -0
- package/dist/runtime/dom/frameScopedConnection.d.ts +7 -0
- package/dist/runtime/dom/frameScopedConnection.js +2 -2
- package/dist/runtime/dom/inspect.d.ts +17 -3
- package/dist/runtime/dom/inspect.js +45 -32
- package/dist/runtime/dom/inspectAllStyles.js +1 -0
- package/dist/runtime/dom/inspectHints.d.ts +1 -1
- package/dist/runtime/dom/inspectModel.d.ts +5 -4
- package/dist/runtime/dom/inspectModel.js +7 -3
- package/dist/runtime/dom/inspectPaintModel.d.ts +2 -0
- package/dist/runtime/dom/inspectPaintModel.js +3 -1
- package/dist/runtime/dom/inspectRules.d.ts +29 -3
- package/dist/runtime/dom/inspectRules.js +205 -11
- package/dist/runtime/dom/inspectScripts.d.ts +29 -2
- package/dist/runtime/dom/inspectScripts.js +49 -10
- package/dist/runtime/dom/layout.d.ts +0 -2
- package/dist/runtime/dom/layout.js +10 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +17 -4
- package/dist/runtime/dom/reactEventHelpers.js +71 -28
- package/dist/runtime/dom/targetNode.d.ts +27 -10
- package/dist/runtime/dom/targetNode.js +283 -16
- package/dist/runtime/dom/wait.js +2 -1
- package/dist/runtime/page/bdgWorld.d.ts +57 -0
- package/dist/runtime/page/bdgWorld.js +180 -0
- package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
- package/dist/runtime/page/replacedBuiltins.js +136 -0
- package/dist/session/QueryCacheManager.d.ts +4 -1
- package/dist/session/QueryCacheManager.js +5 -2
- package/dist/session/chrome.d.ts +4 -1
- package/dist/session/chrome.js +7 -1
- package/dist/session/cleanup/staleSession.d.ts +21 -4
- package/dist/session/cleanup/staleSession.js +79 -9
- package/dist/session/cleanup/userCommands.d.ts +4 -1
- package/dist/session/cleanup/userCommands.js +10 -5
- package/dist/session/daemonSocket.d.ts +10 -0
- package/dist/session/daemonSocket.js +22 -0
- package/dist/session/lastSession.d.ts +6 -3
- package/dist/session/lastSession.js +11 -5
- package/dist/session/paths.d.ts +3 -1
- package/dist/session/paths.js +5 -5
- package/dist/session/portClaims.js +4 -3
- package/dist/session/sessionList.d.ts +13 -5
- package/dist/session/sessionList.js +31 -7
- package/dist/telemetry/a11y.d.ts +15 -1
- package/dist/telemetry/a11y.js +85 -2
- package/dist/telemetry/console.d.ts +2 -1
- package/dist/telemetry/console.js +30 -21
- package/dist/telemetry/har/builder.js +1 -1
- package/dist/telemetry/network.d.ts +13 -16
- package/dist/telemetry/network.js +30 -52
- package/dist/telemetry/networkRetention.d.ts +83 -0
- package/dist/telemetry/networkRetention.js +117 -0
- package/dist/telemetry/pageCrash.d.ts +26 -0
- package/dist/telemetry/pageCrash.js +53 -0
- package/dist/types.d.ts +42 -0
- package/dist/ui/OutputBuilder.d.ts +10 -0
- package/dist/ui/OutputBuilder.js +12 -0
- package/dist/ui/formatters/a11y.d.ts +5 -7
- package/dist/ui/formatters/a11y.js +7 -61
- package/dist/ui/formatters/audit.js +14 -5
- package/dist/ui/formatters/cdp.d.ts +138 -0
- package/dist/ui/formatters/cdp.js +131 -0
- package/dist/ui/formatters/console/chronological.js +7 -5
- package/dist/ui/formatters/console/follow.d.ts +5 -2
- package/dist/ui/formatters/console/follow.js +7 -4
- package/dist/ui/formatters/console/json.d.ts +4 -7
- package/dist/ui/formatters/console/json.js +16 -14
- package/dist/ui/formatters/console/shared.d.ts +47 -2
- package/dist/ui/formatters/console/shared.js +33 -0
- package/dist/ui/formatters/console/summarize.d.ts +9 -2
- package/dist/ui/formatters/console/summarize.js +57 -11
- package/dist/ui/formatters/console.d.ts +3 -2
- package/dist/ui/formatters/console.js +8 -10
- package/dist/ui/formatters/details.js +4 -2
- package/dist/ui/formatters/dom.d.ts +14 -5
- package/dist/ui/formatters/dom.js +30 -13
- package/dist/ui/formatters/helpFormatters.js +1 -1
- package/dist/ui/formatters/inspect.js +9 -3
- package/dist/ui/formatters/installSkill.d.ts +9 -1
- package/dist/ui/formatters/installSkill.js +32 -6
- package/dist/ui/formatters/layout.js +4 -2
- package/dist/ui/formatters/longValues.d.ts +14 -0
- package/dist/ui/formatters/longValues.js +23 -0
- package/dist/ui/formatters/networkList.d.ts +8 -2
- package/dist/ui/formatters/networkList.js +11 -3
- package/dist/ui/formatters/preview.d.ts +6 -1
- package/dist/ui/formatters/preview.js +67 -15
- package/dist/ui/formatters/sessions.d.ts +2 -2
- package/dist/ui/formatters/sessions.js +9 -2
- package/dist/ui/formatters/status.js +7 -0
- package/dist/ui/formatters/triggeredRequests.js +2 -1
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/chrome.d.ts +20 -1
- package/dist/ui/messages/chrome.js +29 -3
- package/dist/ui/messages/commands.d.ts +153 -12
- package/dist/ui/messages/commands.js +198 -15
- package/dist/ui/messages/consoleMessages.d.ts +24 -0
- package/dist/ui/messages/consoleMessages.js +32 -0
- package/dist/ui/messages/networkMessages.d.ts +24 -0
- package/dist/ui/messages/networkMessages.js +45 -0
- package/dist/ui/messages/preview.d.ts +6 -0
- package/dist/ui/messages/preview.js +9 -1
- package/dist/ui/messages/session.d.ts +13 -2
- package/dist/ui/messages/session.js +22 -3
- package/dist/utils/directories.d.ts +34 -0
- package/dist/utils/directories.js +88 -0
- package/dist/utils/display.d.ts +16 -0
- package/dist/utils/display.js +42 -0
- package/dist/utils/exitCodes.d.ts +1 -0
- package/dist/utils/exitCodes.js +6 -0
- package/dist/utils/http.d.ts +9 -2
- package/dist/utils/http.js +4 -3
- package/dist/utils/process.d.ts +12 -0
- package/dist/utils/process.js +25 -0
- package/dist/utils/strings.d.ts +19 -0
- package/dist/utils/strings.js +16 -0
- package/package.json +2 -2
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getAllDomainSummaries } from '../cdp/schema.js';
|
|
5
5
|
import { getOptionBehavior } from './optionBehaviors.js';
|
|
6
6
|
import { readLiveDaemonPid } from '../session/cleanup/staleSession.js';
|
|
7
|
+
import { helpJsonDetailsNote } from '../ui/messages/commands.js';
|
|
7
8
|
import { getAllDecisionTrees } from '../utils/decisionTrees.js';
|
|
8
9
|
import { EXIT_CODE_REGISTRY } from '../utils/exitCodes.js';
|
|
9
10
|
import { getAllTaskMappings } from '../utils/taskMappings.js';
|
|
@@ -35,7 +36,7 @@ function convertOption(option, commandName) {
|
|
|
35
36
|
if (option.argChoices) {
|
|
36
37
|
metadata.choices = option.argChoices;
|
|
37
38
|
}
|
|
38
|
-
const behavior = getOptionBehavior(commandName, option
|
|
39
|
+
const behavior = getOptionBehavior(commandName, option);
|
|
39
40
|
if (behavior) {
|
|
40
41
|
metadata.behavior = behavior;
|
|
41
42
|
}
|
|
@@ -65,6 +66,21 @@ function convertArgument(argument) {
|
|
|
65
66
|
}
|
|
66
67
|
return metadata;
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* The text a command adds after its options in `--help` (examples, output
|
|
71
|
+
* legend), collected from its `afterHelp` listeners. Commander's Command is an
|
|
72
|
+
* EventEmitter at runtime; its typings leave that out.
|
|
73
|
+
*
|
|
74
|
+
* @param command - Commander command instance
|
|
75
|
+
* @returns The text, or undefined when the command adds none
|
|
76
|
+
*/
|
|
77
|
+
function afterHelpText(command) {
|
|
78
|
+
const chunks = [];
|
|
79
|
+
const emitter = command;
|
|
80
|
+
emitter.emit('afterHelp', { error: false, command, write: (text) => chunks.push(text) });
|
|
81
|
+
const text = chunks.join('').trim();
|
|
82
|
+
return text || undefined;
|
|
83
|
+
}
|
|
68
84
|
/**
|
|
69
85
|
* Recursively converts a Commander Command to CommandMetadata.
|
|
70
86
|
*
|
|
@@ -75,6 +91,7 @@ function convertArgument(argument) {
|
|
|
75
91
|
*/
|
|
76
92
|
function convertCommand(command) {
|
|
77
93
|
const commandName = command.name();
|
|
94
|
+
const helpText = afterHelpText(command);
|
|
78
95
|
return {
|
|
79
96
|
name: commandName,
|
|
80
97
|
aliases: command.aliases(),
|
|
@@ -82,9 +99,45 @@ function convertCommand(command) {
|
|
|
82
99
|
usage: command.usage(),
|
|
83
100
|
arguments: command.registeredArguments.map(convertArgument),
|
|
84
101
|
options: command.options.map((opt) => convertOption(opt, commandName)),
|
|
102
|
+
...(helpText && { helpText }),
|
|
85
103
|
subcommands: command.commands.map(convertCommand),
|
|
86
104
|
};
|
|
87
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* An argument as written in usage: `<name>`, `[name]`, `<name...>`.
|
|
108
|
+
*
|
|
109
|
+
* @param argument - Commander argument instance
|
|
110
|
+
* @returns Usage term
|
|
111
|
+
*/
|
|
112
|
+
function argumentTerm(argument) {
|
|
113
|
+
const name = `${argument.name()}${argument.variadic ? '...' : ''}`;
|
|
114
|
+
return argument.required ? `<${name}>` : `[${name}]`;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Recursively converts a Commander Command to its compact summary: first
|
|
118
|
+
* description line, arguments, and visible options with their descriptions.
|
|
119
|
+
* Empty fields are left out.
|
|
120
|
+
*
|
|
121
|
+
* @param command - Commander command instance
|
|
122
|
+
* @returns Compact command summary
|
|
123
|
+
*/
|
|
124
|
+
function convertCompactCommand(command) {
|
|
125
|
+
const aliases = command.aliases();
|
|
126
|
+
const args = command.registeredArguments.map(argumentTerm).join(' ');
|
|
127
|
+
const options = command.options.filter((option) => !option.hidden);
|
|
128
|
+
return {
|
|
129
|
+
name: command.name(),
|
|
130
|
+
...(aliases.length > 0 && { aliases }),
|
|
131
|
+
description: command.description().split('\n')[0] ?? '',
|
|
132
|
+
...(args && { arguments: args }),
|
|
133
|
+
...(options.length > 0 && {
|
|
134
|
+
options: Object.fromEntries(options.map((option) => [option.flags, option.description])),
|
|
135
|
+
}),
|
|
136
|
+
...(command.commands.length > 0 && {
|
|
137
|
+
subcommands: command.commands.map(convertCompactCommand),
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
88
141
|
/**
|
|
89
142
|
* Generates runtime state information.
|
|
90
143
|
*
|
|
@@ -150,10 +203,11 @@ function generateCapabilities() {
|
|
|
150
203
|
};
|
|
151
204
|
}
|
|
152
205
|
/**
|
|
153
|
-
* Generates machine-readable help from a Commander program
|
|
206
|
+
* Generates the full machine-readable help from a Commander program
|
|
207
|
+
* (`bdg --help --json --full`).
|
|
154
208
|
*
|
|
155
209
|
* Includes comprehensive metadata for agent discovery:
|
|
156
|
-
* - Command structure and options
|
|
210
|
+
* - Command structure and options with behaviors
|
|
157
211
|
* - Exit codes with semantic meanings
|
|
158
212
|
* - Task-to-command mappings with CDP alternatives
|
|
159
213
|
* - Runtime state and command availability
|
|
@@ -162,15 +216,6 @@ function generateCapabilities() {
|
|
|
162
216
|
*
|
|
163
217
|
* @param program - Commander program instance
|
|
164
218
|
* @returns Machine-readable help structure
|
|
165
|
-
*
|
|
166
|
-
* @example
|
|
167
|
-
* ```typescript
|
|
168
|
-
* import { program } from 'commander';
|
|
169
|
-
* import { generateMachineReadableHelp } from './help/machineReadableHelp.js';
|
|
170
|
-
*
|
|
171
|
-
* const help = generateMachineReadableHelp(program);
|
|
172
|
-
* console.log(JSON.stringify(help, null, 2));
|
|
173
|
-
* ```
|
|
174
219
|
*/
|
|
175
220
|
export function generateMachineReadableHelp(program) {
|
|
176
221
|
return {
|
|
@@ -186,56 +231,82 @@ export function generateMachineReadableHelp(program) {
|
|
|
186
231
|
};
|
|
187
232
|
}
|
|
188
233
|
/**
|
|
189
|
-
*
|
|
234
|
+
* Generates the compact root help (`bdg --help --json`): the full help with
|
|
235
|
+
* the command tree reduced to names, one-line descriptions and flags.
|
|
236
|
+
*
|
|
237
|
+
* @param program - Commander program instance
|
|
238
|
+
* @returns Compact help structure
|
|
239
|
+
*/
|
|
240
|
+
export function generateCompactHelp(program) {
|
|
241
|
+
return {
|
|
242
|
+
...generateMachineReadableHelp(program),
|
|
243
|
+
details: helpJsonDetailsNote(),
|
|
244
|
+
command: convertCompactCommand(program),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The command a command line addresses: follows the words that name
|
|
249
|
+
* subcommands and skips the others (option values, arguments), stopping at a
|
|
250
|
+
* command without subcommands.
|
|
190
251
|
*
|
|
191
252
|
* @param program - Root Commander program instance
|
|
192
|
-
* @param
|
|
193
|
-
* @returns The
|
|
253
|
+
* @param words - Command-line words, e.g. ['dom', 'query', '.item']
|
|
254
|
+
* @returns The addressed command (the program when no word names one)
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```typescript
|
|
258
|
+
* resolveCommand(program, ['--session', 'a', 'dom', 'query', '.item']).name(); // 'query'
|
|
259
|
+
* ```
|
|
194
260
|
*/
|
|
195
|
-
function
|
|
261
|
+
export function resolveCommand(program, words) {
|
|
196
262
|
let current = program;
|
|
197
|
-
for (const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
263
|
+
for (const word of words) {
|
|
264
|
+
if (current.commands.length === 0)
|
|
265
|
+
break;
|
|
266
|
+
const found = current.commands.find((cmd) => cmd.name() === word || cmd.aliases().includes(word));
|
|
267
|
+
if (found)
|
|
268
|
+
current = found;
|
|
203
269
|
}
|
|
204
270
|
return current;
|
|
205
271
|
}
|
|
206
272
|
/**
|
|
207
|
-
*
|
|
273
|
+
* Full command path, e.g. "bdg dom query".
|
|
208
274
|
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
|
|
275
|
+
* @param command - Commander command instance
|
|
276
|
+
* @returns Names from the program down to the command
|
|
277
|
+
*/
|
|
278
|
+
export function commandPath(command) {
|
|
279
|
+
const names = [];
|
|
280
|
+
for (let level = command; level; level = level.parent)
|
|
281
|
+
names.unshift(level.name());
|
|
282
|
+
return names.join(' ');
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Generates machine-readable help for one command: its full metadata,
|
|
286
|
+
* compact subcommands (a group lists them like the root help does) and the
|
|
287
|
+
* exit codes.
|
|
212
288
|
*
|
|
213
289
|
* @param program - Root Commander program instance
|
|
214
|
-
* @param
|
|
215
|
-
* @returns
|
|
290
|
+
* @param command - The command (from {@link resolveCommand})
|
|
291
|
+
* @returns Help for the command
|
|
216
292
|
*
|
|
217
293
|
* @example
|
|
218
294
|
* ```typescript
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* console.log(help.command.name); // 'query'
|
|
295
|
+
* const help = generateCommandHelp(program, resolveCommand(program, ['dom', 'query']));
|
|
296
|
+
* console.log(help.path); // 'bdg dom query'
|
|
222
297
|
* ```
|
|
223
298
|
*/
|
|
224
|
-
export function
|
|
225
|
-
const targetCommand = findSubcommand(program, commandPath);
|
|
226
|
-
if (!targetCommand) {
|
|
227
|
-
return generateMachineReadableHelp(program);
|
|
228
|
-
}
|
|
299
|
+
export function generateCommandHelp(program, command) {
|
|
229
300
|
return {
|
|
230
301
|
name: program.name(),
|
|
231
302
|
version: program.version() ?? 'unknown',
|
|
232
303
|
description: program.description(),
|
|
233
|
-
|
|
304
|
+
path: commandPath(command),
|
|
305
|
+
command: {
|
|
306
|
+
...convertCommand(command),
|
|
307
|
+
subcommands: command.commands.map(convertCompactCommand),
|
|
308
|
+
},
|
|
234
309
|
exitCodes: [...EXIT_CODE_DOCS],
|
|
235
|
-
taskMappings: getAllTaskMappings(),
|
|
236
|
-
runtimeState: generateRuntimeState(),
|
|
237
|
-
decisionTrees: getAllDecisionTrees(),
|
|
238
|
-
capabilities: generateCapabilities(),
|
|
239
310
|
};
|
|
240
311
|
}
|
|
241
312
|
//# sourceMappingURL=helpJson.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `bdg help <command...>` topics and Commander usage-error hints.
|
|
3
3
|
*/
|
|
4
|
-
import type { Command } from 'commander';
|
|
4
|
+
import type { Command, CommanderError } from 'commander';
|
|
5
5
|
/**
|
|
6
6
|
* The command path of `bdg help <path...>`: the words before the first option.
|
|
7
7
|
*
|
|
@@ -29,4 +29,19 @@ export declare function splitCommanderHint(text: string): {
|
|
|
29
29
|
message: string;
|
|
30
30
|
suggestion?: string;
|
|
31
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Message and suggestion for a Commander usage error: a did-you-mean for an
|
|
34
|
+
* unknown option or command, otherwise a pointer to the command's `--help`.
|
|
35
|
+
* A word typed after a single dash (`-josn`) is matched against the long
|
|
36
|
+
* options.
|
|
37
|
+
*
|
|
38
|
+
* @param error - Commander error (not a help or version display)
|
|
39
|
+
* @param command - Command the error came from (see resolveCommand)
|
|
40
|
+
* @param argv - Process arguments (to name an option as typed)
|
|
41
|
+
* @returns Message and suggestion
|
|
42
|
+
*/
|
|
43
|
+
export declare function usageErrorDetails(error: CommanderError, command: Command, argv?: string[]): {
|
|
44
|
+
message: string;
|
|
45
|
+
suggestion: string;
|
|
46
|
+
};
|
|
32
47
|
//# sourceMappingURL=helpTopic.d.ts.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `bdg help <command...>` topics and Commander usage-error hints.
|
|
3
3
|
*/
|
|
4
|
+
import { commandPath } from './helpJson.js';
|
|
4
5
|
import { CommandError } from '../errors/index.js';
|
|
5
|
-
import { unknownHelpTopicError } from '../errors/messages.js';
|
|
6
|
+
import { missingSubcommandMessage, unknownHelpTopicError, usageHelpSuggestion, } from '../errors/messages.js';
|
|
6
7
|
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
7
8
|
import { findSimilar } from '../utils/suggestions.js';
|
|
8
9
|
/** Commander's typo hint on its own line, e.g. "(Did you mean query?)" */
|
|
@@ -55,4 +56,61 @@ export function splitCommanderHint(text) {
|
|
|
55
56
|
return { message };
|
|
56
57
|
return { message: message.slice(0, hint.index).trim(), suggestion: `Did you mean: ${hint[1]}?` };
|
|
57
58
|
}
|
|
59
|
+
/** The option named in Commander's "unknown option '--x'" message, without an `=value` */
|
|
60
|
+
const UNKNOWN_OPTION = /unknown option '([^'=]+)/;
|
|
61
|
+
/**
|
|
62
|
+
* The long option of a command closest to a mistyped one, hidden global
|
|
63
|
+
* options (`--session`, `--quiet`) included. Up to one edit per three letters
|
|
64
|
+
* of the name counts as a typo, so `--frob` does not suggest `--json`.
|
|
65
|
+
*
|
|
66
|
+
* @param flag - Option as typed, e.g. "--sesion"
|
|
67
|
+
* @param command - Command it was given to
|
|
68
|
+
* @returns Closest long option, if any is similar
|
|
69
|
+
*/
|
|
70
|
+
function closestOption(flag, command) {
|
|
71
|
+
const longs = command.options.flatMap((option) => (option.long ? [option.long] : []));
|
|
72
|
+
const maxDistance = Math.ceil(flag.replace(/^-+/, '').length / 3);
|
|
73
|
+
return findSimilar(flag, longs, { maxDistance })[0];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The option as typed, for one Commander split: it reads `-josn` as `-j`
|
|
77
|
+
* (`--json`) followed by `-osn`, and reports `-osn` as unknown.
|
|
78
|
+
*
|
|
79
|
+
* @param flag - Option Commander reported, e.g. "-osn"
|
|
80
|
+
* @param argv - Process arguments
|
|
81
|
+
* @returns The argument it came from, e.g. "-josn", else the option itself
|
|
82
|
+
*/
|
|
83
|
+
function typedOption(flag, argv) {
|
|
84
|
+
if (flag.startsWith('--'))
|
|
85
|
+
return flag;
|
|
86
|
+
const rest = flag.slice(1);
|
|
87
|
+
return (argv.find((arg) => /^-[^-]/.test(arg) && arg.length > flag.length && arg.endsWith(rest)) ?? flag);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Message and suggestion for a Commander usage error: a did-you-mean for an
|
|
91
|
+
* unknown option or command, otherwise a pointer to the command's `--help`.
|
|
92
|
+
* A word typed after a single dash (`-josn`) is matched against the long
|
|
93
|
+
* options.
|
|
94
|
+
*
|
|
95
|
+
* @param error - Commander error (not a help or version display)
|
|
96
|
+
* @param command - Command the error came from (see resolveCommand)
|
|
97
|
+
* @param argv - Process arguments (to name an option as typed)
|
|
98
|
+
* @returns Message and suggestion
|
|
99
|
+
*/
|
|
100
|
+
export function usageErrorDetails(error, command, argv = process.argv) {
|
|
101
|
+
const help = usageHelpSuggestion(commandPath(command));
|
|
102
|
+
if (error.code === 'commander.help') {
|
|
103
|
+
return { message: missingSubcommandMessage(), suggestion: help };
|
|
104
|
+
}
|
|
105
|
+
const { message, suggestion } = splitCommanderHint(error.message);
|
|
106
|
+
const flag = error.code === 'commander.unknownOption' && UNKNOWN_OPTION.exec(message)?.[1];
|
|
107
|
+
if (!flag)
|
|
108
|
+
return { message, suggestion: suggestion ?? help };
|
|
109
|
+
const typed = typedOption(flag, argv);
|
|
110
|
+
const closest = closestOption(/^-[^-]../.test(typed) ? `-${typed}` : typed, command);
|
|
111
|
+
return {
|
|
112
|
+
message: message.replace(`'${flag}'`, `'${typed}'`),
|
|
113
|
+
suggestion: closest ? `Did you mean: ${closest}?` : help,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
58
116
|
//# sourceMappingURL=helpTopic.js.map
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import { CommandError } from '../errors/index.js';
|
|
2
3
|
import type { InstalledSkill, SkillTarget } from '../types.js';
|
|
4
|
+
/** What installing the skill did, and why it failed for a target, if it did */
|
|
5
|
+
export interface SkillInstallResult {
|
|
6
|
+
/** Targets the skill was installed for (or left unchanged) */
|
|
7
|
+
skills: InstalledSkill[];
|
|
8
|
+
/** Error (82) for the targets that could not be written */
|
|
9
|
+
failure?: CommandError;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
|
-
* Copy the bdg skill into each target's skill directory
|
|
5
|
-
* older
|
|
12
|
+
* Copy the bdg skill into each target's skill directory. A copy that differs
|
|
13
|
+
* (an older version, or one the user edited) is kept as `SKILL.md.bak`
|
|
14
|
+
* before it is overwritten. A target that cannot be written does not stop
|
|
15
|
+
* the others.
|
|
6
16
|
*
|
|
7
17
|
* @param targets - Agents to install for
|
|
8
18
|
* @param home - Home directory the skill roots are relative to
|
|
9
19
|
* @param source - SKILL.md to copy
|
|
10
|
-
* @returns
|
|
11
|
-
* @throws CommandError when the source is missing (83)
|
|
20
|
+
* @returns The targets written, in the given order, and the failure if any
|
|
21
|
+
* @throws CommandError when the source is missing (83)
|
|
12
22
|
*/
|
|
13
|
-
export declare function installSkill(targets: SkillTarget[], home?: string, source?: string):
|
|
23
|
+
export declare function installSkill(targets: SkillTarget[], home?: string, source?: string): SkillInstallResult;
|
|
14
24
|
/**
|
|
15
25
|
* Register the install-skill command.
|
|
16
26
|
*
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'fs';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
4
|
import { runCommand } from './shared/CommandRunner.js';
|
|
5
5
|
import { jsonOption } from './shared/commonOptions.js';
|
|
6
6
|
import { CommandError } from '../errors/index.js';
|
|
7
7
|
import { skillSourceMissingError, skillWriteFailedError } from '../errors/messages.js';
|
|
8
|
-
import { formatInstalledSkills } from '../ui/formatters/installSkill.js';
|
|
8
|
+
import { formatInstalledSkills, formatSkillTargets } from '../ui/formatters/installSkill.js';
|
|
9
|
+
import { createLogger } from '../ui/logging/index.js';
|
|
9
10
|
import { getErrorMessage } from '../utils/errors.js';
|
|
10
11
|
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
12
|
+
import { safeRemoveFile } from '../utils/file.js';
|
|
11
13
|
import { PACKAGE_ROOT } from '../utils/packageRoot.js';
|
|
14
|
+
const log = createLogger('bdg');
|
|
12
15
|
/** The skill shipped with the package (also used by agents working in this repo). */
|
|
13
16
|
const SKILL_SOURCE_PATH = join(PACKAGE_ROOT, '.claude', 'skills', 'bdg', 'SKILL.md');
|
|
14
17
|
/** Skill roots, relative to the home directory, of the agents the skill is installed for. */
|
|
@@ -17,14 +20,16 @@ const SKILL_ROOTS = {
|
|
|
17
20
|
agents: join('.agents', 'skills'),
|
|
18
21
|
};
|
|
19
22
|
/**
|
|
20
|
-
* Copy the bdg skill into each target's skill directory
|
|
21
|
-
* older
|
|
23
|
+
* Copy the bdg skill into each target's skill directory. A copy that differs
|
|
24
|
+
* (an older version, or one the user edited) is kept as `SKILL.md.bak`
|
|
25
|
+
* before it is overwritten. A target that cannot be written does not stop
|
|
26
|
+
* the others.
|
|
22
27
|
*
|
|
23
28
|
* @param targets - Agents to install for
|
|
24
29
|
* @param home - Home directory the skill roots are relative to
|
|
25
30
|
* @param source - SKILL.md to copy
|
|
26
|
-
* @returns
|
|
27
|
-
* @throws CommandError when the source is missing (83)
|
|
31
|
+
* @returns The targets written, in the given order, and the failure if any
|
|
32
|
+
* @throws CommandError when the source is missing (83)
|
|
28
33
|
*/
|
|
29
34
|
export function installSkill(targets, home = homedir(), source = SKILL_SOURCE_PATH) {
|
|
30
35
|
if (!existsSync(source)) {
|
|
@@ -32,31 +37,76 @@ export function installSkill(targets, home = homedir(), source = SKILL_SOURCE_PA
|
|
|
32
37
|
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
33
38
|
}
|
|
34
39
|
const content = readFileSync(source, 'utf-8');
|
|
35
|
-
|
|
40
|
+
const skills = [];
|
|
41
|
+
const failures = [];
|
|
42
|
+
for (const target of targets) {
|
|
43
|
+
const result = writeSkill(target, join(home, SKILL_ROOTS[target], 'bdg', 'SKILL.md'), content);
|
|
44
|
+
if ('error' in result)
|
|
45
|
+
failures.push(result);
|
|
46
|
+
else
|
|
47
|
+
skills.push(result);
|
|
48
|
+
}
|
|
49
|
+
if (failures.length === 0)
|
|
50
|
+
return { skills };
|
|
51
|
+
return { skills, failure: skillFailureError(failures, targets) };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The error for targets the skill could not be written for. When only one of
|
|
55
|
+
* several targets failed, it suggests installing for the other only. Each
|
|
56
|
+
* distinct suggestion is kept, so every failure cause gets its fix.
|
|
57
|
+
*
|
|
58
|
+
* @param failures - Targets that failed (at least one)
|
|
59
|
+
* @param targets - Targets picked
|
|
60
|
+
* @returns Command error (82)
|
|
61
|
+
*/
|
|
62
|
+
function skillFailureError(failures, targets) {
|
|
63
|
+
const other = failures.length === 1 ? targets.find((t) => t !== failures[0]?.target) : undefined;
|
|
64
|
+
const errors = failures.map(({ path, error }) => {
|
|
65
|
+
const code = error.code;
|
|
66
|
+
return skillWriteFailedError(path, getErrorMessage(error), code === 'ENOTDIR' || code === 'EEXIST', other && `--${other}`);
|
|
67
|
+
});
|
|
68
|
+
return new CommandError(errors.map((err) => err.message).join('\n'), { suggestion: [...new Set(errors.map((err) => err.suggestion))].join('\n') }, EXIT_CODES.PERMISSION_DENIED);
|
|
36
69
|
}
|
|
37
70
|
/**
|
|
38
|
-
* Write the skill to one path unless it already holds the same content
|
|
71
|
+
* Write the skill to one path unless it already holds the same content; a
|
|
72
|
+
* different copy is first kept next to it as `SKILL.md.bak` (replacing an
|
|
73
|
+
* earlier backup), so edits to it are not lost. The new text is written to a
|
|
74
|
+
* temporary file first, so a failed write leaves both the copy and the
|
|
75
|
+
* backup as they were; the backup gets the default file mode, whatever the
|
|
76
|
+
* copy's was.
|
|
39
77
|
*
|
|
40
78
|
* @param target - Agent the path belongs to
|
|
41
79
|
* @param path - Destination SKILL.md
|
|
42
80
|
* @param content - Skill text
|
|
43
|
-
* @returns What happened to the file
|
|
44
|
-
*
|
|
81
|
+
* @returns What happened to the file, with the backup path when one was made,
|
|
82
|
+
* or the file that could not be written and why
|
|
45
83
|
*/
|
|
46
84
|
function writeSkill(target, path, content) {
|
|
47
85
|
const existing = existsSync(path) ? readFileSync(path, 'utf-8') : undefined;
|
|
48
86
|
if (existing === content) {
|
|
49
87
|
return { target, path, status: 'unchanged' };
|
|
50
88
|
}
|
|
89
|
+
const backup = existing === undefined ? undefined : `${path}.bak`;
|
|
90
|
+
const temporary = `${path}.tmp`;
|
|
91
|
+
let writing = path;
|
|
51
92
|
try {
|
|
52
93
|
mkdirSync(dirname(path), { recursive: true });
|
|
53
|
-
writeFileSync(
|
|
94
|
+
writeFileSync(temporary, content);
|
|
95
|
+
if (backup !== undefined) {
|
|
96
|
+
writing = backup;
|
|
97
|
+
rmSync(backup, { force: true });
|
|
98
|
+
writeFileSync(backup, existing ?? '');
|
|
99
|
+
}
|
|
100
|
+
writing = path;
|
|
101
|
+
renameSync(temporary, path);
|
|
54
102
|
}
|
|
55
|
-
catch (
|
|
56
|
-
|
|
57
|
-
|
|
103
|
+
catch (error) {
|
|
104
|
+
safeRemoveFile(temporary, 'temporary skill copy', log);
|
|
105
|
+
return { target, path: writing, error };
|
|
58
106
|
}
|
|
59
|
-
|
|
107
|
+
if (backup === undefined)
|
|
108
|
+
return { target, path, status: 'installed' };
|
|
109
|
+
return { target, path, status: 'updated', backup };
|
|
60
110
|
}
|
|
61
111
|
/**
|
|
62
112
|
* Targets picked by the flags; no flag means every agent.
|
|
@@ -68,6 +118,26 @@ function selectedTargets(options) {
|
|
|
68
118
|
const picked = Object.keys(SKILL_ROOTS).filter((target) => options[target]);
|
|
69
119
|
return picked.length > 0 ? picked : Object.keys(SKILL_ROOTS);
|
|
70
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Install the skill for the picked targets. When a target fails, the error
|
|
123
|
+
* still lists the targets that were written (and their backups): JSON
|
|
124
|
+
* `skills`, or the same lines as a successful install.
|
|
125
|
+
*
|
|
126
|
+
* @param options - Parsed command options
|
|
127
|
+
* @returns Command result
|
|
128
|
+
*/
|
|
129
|
+
function installSkillResult(options) {
|
|
130
|
+
const { skills, failure } = installSkill(selectedTargets(options));
|
|
131
|
+
if (!failure)
|
|
132
|
+
return { success: true, data: { skills } };
|
|
133
|
+
const written = skills.length === 0 ? {} : options.json ? { skills } : { written: formatSkillTargets(skills) };
|
|
134
|
+
return {
|
|
135
|
+
success: false,
|
|
136
|
+
error: failure.message,
|
|
137
|
+
exitCode: failure.exitCode,
|
|
138
|
+
errorContext: { ...written, ...failure.metadata },
|
|
139
|
+
};
|
|
140
|
+
}
|
|
71
141
|
/**
|
|
72
142
|
* Register the install-skill command.
|
|
73
143
|
*
|
|
@@ -81,7 +151,7 @@ export function registerInstallSkillCommand(program) {
|
|
|
81
151
|
.option('--agents', 'Only ~/.agents/skills (Codex, Gemini CLI and other agents)')
|
|
82
152
|
.addOption(jsonOption())
|
|
83
153
|
.action(async (options) => {
|
|
84
|
-
await runCommand((opts) => Promise.resolve(
|
|
154
|
+
await runCommand((opts) => Promise.resolve(installSkillResult(opts)), options, formatInstalledSkills);
|
|
85
155
|
});
|
|
86
156
|
}
|
|
87
157
|
//# sourceMappingURL=installSkill.js.map
|