cli-agent-mode 0.1.2 → 0.2.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 +2 -1
- package/dist/index.cjs +16 -13
- package/dist/index.d.cts +8 -17
- package/dist/index.d.mts +8 -17
- package/dist/index.mjs +16 -13
- package/package.json +12 -8
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Two lines turn your CLI into one that agents can drive reliably:
|
|
|
16
16
|
- **Stable exit codes** — `0` ok, `1` runtime error, `2` usage error.
|
|
17
17
|
- **Clean stdout** — stray `console.log` inside actions is redirected to stderr in JSON mode.
|
|
18
18
|
|
|
19
|
-
Zero dependencies. ~4 kB gzipped. ESM and CommonJS, Node
|
|
19
|
+
Zero dependencies. ~4 kB gzipped. ESM and CommonJS, Node 22+ (tested on 22, 24, 26), commander 12–15 (tested in CI).
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
npm i cli-agent-mode
|
|
@@ -131,6 +131,7 @@ If you are already on oclif, you have `--json`. If you are on commander — the
|
|
|
131
131
|
- `--json` is reserved: it is removed from argv before parsing (except after `--`).
|
|
132
132
|
- In JSON mode `console.log/info/debug` are redirected to stderr, but direct `process.stdout.write` calls inside actions are not — return data instead.
|
|
133
133
|
- Typed `@commander-js/extra-typings` is not supported yet.
|
|
134
|
+
- commander 15 is ESM-only: TypeScript projects compiled as CommonJS need TypeScript 5.9+ to import it (a commander limitation, not specific to this package).
|
|
134
135
|
|
|
135
136
|
## License
|
|
136
137
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let commander = require("commander");
|
|
3
3
|
let node_util = require("node:util");
|
|
4
|
-
|
|
4
|
+
// src/detect.ts
|
|
5
5
|
/**
|
|
6
6
|
* Synchronous, dependency-free detection of AI coding agents.
|
|
7
7
|
* Env variables mirror @vercel/detect-agent (Nov 2026) plus the `AI_AGENT` convention.
|
|
@@ -21,8 +21,7 @@ function detectAgent(env = process.env) {
|
|
|
21
21
|
if (env.COPILOT_MODEL || env.COPILOT_ALLOW_ALL) return "github-copilot";
|
|
22
22
|
if (env.REPL_ID) return "replit";
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
//#region src/describe.ts
|
|
24
|
+
// src/describe.ts
|
|
26
25
|
const clean = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== "" && v !== false && !(Array.isArray(v) && v.length === 0)));
|
|
27
26
|
function describeArgument(a) {
|
|
28
27
|
return clean({
|
|
@@ -71,8 +70,7 @@ function findCommand(root, path) {
|
|
|
71
70
|
}
|
|
72
71
|
return cur;
|
|
73
72
|
}
|
|
74
|
-
|
|
75
|
-
//#region src/errors.ts
|
|
73
|
+
// src/errors.ts
|
|
76
74
|
/**
|
|
77
75
|
* An error with a stable machine-readable `code`.
|
|
78
76
|
*
|
|
@@ -101,9 +99,9 @@ const EXIT = {
|
|
|
101
99
|
ERROR: 1,
|
|
102
100
|
USAGE: 2
|
|
103
101
|
};
|
|
104
|
-
|
|
105
|
-
//#region src/agent-mode.ts
|
|
102
|
+
// src/agent-mode.ts
|
|
106
103
|
const states = /* @__PURE__ */ new WeakMap();
|
|
104
|
+
const hooked = /* @__PURE__ */ new WeakSet();
|
|
107
105
|
const rootOf = (cmd) => {
|
|
108
106
|
let c = cmd;
|
|
109
107
|
while (c.parent) c = c.parent;
|
|
@@ -198,11 +196,18 @@ async function run(program, runOptions = {}) {
|
|
|
198
196
|
const json = runOptions.json ?? (extracted.json || (forced ?? (state.options.autoDetect && detectAgent(env) !== void 0)));
|
|
199
197
|
const mode = json ? "json" : "human";
|
|
200
198
|
let outBuf = "";
|
|
201
|
-
|
|
199
|
+
state.current = program;
|
|
202
200
|
const restore = [];
|
|
203
201
|
walk(program, (cmd) => {
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
if (!hooked.has(cmd)) {
|
|
203
|
+
hooked.add(cmd);
|
|
204
|
+
cmd.hook("preSubcommand", (_parent, sub) => {
|
|
205
|
+
const s = states.get(rootOf(sub));
|
|
206
|
+
if (s) s.current = sub;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const prevOutput = { ...cmd.configureOutput() };
|
|
210
|
+
const prevHelp = { ...cmd.configureHelp() };
|
|
206
211
|
restore.push(() => {
|
|
207
212
|
cmd.configureOutput(prevOutput);
|
|
208
213
|
cmd.configureHelp(prevHelp);
|
|
@@ -213,7 +218,6 @@ async function run(program, runOptions = {}) {
|
|
|
213
218
|
writeOut: (s) => json ? outBuf += s : stdout.write(s),
|
|
214
219
|
writeErr: (s) => json ? void 0 : stderr.write(s),
|
|
215
220
|
outputError: (s, write) => {
|
|
216
|
-
errorCommand = cmd;
|
|
217
221
|
if (!json) write(s);
|
|
218
222
|
}
|
|
219
223
|
});
|
|
@@ -264,7 +268,7 @@ async function run(program, runOptions = {}) {
|
|
|
264
268
|
exitCode = EXIT.OK;
|
|
265
269
|
if (!json) printed = true;
|
|
266
270
|
} else {
|
|
267
|
-
const { payload, code } = toPayload(err, program,
|
|
271
|
+
const { payload, code } = toPayload(err, program, state.current ?? program, state.options.describeCommand);
|
|
268
272
|
envelope = {
|
|
269
273
|
ok: false,
|
|
270
274
|
error: payload
|
|
@@ -327,7 +331,6 @@ function toPayload(err, root, at, describeName) {
|
|
|
327
331
|
};
|
|
328
332
|
}
|
|
329
333
|
const strip = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
330
|
-
//#endregion
|
|
331
334
|
exports.AgentError = AgentError;
|
|
332
335
|
exports.EXIT = EXIT;
|
|
333
336
|
exports.agentMode = agentMode;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/// <reference path="./commander-augment.d.ts" />
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
|
|
4
|
-
//#region src/errors.d.ts
|
|
5
3
|
interface AgentErrorOptions {
|
|
6
4
|
/** One concrete next step the agent (or human) can follow literally. */
|
|
7
5
|
suggestion?: string;
|
|
@@ -18,7 +16,7 @@ interface AgentErrorOptions {
|
|
|
18
16
|
* suggestion: 'Run "mycli env list" to see available environments.',
|
|
19
17
|
* });
|
|
20
18
|
*/
|
|
21
|
-
declare class AgentError extends Error {
|
|
19
|
+
export declare class AgentError extends Error {
|
|
22
20
|
readonly code: string;
|
|
23
21
|
readonly suggestion?: string;
|
|
24
22
|
readonly details?: unknown;
|
|
@@ -39,13 +37,11 @@ type Envelope<T = unknown> = {
|
|
|
39
37
|
error: ErrorPayload;
|
|
40
38
|
};
|
|
41
39
|
/** Exit codes used by cli-agent-mode. */
|
|
42
|
-
declare const EXIT: {
|
|
40
|
+
export declare const EXIT: {
|
|
43
41
|
readonly OK: 0;
|
|
44
42
|
readonly ERROR: 1;
|
|
45
43
|
readonly USAGE: 2;
|
|
46
44
|
};
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/agent-mode.d.ts
|
|
49
45
|
interface AgentModeOptions {
|
|
50
46
|
/** Switch to JSON automatically when an AI agent is detected (AI_AGENT, CLAUDECODE, CURSOR_AGENT, ...). Default: true. */
|
|
51
47
|
autoDetect?: boolean;
|
|
@@ -83,11 +79,9 @@ interface RunResult {
|
|
|
83
79
|
* program.command('deploy <env>').action(async (env) => ({ url: `https://${env}.example.com` }));
|
|
84
80
|
* await run(program);
|
|
85
81
|
*/
|
|
86
|
-
declare function agentMode<T extends Command>(program: T, options?: AgentModeOptions): T;
|
|
82
|
+
export declare function agentMode<T extends Command>(program: T, options?: AgentModeOptions): T;
|
|
87
83
|
/** Parse arguments, run the matching action and print the result or error in the right format. */
|
|
88
|
-
declare function run(program: Command, runOptions?: RunOptions): Promise<RunResult>;
|
|
89
|
-
//#endregion
|
|
90
|
-
//#region src/describe.d.ts
|
|
84
|
+
export declare function run(program: Command, runOptions?: RunOptions): Promise<RunResult>;
|
|
91
85
|
interface ArgumentSchema {
|
|
92
86
|
name: string;
|
|
93
87
|
description?: string;
|
|
@@ -119,17 +113,14 @@ interface CommandSchema {
|
|
|
119
113
|
commands?: CommandSchema[];
|
|
120
114
|
}
|
|
121
115
|
/** Compact JSON schema of a command and all of its visible subcommands. */
|
|
122
|
-
declare function describeCommand(cmd: Command): CommandSchema;
|
|
116
|
+
export declare function describeCommand(cmd: Command): CommandSchema;
|
|
123
117
|
/** Resolve `["deploy", "preview"]` to the nested subcommand (by name or alias). */
|
|
124
|
-
declare function findCommand(root: Command, path: string[]): Command | undefined;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/detect.d.ts
|
|
118
|
+
export declare function findCommand(root: Command, path: string[]): Command | undefined;
|
|
127
119
|
/**
|
|
128
120
|
* Synchronous, dependency-free detection of AI coding agents.
|
|
129
121
|
* Env variables mirror @vercel/detect-agent (Nov 2026) plus the `AI_AGENT` convention.
|
|
130
122
|
* CURSOR_TRACE_ID is deliberately ignored: it is also set in Cursor's terminal for humans.
|
|
131
123
|
* Returns the agent name or `undefined`.
|
|
132
124
|
*/
|
|
133
|
-
declare function detectAgent(env?: NodeJS.ProcessEnv): string | undefined;
|
|
134
|
-
|
|
135
|
-
export { AgentError, type AgentErrorOptions, type AgentModeOptions, type ArgumentSchema, type CommandSchema, EXIT, type Envelope, type ErrorPayload, type OptionSchema, type RunOptions, type RunResult, agentMode, describeCommand, detectAgent, findCommand, run };
|
|
125
|
+
export declare function detectAgent(env?: NodeJS.ProcessEnv): string | undefined;
|
|
126
|
+
export type { AgentErrorOptions, AgentModeOptions, ArgumentSchema, CommandSchema, Envelope, ErrorPayload, OptionSchema, RunOptions, RunResult };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/// <reference path="./commander-augment.d.ts" />
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
|
|
4
|
-
//#region src/errors.d.ts
|
|
5
3
|
interface AgentErrorOptions {
|
|
6
4
|
/** One concrete next step the agent (or human) can follow literally. */
|
|
7
5
|
suggestion?: string;
|
|
@@ -18,7 +16,7 @@ interface AgentErrorOptions {
|
|
|
18
16
|
* suggestion: 'Run "mycli env list" to see available environments.',
|
|
19
17
|
* });
|
|
20
18
|
*/
|
|
21
|
-
declare class AgentError extends Error {
|
|
19
|
+
export declare class AgentError extends Error {
|
|
22
20
|
readonly code: string;
|
|
23
21
|
readonly suggestion?: string;
|
|
24
22
|
readonly details?: unknown;
|
|
@@ -39,13 +37,11 @@ type Envelope<T = unknown> = {
|
|
|
39
37
|
error: ErrorPayload;
|
|
40
38
|
};
|
|
41
39
|
/** Exit codes used by cli-agent-mode. */
|
|
42
|
-
declare const EXIT: {
|
|
40
|
+
export declare const EXIT: {
|
|
43
41
|
readonly OK: 0;
|
|
44
42
|
readonly ERROR: 1;
|
|
45
43
|
readonly USAGE: 2;
|
|
46
44
|
};
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/agent-mode.d.ts
|
|
49
45
|
interface AgentModeOptions {
|
|
50
46
|
/** Switch to JSON automatically when an AI agent is detected (AI_AGENT, CLAUDECODE, CURSOR_AGENT, ...). Default: true. */
|
|
51
47
|
autoDetect?: boolean;
|
|
@@ -83,11 +79,9 @@ interface RunResult {
|
|
|
83
79
|
* program.command('deploy <env>').action(async (env) => ({ url: `https://${env}.example.com` }));
|
|
84
80
|
* await run(program);
|
|
85
81
|
*/
|
|
86
|
-
declare function agentMode<T extends Command>(program: T, options?: AgentModeOptions): T;
|
|
82
|
+
export declare function agentMode<T extends Command>(program: T, options?: AgentModeOptions): T;
|
|
87
83
|
/** Parse arguments, run the matching action and print the result or error in the right format. */
|
|
88
|
-
declare function run(program: Command, runOptions?: RunOptions): Promise<RunResult>;
|
|
89
|
-
//#endregion
|
|
90
|
-
//#region src/describe.d.ts
|
|
84
|
+
export declare function run(program: Command, runOptions?: RunOptions): Promise<RunResult>;
|
|
91
85
|
interface ArgumentSchema {
|
|
92
86
|
name: string;
|
|
93
87
|
description?: string;
|
|
@@ -119,17 +113,14 @@ interface CommandSchema {
|
|
|
119
113
|
commands?: CommandSchema[];
|
|
120
114
|
}
|
|
121
115
|
/** Compact JSON schema of a command and all of its visible subcommands. */
|
|
122
|
-
declare function describeCommand(cmd: Command): CommandSchema;
|
|
116
|
+
export declare function describeCommand(cmd: Command): CommandSchema;
|
|
123
117
|
/** Resolve `["deploy", "preview"]` to the nested subcommand (by name or alias). */
|
|
124
|
-
declare function findCommand(root: Command, path: string[]): Command | undefined;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/detect.d.ts
|
|
118
|
+
export declare function findCommand(root: Command, path: string[]): Command | undefined;
|
|
127
119
|
/**
|
|
128
120
|
* Synchronous, dependency-free detection of AI coding agents.
|
|
129
121
|
* Env variables mirror @vercel/detect-agent (Nov 2026) plus the `AI_AGENT` convention.
|
|
130
122
|
* CURSOR_TRACE_ID is deliberately ignored: it is also set in Cursor's terminal for humans.
|
|
131
123
|
* Returns the agent name or `undefined`.
|
|
132
124
|
*/
|
|
133
|
-
declare function detectAgent(env?: NodeJS.ProcessEnv): string | undefined;
|
|
134
|
-
|
|
135
|
-
export { AgentError, type AgentErrorOptions, type AgentModeOptions, type ArgumentSchema, type CommandSchema, EXIT, type Envelope, type ErrorPayload, type OptionSchema, type RunOptions, type RunResult, agentMode, describeCommand, detectAgent, findCommand, run };
|
|
125
|
+
export declare function detectAgent(env?: NodeJS.ProcessEnv): string | undefined;
|
|
126
|
+
export type { AgentErrorOptions, AgentModeOptions, ArgumentSchema, CommandSchema, Envelope, ErrorPayload, OptionSchema, RunOptions, RunResult };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommanderError } from "commander";
|
|
2
2
|
import { format } from "node:util";
|
|
3
|
-
|
|
3
|
+
// src/detect.ts
|
|
4
4
|
/**
|
|
5
5
|
* Synchronous, dependency-free detection of AI coding agents.
|
|
6
6
|
* Env variables mirror @vercel/detect-agent (Nov 2026) plus the `AI_AGENT` convention.
|
|
@@ -20,8 +20,7 @@ function detectAgent(env = process.env) {
|
|
|
20
20
|
if (env.COPILOT_MODEL || env.COPILOT_ALLOW_ALL) return "github-copilot";
|
|
21
21
|
if (env.REPL_ID) return "replit";
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
//#region src/describe.ts
|
|
23
|
+
// src/describe.ts
|
|
25
24
|
const clean = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== "" && v !== false && !(Array.isArray(v) && v.length === 0)));
|
|
26
25
|
function describeArgument(a) {
|
|
27
26
|
return clean({
|
|
@@ -70,8 +69,7 @@ function findCommand(root, path) {
|
|
|
70
69
|
}
|
|
71
70
|
return cur;
|
|
72
71
|
}
|
|
73
|
-
|
|
74
|
-
//#region src/errors.ts
|
|
72
|
+
// src/errors.ts
|
|
75
73
|
/**
|
|
76
74
|
* An error with a stable machine-readable `code`.
|
|
77
75
|
*
|
|
@@ -100,9 +98,9 @@ const EXIT = {
|
|
|
100
98
|
ERROR: 1,
|
|
101
99
|
USAGE: 2
|
|
102
100
|
};
|
|
103
|
-
|
|
104
|
-
//#region src/agent-mode.ts
|
|
101
|
+
// src/agent-mode.ts
|
|
105
102
|
const states = /* @__PURE__ */ new WeakMap();
|
|
103
|
+
const hooked = /* @__PURE__ */ new WeakSet();
|
|
106
104
|
const rootOf = (cmd) => {
|
|
107
105
|
let c = cmd;
|
|
108
106
|
while (c.parent) c = c.parent;
|
|
@@ -197,11 +195,18 @@ async function run(program, runOptions = {}) {
|
|
|
197
195
|
const json = runOptions.json ?? (extracted.json || (forced ?? (state.options.autoDetect && detectAgent(env) !== void 0)));
|
|
198
196
|
const mode = json ? "json" : "human";
|
|
199
197
|
let outBuf = "";
|
|
200
|
-
|
|
198
|
+
state.current = program;
|
|
201
199
|
const restore = [];
|
|
202
200
|
walk(program, (cmd) => {
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
if (!hooked.has(cmd)) {
|
|
202
|
+
hooked.add(cmd);
|
|
203
|
+
cmd.hook("preSubcommand", (_parent, sub) => {
|
|
204
|
+
const s = states.get(rootOf(sub));
|
|
205
|
+
if (s) s.current = sub;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const prevOutput = { ...cmd.configureOutput() };
|
|
209
|
+
const prevHelp = { ...cmd.configureHelp() };
|
|
205
210
|
restore.push(() => {
|
|
206
211
|
cmd.configureOutput(prevOutput);
|
|
207
212
|
cmd.configureHelp(prevHelp);
|
|
@@ -212,7 +217,6 @@ async function run(program, runOptions = {}) {
|
|
|
212
217
|
writeOut: (s) => json ? outBuf += s : stdout.write(s),
|
|
213
218
|
writeErr: (s) => json ? void 0 : stderr.write(s),
|
|
214
219
|
outputError: (s, write) => {
|
|
215
|
-
errorCommand = cmd;
|
|
216
220
|
if (!json) write(s);
|
|
217
221
|
}
|
|
218
222
|
});
|
|
@@ -263,7 +267,7 @@ async function run(program, runOptions = {}) {
|
|
|
263
267
|
exitCode = EXIT.OK;
|
|
264
268
|
if (!json) printed = true;
|
|
265
269
|
} else {
|
|
266
|
-
const { payload, code } = toPayload(err, program,
|
|
270
|
+
const { payload, code } = toPayload(err, program, state.current ?? program, state.options.describeCommand);
|
|
267
271
|
envelope = {
|
|
268
272
|
ok: false,
|
|
269
273
|
error: payload
|
|
@@ -326,5 +330,4 @@ function toPayload(err, root, at, describeName) {
|
|
|
326
330
|
};
|
|
327
331
|
}
|
|
328
332
|
const strip = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
329
|
-
//#endregion
|
|
330
333
|
export { AgentError, EXIT, agentMode, describeCommand, detectAgent, findCommand, run };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cli-agent-mode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Make any commander.js CLI agent-friendly: --json output envelopes, machine-readable errors with suggestions, a `describe` command that emits the CLI schema, and stable exit codes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
27
|
+
"node": ">=22"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "tsdown src/index.ts --dts --format esm,cjs && node scripts/postbuild.mjs",
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
"commander": ">=12"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^20.
|
|
40
|
-
"commander": "^
|
|
41
|
-
"tsdown": "^0.
|
|
39
|
+
"@types/node": "^22.20.5",
|
|
40
|
+
"commander": "^15.1.0",
|
|
41
|
+
"tsdown": "^0.23.7",
|
|
42
42
|
"tsx": "^4.23.15",
|
|
43
|
-
"typescript": "^
|
|
44
|
-
"vitest": "^
|
|
43
|
+
"typescript": "^7.0.2",
|
|
44
|
+
"vitest": "^5.1.0"
|
|
45
45
|
},
|
|
46
46
|
"repository": {
|
|
47
47
|
"type": "git",
|
|
@@ -65,5 +65,9 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"main": "./dist/index.cjs",
|
|
68
|
-
"types": "./dist/index.d.cts"
|
|
68
|
+
"types": "./dist/index.d.cts",
|
|
69
|
+
"allowScripts": {
|
|
70
|
+
"esbuild": false,
|
|
71
|
+
"fsevents": false
|
|
72
|
+
}
|
|
69
73
|
}
|