@optique/core 1.4.0-dev.2895 → 1.4.0-dev.2899
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/facade.cjs +3 -10
- package/dist/facade.d.cts +0 -11
- package/dist/facade.d.ts +0 -11
- package/dist/facade.js +4 -11
- package/dist/usage-internals.cjs +1 -99
- package/dist/usage-internals.js +2 -99
- package/package.json +2 -2
- package/skills/optique/SKILL.md +4 -4
package/dist/facade.cjs
CHANGED
|
@@ -818,7 +818,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
818
818
|
options = optionsParam ?? {};
|
|
819
819
|
}
|
|
820
820
|
require_validate.validateProgramName(programName);
|
|
821
|
-
const { colors, messageFormatter, theme: requestedTheme, maxWidth: requestedMaxWidth, termWidth, showDefault, showChoices, showAliases, showEnvironment, sectionOrder, helpSections, showUsage, usageLine, commandList = "recursive", aboveError = "usage",
|
|
821
|
+
const { colors, messageFormatter, theme: requestedTheme, maxWidth: requestedMaxWidth, termWidth, showDefault, showChoices, showAliases, showEnvironment, sectionOrder, helpSections, showUsage, usageLine, commandList = "recursive", aboveError = "usage", onError = () => {
|
|
822
822
|
throw new RunParserError("Failed to parse command line arguments.");
|
|
823
823
|
}, stderr = console.error, stdout = console.log, brief, description, examples, author, bugs, footer } = options;
|
|
824
824
|
let maxWidth = requestedMaxWidth;
|
|
@@ -1117,15 +1117,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1117
1117
|
})));
|
|
1118
1118
|
}
|
|
1119
1119
|
if (effectiveAboveError === "usage") {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
const alternativeCount = optionCount + Number(helpParsers.helpCommand != null) + Number(versionParsers.versionCommand != null) + Number(completionParsers.completionCommand != null);
|
|
1123
|
-
const errorUsageTerms = aboveError === "usage" && errorUsage === "command" ? require_usage_internals.projectCommandUsage(rootUsage, classified.commandPath, alternativeCount === 0 ? void 0 : {
|
|
1124
|
-
optionCount,
|
|
1125
|
-
alternativeCount
|
|
1126
|
-
}) ?? rootUsage : rootUsage;
|
|
1127
|
-
resolveUsageWidth(errorUsageTerms);
|
|
1128
|
-
stderr(`${usageLabel()}${indentLines(require_usage.formatUsage(programName, errorUsageTerms, {
|
|
1120
|
+
resolveUsageWidth(augmentedParser.usage);
|
|
1121
|
+
stderr(`${usageLabel()}${indentLines(require_usage.formatUsage(programName, augmentedParser.usage, {
|
|
1129
1122
|
theme,
|
|
1130
1123
|
colors,
|
|
1131
1124
|
maxWidth: maxWidth == null ? void 0 : maxWidth - usageLabelWidth(),
|
package/dist/facade.d.cts
CHANGED
|
@@ -326,17 +326,6 @@ interface RunOptions<THelp, TError> {
|
|
|
326
326
|
* @default `"usage"`
|
|
327
327
|
*/
|
|
328
328
|
readonly aboveError?: "usage" | "help" | "none";
|
|
329
|
-
/**
|
|
330
|
-
* Scope of the compact preamble when `aboveError` is `"usage"`.
|
|
331
|
-
* `"command"` uses the failed parse's canonical command path and usage
|
|
332
|
-
* metadata, retaining parent options. Hidden or unresolved paths and
|
|
333
|
-
* unsupported compositions fall back to root usage. Neither mode applies
|
|
334
|
-
* help-only `usageLine` overrides or evaluates the parser again.
|
|
335
|
-
*
|
|
336
|
-
* @default `"root"`
|
|
337
|
-
* @since 1.4.0
|
|
338
|
-
*/
|
|
339
|
-
readonly errorUsage?: "root" | "command";
|
|
340
329
|
/**
|
|
341
330
|
* Callback invoked after error output for a parse failure, an invalid
|
|
342
331
|
* command path before help, or a missing or unsupported completion shell.
|
package/dist/facade.d.ts
CHANGED
|
@@ -326,17 +326,6 @@ interface RunOptions<THelp, TError> {
|
|
|
326
326
|
* @default `"usage"`
|
|
327
327
|
*/
|
|
328
328
|
readonly aboveError?: "usage" | "help" | "none";
|
|
329
|
-
/**
|
|
330
|
-
* Scope of the compact preamble when `aboveError` is `"usage"`.
|
|
331
|
-
* `"command"` uses the failed parse's canonical command path and usage
|
|
332
|
-
* metadata, retaining parent options. Hidden or unresolved paths and
|
|
333
|
-
* unsupported compositions fall back to root usage. Neither mode applies
|
|
334
|
-
* help-only `usageLine` overrides or evaluates the parser again.
|
|
335
|
-
*
|
|
336
|
-
* @default `"root"`
|
|
337
|
-
* @since 1.4.0
|
|
338
|
-
*/
|
|
339
|
-
readonly errorUsage?: "root" | "command";
|
|
340
329
|
/**
|
|
341
330
|
* Callback invoked after error output for a parse failure, an invalid
|
|
342
331
|
* command path before help, or a missing or unsupported completion shell.
|
package/dist/facade.js
CHANGED
|
@@ -12,7 +12,7 @@ import { collectExplicitSourceValues, collectExplicitSourceValuesAsync, createDe
|
|
|
12
12
|
import { createInputTrace } from "./input-trace.js";
|
|
13
13
|
import { attemptParseAsync, attemptParseSync, createEffectfulCompletionSession, createParserContext, getDocPage } from "./internal/parser.js";
|
|
14
14
|
import { bash, fish, nu, pwsh, zsh } from "./completion.js";
|
|
15
|
-
import { collectActiveOptionNames, collectRootOptionNames
|
|
15
|
+
import { collectActiveOptionNames, collectRootOptionNames } from "./usage-internals.js";
|
|
16
16
|
import { allowDuplicateLeadingCommandNamesKey, hiddenCommandAliasesKey } from "./internal/command-alias.js";
|
|
17
17
|
import { completeOrExtractPhase2Seed } from "./phase2-seed.js";
|
|
18
18
|
import { multiple, optional, withDefault } from "./modifiers.js";
|
|
@@ -818,7 +818,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
818
818
|
options = optionsParam ?? {};
|
|
819
819
|
}
|
|
820
820
|
validateProgramName(programName);
|
|
821
|
-
const { colors, messageFormatter, theme: requestedTheme, maxWidth: requestedMaxWidth, termWidth, showDefault, showChoices, showAliases, showEnvironment, sectionOrder, helpSections, showUsage, usageLine, commandList = "recursive", aboveError = "usage",
|
|
821
|
+
const { colors, messageFormatter, theme: requestedTheme, maxWidth: requestedMaxWidth, termWidth, showDefault, showChoices, showAliases, showEnvironment, sectionOrder, helpSections, showUsage, usageLine, commandList = "recursive", aboveError = "usage", onError = () => {
|
|
822
822
|
throw new RunParserError("Failed to parse command line arguments.");
|
|
823
823
|
}, stderr = console.error, stdout = console.log, brief, description, examples, author, bugs, footer } = options;
|
|
824
824
|
let maxWidth = requestedMaxWidth;
|
|
@@ -1117,15 +1117,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1117
1117
|
})));
|
|
1118
1118
|
}
|
|
1119
1119
|
if (effectiveAboveError === "usage") {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
const alternativeCount = optionCount + Number(helpParsers.helpCommand != null) + Number(versionParsers.versionCommand != null) + Number(completionParsers.completionCommand != null);
|
|
1123
|
-
const errorUsageTerms = aboveError === "usage" && errorUsage === "command" ? projectCommandUsage(rootUsage, classified.commandPath, alternativeCount === 0 ? void 0 : {
|
|
1124
|
-
optionCount,
|
|
1125
|
-
alternativeCount
|
|
1126
|
-
}) ?? rootUsage : rootUsage;
|
|
1127
|
-
resolveUsageWidth(errorUsageTerms);
|
|
1128
|
-
stderr(`${usageLabel()}${indentLines(formatUsage(programName, errorUsageTerms, {
|
|
1120
|
+
resolveUsageWidth(augmentedParser.usage);
|
|
1121
|
+
stderr(`${usageLabel()}${indentLines(formatUsage(programName, augmentedParser.usage, {
|
|
1129
1122
|
theme,
|
|
1130
1123
|
colors,
|
|
1131
1124
|
maxWidth: maxWidth == null ? void 0 : maxWidth - usageLabelWidth(),
|
package/dist/usage-internals.cjs
CHANGED
|
@@ -2,103 +2,6 @@ const require_usage = require('./usage.cjs');
|
|
|
2
2
|
|
|
3
3
|
//#region src/usage-internals.ts
|
|
4
4
|
/**
|
|
5
|
-
* Projects augmented runner usage onto a recorded canonical command path.
|
|
6
|
-
* Unsupported or ambiguous metadata returns undefined, preserving root usage.
|
|
7
|
-
* No parser, documentation, or usage-override callbacks are evaluated.
|
|
8
|
-
* @param usage The runner's original augmented usage.
|
|
9
|
-
* @param path The canonical path recorded by the failed parse.
|
|
10
|
-
* @param meta The known augmentation boundary, absent without alternatives.
|
|
11
|
-
* @returns The selected grammar, or undefined when projection is uncertain.
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
14
|
-
function projectCommandUsage(usage, path, meta) {
|
|
15
|
-
if (path.length === 0) return void 0;
|
|
16
|
-
if (meta == null) return projectCommandTerms(usage, path, 0);
|
|
17
|
-
const top = usage[0];
|
|
18
|
-
if (usage.length !== 1 || top.type !== "exclusive" || top.terms.length !== meta.alternativeCount + 1) return void 0;
|
|
19
|
-
const selected = projectCommandTerms(top.terms[meta.optionCount], path, 0);
|
|
20
|
-
if (selected == null) return void 0;
|
|
21
|
-
const options = top.terms.slice(0, meta.optionCount).filter((branch) => branch.some((term) => term.type === "option" && !require_usage.isUsageHidden(term.hidden)));
|
|
22
|
-
return options.length === 0 ? selected : [{
|
|
23
|
-
type: "exclusive",
|
|
24
|
-
terms: [...options, selected]
|
|
25
|
-
}];
|
|
26
|
-
}
|
|
27
|
-
function containsCommand(usage) {
|
|
28
|
-
return usage.some((term) => {
|
|
29
|
-
switch (term.type) {
|
|
30
|
-
case "command": return true;
|
|
31
|
-
case "exclusive": return term.terms.some(containsCommand);
|
|
32
|
-
case "optional":
|
|
33
|
-
case "multiple":
|
|
34
|
-
case "sequence": return containsCommand(term.terms);
|
|
35
|
-
default: return false;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
/** Undefined distinguishes unsupported metadata from a command-free branch. */
|
|
40
|
-
function firstCommandNames(usage) {
|
|
41
|
-
const hosts = usage.filter((term) => containsCommand([term]));
|
|
42
|
-
const first = hosts[0];
|
|
43
|
-
if (first == null) return [];
|
|
44
|
-
if (first.type === "command") return [first.name];
|
|
45
|
-
if (hosts.length !== 1) return void 0;
|
|
46
|
-
if (first.type === "sequence") return firstCommandNames(first.terms);
|
|
47
|
-
if (first.type !== "exclusive") return void 0;
|
|
48
|
-
const names = [];
|
|
49
|
-
for (const branch of first.terms) {
|
|
50
|
-
const found = firstCommandNames(branch);
|
|
51
|
-
if (found == null) return void 0;
|
|
52
|
-
names.push(...found);
|
|
53
|
-
}
|
|
54
|
-
return names;
|
|
55
|
-
}
|
|
56
|
-
function projectCommandTerms(usage, path, offset) {
|
|
57
|
-
if (offset === path.length) return usage;
|
|
58
|
-
const index = usage.findIndex((term) => containsCommand([term]));
|
|
59
|
-
if (index < 0) return void 0;
|
|
60
|
-
const host = usage[index];
|
|
61
|
-
const prefix = usage.slice(0, index);
|
|
62
|
-
const suffix = usage.slice(index + 1);
|
|
63
|
-
if (host.type === "command") {
|
|
64
|
-
if (host.name !== path[offset] || require_usage.isUsageHidden(host.hidden)) return void 0;
|
|
65
|
-
const rest = projectCommandTerms(suffix, path, offset + 1);
|
|
66
|
-
return rest == null ? void 0 : [
|
|
67
|
-
...prefix,
|
|
68
|
-
host,
|
|
69
|
-
...rest
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
if (containsCommand(suffix)) return void 0;
|
|
73
|
-
if (host.type === "sequence") {
|
|
74
|
-
const terms$1 = projectCommandTerms(host.terms, path, offset);
|
|
75
|
-
return terms$1 == null ? void 0 : [
|
|
76
|
-
...prefix,
|
|
77
|
-
{
|
|
78
|
-
...host,
|
|
79
|
-
terms: terms$1
|
|
80
|
-
},
|
|
81
|
-
...suffix
|
|
82
|
-
];
|
|
83
|
-
}
|
|
84
|
-
if (host.type !== "exclusive") return void 0;
|
|
85
|
-
let selected;
|
|
86
|
-
for (const branch of host.terms) {
|
|
87
|
-
const names = firstCommandNames(branch);
|
|
88
|
-
if (names == null) return void 0;
|
|
89
|
-
if (!names.includes(path[offset])) continue;
|
|
90
|
-
if (selected != null) return void 0;
|
|
91
|
-
selected = branch;
|
|
92
|
-
}
|
|
93
|
-
if (selected == null) return void 0;
|
|
94
|
-
const terms = projectCommandTerms(selected, path, offset);
|
|
95
|
-
return terms == null ? void 0 : [
|
|
96
|
-
...prefix,
|
|
97
|
-
...terms,
|
|
98
|
-
...suffix
|
|
99
|
-
];
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
5
|
* Collects option names and command names that are valid as the *immediate*
|
|
103
6
|
* next token at the current parse position ("leading candidates").
|
|
104
7
|
*
|
|
@@ -249,5 +152,4 @@ exports.collectActiveOptionNames = collectActiveOptionNames;
|
|
|
249
152
|
exports.collectLeadingCandidates = collectLeadingCandidates;
|
|
250
153
|
exports.collectOptionNamesAtCurrentCommandDepth = collectOptionNamesAtCurrentCommandDepth;
|
|
251
154
|
exports.collectRootOptionNames = collectRootOptionNames;
|
|
252
|
-
exports.extractLeadingCommandNames = extractLeadingCommandNames;
|
|
253
|
-
exports.projectCommandUsage = projectCommandUsage;
|
|
155
|
+
exports.extractLeadingCommandNames = extractLeadingCommandNames;
|
package/dist/usage-internals.js
CHANGED
|
@@ -1,104 +1,7 @@
|
|
|
1
|
-
import { isSuggestionHidden
|
|
1
|
+
import { isSuggestionHidden } from "./usage.js";
|
|
2
2
|
|
|
3
3
|
//#region src/usage-internals.ts
|
|
4
4
|
/**
|
|
5
|
-
* Projects augmented runner usage onto a recorded canonical command path.
|
|
6
|
-
* Unsupported or ambiguous metadata returns undefined, preserving root usage.
|
|
7
|
-
* No parser, documentation, or usage-override callbacks are evaluated.
|
|
8
|
-
* @param usage The runner's original augmented usage.
|
|
9
|
-
* @param path The canonical path recorded by the failed parse.
|
|
10
|
-
* @param meta The known augmentation boundary, absent without alternatives.
|
|
11
|
-
* @returns The selected grammar, or undefined when projection is uncertain.
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
14
|
-
function projectCommandUsage(usage, path, meta) {
|
|
15
|
-
if (path.length === 0) return void 0;
|
|
16
|
-
if (meta == null) return projectCommandTerms(usage, path, 0);
|
|
17
|
-
const top = usage[0];
|
|
18
|
-
if (usage.length !== 1 || top.type !== "exclusive" || top.terms.length !== meta.alternativeCount + 1) return void 0;
|
|
19
|
-
const selected = projectCommandTerms(top.terms[meta.optionCount], path, 0);
|
|
20
|
-
if (selected == null) return void 0;
|
|
21
|
-
const options = top.terms.slice(0, meta.optionCount).filter((branch) => branch.some((term) => term.type === "option" && !isUsageHidden(term.hidden)));
|
|
22
|
-
return options.length === 0 ? selected : [{
|
|
23
|
-
type: "exclusive",
|
|
24
|
-
terms: [...options, selected]
|
|
25
|
-
}];
|
|
26
|
-
}
|
|
27
|
-
function containsCommand(usage) {
|
|
28
|
-
return usage.some((term) => {
|
|
29
|
-
switch (term.type) {
|
|
30
|
-
case "command": return true;
|
|
31
|
-
case "exclusive": return term.terms.some(containsCommand);
|
|
32
|
-
case "optional":
|
|
33
|
-
case "multiple":
|
|
34
|
-
case "sequence": return containsCommand(term.terms);
|
|
35
|
-
default: return false;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
/** Undefined distinguishes unsupported metadata from a command-free branch. */
|
|
40
|
-
function firstCommandNames(usage) {
|
|
41
|
-
const hosts = usage.filter((term) => containsCommand([term]));
|
|
42
|
-
const first = hosts[0];
|
|
43
|
-
if (first == null) return [];
|
|
44
|
-
if (first.type === "command") return [first.name];
|
|
45
|
-
if (hosts.length !== 1) return void 0;
|
|
46
|
-
if (first.type === "sequence") return firstCommandNames(first.terms);
|
|
47
|
-
if (first.type !== "exclusive") return void 0;
|
|
48
|
-
const names = [];
|
|
49
|
-
for (const branch of first.terms) {
|
|
50
|
-
const found = firstCommandNames(branch);
|
|
51
|
-
if (found == null) return void 0;
|
|
52
|
-
names.push(...found);
|
|
53
|
-
}
|
|
54
|
-
return names;
|
|
55
|
-
}
|
|
56
|
-
function projectCommandTerms(usage, path, offset) {
|
|
57
|
-
if (offset === path.length) return usage;
|
|
58
|
-
const index = usage.findIndex((term) => containsCommand([term]));
|
|
59
|
-
if (index < 0) return void 0;
|
|
60
|
-
const host = usage[index];
|
|
61
|
-
const prefix = usage.slice(0, index);
|
|
62
|
-
const suffix = usage.slice(index + 1);
|
|
63
|
-
if (host.type === "command") {
|
|
64
|
-
if (host.name !== path[offset] || isUsageHidden(host.hidden)) return void 0;
|
|
65
|
-
const rest = projectCommandTerms(suffix, path, offset + 1);
|
|
66
|
-
return rest == null ? void 0 : [
|
|
67
|
-
...prefix,
|
|
68
|
-
host,
|
|
69
|
-
...rest
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
if (containsCommand(suffix)) return void 0;
|
|
73
|
-
if (host.type === "sequence") {
|
|
74
|
-
const terms$1 = projectCommandTerms(host.terms, path, offset);
|
|
75
|
-
return terms$1 == null ? void 0 : [
|
|
76
|
-
...prefix,
|
|
77
|
-
{
|
|
78
|
-
...host,
|
|
79
|
-
terms: terms$1
|
|
80
|
-
},
|
|
81
|
-
...suffix
|
|
82
|
-
];
|
|
83
|
-
}
|
|
84
|
-
if (host.type !== "exclusive") return void 0;
|
|
85
|
-
let selected;
|
|
86
|
-
for (const branch of host.terms) {
|
|
87
|
-
const names = firstCommandNames(branch);
|
|
88
|
-
if (names == null) return void 0;
|
|
89
|
-
if (!names.includes(path[offset])) continue;
|
|
90
|
-
if (selected != null) return void 0;
|
|
91
|
-
selected = branch;
|
|
92
|
-
}
|
|
93
|
-
if (selected == null) return void 0;
|
|
94
|
-
const terms = projectCommandTerms(selected, path, offset);
|
|
95
|
-
return terms == null ? void 0 : [
|
|
96
|
-
...prefix,
|
|
97
|
-
...terms,
|
|
98
|
-
...suffix
|
|
99
|
-
];
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
5
|
* Collects option names and command names that are valid as the *immediate*
|
|
103
6
|
* next token at the current parse position ("leading candidates").
|
|
104
7
|
*
|
|
@@ -245,4 +148,4 @@ function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
|
|
|
245
148
|
}
|
|
246
149
|
|
|
247
150
|
//#endregion
|
|
248
|
-
export { collectActiveOptionNames, collectLeadingCandidates, collectOptionNamesAtCurrentCommandDepth, collectRootOptionNames, extractLeadingCommandNames
|
|
151
|
+
export { collectActiveOptionNames, collectLeadingCandidates, collectOptionNamesAtCurrentCommandDepth, collectRootOptionNames, extractLeadingCommandNames };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.4.0-dev.
|
|
3
|
+
"version": "1.4.0-dev.2899",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
},
|
|
262
262
|
"sideEffects": false,
|
|
263
263
|
"devDependencies": {
|
|
264
|
-
"@optique/env": "1.4.0-dev.
|
|
264
|
+
"@optique/env": "1.4.0-dev.2899+9c2973b0",
|
|
265
265
|
"@types/node": "^24.0.0",
|
|
266
266
|
"fast-check": "^4.7.0",
|
|
267
267
|
"tsdown": "^0.13.0",
|
package/skills/optique/SKILL.md
CHANGED
|
@@ -80,9 +80,9 @@ Core rules
|
|
|
80
80
|
Show hidden `aliases` in help with `showAliases` on `command()` or runner.
|
|
81
81
|
- Use `run(parser, { completion: "both" })` for completion, or the object form
|
|
82
82
|
with `completion.errors` for custom shell errors. Do not hand-write scripts.
|
|
83
|
-
- Use `usageLine: [{ type: "ellipsis" }]`
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
- Use `usageLine: [{ type: "ellipsis" }]` in runner options when a large root
|
|
84
|
+
synopsis should become a compact `Usage: myapp ...` line. This applies only
|
|
85
|
+
to root full help; use `command()`'s `usageLine` for subcommand help.
|
|
86
86
|
- Use `showUsage: false` in runner options when full help should show the
|
|
87
87
|
brief and sections without `Usage:`. Set `command()`'s `showUsage: true`
|
|
88
88
|
to restore it; children inherit the nearest explicit ancestor setting.
|
|
@@ -263,7 +263,6 @@ For the detailed maintained guide, use <https://optique.dev/pitfalls.md>.
|
|
|
263
263
|
Reference links
|
|
264
264
|
---------------
|
|
265
265
|
|
|
266
|
-
- Documentation index for agents: <https://optique.dev/llms.txt>
|
|
267
266
|
- Runners and entry points: <https://optique.dev/concepts/runners.md>
|
|
268
267
|
- Primitive parsers: <https://optique.dev/concepts/primitives.md>
|
|
269
268
|
- Construct combinators: <https://optique.dev/concepts/constructs.md>
|
|
@@ -273,6 +272,7 @@ Reference links
|
|
|
273
272
|
- Structured messages: <https://optique.dev/concepts/messages.md>
|
|
274
273
|
- Shell completion: <https://optique.dev/concepts/completion.md>
|
|
275
274
|
- Command discovery: <https://optique.dev/concepts/discover.md>
|
|
275
|
+
- CLI: <https://github.com/dahlia/optique/tree/main/examples/file-inspect>
|
|
276
276
|
- Man pages: <https://optique.dev/concepts/man.md>
|
|
277
277
|
|
|
278
278
|
|