@forwardimpact/libcli 0.1.8 → 0.1.9

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 CHANGED
@@ -1,6 +1,11 @@
1
1
  # libcli
2
2
 
3
- Shared CLI infrastructure for Forward Impact products.
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.8",
4
- "description": "Agent-friendly CLIs: argument parsing, handler dispatch, grep-friendly help, JSON mode, and skill-doc links in `--help`.",
3
+ "version": "0.1.9",
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
- "forwardimpact": {
21
- "capability": "agent-capability",
22
- "needs": [
23
- "Parse CLI args and render help",
24
- "Render colored tables and JSON output",
25
- "Surface skill-doc links in CLI --help output"
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": {
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
- * Format an error message
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
- * Format a warning message
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();