@forwardimpact/libcli 0.1.8 → 0.1.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/README.md +6 -1
- package/package.json +13 -11
- package/src/cli.js +9 -0
- package/src/format.js +2 -2
- package/src/help.js +4 -0
- package/src/summary.js +2 -0
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# libcli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- BEGIN:description — Do not edit. Generated from package.json. -->
|
|
4
|
+
|
|
5
|
+
Agent-friendly CLIs — self-documenting entry points that humans and agents reach
|
|
6
|
+
through the same interface.
|
|
7
|
+
|
|
8
|
+
<!-- END:description -->
|
|
4
9
|
|
|
5
10
|
## Getting Started
|
|
6
11
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/libcli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Agent-friendly CLIs
|
|
3
|
+
"version": "0.1.10",
|
|
4
|
+
"description": "Agent-friendly CLIs — self-documenting entry points that humans and agents reach through the same interface.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
7
7
|
"agent",
|
|
@@ -17,14 +17,16 @@
|
|
|
17
17
|
},
|
|
18
18
|
"license": "Apache-2.0",
|
|
19
19
|
"author": "D. Olsson <hi@senzilla.io>",
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
"jobs": [
|
|
21
|
+
{
|
|
22
|
+
"user": "Platform Builders",
|
|
23
|
+
"goal": "Enable Agents on Every Surface",
|
|
24
|
+
"trigger": "Building an interface and realizing agents can't discover or navigate it the same way humans do.",
|
|
25
|
+
"bigHire": "give agents and humans the same interface so capabilities don't need separate paths.",
|
|
26
|
+
"littleHire": "add a capability and know both humans and agents can reach it without a separate integration.",
|
|
27
|
+
"competesWith": "hand-written argument parsing; separate agent and human interfaces; tolerating agents that can't self-serve"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
28
30
|
"type": "module",
|
|
29
31
|
"main": "./src/index.js",
|
|
30
32
|
"exports": {
|
|
@@ -42,7 +44,7 @@
|
|
|
42
44
|
},
|
|
43
45
|
"engines": {
|
|
44
46
|
"bun": ">=1.2.0",
|
|
45
|
-
"node": ">=
|
|
47
|
+
"node": ">=22.0.0"
|
|
46
48
|
},
|
|
47
49
|
"publishConfig": {
|
|
48
50
|
"access": "public"
|
package/src/cli.js
CHANGED
|
@@ -2,11 +2,13 @@ import { parseArgs } from "node:util";
|
|
|
2
2
|
import { HelpRenderer } from "./help.js";
|
|
3
3
|
import { freezeInvocationContext } from "./invocation-context.js";
|
|
4
4
|
|
|
5
|
+
/** Command-line interface that parses argv against a definition of commands, options, and help. */
|
|
5
6
|
export class Cli {
|
|
6
7
|
#definition;
|
|
7
8
|
#proc;
|
|
8
9
|
#helpRenderer;
|
|
9
10
|
|
|
11
|
+
/** Build a CLI from a definition, wiring in the process handle and help renderer; throws if the deprecated top-level `options` key is present or if any command option name collides with a global option. */
|
|
10
12
|
constructor(definition, { process, helpRenderer }) {
|
|
11
13
|
if (definition.options) {
|
|
12
14
|
throw new Error(
|
|
@@ -37,10 +39,12 @@ export class Cli {
|
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
/** Return the CLI program name from the definition. */
|
|
40
43
|
get name() {
|
|
41
44
|
return this.#definition.name;
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
/** Parse argv into values and positionals, handling --help and --version; returns null when help or version is printed. */
|
|
44
48
|
parse(argv) {
|
|
45
49
|
const command = this.#findCommand(argv);
|
|
46
50
|
const options = this.#buildOptions(command);
|
|
@@ -130,6 +134,7 @@ export class Cli {
|
|
|
130
134
|
return null;
|
|
131
135
|
}
|
|
132
136
|
|
|
137
|
+
/** Match parsed positionals to a subcommand and invoke its handler with a frozen invocation context. */
|
|
133
138
|
dispatch(parsed, { data }) {
|
|
134
139
|
const command = this.#findCommand(parsed.positionals);
|
|
135
140
|
if (!command) {
|
|
@@ -155,21 +160,25 @@ export class Cli {
|
|
|
155
160
|
return command.handler(ctx);
|
|
156
161
|
}
|
|
157
162
|
|
|
163
|
+
/** Print the top-level help text to stdout. */
|
|
158
164
|
showHelp() {
|
|
159
165
|
this.#helpRenderer.render(this.#definition, this.#proc.stdout);
|
|
160
166
|
}
|
|
161
167
|
|
|
168
|
+
/** Write an error message to stderr and set exit code 1. */
|
|
162
169
|
error(message) {
|
|
163
170
|
this.#proc.stderr.write(`${this.#definition.name}: error: ${message}\n`);
|
|
164
171
|
this.#proc.exitCode = 1;
|
|
165
172
|
}
|
|
166
173
|
|
|
174
|
+
/** Write a usage error message to stderr and set exit code 2. */
|
|
167
175
|
usageError(message) {
|
|
168
176
|
this.#proc.stderr.write(`${this.#definition.name}: error: ${message}\n`);
|
|
169
177
|
this.#proc.exitCode = 2;
|
|
170
178
|
}
|
|
171
179
|
}
|
|
172
180
|
|
|
181
|
+
/** Create a Cli instance wired to the real process and a default HelpRenderer. */
|
|
173
182
|
export function createCli(definition) {
|
|
174
183
|
const helpRenderer = new HelpRenderer({ process });
|
|
175
184
|
return new Cli(definition, { process, helpRenderer });
|
package/src/format.js
CHANGED
|
@@ -84,7 +84,7 @@ export function formatTable(headers, rows, options = {}, proc = process) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
*
|
|
87
|
+
* Prefix the message with "Error: " and colorize red.
|
|
88
88
|
* @param {string} message
|
|
89
89
|
* @param {object} proc
|
|
90
90
|
* @returns {string}
|
|
@@ -104,7 +104,7 @@ export function formatSuccess(message, proc = process) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
*
|
|
107
|
+
* Prefix the message with "Warning: " and colorize yellow.
|
|
108
108
|
* @param {string} message
|
|
109
109
|
* @param {object} proc
|
|
110
110
|
* @returns {string}
|
package/src/help.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { supportsColor } from "./color.js";
|
|
2
2
|
import { formatHeader, formatSubheader } from "./format.js";
|
|
3
3
|
|
|
4
|
+
/** Render CLI help output as formatted text or JSON from a CLI definition. */
|
|
4
5
|
export class HelpRenderer {
|
|
5
6
|
#proc;
|
|
6
7
|
|
|
8
|
+
/** Store the process handle for stdout access and color detection. */
|
|
7
9
|
constructor({ process }) {
|
|
8
10
|
this.#proc = process;
|
|
9
11
|
}
|
|
@@ -145,6 +147,7 @@ export class HelpRenderer {
|
|
|
145
147
|
stream.write(lines.join("\n"));
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
/** Render human-readable help text for the full CLI or a single command to the given stream. */
|
|
148
151
|
render(definition, stream, command) {
|
|
149
152
|
const out = stream || this.#proc.stdout;
|
|
150
153
|
if (command) {
|
|
@@ -163,6 +166,7 @@ export class HelpRenderer {
|
|
|
163
166
|
out.write(lines.join("\n"));
|
|
164
167
|
}
|
|
165
168
|
|
|
169
|
+
/** Render the CLI definition or a single command as pretty-printed JSON to the given stream. */
|
|
166
170
|
renderJson(definition, stream, command) {
|
|
167
171
|
const out = stream || this.#proc.stdout;
|
|
168
172
|
if (command) {
|
package/src/summary.js
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
const LEVELS = { error: 0, warn: 1, info: 2, debug: 3, trace: 3 };
|
|
6
6
|
const DEFAULT_LEVEL = "info";
|
|
7
7
|
|
|
8
|
+
/** Render post-run summary blocks to stdout; successful blocks are suppressed only when LOG_LEVEL=error is explicitly set (default level is "info", which renders all blocks). */
|
|
8
9
|
export class SummaryRenderer {
|
|
9
10
|
#proc;
|
|
10
11
|
#level;
|
|
11
12
|
|
|
13
|
+
/** Initialize the renderer, reading LOG_LEVEL from the environment; defaults to "info" (all blocks rendered) when LOG_LEVEL is absent or unrecognized. */
|
|
12
14
|
constructor({ process }) {
|
|
13
15
|
this.#proc = process;
|
|
14
16
|
const raw = (process.env?.LOG_LEVEL || "").toLowerCase().trim();
|