incur 0.4.8 → 0.4.10
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/dist/Cli.d.ts +69 -19
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +419 -73
- package/dist/Cli.js.map +1 -1
- package/dist/Completions.d.ts +2 -1
- package/dist/Completions.d.ts.map +1 -1
- package/dist/Completions.js +52 -13
- package/dist/Completions.js.map +1 -1
- package/dist/Formatter.d.ts.map +1 -1
- package/dist/Formatter.js +6 -5
- package/dist/Formatter.js.map +1 -1
- package/dist/Help.d.ts +5 -0
- package/dist/Help.d.ts.map +1 -1
- package/dist/Help.js +19 -5
- package/dist/Help.js.map +1 -1
- package/dist/Mcp.d.ts +21 -0
- package/dist/Mcp.d.ts.map +1 -1
- package/dist/Mcp.js +44 -13
- package/dist/Mcp.js.map +1 -1
- package/dist/Parser.d.ts +14 -0
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +127 -1
- package/dist/Parser.js.map +1 -1
- package/dist/Skill.d.ts.map +1 -1
- package/dist/Skill.js +5 -2
- package/dist/Skill.js.map +1 -1
- package/dist/Skillgen.d.ts.map +1 -1
- package/dist/Skillgen.js +4 -38
- package/dist/Skillgen.js.map +1 -1
- package/dist/SyncMcp.d.ts.map +1 -1
- package/dist/SyncMcp.js +75 -8
- package/dist/SyncMcp.js.map +1 -1
- package/dist/SyncSkills.d.ts +9 -0
- package/dist/SyncSkills.d.ts.map +1 -1
- package/dist/SyncSkills.js +13 -74
- package/dist/SyncSkills.js.map +1 -1
- package/dist/bin.d.ts +1 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/internal/command.d.ts +31 -19
- package/dist/internal/command.d.ts.map +1 -1
- package/dist/internal/command.js +10 -5
- package/dist/internal/command.js.map +1 -1
- package/dist/internal/cta.d.ts +22 -0
- package/dist/internal/cta.d.ts.map +1 -0
- package/dist/internal/cta.js +25 -0
- package/dist/internal/cta.js.map +1 -0
- package/dist/internal/json.d.ts +5 -0
- package/dist/internal/json.d.ts.map +1 -0
- package/dist/internal/json.js +13 -0
- package/dist/internal/json.js.map +1 -0
- package/dist/internal/yaml.d.ts +12 -0
- package/dist/internal/yaml.d.ts.map +1 -0
- package/dist/internal/yaml.js +20 -0
- package/dist/internal/yaml.js.map +1 -0
- package/dist/middleware.d.ts +8 -4
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +1 -1
- package/dist/middleware.js.map +1 -1
- package/package.json +1 -1
- package/src/Cli.test-d.ts +73 -0
- package/src/Cli.test.ts +1536 -48
- package/src/Cli.ts +606 -108
- package/src/Completions.test.ts +85 -0
- package/src/Completions.ts +48 -9
- package/src/Formatter.test.ts +17 -0
- package/src/Formatter.ts +7 -5
- package/src/Help.test.ts +32 -1
- package/src/Help.ts +42 -4
- package/src/Mcp.test.ts +289 -0
- package/src/Mcp.ts +68 -13
- package/src/Parser.test.ts +173 -0
- package/src/Parser.ts +132 -1
- package/src/Skill.test.ts +6 -0
- package/src/Skill.ts +8 -5
- package/src/Skillgen.test.ts +55 -6
- package/src/Skillgen.ts +9 -35
- package/src/SyncMcp.test.ts +89 -0
- package/src/SyncMcp.ts +72 -8
- package/src/SyncSkills.test.ts +78 -1
- package/src/SyncSkills.ts +20 -78
- package/src/bun-compile.test.ts +5 -0
- package/src/e2e.test.ts +166 -12
- package/src/internal/command.ts +12 -4
- package/src/internal/cta.ts +58 -0
- package/src/internal/json.ts +16 -0
- package/src/internal/yaml.ts +23 -0
- package/src/lazy-imports.test.ts +94 -0
- package/src/middleware.ts +12 -3
package/src/Completions.test.ts
CHANGED
|
@@ -226,6 +226,90 @@ describe('complete', () => {
|
|
|
226
226
|
})
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
+
describe('complete with globals', () => {
|
|
230
|
+
const globalSchema = z.object({
|
|
231
|
+
rpcUrl: z.string().optional().describe('RPC endpoint URL'),
|
|
232
|
+
chain: z.enum(['mainnet', 'sepolia', 'goerli']).default('mainnet').describe('Target chain'),
|
|
233
|
+
dryRun: z.boolean().default(false).describe('Dry run mode'),
|
|
234
|
+
})
|
|
235
|
+
const globalAlias = { rpcUrl: 'r', dryRun: 'd' }
|
|
236
|
+
const globals = { schema: globalSchema, alias: globalAlias }
|
|
237
|
+
|
|
238
|
+
test('global flags appear as completion candidates when typing --', () => {
|
|
239
|
+
const cli = makeCli()
|
|
240
|
+
const commands = Cli.toCommands.get(cli)!
|
|
241
|
+
const candidates = Completions.complete(commands, undefined, ['mycli', 'build', '--'], 2, globals)
|
|
242
|
+
const values = candidates.map((c) => c.value)
|
|
243
|
+
expect(values).toContain('--rpc-url')
|
|
244
|
+
expect(values).toContain('--chain')
|
|
245
|
+
expect(values).toContain('--dry-run')
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
test('global short aliases appear as candidates when typing -', () => {
|
|
249
|
+
const cli = makeCli()
|
|
250
|
+
const commands = Cli.toCommands.get(cli)!
|
|
251
|
+
const candidates = Completions.complete(commands, undefined, ['mycli', 'build', '-'], 2, globals)
|
|
252
|
+
const values = candidates.map((c) => c.value)
|
|
253
|
+
expect(values).toContain('-r')
|
|
254
|
+
expect(values).toContain('-d')
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
test('global flags do not duplicate command-specific flags', () => {
|
|
258
|
+
// Create a CLI where a command has --chain already
|
|
259
|
+
const cli = Cli.create('mycli', { version: '1.0.0' })
|
|
260
|
+
cli.command('deploy', {
|
|
261
|
+
description: 'Deploy',
|
|
262
|
+
options: z.object({
|
|
263
|
+
chain: z.string().optional().describe('Chain override'),
|
|
264
|
+
}),
|
|
265
|
+
run: () => ({}),
|
|
266
|
+
})
|
|
267
|
+
const commands = Cli.toCommands.get(cli)!
|
|
268
|
+
const rootCmd = { options: z.object({ chain: z.string().optional() }) }
|
|
269
|
+
const dupeGlobals = { schema: z.object({ chain: z.string().optional().describe('Global chain') }) }
|
|
270
|
+
const candidates = Completions.complete(
|
|
271
|
+
commands,
|
|
272
|
+
rootCmd,
|
|
273
|
+
['mycli', 'deploy', '--'],
|
|
274
|
+
2,
|
|
275
|
+
dupeGlobals,
|
|
276
|
+
)
|
|
277
|
+
const chainCount = candidates.filter((c) => c.value === '--chain').length
|
|
278
|
+
expect(chainCount).toBe(1)
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
test('global option value completion for enum', () => {
|
|
282
|
+
const cli = makeCli()
|
|
283
|
+
const commands = Cli.toCommands.get(cli)!
|
|
284
|
+
const candidates = Completions.complete(
|
|
285
|
+
commands,
|
|
286
|
+
undefined,
|
|
287
|
+
['mycli', 'build', '--chain', ''],
|
|
288
|
+
3,
|
|
289
|
+
globals,
|
|
290
|
+
)
|
|
291
|
+
const values = candidates.map((c) => c.value)
|
|
292
|
+
expect(values).toEqual(['mainnet', 'sepolia', 'goerli'])
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
test('global boolean flag does not consume next token as value in completions', () => {
|
|
296
|
+
const cli = makeCli()
|
|
297
|
+
const commands = Cli.toCommands.get(cli)!
|
|
298
|
+
// After --dry-run (boolean), the next token should suggest subcommands, not be consumed as value
|
|
299
|
+
const candidates = Completions.complete(
|
|
300
|
+
commands,
|
|
301
|
+
undefined,
|
|
302
|
+
['mycli', '--dry-run', ''],
|
|
303
|
+
2,
|
|
304
|
+
globals,
|
|
305
|
+
)
|
|
306
|
+
const values = candidates.map((c) => c.value)
|
|
307
|
+
// Should suggest subcommands since --dry-run is boolean and doesn't consume next token
|
|
308
|
+
expect(values).toContain('build')
|
|
309
|
+
expect(values).toContain('test')
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
|
|
229
313
|
describe('format', () => {
|
|
230
314
|
const candidates: Completions.Candidate[] = [
|
|
231
315
|
{ value: '--target', description: 'Build target' },
|
|
@@ -515,6 +599,7 @@ describe('serve integration', () => {
|
|
|
515
599
|
_COMPLETE_INDEX: '2',
|
|
516
600
|
})
|
|
517
601
|
expect(output).toContain('add')
|
|
602
|
+
expect(output).toContain('doctor')
|
|
518
603
|
})
|
|
519
604
|
|
|
520
605
|
test('COMPLETE=zsh with words outputs candidates in zsh format', async () => {
|
package/src/Completions.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { z } from 'zod'
|
|
2
2
|
|
|
3
|
+
import type { GlobalsDescriptor } from './Cli.js'
|
|
3
4
|
import type { Shell } from './internal/command.js'
|
|
5
|
+
import { toKebab } from './internal/helpers.js'
|
|
4
6
|
|
|
5
7
|
/** A completion candidate with an optional description. */
|
|
6
8
|
export type Candidate = {
|
|
@@ -41,6 +43,7 @@ export function register(shell: Shell, name: string): string {
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
|
|
44
47
|
/**
|
|
45
48
|
* Computes completion candidates for the given argv words and cursor index.
|
|
46
49
|
* Walks the command tree to resolve the active command, then suggests
|
|
@@ -51,6 +54,7 @@ export function complete(
|
|
|
51
54
|
rootCommand: CommandEntry | undefined,
|
|
52
55
|
argv: string[],
|
|
53
56
|
index: number,
|
|
57
|
+
globals?: GlobalsDescriptor | undefined,
|
|
54
58
|
): Candidate[] {
|
|
55
59
|
const current = argv[index] ?? ''
|
|
56
60
|
|
|
@@ -84,7 +88,7 @@ export function complete(
|
|
|
84
88
|
if (leaf?.options) {
|
|
85
89
|
const shape = leaf.options.shape as Record<string, any>
|
|
86
90
|
for (const key of Object.keys(shape)) {
|
|
87
|
-
const kebab = key
|
|
91
|
+
const kebab = toKebab(key)
|
|
88
92
|
const flag = `--${kebab}`
|
|
89
93
|
if (flag.startsWith(current))
|
|
90
94
|
candidates.push({ value: flag, description: descriptionOf(shape[key]) })
|
|
@@ -99,6 +103,25 @@ export function complete(
|
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
}
|
|
106
|
+
// Global options
|
|
107
|
+
if (globals) {
|
|
108
|
+
const globalShape = globals.schema.shape as Record<string, any>
|
|
109
|
+
for (const key of Object.keys(globalShape)) {
|
|
110
|
+
const kebab = toKebab(key)
|
|
111
|
+
const flag = `--${kebab}`
|
|
112
|
+
if (flag.startsWith(current) && !candidates.some((c) => c.value === flag))
|
|
113
|
+
candidates.push({ value: flag, description: descriptionOf(globalShape[key]) })
|
|
114
|
+
}
|
|
115
|
+
// Global short aliases
|
|
116
|
+
if (globals.alias)
|
|
117
|
+
for (const [name, short] of Object.entries(globals.alias)) {
|
|
118
|
+
const flag = `-${short}`
|
|
119
|
+
if (flag.startsWith(current) && !candidates.some((c) => c.value === flag)) {
|
|
120
|
+
const desc = descriptionOf(globalShape[name])
|
|
121
|
+
candidates.push({ value: flag, description: desc })
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
102
125
|
return candidates
|
|
103
126
|
}
|
|
104
127
|
|
|
@@ -106,15 +129,31 @@ export function complete(
|
|
|
106
129
|
if (index > 0) {
|
|
107
130
|
const prev = argv[index - 1]!
|
|
108
131
|
const leaf = scope.leaf
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
132
|
+
if (prev.startsWith('-')) {
|
|
133
|
+
// Try command-specific options first
|
|
134
|
+
if (leaf?.options) {
|
|
135
|
+
const name = resolveOptionName(prev, leaf)
|
|
136
|
+
if (name) {
|
|
137
|
+
const values = possibleValues(name, leaf.options)
|
|
138
|
+
if (values) {
|
|
139
|
+
for (const v of values) if (v.startsWith(current)) candidates.push({ value: v })
|
|
140
|
+
return candidates
|
|
141
|
+
}
|
|
142
|
+
if (!isBooleanOption(name, leaf.options)) return candidates
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Try global options
|
|
146
|
+
if (globals) {
|
|
147
|
+
const globalEntry: CommandEntry = { options: globals.schema, alias: globals.alias }
|
|
148
|
+
const name = resolveOptionName(prev, globalEntry)
|
|
149
|
+
if (name) {
|
|
150
|
+
const values = possibleValues(name, globals.schema)
|
|
151
|
+
if (values) {
|
|
152
|
+
for (const v of values) if (v.startsWith(current)) candidates.push({ value: v })
|
|
153
|
+
return candidates
|
|
154
|
+
}
|
|
155
|
+
if (!isBooleanOption(name, globals.schema)) return candidates
|
|
116
156
|
}
|
|
117
|
-
if (!isBooleanOption(name, leaf.options)) return candidates
|
|
118
157
|
}
|
|
119
158
|
}
|
|
120
159
|
}
|
package/src/Formatter.test.ts
CHANGED
|
@@ -62,6 +62,15 @@ describe('format', () => {
|
|
|
62
62
|
`)
|
|
63
63
|
})
|
|
64
64
|
|
|
65
|
+
test('formats bigint values as strings in JSON', () => {
|
|
66
|
+
const result = Formatter.format({ expiry: 2461152330n }, 'json')
|
|
67
|
+
expect(result).toMatchInlineSnapshot(`
|
|
68
|
+
"{
|
|
69
|
+
"expiry": "2461152330"
|
|
70
|
+
}"
|
|
71
|
+
`)
|
|
72
|
+
})
|
|
73
|
+
|
|
65
74
|
test('formats as YAML', () => {
|
|
66
75
|
const result = Formatter.format({ message: 'hello' }, 'yaml')
|
|
67
76
|
expect(result).toMatchInlineSnapshot(`
|
|
@@ -319,6 +328,14 @@ describe('format jsonl', () => {
|
|
|
319
328
|
`)
|
|
320
329
|
})
|
|
321
330
|
|
|
331
|
+
test('array outputs bigint values as strings', () => {
|
|
332
|
+
const result = Formatter.format([{ expiry: 2461152330n }, { expiry: 2461152331n }], 'jsonl')
|
|
333
|
+
expect(result).toMatchInlineSnapshot(`
|
|
334
|
+
"{"expiry":"2461152330"}
|
|
335
|
+
{"expiry":"2461152331"}"
|
|
336
|
+
`)
|
|
337
|
+
})
|
|
338
|
+
|
|
322
339
|
test('scalar value outputs JSON', () => {
|
|
323
340
|
expect(Formatter.format(42, 'jsonl')).toMatchInlineSnapshot(`"42"`)
|
|
324
341
|
expect(Formatter.format('hi', 'jsonl')).toMatchInlineSnapshot(`""hi""`)
|
package/src/Formatter.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { encode } from '@toon-format/toon'
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import * as Json from './internal/json.js'
|
|
4
|
+
import * as Yaml from './internal/yaml.js'
|
|
3
5
|
|
|
4
6
|
/** Supported output formats. */
|
|
5
7
|
export type Format = 'toon' | 'json' | 'yaml' | 'md' | 'jsonl'
|
|
@@ -16,13 +18,13 @@ export function format(value: unknown, fmt: Format = 'toon'): string {
|
|
|
16
18
|
} catch {}
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
|
-
return
|
|
21
|
+
return Json.stringify(value, 2)
|
|
20
22
|
}
|
|
21
|
-
if (fmt === 'yaml') return
|
|
23
|
+
if (fmt === 'yaml') return Yaml.loadSync().stringify(value)
|
|
22
24
|
if (fmt === 'md') return formatMarkdown(value)
|
|
23
25
|
if (fmt === 'jsonl') {
|
|
24
|
-
if (Array.isArray(value)) return value.map((v) =>
|
|
25
|
-
return
|
|
26
|
+
if (Array.isArray(value)) return value.map((v) => Json.stringify(v)).join('\n')
|
|
27
|
+
return Json.stringify(value)
|
|
26
28
|
}
|
|
27
29
|
// toon (default)
|
|
28
30
|
if (isScalar(value)) return String(value)
|
package/src/Help.test.ts
CHANGED
|
@@ -392,7 +392,7 @@ describe('formatRoot', () => {
|
|
|
392
392
|
|
|
393
393
|
Integrations:
|
|
394
394
|
completions Generate shell completion script
|
|
395
|
-
mcp
|
|
395
|
+
mcp Register as MCP server (add, doctor)
|
|
396
396
|
skills Sync skill files to agents (add, list)
|
|
397
397
|
|
|
398
398
|
Global Options:
|
|
@@ -411,4 +411,35 @@ describe('formatRoot', () => {
|
|
|
411
411
|
--version Show version"
|
|
412
412
|
`)
|
|
413
413
|
})
|
|
414
|
+
|
|
415
|
+
test('formatCommand shows custom global options with deprecated flag', () => {
|
|
416
|
+
const result = Help.formatCommand('tool deploy', {
|
|
417
|
+
description: 'Deploy app',
|
|
418
|
+
globals: {
|
|
419
|
+
schema: z.object({
|
|
420
|
+
rpcUrl: z.string().optional().describe('RPC endpoint URL'),
|
|
421
|
+
oldRpc: z.string().optional().describe('Old RPC endpoint').meta({ deprecated: true }),
|
|
422
|
+
}),
|
|
423
|
+
alias: { rpcUrl: 'r' },
|
|
424
|
+
},
|
|
425
|
+
})
|
|
426
|
+
expect(result).toContain('Custom Global Options:')
|
|
427
|
+
expect(result).toContain('--rpc-url, -r <string>')
|
|
428
|
+
expect(result).toContain('RPC endpoint URL')
|
|
429
|
+
expect(result).toContain('[deprecated] Old RPC endpoint')
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
test('formatRoot shows custom global options', () => {
|
|
433
|
+
const result = Help.formatRoot('tool', {
|
|
434
|
+
globals: {
|
|
435
|
+
schema: z.object({
|
|
436
|
+
chain: z.string().default('mainnet').describe('Target chain'),
|
|
437
|
+
}),
|
|
438
|
+
},
|
|
439
|
+
commands: [{ name: 'deploy', description: 'Deploy' }],
|
|
440
|
+
})
|
|
441
|
+
expect(result).toContain('Custom Global Options:')
|
|
442
|
+
expect(result).toContain('--chain <string>')
|
|
443
|
+
expect(result).toContain('Target chain (default: mainnet)')
|
|
444
|
+
})
|
|
414
445
|
})
|
package/src/Help.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
+
import type { GlobalsDescriptor } from './Cli.js'
|
|
3
4
|
import { builtinCommands } from './internal/command.js'
|
|
4
5
|
import { toKebab } from './internal/helpers.js'
|
|
5
6
|
import { defaultEnvSource } from './Parser.js'
|
|
6
7
|
|
|
7
8
|
/** Formats help text for a router CLI or command group. */
|
|
8
9
|
export function formatRoot(name: string, options: formatRoot.Options = {}): string {
|
|
9
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
aliases,
|
|
12
|
+
configFlag,
|
|
13
|
+
description,
|
|
14
|
+
globals,
|
|
15
|
+
version,
|
|
16
|
+
commands = [],
|
|
17
|
+
root = false,
|
|
18
|
+
} = options
|
|
10
19
|
const lines: string[] = []
|
|
11
20
|
|
|
12
21
|
// Header
|
|
@@ -31,7 +40,7 @@ export function formatRoot(name: string, options: formatRoot.Options = {}): stri
|
|
|
31
40
|
}
|
|
32
41
|
}
|
|
33
42
|
|
|
34
|
-
lines.push(...globalOptionsLines(root, configFlag))
|
|
43
|
+
lines.push(...globalOptionsLines(root, configFlag, globals))
|
|
35
44
|
|
|
36
45
|
return lines.join('\n')
|
|
37
46
|
}
|
|
@@ -46,6 +55,8 @@ export declare namespace formatRoot {
|
|
|
46
55
|
commands?: { name: string; description?: string | undefined }[] | undefined
|
|
47
56
|
/** A short description of the CLI or group. */
|
|
48
57
|
description?: string | undefined
|
|
58
|
+
/** Custom global options schema and alias map. */
|
|
59
|
+
globals?: GlobalsDescriptor | undefined
|
|
49
60
|
/** Show root-level built-in commands and flags. */
|
|
50
61
|
root?: boolean | undefined
|
|
51
62
|
/** CLI version string. */
|
|
@@ -71,6 +82,8 @@ export declare namespace formatCommand {
|
|
|
71
82
|
env?: z.ZodObject<any> | undefined
|
|
72
83
|
/** Override environment variable source for "set:" display. Defaults to `process.env`. */
|
|
73
84
|
envSource?: Record<string, string | undefined> | undefined
|
|
85
|
+
/** Custom global options schema and alias map. */
|
|
86
|
+
globals?: GlobalsDescriptor | undefined
|
|
74
87
|
/** Formatted usage examples. */
|
|
75
88
|
examples?: { command: string; description?: string }[] | undefined
|
|
76
89
|
/** Plain text hint displayed after examples and before global options. */
|
|
@@ -102,6 +115,7 @@ export function formatCommand(name: string, options: formatCommand.Options = {})
|
|
|
102
115
|
aliases,
|
|
103
116
|
configFlag,
|
|
104
117
|
description,
|
|
118
|
+
globals,
|
|
105
119
|
version,
|
|
106
120
|
args,
|
|
107
121
|
env,
|
|
@@ -206,7 +220,7 @@ export function formatCommand(name: string, options: formatCommand.Options = {})
|
|
|
206
220
|
}
|
|
207
221
|
}
|
|
208
222
|
|
|
209
|
-
if (!options.hideGlobalOptions) lines.push(...globalOptionsLines(root, configFlag))
|
|
223
|
+
if (!options.hideGlobalOptions) lines.push(...globalOptionsLines(root, configFlag, globals))
|
|
210
224
|
|
|
211
225
|
// Environment Variables
|
|
212
226
|
if (env) {
|
|
@@ -340,7 +354,11 @@ function extractDeprecated(schema: unknown): boolean | undefined {
|
|
|
340
354
|
}
|
|
341
355
|
|
|
342
356
|
/** Renders the built-in commands and global options block. Root-only items are hidden for subcommands. */
|
|
343
|
-
function globalOptionsLines(
|
|
357
|
+
function globalOptionsLines(
|
|
358
|
+
root = false,
|
|
359
|
+
configFlag?: string,
|
|
360
|
+
globals?: GlobalsDescriptor,
|
|
361
|
+
): string[] {
|
|
344
362
|
const lines: string[] = []
|
|
345
363
|
|
|
346
364
|
if (root) {
|
|
@@ -361,6 +379,26 @@ function globalOptionsLines(root = false, configFlag?: string): string[] {
|
|
|
361
379
|
)
|
|
362
380
|
}
|
|
363
381
|
|
|
382
|
+
if (globals) {
|
|
383
|
+
const entries = optionEntries(globals.schema, globals.alias)
|
|
384
|
+
if (entries.length > 0) {
|
|
385
|
+
const maxLen = Math.max(...entries.map((e) => e.flag.length))
|
|
386
|
+
lines.push(
|
|
387
|
+
'',
|
|
388
|
+
'Custom Global Options:',
|
|
389
|
+
...entries.map((entry) => {
|
|
390
|
+
const padding = ' '.repeat(maxLen - entry.flag.length)
|
|
391
|
+
const prefix = entry.deprecated ? '[deprecated] ' : ''
|
|
392
|
+
const desc =
|
|
393
|
+
entry.defaultValue !== undefined
|
|
394
|
+
? `${prefix}${entry.description} (default: ${entry.defaultValue})`
|
|
395
|
+
: `${prefix}${entry.description}`
|
|
396
|
+
return ` ${entry.flag}${padding} ${desc}`
|
|
397
|
+
}),
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
364
402
|
const flags = [
|
|
365
403
|
...(configFlag
|
|
366
404
|
? [{ flag: `--${configFlag} <path>`, desc: 'Load JSON option defaults from a file' }]
|