@outfitter/cli 0.5.2 → 1.0.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/README.md +179 -60
- package/dist/actions.d.ts +5 -2
- package/dist/actions.js +2 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +8 -1
- package/dist/colors/index.js +1 -17
- package/dist/command.d.ts +3 -43
- package/dist/command.js +241 -13
- package/dist/envelope.d.ts +5 -0
- package/dist/envelope.js +160 -0
- package/dist/flags.d.ts +5 -189
- package/dist/flags.js +5 -1
- package/dist/hints.d.ts +34 -0
- package/dist/hints.js +26 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -17
- package/dist/input.d.ts +3 -124
- package/dist/input.js +14 -359
- package/dist/internal/envelope-helpers.d.ts +4 -0
- package/dist/internal/envelope-helpers.js +24 -0
- package/dist/internal/envelope-types.d.ts +3 -0
- package/dist/internal/flag-builders.d.ts +3 -0
- package/dist/internal/flag-builders.js +155 -0
- package/dist/internal/flag-types.d.ts +3 -0
- package/dist/internal/flag-types.js +13 -0
- package/dist/internal/hint-action-graph.d.ts +5 -0
- package/dist/internal/hint-action-graph.js +11 -0
- package/dist/internal/hint-command-tree.d.ts +5 -0
- package/dist/internal/hint-command-tree.js +9 -0
- package/dist/internal/hint-error-recovery.d.ts +2 -0
- package/dist/internal/hint-error-recovery.js +7 -0
- package/dist/internal/hint-types.d.ts +4 -0
- package/dist/internal/hint-types.js +1 -0
- package/dist/internal/input-helpers.d.ts +18 -0
- package/dist/internal/input-helpers.js +11 -0
- package/dist/internal/input-normalization.d.ts +3 -0
- package/dist/internal/input-normalization.js +9 -0
- package/dist/internal/input-parsers.d.ts +3 -0
- package/dist/internal/input-parsers.js +19 -0
- package/dist/internal/input-security.d.ts +22 -0
- package/dist/internal/input-security.js +11 -0
- package/dist/internal/output-formatting.d.ts +3 -0
- package/dist/internal/output-formatting.js +21 -0
- package/dist/internal/presets.d.ts +3 -0
- package/dist/{shared/@outfitter/cli-pdb7znbq.js → internal/presets.js} +49 -223
- package/dist/internal/schema-commands.d.ts +3 -0
- package/dist/{shared/@outfitter/cli-0cjts94k.js → internal/schema-commands.js} +12 -100
- package/dist/internal/schema-formatting.d.ts +2 -0
- package/dist/internal/schema-formatting.js +7 -0
- package/dist/internal/schema-types.d.ts +2 -0
- package/dist/internal/schema-types.js +1 -0
- package/dist/output.d.ts +4 -3
- package/dist/output.js +10 -2
- package/dist/pagination.d.ts +1 -1
- package/dist/query.d.ts +84 -2
- package/dist/query.js +8 -45
- package/dist/schema-input.d.ts +80 -0
- package/dist/schema-input.js +15 -0
- package/dist/schema.d.ts +4 -1
- package/dist/schema.js +1 -1
- package/dist/shared/@outfitter/cli-10wxfc78.d.ts +45 -0
- package/dist/shared/@outfitter/cli-16wg5mka.d.ts +71 -0
- package/dist/shared/@outfitter/cli-1q5redaj.js +267 -0
- package/dist/shared/@outfitter/cli-2dfxs239.js +98 -0
- package/dist/shared/@outfitter/cli-30mt7c5w.d.ts +112 -0
- package/dist/shared/@outfitter/cli-3jta1h1h.js +134 -0
- package/dist/shared/@outfitter/cli-4h85mpth.js +76 -0
- package/dist/shared/@outfitter/cli-6shkwxdc.js +28 -0
- package/dist/shared/@outfitter/cli-89335n9a.js +16 -0
- package/dist/shared/@outfitter/cli-8999qjdd.js +3 -0
- package/dist/shared/@outfitter/cli-8cfxdady.js +60 -0
- package/dist/shared/@outfitter/cli-bcajqy33.d.ts +25 -0
- package/dist/shared/@outfitter/cli-c09332vm.d.ts +39 -0
- package/dist/shared/@outfitter/cli-cgha038c.d.ts +3 -0
- package/dist/shared/@outfitter/{cli-zahqsaby.js → cli-d40m2x1d.js} +19 -3
- package/dist/shared/@outfitter/{cli-7wp5nj0s.js → cli-dg0cz7rw.js} +39 -81
- package/dist/shared/@outfitter/cli-dv8kk4jw.d.ts +24 -0
- package/dist/shared/@outfitter/cli-g43887b7.js +20 -0
- package/dist/shared/@outfitter/cli-gqtkhgw4.js +52 -0
- package/dist/shared/@outfitter/cli-h4ejpmjs.d.ts +104 -0
- package/dist/shared/@outfitter/cli-htzez8v2.js +70 -0
- package/dist/shared/@outfitter/cli-hvg2m5gf.js +79 -0
- package/dist/shared/@outfitter/cli-n54zs151.d.ts +78 -0
- package/dist/shared/@outfitter/cli-nbpgw7z7.d.ts +15 -0
- package/dist/shared/@outfitter/cli-nkt399zf.d.ts +94 -0
- package/dist/shared/@outfitter/cli-pmd04gtv.d.ts +60 -0
- package/dist/shared/@outfitter/{cli-xy3gs50c.d.ts → cli-q6csxmeh.d.ts} +19 -12
- package/dist/shared/@outfitter/cli-qcskd96y.d.ts +11 -0
- package/dist/shared/@outfitter/cli-ry7btmy4.js +118 -0
- package/dist/shared/@outfitter/cli-sy99pjyj.js +32 -0
- package/dist/shared/@outfitter/cli-tm2fzngs.d.ts +23 -0
- package/dist/shared/@outfitter/cli-vvvhjwks.js +106 -0
- package/dist/shared/@outfitter/cli-wjv7g1aq.d.ts +16 -0
- package/dist/shared/@outfitter/{cli-98aa9104.d.ts → cli-x6qr7bnd.d.ts} +338 -16
- package/dist/shared/@outfitter/cli-xde45xcc.d.ts +53 -0
- package/dist/shared/@outfitter/cli-xw8ys1je.d.ts +123 -0
- package/dist/shared/@outfitter/cli-yfewnyc2.d.ts +43 -0
- package/dist/shared/@outfitter/cli-zkzj0q4q.js +99 -0
- package/dist/shared/@outfitter/cli-zv3ah6f0.js +3 -0
- package/dist/streaming.d.ts +47 -0
- package/dist/streaming.js +13 -0
- package/dist/terminal/index.js +1 -19
- package/dist/truncation.d.ts +104 -0
- package/dist/truncation.js +111 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.js +0 -5
- package/dist/verbs.d.ts +1 -1
- package/package.json +66 -36
- package/dist/shared/@outfitter/cli-n1k0d23k.d.ts +0 -33
- /package/dist/{shared/@outfitter/cli-zw75pdk8.js → internal/envelope-types.js} +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ColorFlags, ExecutionFlags, ExecutionPresetConfig, FlagPreset, InteractionFlags, PaginationFlags, PaginationPresetConfig, ProjectionFlags, StrictFlags, TimeWindowFlags, TimeWindowPresetConfig } from "./cli-x6qr7bnd.js";
|
|
2
|
+
/**
|
|
3
|
+
* Verbose output flag preset.
|
|
4
|
+
*
|
|
5
|
+
* Adds: `-v, --verbose`
|
|
6
|
+
* Resolves: `{ verbose: boolean }`
|
|
7
|
+
*/
|
|
8
|
+
declare function verbosePreset(): FlagPreset<{
|
|
9
|
+
verbose: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Working directory flag preset.
|
|
13
|
+
*
|
|
14
|
+
* Adds: `--cwd <path>`
|
|
15
|
+
* Resolves: `{ cwd: string }` (defaults to `process.cwd()`)
|
|
16
|
+
*/
|
|
17
|
+
declare function cwdPreset(): FlagPreset<{
|
|
18
|
+
cwd: string;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Dry-run flag preset.
|
|
22
|
+
*
|
|
23
|
+
* Adds: `--dry-run`
|
|
24
|
+
* Resolves: `{ dryRun: boolean }`
|
|
25
|
+
*/
|
|
26
|
+
declare function dryRunPreset(): FlagPreset<{
|
|
27
|
+
dryRun: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Force flag preset.
|
|
31
|
+
*
|
|
32
|
+
* Adds: `-f, --force`
|
|
33
|
+
* Resolves: `{ force: boolean }`
|
|
34
|
+
*/
|
|
35
|
+
declare function forcePreset(): FlagPreset<{
|
|
36
|
+
force: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Interaction mode flag preset.
|
|
40
|
+
*
|
|
41
|
+
* Adds: `--non-interactive`, `--no-input`, `-y, --yes`
|
|
42
|
+
* Resolves: `{ interactive: boolean, yes: boolean }`
|
|
43
|
+
*
|
|
44
|
+
* `interactive` defaults to `true` and is set to `false` when
|
|
45
|
+
* `--non-interactive` or `--no-input` is passed. The two flags
|
|
46
|
+
* are synonyms for user convenience.
|
|
47
|
+
*/
|
|
48
|
+
declare function interactionPreset(): FlagPreset<InteractionFlags>;
|
|
49
|
+
/**
|
|
50
|
+
* Strict mode flag preset.
|
|
51
|
+
*
|
|
52
|
+
* Adds: `--strict`
|
|
53
|
+
* Resolves: `{ strict: boolean }`
|
|
54
|
+
*/
|
|
55
|
+
declare function strictPreset(): FlagPreset<StrictFlags>;
|
|
56
|
+
/**
|
|
57
|
+
* Color mode flag preset.
|
|
58
|
+
*
|
|
59
|
+
* Adds: `--color [mode]`, `--no-color`
|
|
60
|
+
* Resolves: `{ color: "auto" | "always" | "never" }`
|
|
61
|
+
*
|
|
62
|
+
* Commander's `--no-color` negation sets `flags["color"]` to `false`,
|
|
63
|
+
* which resolves to `"never"`. Invalid values default to `"auto"`.
|
|
64
|
+
*
|
|
65
|
+
* This preset resolves the user's *intent*. Consumers should compose
|
|
66
|
+
* with terminal detection (`supportsColor()`, `resolveColorEnv()`)
|
|
67
|
+
* to determine actual color output behavior.
|
|
68
|
+
*/
|
|
69
|
+
declare function colorPreset(): FlagPreset<ColorFlags>;
|
|
70
|
+
/**
|
|
71
|
+
* Projection flag preset.
|
|
72
|
+
*
|
|
73
|
+
* Adds: `--fields <fields>`, `--exclude-fields <fields>`, `--count`
|
|
74
|
+
* Resolves: `{ fields: string[] | undefined, excludeFields: string[] | undefined, count: boolean }`
|
|
75
|
+
*
|
|
76
|
+
* Fields are parsed as comma-separated strings with whitespace trimming.
|
|
77
|
+
* `undefined` when not provided (not empty array) to distinguish
|
|
78
|
+
* "not specified" from "empty".
|
|
79
|
+
*
|
|
80
|
+
* Conflict between `--fields` and `--exclude-fields` is a handler
|
|
81
|
+
* concern (documented, not enforced).
|
|
82
|
+
*/
|
|
83
|
+
declare function projectionPreset(): FlagPreset<ProjectionFlags>;
|
|
84
|
+
/**
|
|
85
|
+
* Time-window flag preset.
|
|
86
|
+
*
|
|
87
|
+
* Adds: `--since <date>`, `--until <date>`
|
|
88
|
+
* Resolves: `{ since: Date | undefined, until: Date | undefined }`
|
|
89
|
+
*
|
|
90
|
+
* Accepts ISO 8601 dates (`2024-01-15`) or relative durations
|
|
91
|
+
* (`7d`, `24h`, `30m`, `2w`). Durations are past-relative
|
|
92
|
+
* (subtracted from now).
|
|
93
|
+
*
|
|
94
|
+
* Returns `undefined` for unparseable values (does not throw).
|
|
95
|
+
* When `config.maxRange` is set and both bounds are provided,
|
|
96
|
+
* ranges above the limit are treated as invalid.
|
|
97
|
+
*/
|
|
98
|
+
declare function timeWindowPreset(config?: TimeWindowPresetConfig): FlagPreset<TimeWindowFlags>;
|
|
99
|
+
/**
|
|
100
|
+
* Execution flag preset.
|
|
101
|
+
*
|
|
102
|
+
* Adds: `--timeout <ms>`, `--retries <n>`, `--offline`
|
|
103
|
+
* Resolves: `{ timeout: number | undefined, retries: number, offline: boolean }`
|
|
104
|
+
*
|
|
105
|
+
* Timeout is parsed as a positive integer in milliseconds.
|
|
106
|
+
* Retries are parsed as a non-negative integer, clamped to maxRetries.
|
|
107
|
+
*/
|
|
108
|
+
declare function executionPreset(config?: ExecutionPresetConfig): FlagPreset<ExecutionFlags>;
|
|
109
|
+
/**
|
|
110
|
+
* Pagination flag preset.
|
|
111
|
+
*
|
|
112
|
+
* Adds: `-l, --limit <n>`, `--next`, `--reset`
|
|
113
|
+
* Resolves: `{ limit: number, next: boolean, reset: boolean }`
|
|
114
|
+
*
|
|
115
|
+
* Limit is parsed as an integer, clamped to maxLimit, and defaults
|
|
116
|
+
* to defaultLimit on invalid input. Mutual exclusivity of --next
|
|
117
|
+
* and --reset is a handler concern (not enforced here).
|
|
118
|
+
*
|
|
119
|
+
* Integrates with loadCursor/saveCursor/clearCursor from
|
|
120
|
+
* `@outfitter/cli/pagination`.
|
|
121
|
+
*/
|
|
122
|
+
declare function paginationPreset(config?: PaginationPresetConfig): FlagPreset<PaginationFlags>;
|
|
123
|
+
export { verbosePreset, cwdPreset, dryRunPreset, forcePreset, interactionPreset, strictPreset, colorPreset, projectionPreset, timeWindowPreset, executionPreset, paginationPreset };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CommandTree } from "./cli-16wg5mka.js";
|
|
2
|
+
import { CLIHint } from "@outfitter/contracts";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
/**
|
|
5
|
+
* Build a structured command tree from a Commander program instance.
|
|
6
|
+
*
|
|
7
|
+
* Recursively walks the program's registered commands, extracting
|
|
8
|
+
* names, descriptions, options, and nested subcommands.
|
|
9
|
+
*
|
|
10
|
+
* @param program - The Commander program (root command)
|
|
11
|
+
* @returns A structured command tree
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { Command } from "commander";
|
|
16
|
+
* import { buildCommandTree } from "@outfitter/cli/hints";
|
|
17
|
+
*
|
|
18
|
+
* const program = new Command("my-cli").version("1.0.0");
|
|
19
|
+
* program.command("list").description("List items");
|
|
20
|
+
*
|
|
21
|
+
* const tree = buildCommandTree(program);
|
|
22
|
+
* // { name: "my-cli", version: "1.0.0", commands: [{ name: "list", description: "List items" }] }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function buildCommandTree(program: Command): CommandTree;
|
|
26
|
+
/**
|
|
27
|
+
* Auto-generate CLIHint[] from a command tree (Tier 1).
|
|
28
|
+
*
|
|
29
|
+
* Produces one hint per registered command, including nested subcommands
|
|
30
|
+
* with their full command path.
|
|
31
|
+
*
|
|
32
|
+
* @param tree - The command tree from buildCommandTree()
|
|
33
|
+
* @returns Array of CLI hints for available commands
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const tree = buildCommandTree(program);
|
|
38
|
+
* const hints = commandTreeHints(tree);
|
|
39
|
+
* // [{ description: "List items", command: "my-cli list" }, ...]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function commandTreeHints(tree: CommandTree): CLIHint[];
|
|
43
|
+
export { buildCommandTree, commandTreeHints };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/internal/schema-formatting.ts
|
|
3
|
+
function formatManifestHuman(manifest, programName, actionId) {
|
|
4
|
+
if (actionId) {
|
|
5
|
+
return formatActionDetail(manifest, actionId);
|
|
6
|
+
}
|
|
7
|
+
return formatSummary(manifest, programName);
|
|
8
|
+
}
|
|
9
|
+
function formatSummary(manifest, programName) {
|
|
10
|
+
const lines = [];
|
|
11
|
+
const name = programName ?? "cli";
|
|
12
|
+
const actionCount = manifest.actions.length;
|
|
13
|
+
const surfaceCount = manifest.surfaces.length;
|
|
14
|
+
const surfaceLabel = surfaceCount === 1 ? `${surfaceCount} surface` : `${surfaceCount} surfaces`;
|
|
15
|
+
lines.push(`${name} \u2014 ${actionCount} actions across ${surfaceLabel}`);
|
|
16
|
+
lines.push("");
|
|
17
|
+
const grouped = new Map;
|
|
18
|
+
const ungrouped = [];
|
|
19
|
+
for (const action of manifest.actions) {
|
|
20
|
+
const group = action.cli?.group;
|
|
21
|
+
if (group) {
|
|
22
|
+
const existing = grouped.get(group) ?? [];
|
|
23
|
+
existing.push(action);
|
|
24
|
+
grouped.set(group, existing);
|
|
25
|
+
} else {
|
|
26
|
+
ungrouped.push(action);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const [groupName, groupActions] of grouped.entries()) {
|
|
30
|
+
lines.push(groupName);
|
|
31
|
+
for (const action of groupActions) {
|
|
32
|
+
const commandPart = action.cli?.command ?? "";
|
|
33
|
+
const isBase = !commandPart || commandPart.startsWith("[") || commandPart.startsWith("<");
|
|
34
|
+
const displayCommand = isBase ? ` ${groupName} ${commandPart}`.trimEnd() : ` ${groupName} ${commandPart}`;
|
|
35
|
+
const desc = action.cli?.description ?? action.description ?? "";
|
|
36
|
+
lines.push(padCommand(displayCommand, desc));
|
|
37
|
+
}
|
|
38
|
+
lines.push("");
|
|
39
|
+
}
|
|
40
|
+
for (const action of ungrouped) {
|
|
41
|
+
const commandPart = action.cli?.command ?? action.id;
|
|
42
|
+
const desc = action.cli?.description ?? action.description ?? "";
|
|
43
|
+
lines.push(padCommand(`${commandPart}`, desc));
|
|
44
|
+
}
|
|
45
|
+
lines.push("");
|
|
46
|
+
lines.push("Use --output json for machine-readable format.");
|
|
47
|
+
lines.push("Use --surface <name> to filter (cli, mcp, api, server).");
|
|
48
|
+
return lines.join(`
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
function padCommand(command, description) {
|
|
52
|
+
const padding = Math.max(1, 32 - command.length);
|
|
53
|
+
return `${command}${" ".repeat(padding)}${description}`;
|
|
54
|
+
}
|
|
55
|
+
function formatActionDetail(manifest, actionId) {
|
|
56
|
+
const entry = manifest.actions.find((a) => a.id === actionId);
|
|
57
|
+
if (!entry) {
|
|
58
|
+
return `Unknown action: ${actionId}`;
|
|
59
|
+
}
|
|
60
|
+
const lines = [];
|
|
61
|
+
const desc = entry.cli?.description ?? entry.description ?? "";
|
|
62
|
+
lines.push(`${entry.id} \u2014 ${desc}`);
|
|
63
|
+
lines.push("");
|
|
64
|
+
if (entry.cli) {
|
|
65
|
+
const group = entry.cli.group;
|
|
66
|
+
const commandPart = entry.cli.command ?? (group ? "" : entry.id);
|
|
67
|
+
const fullCommand = group ? `${group} ${commandPart}`.trimEnd() : commandPart;
|
|
68
|
+
lines.push(` Command: ${fullCommand}`);
|
|
69
|
+
}
|
|
70
|
+
lines.push(` Surfaces: ${entry.surfaces.join(", ")}`);
|
|
71
|
+
if (entry.cli?.group) {
|
|
72
|
+
lines.push(` Group: ${entry.cli.group}`);
|
|
73
|
+
}
|
|
74
|
+
if (entry.cli?.aliases && entry.cli.aliases.length > 0) {
|
|
75
|
+
lines.push(` Aliases: ${entry.cli.aliases.join(", ")}`);
|
|
76
|
+
}
|
|
77
|
+
if (entry.cli?.options && entry.cli.options.length > 0) {
|
|
78
|
+
lines.push("");
|
|
79
|
+
lines.push(" Options:");
|
|
80
|
+
for (const opt of entry.cli.options) {
|
|
81
|
+
const defaultStr = opt.defaultValue !== undefined ? ` [${String(opt.defaultValue)}]` : "";
|
|
82
|
+
lines.push(padCommand(` ${opt.flags}`, `${opt.description}${defaultStr}`));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (entry.mcp) {
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push(" MCP:");
|
|
88
|
+
if (entry.mcp.tool) {
|
|
89
|
+
lines.push(` Tool: ${entry.mcp.tool}`);
|
|
90
|
+
}
|
|
91
|
+
if (entry.mcp.description) {
|
|
92
|
+
lines.push(` Description: ${entry.mcp.description}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return lines.join(`
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { formatManifestHuman };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "./shared/@outfitter/cli-c09332vm.js";
|
|
2
|
+
import "./shared/@outfitter/cli-nkt399zf.js";
|
|
3
|
+
import { CommandEnvelope } from "./shared/@outfitter/cli-30mt7c5w.js";
|
|
4
|
+
import "./shared/@outfitter/cli-x6qr7bnd.js";
|
|
5
|
+
import { ProgressCallback, StreamEvent } from "@outfitter/contracts/stream";
|
|
6
|
+
/**
|
|
7
|
+
* A single line of NDJSON stream output.
|
|
8
|
+
*
|
|
9
|
+
* Can be a stream event (start, step, progress) or a terminal envelope.
|
|
10
|
+
*/
|
|
11
|
+
type StreamLine = StreamEvent | CommandEnvelope;
|
|
12
|
+
/**
|
|
13
|
+
* Write a single NDJSON line to stdout.
|
|
14
|
+
*
|
|
15
|
+
* The data is serialized as compact JSON followed by a newline character.
|
|
16
|
+
* Writes synchronously to stdout to maintain event ordering.
|
|
17
|
+
*
|
|
18
|
+
* @param data - Any JSON-serializable value to write as a single NDJSON line
|
|
19
|
+
*/
|
|
20
|
+
declare function writeNdjsonLine(data: unknown): void;
|
|
21
|
+
/**
|
|
22
|
+
* Write a terminal envelope as the final NDJSON line to stdout.
|
|
23
|
+
*
|
|
24
|
+
* In stream mode, both success and error envelopes are written to stdout
|
|
25
|
+
* (not stderr) so the entire NDJSON stream is on a single file descriptor.
|
|
26
|
+
*
|
|
27
|
+
* @param envelope - The terminal command envelope (success or error)
|
|
28
|
+
*/
|
|
29
|
+
declare function writeStreamEnvelope(envelope: CommandEnvelope): void;
|
|
30
|
+
/**
|
|
31
|
+
* Create a `ProgressCallback` that writes NDJSON lines to stdout.
|
|
32
|
+
*
|
|
33
|
+
* The callback is provided to handlers via `ctx.progress` when streaming
|
|
34
|
+
* is active. Each call to the returned function writes one NDJSON line.
|
|
35
|
+
*
|
|
36
|
+
* @param _commandName - Optional command name (reserved for future use in adapter context)
|
|
37
|
+
* @returns A `ProgressCallback` that writes stream events as NDJSON
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const progress = createNdjsonProgress("deploy");
|
|
42
|
+
* progress({ type: "start", command: "deploy", ts: new Date().toISOString() });
|
|
43
|
+
* progress({ type: "progress", current: 1, total: 10 });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function createNdjsonProgress(_commandName?: string): ProgressCallback;
|
|
47
|
+
export { writeStreamEnvelope, writeNdjsonLine, createNdjsonProgress, StreamLine };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
createNdjsonProgress,
|
|
4
|
+
writeNdjsonLine,
|
|
5
|
+
writeStreamEnvelope
|
|
6
|
+
} from "./shared/@outfitter/cli-g43887b7.js";
|
|
7
|
+
import"./shared/@outfitter/cli-4h85mpth.js";
|
|
8
|
+
import"./shared/@outfitter/cli-dg0cz7rw.js";
|
|
9
|
+
export {
|
|
10
|
+
writeStreamEnvelope,
|
|
11
|
+
writeNdjsonLine,
|
|
12
|
+
createNdjsonProgress
|
|
13
|
+
};
|
package/dist/terminal/index.js
CHANGED
|
@@ -1,19 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
getEnvValue,
|
|
4
|
-
getTerminalWidth,
|
|
5
|
-
hasNoColorEnv,
|
|
6
|
-
isInteractive,
|
|
7
|
-
resolveColorEnv,
|
|
8
|
-
resolveForceColorEnv,
|
|
9
|
-
supportsColor
|
|
10
|
-
} from "../shared/@outfitter/cli-jbj78ac5.js";
|
|
11
|
-
export {
|
|
12
|
-
supportsColor,
|
|
13
|
-
resolveForceColorEnv,
|
|
14
|
-
resolveColorEnv,
|
|
15
|
-
isInteractive,
|
|
16
|
-
hasNoColorEnv,
|
|
17
|
-
getTerminalWidth,
|
|
18
|
-
getEnvValue
|
|
19
|
-
};
|
|
1
|
+
export { getEnvValue, getTerminalWidth, hasNoColorEnv, isInteractive, resolveColorEnv, resolveForceColorEnv, supportsColor } from "./detection.js";
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { CLIHint } from "@outfitter/contracts";
|
|
2
|
+
/**
|
|
3
|
+
* Default threshold (in items) above which a file pointer is generated
|
|
4
|
+
* for the full output. Can be overridden via `filePointerThreshold` option.
|
|
5
|
+
*/
|
|
6
|
+
declare const DEFAULT_FILE_POINTER_THRESHOLD = 1e3;
|
|
7
|
+
/**
|
|
8
|
+
* Options for output truncation.
|
|
9
|
+
*/
|
|
10
|
+
interface TruncationOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Command name used in pagination hints.
|
|
13
|
+
* When provided, hints include the full command for continuation.
|
|
14
|
+
*/
|
|
15
|
+
readonly commandName?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Threshold (in items) above which full output is written to a temp file.
|
|
18
|
+
* Defaults to {@link DEFAULT_FILE_POINTER_THRESHOLD}.
|
|
19
|
+
*/
|
|
20
|
+
readonly filePointerThreshold?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Maximum number of items to include in the output.
|
|
23
|
+
* When undefined, output is not truncated.
|
|
24
|
+
*/
|
|
25
|
+
readonly limit?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Starting offset for pagination (0-based).
|
|
28
|
+
* Defaults to 0.
|
|
29
|
+
*/
|
|
30
|
+
readonly offset?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Custom temp directory for file pointers.
|
|
33
|
+
* Defaults to the OS temp directory.
|
|
34
|
+
* Primarily used for testing fault injection.
|
|
35
|
+
*/
|
|
36
|
+
readonly tempDir?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Metadata about truncation applied to the output.
|
|
40
|
+
*
|
|
41
|
+
* Present only when truncation was applied.
|
|
42
|
+
*/
|
|
43
|
+
interface TruncationMetadata {
|
|
44
|
+
/**
|
|
45
|
+
* Path to a temp file containing the complete output.
|
|
46
|
+
* Present only when output exceeds the file pointer threshold.
|
|
47
|
+
*/
|
|
48
|
+
readonly full_output?: string;
|
|
49
|
+
/** Number of items in the truncated output. */
|
|
50
|
+
readonly showing: number;
|
|
51
|
+
/** Total number of items before truncation. */
|
|
52
|
+
readonly total: number;
|
|
53
|
+
/** Always `true` when metadata is present. */
|
|
54
|
+
readonly truncated: true;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result of applying truncation to an output array.
|
|
58
|
+
*
|
|
59
|
+
* @typeParam T - Type of items in the output array
|
|
60
|
+
*/
|
|
61
|
+
interface TruncationResult<T = unknown> {
|
|
62
|
+
/** The (possibly truncated) output data. */
|
|
63
|
+
readonly data: T[];
|
|
64
|
+
/** Pagination and warning hints. Empty when no truncation applied. */
|
|
65
|
+
readonly hints: CLIHint[];
|
|
66
|
+
/** Truncation metadata. Undefined when no truncation was applied. */
|
|
67
|
+
readonly metadata: TruncationMetadata | undefined;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Truncate output with pagination hints and optional file pointers.
|
|
71
|
+
*
|
|
72
|
+
* When `limit` is not configured (undefined), output passes through untouched.
|
|
73
|
+
* When data length is at or below limit, output passes through untouched.
|
|
74
|
+
* When data exceeds limit, it is truncated with metadata and hints.
|
|
75
|
+
*
|
|
76
|
+
* For very large output (exceeding `filePointerThreshold`), the full result
|
|
77
|
+
* is written to a temp file and a file pointer is included in metadata.
|
|
78
|
+
* If the file write fails, truncated output is returned with a warning hint.
|
|
79
|
+
*
|
|
80
|
+
* @typeParam T - Type of items in the output array
|
|
81
|
+
* @param data - The output data to potentially truncate
|
|
82
|
+
* @param options - Truncation configuration
|
|
83
|
+
* @returns Truncation result with data, metadata, and hints
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* import { truncateOutput } from "@outfitter/cli/truncation";
|
|
88
|
+
*
|
|
89
|
+
* // No truncation (limit not set)
|
|
90
|
+
* const result1 = truncateOutput(items, {});
|
|
91
|
+
* // result1.data === items, result1.metadata === undefined
|
|
92
|
+
*
|
|
93
|
+
* // Truncate to 20 items
|
|
94
|
+
* const result2 = truncateOutput(items, { limit: 20, commandName: "list" });
|
|
95
|
+
* // result2.data.length === 20
|
|
96
|
+
* // result2.metadata === { showing: 20, total: 100, truncated: true }
|
|
97
|
+
* // result2.hints includes pagination continuation
|
|
98
|
+
*
|
|
99
|
+
* // With offset (page 2)
|
|
100
|
+
* const result3 = truncateOutput(items, { limit: 20, offset: 20 });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare function truncateOutput<T>(data: T[] | unknown, options: TruncationOptions): TruncationResult<T>;
|
|
104
|
+
export { truncateOutput, TruncationResult, TruncationOptions, TruncationMetadata, DEFAULT_FILE_POINTER_THRESHOLD };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import"./shared/@outfitter/cli-4h85mpth.js";
|
|
3
|
+
import {
|
|
4
|
+
cliStringify
|
|
5
|
+
} from "./shared/@outfitter/cli-dg0cz7rw.js";
|
|
6
|
+
|
|
7
|
+
// packages/cli/src/truncation.ts
|
|
8
|
+
import { writeFileSync } from "fs";
|
|
9
|
+
import { tmpdir } from "os";
|
|
10
|
+
import { isAbsolute, join, normalize } from "path";
|
|
11
|
+
var DEFAULT_FILE_POINTER_THRESHOLD = 1000;
|
|
12
|
+
var TEMP_FILE_PREFIX = "outfitter-output-";
|
|
13
|
+
var PATH_TRAVERSAL_PATTERN = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
|
|
14
|
+
function validateTempDir(dir) {
|
|
15
|
+
if (!isAbsolute(dir)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const normalized = normalize(dir);
|
|
19
|
+
if (PATH_TRAVERSAL_PATTERN.test(normalized)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (PATH_TRAVERSAL_PATTERN.test(dir)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
function generateTempFilePath(dir) {
|
|
28
|
+
const timestamp = Date.now();
|
|
29
|
+
const random = Math.random().toString(36).slice(2, 8);
|
|
30
|
+
return join(dir, `${TEMP_FILE_PREFIX}${timestamp}-${random}.json`);
|
|
31
|
+
}
|
|
32
|
+
function writeFullOutput(data, tempDir) {
|
|
33
|
+
try {
|
|
34
|
+
const filePath = generateTempFilePath(tempDir);
|
|
35
|
+
const content = cliStringify(data, true);
|
|
36
|
+
writeFileSync(filePath, content, "utf-8");
|
|
37
|
+
return { path: filePath };
|
|
38
|
+
} catch (err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40
|
+
return { error: message };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function buildPaginationHints(total, limit, offset, commandName) {
|
|
44
|
+
const hints = [];
|
|
45
|
+
const nextOffset = offset + limit;
|
|
46
|
+
if (nextOffset < total) {
|
|
47
|
+
const remaining = total - nextOffset;
|
|
48
|
+
const nextPageSize = Math.min(limit, remaining);
|
|
49
|
+
const cmdPrefix = commandName ? `${commandName} ` : "";
|
|
50
|
+
hints.push({
|
|
51
|
+
description: `Show next ${nextPageSize} of ${remaining} remaining items`,
|
|
52
|
+
command: `${cmdPrefix}--offset ${nextOffset} --limit ${limit}`
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return hints;
|
|
56
|
+
}
|
|
57
|
+
function truncateOutput(data, options) {
|
|
58
|
+
const { limit, commandName } = options;
|
|
59
|
+
if (!Array.isArray(data)) {
|
|
60
|
+
return {
|
|
61
|
+
data,
|
|
62
|
+
metadata: undefined,
|
|
63
|
+
hints: []
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const items = data;
|
|
67
|
+
if (limit === undefined) {
|
|
68
|
+
return {
|
|
69
|
+
data: items,
|
|
70
|
+
metadata: undefined,
|
|
71
|
+
hints: []
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const total = items.length;
|
|
75
|
+
if (total <= limit && (options.offset === undefined || options.offset <= 0)) {
|
|
76
|
+
return {
|
|
77
|
+
data: items,
|
|
78
|
+
metadata: undefined,
|
|
79
|
+
hints: []
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
83
|
+
const sliced = items.slice(offset, offset + limit);
|
|
84
|
+
const showing = sliced.length;
|
|
85
|
+
const hints = buildPaginationHints(total, limit, offset, commandName);
|
|
86
|
+
const filePointerThreshold = options.filePointerThreshold ?? DEFAULT_FILE_POINTER_THRESHOLD;
|
|
87
|
+
let fullOutput;
|
|
88
|
+
if (total > filePointerThreshold) {
|
|
89
|
+
const rawTempDir = options.tempDir;
|
|
90
|
+
const tempDir = rawTempDir ? validateTempDir(rawTempDir) ?? tmpdir() : tmpdir();
|
|
91
|
+
const writeResult = writeFullOutput(items, tempDir);
|
|
92
|
+
if ("path" in writeResult) {
|
|
93
|
+
fullOutput = writeResult.path;
|
|
94
|
+
} else {
|
|
95
|
+
hints.push({
|
|
96
|
+
description: `Warning: Could not write full output to file (${writeResult.error})`,
|
|
97
|
+
command: `${commandName ? `${commandName} ` : ""}--limit ${total}`
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const metadata = fullOutput ? { showing, total, truncated: true, full_output: fullOutput } : { showing, total, truncated: true };
|
|
102
|
+
return {
|
|
103
|
+
data: sliced,
|
|
104
|
+
metadata,
|
|
105
|
+
hints
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export {
|
|
109
|
+
truncateOutput,
|
|
110
|
+
DEFAULT_FILE_POINTER_THRESHOLD
|
|
111
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BooleanFlagPresetConfig, CLI, CLIConfig, CancelledError, CollectIdsOptions, ColorFlags, ColorMode, CommandAction, CommandBuilder, CommandConfig, CommandFlags, ComposedPreset, CursorOptions, DateRange, EnumFlagPresetConfig, ErrorCategory, ExecutionFlags, ExecutionPresetConfig, ExpandFileOptions, FilterExpression, FlagPreset, FlagPresetConfig, InteractionFlags, KeyValuePair, NormalizeIdOptions, NumberFlagPresetConfig, NumericRange, OutputMode, OutputOptions, PaginationFlags, PaginationPresetConfig, PaginationState, ParseGlobOptions, ProjectionFlags, Range, Result, SortCriteria, StrictFlags, StringListFlagPresetConfig, TimeWindowFlags, TimeWindowPresetConfig, ValidationError, VerbConfig, VerbFamily } from "./shared/@outfitter/cli-
|
|
2
|
-
export { VerbFamily, VerbConfig, ValidationError, TimeWindowPresetConfig, TimeWindowFlags, StringListFlagPresetConfig, StrictFlags, SortCriteria, Result, Range, ProjectionFlags, ParseGlobOptions, PaginationState, PaginationPresetConfig, PaginationFlags, OutputOptions, OutputMode, NumericRange, NumberFlagPresetConfig, NormalizeIdOptions, KeyValuePair, InteractionFlags, FlagPresetConfig, FlagPreset, FilterExpression, ExpandFileOptions, ExecutionPresetConfig, ExecutionFlags, ErrorCategory, EnumFlagPresetConfig, DateRange, CursorOptions, ComposedPreset, CommandFlags, CommandConfig, CommandBuilder, CommandAction, ColorMode, ColorFlags, CollectIdsOptions, CancelledError, CLIConfig, CLI, BooleanFlagPresetConfig };
|
|
1
|
+
import { AnyPreset, BooleanFlagPresetConfig, CLI, CLIConfig, CancelledError, CollectIdsOptions, ColorFlags, ColorMode, CommandAction, CommandBuilder, CommandConfig, CommandFlags, ComposedPreset, ContextFactory, CursorOptions, DateRange, EnumFlagPresetConfig, ErrorCategory, ErrorHintFn, ExecutionFlags, ExecutionPresetConfig, ExpandFileOptions, FilterExpression, FlagPreset, FlagPresetConfig, InteractionFlags, KeyValuePair, NormalizeIdOptions, NumberFlagPresetConfig, NumericRange, OutputMode, OutputOptions, PaginationFlags, PaginationPresetConfig, PaginationState, ParseGlobOptions, ProjectionFlags, Range, RelatedToDeclaration, RelatedToOptions, Result, SchemaPreset, SchemaPresetConfig, SortCriteria, StrictFlags, StringListFlagPresetConfig, SuccessHintFn, TimeWindowFlags, TimeWindowPresetConfig, ValidationError, VerbConfig, VerbFamily, ZodObjectLike } from "./shared/@outfitter/cli-x6qr7bnd.js";
|
|
2
|
+
export { ZodObjectLike, VerbFamily, VerbConfig, ValidationError, TimeWindowPresetConfig, TimeWindowFlags, SuccessHintFn, StringListFlagPresetConfig, StrictFlags, SortCriteria, SchemaPresetConfig, SchemaPreset, Result, RelatedToOptions, RelatedToDeclaration, Range, ProjectionFlags, ParseGlobOptions, PaginationState, PaginationPresetConfig, PaginationFlags, OutputOptions, OutputMode, NumericRange, NumberFlagPresetConfig, NormalizeIdOptions, KeyValuePair, InteractionFlags, FlagPresetConfig, FlagPreset, FilterExpression, ExpandFileOptions, ExecutionPresetConfig, ExecutionFlags, ErrorHintFn, ErrorCategory, EnumFlagPresetConfig, DateRange, CursorOptions, ContextFactory, ComposedPreset, CommandFlags, CommandConfig, CommandBuilder, CommandAction, ColorMode, ColorFlags, CollectIdsOptions, CancelledError, CLIConfig, CLI, BooleanFlagPresetConfig, AnyPreset };
|
package/dist/types.js
CHANGED
package/dist/verbs.d.ts
CHANGED