@memberjunction/cli-core 6.1.0-edge.3 → 6.1.0-edge.5
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/base-cli-plugin.d.ts +30 -4
- package/dist/base-cli-plugin.d.ts.map +1 -1
- package/dist/base-cli-plugin.js +60 -9
- package/dist/base-cli-plugin.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +115 -0
- package/dist/interaction.d.ts.map +1 -0
- package/dist/interaction.js +182 -0
- package/dist/interaction.js.map +1 -0
- package/dist/output-format.d.ts +58 -0
- package/dist/output-format.d.ts.map +1 -0
- package/dist/output-format.js +67 -0
- package/dist/output-format.js.map +1 -0
- package/dist/plugin-registry.d.ts +19 -0
- package/dist/plugin-registry.d.ts.map +1 -1
- package/dist/plugin-registry.js +28 -0
- package/dist/plugin-registry.js.map +1 -1
- package/dist/runtime-host.d.ts +20 -2
- package/dist/runtime-host.d.ts.map +1 -1
- package/dist/runtime-host.js +29 -4
- package/dist/runtime-host.js.map +1 -1
- package/dist/serialize.d.ts +18 -2
- package/dist/serialize.d.ts.map +1 -1
- package/dist/serialize.js +17 -6
- package/dist/serialize.js.map +1 -1
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +29 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import type
|
|
2
|
+
import { type IMJCLIRuntimeHost, type MJCLIResult, type PluginUsage } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Abstract base for every pluggable `mj` command (plan D1/D2).
|
|
5
5
|
*
|
|
@@ -9,9 +9,19 @@ import type { IMJCLIRuntimeHost, MJCLIResult, PluginUsage } from './types.js';
|
|
|
9
9
|
* shared {@link BaseCLIPlugin.run} wires up the {@link IMJCLIRuntimeHost}, emits
|
|
10
10
|
* the runtime advisory, renders the result per `--format`, and sets the exit code.
|
|
11
11
|
*
|
|
12
|
-
* The global flags `--format`, `--verbose`,
|
|
13
|
-
* {@link BaseCLIPlugin.baseFlags} and inherited by every subclass
|
|
14
|
-
* native `baseFlags` merging — no per-command duplication (plan D3).
|
|
12
|
+
* The global flags `--format`, `--verbose`, `--no-banner`, and `--interactive`
|
|
13
|
+
* are declared on {@link BaseCLIPlugin.baseFlags} and inherited by every subclass
|
|
14
|
+
* via oclif's native `baseFlags` merging — no per-command duplication (plan D3).
|
|
15
|
+
*
|
|
16
|
+
* Two defaults are inferred here rather than declared per command, so that a human
|
|
17
|
+
* and an agent each get the right behaviour without either having to ask for it:
|
|
18
|
+
* - **Format follows the pipe.** With no explicit `--format`, a non-TTY stdout
|
|
19
|
+
* resolves to `json`. A caller that redirected stdout has already said it is a
|
|
20
|
+
* machine; it should not also have to remember a flag.
|
|
21
|
+
* - **Prompting follows the terminal.** {@link BaseCLIPlugin.Interactive} is true at a
|
|
22
|
+
* real terminal and false when piped, spawned, or running in CI. A
|
|
23
|
+
* {@link NonInteractiveError} escaping `Execute` is rendered as a structured,
|
|
24
|
+
* actionable result rather than a stack trace.
|
|
15
25
|
*/
|
|
16
26
|
export declare abstract class BaseCLIPlugin extends Command {
|
|
17
27
|
/** Inherited by every subclass through oclif's static `baseFlags` mechanism. */
|
|
@@ -19,6 +29,7 @@ export declare abstract class BaseCLIPlugin extends Command {
|
|
|
19
29
|
format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
30
|
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
31
|
'no-banner': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
32
|
+
interactive: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
22
33
|
};
|
|
23
34
|
/**
|
|
24
35
|
* Every plugin declares its own usage + runtime metadata. The CLI root reads
|
|
@@ -28,6 +39,13 @@ export declare abstract class BaseCLIPlugin extends Command {
|
|
|
28
39
|
*/
|
|
29
40
|
static Usage: PluginUsage;
|
|
30
41
|
protected Host: IMJCLIRuntimeHost;
|
|
42
|
+
/**
|
|
43
|
+
* Whether this run may prompt — detected from the terminal unless `--interactive` /
|
|
44
|
+
* `--no-interactive` says otherwise. Subclasses pass this into `ResolveOrPrompt`
|
|
45
|
+
* rather than calling `@inquirer` directly, so a missing value fails fast with the
|
|
46
|
+
* flag to pass instead of blocking on stdin.
|
|
47
|
+
*/
|
|
48
|
+
protected Interactive: boolean;
|
|
31
49
|
/** Parsed flags, captured once in {@link run}; read via {@link GetFlags}. */
|
|
32
50
|
private parsedFlags;
|
|
33
51
|
/**
|
|
@@ -45,6 +63,14 @@ export declare abstract class BaseCLIPlugin extends Command {
|
|
|
45
63
|
* oclif entry point — do NOT override in subclasses. Override {@link Execute}.
|
|
46
64
|
*/
|
|
47
65
|
run(): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Runs {@link BaseCLIPlugin.Execute}, converting a {@link NonInteractiveError} into a
|
|
68
|
+
* normal failed result. A command that asked for a value it wasn't given has NOT
|
|
69
|
+
* crashed — it has a precise, recoverable complaint, and an agent gets far more from
|
|
70
|
+
* `{code:'E_NON_INTERACTIVE', suggestion:'Pass --entity …'}` than from a stack trace.
|
|
71
|
+
* Every other error keeps propagating to oclif untouched.
|
|
72
|
+
*/
|
|
73
|
+
private RunExecute;
|
|
48
74
|
/**
|
|
49
75
|
* Optional post-Emit hook. Override to release resources (DB pools, singletons)
|
|
50
76
|
* and, when necessary, `process.exit()` to terminate lingering background work.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-cli-plugin.d.ts","sourceRoot":"","sources":["../src/base-cli-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"base-cli-plugin.d.ts","sourceRoot":"","sources":["../src/base-cli-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAC;AAI7C,OAAO,EAAmB,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,8BAAsB,aAAc,SAAQ,OAAO;IACjD,gFAAgF;IAChF,OAAgB,SAAS;;;;;MAevB;IAEF;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC;IAE1B,SAAS,CAAC,IAAI,EAAG,iBAAiB,CAAC;IAEnC;;;;;OAKG;IACH,SAAS,CAAC,WAAW,UAAS;IAE9B,6EAA6E;IAC7E,OAAO,CAAC,WAAW,CAAU;IAE7B;;;;;;;;;OASG;IACH,SAAS,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IAI1B;;OAEG;IACG,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC1B;;;;;;OAMG;YACW,UAAU;IAcxB;;;OAGG;cACa,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,+DAA+D;IAC/D,SAAS,CAAC,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;CACnD"}
|
package/dist/base-cli-plugin.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { MJCLIRuntimeHost } from './runtime-host.js';
|
|
3
|
+
import { ResolveOutputFormat } from './output-format.js';
|
|
4
|
+
import { NonInteractiveError, ResolveInteractivity } from './interaction.js';
|
|
5
|
+
import { MJCLIErrorCodes } from './types.js';
|
|
3
6
|
/**
|
|
4
7
|
* Abstract base for every pluggable `mj` command (plan D1/D2).
|
|
5
8
|
*
|
|
@@ -9,20 +12,45 @@ import { MJCLIRuntimeHost } from './runtime-host.js';
|
|
|
9
12
|
* shared {@link BaseCLIPlugin.run} wires up the {@link IMJCLIRuntimeHost}, emits
|
|
10
13
|
* the runtime advisory, renders the result per `--format`, and sets the exit code.
|
|
11
14
|
*
|
|
12
|
-
* The global flags `--format`, `--verbose`,
|
|
13
|
-
* {@link BaseCLIPlugin.baseFlags} and inherited by every subclass
|
|
14
|
-
* native `baseFlags` merging — no per-command duplication (plan D3).
|
|
15
|
+
* The global flags `--format`, `--verbose`, `--no-banner`, and `--interactive`
|
|
16
|
+
* are declared on {@link BaseCLIPlugin.baseFlags} and inherited by every subclass
|
|
17
|
+
* via oclif's native `baseFlags` merging — no per-command duplication (plan D3).
|
|
18
|
+
*
|
|
19
|
+
* Two defaults are inferred here rather than declared per command, so that a human
|
|
20
|
+
* and an agent each get the right behaviour without either having to ask for it:
|
|
21
|
+
* - **Format follows the pipe.** With no explicit `--format`, a non-TTY stdout
|
|
22
|
+
* resolves to `json`. A caller that redirected stdout has already said it is a
|
|
23
|
+
* machine; it should not also have to remember a flag.
|
|
24
|
+
* - **Prompting follows the terminal.** {@link BaseCLIPlugin.Interactive} is true at a
|
|
25
|
+
* real terminal and false when piped, spawned, or running in CI. A
|
|
26
|
+
* {@link NonInteractiveError} escaping `Execute` is rendered as a structured,
|
|
27
|
+
* actionable result rather than a stack trace.
|
|
15
28
|
*/
|
|
16
29
|
export class BaseCLIPlugin extends Command {
|
|
30
|
+
constructor() {
|
|
31
|
+
super(...arguments);
|
|
32
|
+
/**
|
|
33
|
+
* Whether this run may prompt — detected from the terminal unless `--interactive` /
|
|
34
|
+
* `--no-interactive` says otherwise. Subclasses pass this into `ResolveOrPrompt`
|
|
35
|
+
* rather than calling `@inquirer` directly, so a missing value fails fast with the
|
|
36
|
+
* flag to pass instead of blocking on stdin.
|
|
37
|
+
*/
|
|
38
|
+
this.Interactive = false;
|
|
39
|
+
}
|
|
17
40
|
/** Inherited by every subclass through oclif's static `baseFlags` mechanism. */
|
|
18
41
|
static { this.baseFlags = {
|
|
19
42
|
format: Flags.string({
|
|
20
|
-
options: ['text', 'json', 'md'],
|
|
21
|
-
|
|
22
|
-
|
|
43
|
+
options: ['text', 'json', 'md', 'human', 'console', 'markdown'],
|
|
44
|
+
description: 'Output format: text (human), json (machine-readable), md (Markdown-fenced). ' +
|
|
45
|
+
'Defaults to text on a terminal and json when stdout is piped.',
|
|
23
46
|
}),
|
|
24
47
|
verbose: Flags.boolean({ char: 'v', default: false, description: 'Show detailed output' }),
|
|
25
48
|
'no-banner': Flags.boolean({ default: false, description: 'Suppress the startup banner and runtime advisory' }),
|
|
49
|
+
interactive: Flags.boolean({
|
|
50
|
+
allowNo: true,
|
|
51
|
+
description: 'Allow interactive prompts. Defaults to on at a terminal and off when piped, spawned, or in CI, ' +
|
|
52
|
+
'so an agent never hangs on a question. Use --no-interactive to force it off.',
|
|
53
|
+
}),
|
|
26
54
|
}; }
|
|
27
55
|
/**
|
|
28
56
|
* The flags parsed for this command. Subclasses call this in {@link Execute}
|
|
@@ -47,16 +75,17 @@ export class BaseCLIPlugin extends Command {
|
|
|
47
75
|
const { flags } = await this.parse(ctor);
|
|
48
76
|
this.parsedFlags = flags;
|
|
49
77
|
const f = flags;
|
|
50
|
-
const format = f.format
|
|
78
|
+
const { format } = ResolveOutputFormat({ formatFlag: f.format });
|
|
51
79
|
const verbose = !!f.verbose;
|
|
52
80
|
const noBanner = !!f['no-banner'];
|
|
53
|
-
this.
|
|
81
|
+
this.Interactive = ResolveInteractivity({ interactiveFlag: f.interactive }).interactive;
|
|
82
|
+
this.Host = new MJCLIRuntimeHost(format, verbose, noBanner, { interactive: this.Interactive });
|
|
54
83
|
// Announce runtime expectation up front (stderr in JSON mode) so an agent
|
|
55
84
|
// reading the stream can budget its timeout — see plan §5/§6.
|
|
56
85
|
if (ctor.Usage) {
|
|
57
86
|
this.Host.AnnounceRuntime(ctor.Usage);
|
|
58
87
|
}
|
|
59
|
-
const result = await this.
|
|
88
|
+
const result = await this.RunExecute(ctor);
|
|
60
89
|
this.Host.Emit(result);
|
|
61
90
|
// Optional cleanup hook (e.g. close DB pools, reset singletons). Runs after
|
|
62
91
|
// Emit so the result is always rendered even when cleanup hard-exits.
|
|
@@ -67,6 +96,28 @@ export class BaseCLIPlugin extends Command {
|
|
|
67
96
|
this.exit(1);
|
|
68
97
|
}
|
|
69
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Runs {@link BaseCLIPlugin.Execute}, converting a {@link NonInteractiveError} into a
|
|
101
|
+
* normal failed result. A command that asked for a value it wasn't given has NOT
|
|
102
|
+
* crashed — it has a precise, recoverable complaint, and an agent gets far more from
|
|
103
|
+
* `{code:'E_NON_INTERACTIVE', suggestion:'Pass --entity …'}` than from a stack trace.
|
|
104
|
+
* Every other error keeps propagating to oclif untouched.
|
|
105
|
+
*/
|
|
106
|
+
async RunExecute(ctor) {
|
|
107
|
+
try {
|
|
108
|
+
return await this.Execute();
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
if (!(e instanceof NonInteractiveError))
|
|
112
|
+
throw e;
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
command: ctor.Usage?.command ?? this.id ?? 'unknown',
|
|
116
|
+
durationSeconds: 0,
|
|
117
|
+
errors: [{ message: e.message, code: MJCLIErrorCodes.NonInteractive, suggestion: e.suggestion }],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
70
121
|
/**
|
|
71
122
|
* Optional post-Emit hook. Override to release resources (DB pools, singletons)
|
|
72
123
|
* and, when necessary, `process.exit()` to terminate lingering background work.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-cli-plugin.js","sourceRoot":"","sources":["../src/base-cli-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"base-cli-plugin.js","sourceRoot":"","sources":["../src/base-cli-plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
2
|
export { MJCLIRuntimeHost } from './runtime-host.js';
|
|
3
|
+
export type { RuntimeHostOptions } from './runtime-host.js';
|
|
3
4
|
export { BaseCLIPlugin } from './base-cli-plugin.js';
|
|
4
5
|
export { SerializeResult } from './serialize.js';
|
|
6
|
+
export type { SerializeOptions } from './serialize.js';
|
|
7
|
+
export { ResolveOutputFormat, NormalizeFormatAlias, ShouldSuppressChrome, FORMAT_ENV, } from './output-format.js';
|
|
8
|
+
export type { FormatResolutionInput, FormatResolution } from './output-format.js';
|
|
9
|
+
export { ResolveInteractivity, ResolveOrPrompt, RequireInteractive, NonInteractiveError, INTERACTIVE_ENV, NON_INTERACTIVE_CODE, } from './interaction.js';
|
|
10
|
+
export type { InteractivityInput, InteractivityDecision, InteractivityReason, ResolveOrPromptOptions, } from './interaction.js';
|
|
5
11
|
export { CLIPluginRegistry, PLUGIN_CONFIG_FILENAME, } from './plugin-registry.js';
|
|
6
12
|
export type { UsageDomainSummary, UsageDomainMap, UsageDomainDetail, PluginLoadResult, } from './plugin-registry.js';
|
|
7
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,5 +2,7 @@ export * from './types.js';
|
|
|
2
2
|
export { MJCLIRuntimeHost } from './runtime-host.js';
|
|
3
3
|
export { BaseCLIPlugin } from './base-cli-plugin.js';
|
|
4
4
|
export { SerializeResult } from './serialize.js';
|
|
5
|
+
export { ResolveOutputFormat, NormalizeFormatAlias, ShouldSuppressChrome, FORMAT_ENV, } from './output-format.js';
|
|
6
|
+
export { ResolveInteractivity, ResolveOrPrompt, RequireInteractive, NonInteractiveError, INTERACTIVE_ENV, NON_INTERACTIVE_CODE, } from './interaction.js';
|
|
5
7
|
export { CLIPluginRegistry, PLUGIN_CONFIG_FILENAME, } from './plugin-registry.js';
|
|
6
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAOvB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forces interactivity on (`1`/`true`) or off (`0`/`false`) for a whole shell session,
|
|
3
|
+
* overriding TTY detection. An agent harness that shells out through a pty should set
|
|
4
|
+
* this to `0` so its subprocesses can never block on a question.
|
|
5
|
+
*/
|
|
6
|
+
export declare const INTERACTIVE_ENV = "MJ_CLI_INTERACTIVE";
|
|
7
|
+
/**
|
|
8
|
+
* Stable code carried by {@link NonInteractiveError} and its result-envelope entry.
|
|
9
|
+
* Re-exported from the {@link MJCLIErrorCodes} catalog rather than restated, so the
|
|
10
|
+
* error thrown here and the `code` an agent branches on can never drift apart.
|
|
11
|
+
*/
|
|
12
|
+
export declare const NON_INTERACTIVE_CODE: "E_NON_INTERACTIVE";
|
|
13
|
+
/** Inputs to {@link ResolveInteractivity}. Every field is injectable for tests. */
|
|
14
|
+
export interface InteractivityInput {
|
|
15
|
+
/**
|
|
16
|
+
* The `--interactive` / `--no-interactive` flag value, when the caller passed one.
|
|
17
|
+
* `undefined` means "not specified" — that is what lets detection run.
|
|
18
|
+
*/
|
|
19
|
+
interactiveFlag?: boolean;
|
|
20
|
+
/** Defaults to `process.env`. */
|
|
21
|
+
env?: NodeJS.ProcessEnv;
|
|
22
|
+
/** Defaults to `process.stdin.isTTY`. A prompt needs a real stdin to read from. */
|
|
23
|
+
stdinIsTTY?: boolean;
|
|
24
|
+
/** Defaults to `process.stdout.isTTY`. A prompt needs a real stdout to render on. */
|
|
25
|
+
stdoutIsTTY?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Why this run may or may not prompt. Machine-stable, so errors and tests can use it. */
|
|
28
|
+
export type InteractivityReason =
|
|
29
|
+
/** `--no-interactive` was passed. */
|
|
30
|
+
'flag-off'
|
|
31
|
+
/** `--interactive` was passed and there is a usable terminal. */
|
|
32
|
+
| 'flag-on'
|
|
33
|
+
/** {@link INTERACTIVE_ENV} is `0`/`false`. */
|
|
34
|
+
| 'env-off'
|
|
35
|
+
/** {@link INTERACTIVE_ENV} is `1`/`true` and there is a usable terminal. */
|
|
36
|
+
| 'env-on'
|
|
37
|
+
/** No terminal on stdin and/or stdout — piped, redirected, or spawned. */
|
|
38
|
+
| 'no-tty'
|
|
39
|
+
/** A terminal is present, but a CI environment variable says this is a build. */
|
|
40
|
+
| 'ci'
|
|
41
|
+
/** `TERM=dumb` — a terminal that cannot render a prompt. */
|
|
42
|
+
| 'dumb-terminal'
|
|
43
|
+
/** A real terminal with nothing indicating otherwise: a human is presumed present. */
|
|
44
|
+
| 'tty-detected';
|
|
45
|
+
/** The decision plus the rule that produced it. */
|
|
46
|
+
export interface InteractivityDecision {
|
|
47
|
+
interactive: boolean;
|
|
48
|
+
reason: InteractivityReason;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Decides whether this run may prompt, most explicit signal first:
|
|
52
|
+
*
|
|
53
|
+
* 1. `--no-interactive` → never
|
|
54
|
+
* 2. `--interactive` → yes, if there is a terminal to prompt on
|
|
55
|
+
* 3. {@link INTERACTIVE_ENV} → the same, one level down
|
|
56
|
+
* 4. no terminal on stdin or stdout → never
|
|
57
|
+
* 5. a CI environment variable is set → never
|
|
58
|
+
* 6. `TERM=dumb` → never
|
|
59
|
+
* 7. otherwise → yes; a real terminal means a human
|
|
60
|
+
*
|
|
61
|
+
* Note the asymmetry at steps 2 and 3: asking for interactivity without a terminal
|
|
62
|
+
* resolves to NON-interactive with reason `no-tty` rather than throwing. The caller
|
|
63
|
+
* is then free to fail at the exact point a value is missing, which is far more
|
|
64
|
+
* actionable than a blanket "no TTY" error at startup.
|
|
65
|
+
*/
|
|
66
|
+
export declare function ResolveInteractivity(input?: InteractivityInput): InteractivityDecision;
|
|
67
|
+
/**
|
|
68
|
+
* Thrown when a command needs a value it wasn't given and isn't allowed to ask for.
|
|
69
|
+
*
|
|
70
|
+
* Carries the two fields an agent needs to recover unaided: a stable
|
|
71
|
+
* {@link NonInteractiveError.code} to branch on, and a {@link NonInteractiveError.suggestion}
|
|
72
|
+
* naming the exact flag to pass. `MJCLIResultError` mirrors both, so a plugin can put
|
|
73
|
+
* this straight into its result envelope.
|
|
74
|
+
*/
|
|
75
|
+
export declare class NonInteractiveError extends Error {
|
|
76
|
+
/** Always {@link NON_INTERACTIVE_CODE}. */
|
|
77
|
+
readonly code: "E_NON_INTERACTIVE";
|
|
78
|
+
/** The concrete remedy, e.g. `Pass --entity "MJ: AI Prompts".` */
|
|
79
|
+
readonly suggestion: string;
|
|
80
|
+
/** Why prompting was refused — from {@link InteractivityDecision.reason}. */
|
|
81
|
+
readonly reason: InteractivityReason;
|
|
82
|
+
constructor(what: string, suggestion: string, reason: InteractivityReason);
|
|
83
|
+
}
|
|
84
|
+
/** Options for {@link ResolveOrPrompt}. */
|
|
85
|
+
export interface ResolveOrPromptOptions<T> {
|
|
86
|
+
/**
|
|
87
|
+
* The value already supplied by a flag. Any value other than `undefined` wins
|
|
88
|
+
* outright — including `false` and `''`, which are legitimate answers.
|
|
89
|
+
*/
|
|
90
|
+
flagValue: T | undefined;
|
|
91
|
+
/** Asks the human. Only ever invoked when {@link ResolveInteractivity} allows it. */
|
|
92
|
+
prompt: () => Promise<T>;
|
|
93
|
+
/** What is being asked for, for the error message — e.g. `An entity name`. */
|
|
94
|
+
what: string;
|
|
95
|
+
/** The exact remedy, e.g. `Pass --entity "MJ: AI Prompts".` */
|
|
96
|
+
suggestion: string;
|
|
97
|
+
/** Interactivity state; defaults to reading the env/TTY. */
|
|
98
|
+
interactivity?: InteractivityInput;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The single choke point every prompt in the CLI goes through.
|
|
102
|
+
*
|
|
103
|
+
* Resolution order: an explicit flag wins; otherwise prompt if this run is allowed to;
|
|
104
|
+
* otherwise throw {@link NonInteractiveError} naming the flag. A command that routes all
|
|
105
|
+
* its prompts through this can never hang an agent, and still behaves exactly as before
|
|
106
|
+
* for a human at a terminal.
|
|
107
|
+
*/
|
|
108
|
+
export declare function ResolveOrPrompt<T>(options: ResolveOrPromptOptions<T>): Promise<T>;
|
|
109
|
+
/**
|
|
110
|
+
* Guards a whole command (rather than one value) that is interactive by nature — e.g.
|
|
111
|
+
* the setup wizard, which asks two dozen questions with no flag equivalents. Throws
|
|
112
|
+
* {@link NonInteractiveError} unless this run may prompt.
|
|
113
|
+
*/
|
|
114
|
+
export declare function RequireInteractive(what: string, suggestion: string, interactivity?: InteractivityInput): void;
|
|
115
|
+
//# sourceMappingURL=interaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../src/interaction.ts"],"names":[],"mappings":"AAoBA;;;;GAIG;AACH,eAAO,MAAM,eAAe,uBAAuB,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,qBAAiC,CAAC;AAoBnE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qFAAqF;IACrF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,0FAA0F;AAC1F,MAAM,MAAM,mBAAmB;AAC7B,qCAAqC;AACnC,UAAU;AACZ,iEAAiE;GAC/D,SAAS;AACX,8CAA8C;GAC5C,SAAS;AACX,4EAA4E;GAC1E,QAAQ;AACV,0EAA0E;GACxE,QAAQ;AACV,iFAAiF;GAC/E,IAAI;AACN,4DAA4D;GAC1D,eAAe;AACjB,sFAAsF;GACpF,cAAc,CAAC;AAEnB,mDAAmD;AACnD,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAkBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,GAAE,kBAAuB,GAAG,qBAAqB,CAsB1F;AAmCD;;;;;;;GAOG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,2CAA2C;IAC3C,SAAgB,IAAI,sBAAwB;IAC5C,kEAAkE;IAClE,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,6EAA6E;IAC7E,SAAgB,MAAM,EAAE,mBAAmB,CAAC;gBAEhC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;CAM1E;AAED,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC;;;OAGG;IACH,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC;IACzB,qFAAqF;IACrF,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOvF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAG7G"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactivity resolution: detect whether a human is actually present, and let
|
|
3
|
+
* either side say otherwise explicitly.
|
|
4
|
+
*
|
|
5
|
+
* A prompt is a blocking question. A human at a terminal can answer one; an agent,
|
|
6
|
+
* a CI job, or a container cannot, and under the old behaviour it simply hung on
|
|
7
|
+
* stdin with no output explaining why. The fix is not to take prompting away from
|
|
8
|
+
* humans — it is to stop *assuming* one is there.
|
|
9
|
+
*
|
|
10
|
+
* So the default is inferred rather than fixed: a real terminal on both stdin and
|
|
11
|
+
* stdout means a human, and everything else means automation. `--interactive` and
|
|
12
|
+
* `--no-interactive` (plus {@link INTERACTIVE_ENV}) override the inference in either
|
|
13
|
+
* direction. When a command needs a value it wasn't given and may not ask for it, it
|
|
14
|
+
* **fails fast naming the flag** instead of waiting on stdin.
|
|
15
|
+
*
|
|
16
|
+
* Both entry points here are pure functions over injected state — no direct
|
|
17
|
+
* `process` reads — so a test can drive every branch without a real TTY.
|
|
18
|
+
*/
|
|
19
|
+
import { MJCLIErrorCodes } from './types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Forces interactivity on (`1`/`true`) or off (`0`/`false`) for a whole shell session,
|
|
22
|
+
* overriding TTY detection. An agent harness that shells out through a pty should set
|
|
23
|
+
* this to `0` so its subprocesses can never block on a question.
|
|
24
|
+
*/
|
|
25
|
+
export const INTERACTIVE_ENV = 'MJ_CLI_INTERACTIVE';
|
|
26
|
+
/**
|
|
27
|
+
* Stable code carried by {@link NonInteractiveError} and its result-envelope entry.
|
|
28
|
+
* Re-exported from the {@link MJCLIErrorCodes} catalog rather than restated, so the
|
|
29
|
+
* error thrown here and the `code` an agent branches on can never drift apart.
|
|
30
|
+
*/
|
|
31
|
+
export const NON_INTERACTIVE_CODE = MJCLIErrorCodes.NonInteractive;
|
|
32
|
+
/**
|
|
33
|
+
* Environment variables that mean "this is an automated build", checked when a TTY is
|
|
34
|
+
* present anyway (some runners allocate one). Any value other than the empty string,
|
|
35
|
+
* `0`, or `false` counts as set — CI systems variously use `true`, `1`, or their own name.
|
|
36
|
+
*/
|
|
37
|
+
const CI_ENV_VARS = [
|
|
38
|
+
'CI',
|
|
39
|
+
'CONTINUOUS_INTEGRATION',
|
|
40
|
+
'GITHUB_ACTIONS',
|
|
41
|
+
'GITLAB_CI',
|
|
42
|
+
'BUILDKITE',
|
|
43
|
+
'CIRCLECI',
|
|
44
|
+
'TRAVIS',
|
|
45
|
+
'TEAMCITY_VERSION',
|
|
46
|
+
'TF_BUILD',
|
|
47
|
+
'JENKINS_URL',
|
|
48
|
+
];
|
|
49
|
+
/** Treats `''`, `'0'`, and `'false'` as unset; anything else as set. */
|
|
50
|
+
function envFlagIsSet(value) {
|
|
51
|
+
if (value === undefined)
|
|
52
|
+
return false;
|
|
53
|
+
const v = value.trim().toLowerCase();
|
|
54
|
+
return v !== '' && v !== '0' && v !== 'false';
|
|
55
|
+
}
|
|
56
|
+
/** `1`/`true` → true, `0`/`false` → false, anything else (including unset) → undefined. */
|
|
57
|
+
function envTriState(value) {
|
|
58
|
+
if (value === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
const v = value.trim().toLowerCase();
|
|
61
|
+
if (v === '1' || v === 'true')
|
|
62
|
+
return true;
|
|
63
|
+
if (v === '0' || v === 'false')
|
|
64
|
+
return false;
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Decides whether this run may prompt, most explicit signal first:
|
|
69
|
+
*
|
|
70
|
+
* 1. `--no-interactive` → never
|
|
71
|
+
* 2. `--interactive` → yes, if there is a terminal to prompt on
|
|
72
|
+
* 3. {@link INTERACTIVE_ENV} → the same, one level down
|
|
73
|
+
* 4. no terminal on stdin or stdout → never
|
|
74
|
+
* 5. a CI environment variable is set → never
|
|
75
|
+
* 6. `TERM=dumb` → never
|
|
76
|
+
* 7. otherwise → yes; a real terminal means a human
|
|
77
|
+
*
|
|
78
|
+
* Note the asymmetry at steps 2 and 3: asking for interactivity without a terminal
|
|
79
|
+
* resolves to NON-interactive with reason `no-tty` rather than throwing. The caller
|
|
80
|
+
* is then free to fail at the exact point a value is missing, which is far more
|
|
81
|
+
* actionable than a blanket "no TTY" error at startup.
|
|
82
|
+
*/
|
|
83
|
+
export function ResolveInteractivity(input = {}) {
|
|
84
|
+
const env = input.env ?? process.env;
|
|
85
|
+
const stdinIsTTY = input.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
86
|
+
const stdoutIsTTY = input.stdoutIsTTY ?? process.stdout.isTTY === true;
|
|
87
|
+
const hasTerminal = stdinIsTTY && stdoutIsTTY;
|
|
88
|
+
if (input.interactiveFlag === false)
|
|
89
|
+
return { interactive: false, reason: 'flag-off' };
|
|
90
|
+
if (input.interactiveFlag === true) {
|
|
91
|
+
return hasTerminal ? { interactive: true, reason: 'flag-on' } : { interactive: false, reason: 'no-tty' };
|
|
92
|
+
}
|
|
93
|
+
const fromEnv = envTriState(env[INTERACTIVE_ENV]);
|
|
94
|
+
if (fromEnv === false)
|
|
95
|
+
return { interactive: false, reason: 'env-off' };
|
|
96
|
+
if (fromEnv === true) {
|
|
97
|
+
return hasTerminal ? { interactive: true, reason: 'env-on' } : { interactive: false, reason: 'no-tty' };
|
|
98
|
+
}
|
|
99
|
+
if (!hasTerminal)
|
|
100
|
+
return { interactive: false, reason: 'no-tty' };
|
|
101
|
+
if (CI_ENV_VARS.some((name) => envFlagIsSet(env[name])))
|
|
102
|
+
return { interactive: false, reason: 'ci' };
|
|
103
|
+
if (env.TERM?.trim().toLowerCase() === 'dumb')
|
|
104
|
+
return { interactive: false, reason: 'dumb-terminal' };
|
|
105
|
+
return { interactive: true, reason: 'tty-detected' };
|
|
106
|
+
}
|
|
107
|
+
/** Explains, in one clause, why prompting was refused — so the error can say it out loud. */
|
|
108
|
+
function describeReason(reason) {
|
|
109
|
+
switch (reason) {
|
|
110
|
+
case 'no-tty':
|
|
111
|
+
return 'this run has no interactive terminal';
|
|
112
|
+
case 'ci':
|
|
113
|
+
return 'this run looks like CI';
|
|
114
|
+
case 'dumb-terminal':
|
|
115
|
+
return 'this terminal cannot display a prompt (TERM=dumb)';
|
|
116
|
+
case 'flag-off':
|
|
117
|
+
return '--no-interactive was passed';
|
|
118
|
+
case 'env-off':
|
|
119
|
+
return `${INTERACTIVE_ENV} is set to off`;
|
|
120
|
+
default:
|
|
121
|
+
return 'this run is non-interactive';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** The "you could also just ask me" half of the message, omitted when it would be wrong. */
|
|
125
|
+
function describeRemedy(reason) {
|
|
126
|
+
// Telling someone to pass --interactive when there is no terminal to prompt on
|
|
127
|
+
// would send them in a circle.
|
|
128
|
+
switch (reason) {
|
|
129
|
+
case 'no-tty':
|
|
130
|
+
case 'dumb-terminal':
|
|
131
|
+
return '';
|
|
132
|
+
case 'flag-off':
|
|
133
|
+
return ' (Or drop --no-interactive to be prompted for it.)';
|
|
134
|
+
default:
|
|
135
|
+
return ' (Or pass --interactive to be prompted for it.)';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Thrown when a command needs a value it wasn't given and isn't allowed to ask for.
|
|
140
|
+
*
|
|
141
|
+
* Carries the two fields an agent needs to recover unaided: a stable
|
|
142
|
+
* {@link NonInteractiveError.code} to branch on, and a {@link NonInteractiveError.suggestion}
|
|
143
|
+
* naming the exact flag to pass. `MJCLIResultError` mirrors both, so a plugin can put
|
|
144
|
+
* this straight into its result envelope.
|
|
145
|
+
*/
|
|
146
|
+
export class NonInteractiveError extends Error {
|
|
147
|
+
constructor(what, suggestion, reason) {
|
|
148
|
+
super(`${what} is required and ${describeReason(reason)}. ${suggestion}${describeRemedy(reason)}`);
|
|
149
|
+
/** Always {@link NON_INTERACTIVE_CODE}. */
|
|
150
|
+
this.code = NON_INTERACTIVE_CODE;
|
|
151
|
+
this.name = 'NonInteractiveError';
|
|
152
|
+
this.suggestion = suggestion;
|
|
153
|
+
this.reason = reason;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The single choke point every prompt in the CLI goes through.
|
|
158
|
+
*
|
|
159
|
+
* Resolution order: an explicit flag wins; otherwise prompt if this run is allowed to;
|
|
160
|
+
* otherwise throw {@link NonInteractiveError} naming the flag. A command that routes all
|
|
161
|
+
* its prompts through this can never hang an agent, and still behaves exactly as before
|
|
162
|
+
* for a human at a terminal.
|
|
163
|
+
*/
|
|
164
|
+
export async function ResolveOrPrompt(options) {
|
|
165
|
+
if (options.flagValue !== undefined)
|
|
166
|
+
return options.flagValue;
|
|
167
|
+
const decision = ResolveInteractivity(options.interactivity);
|
|
168
|
+
if (decision.interactive)
|
|
169
|
+
return await options.prompt();
|
|
170
|
+
throw new NonInteractiveError(options.what, options.suggestion, decision.reason);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Guards a whole command (rather than one value) that is interactive by nature — e.g.
|
|
174
|
+
* the setup wizard, which asks two dozen questions with no flag equivalents. Throws
|
|
175
|
+
* {@link NonInteractiveError} unless this run may prompt.
|
|
176
|
+
*/
|
|
177
|
+
export function RequireInteractive(what, suggestion, interactivity) {
|
|
178
|
+
const decision = ResolveInteractivity(interactivity);
|
|
179
|
+
if (!decision.interactive)
|
|
180
|
+
throw new NonInteractiveError(what, suggestion, decision.reason);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=interaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction.js","sourceRoot":"","sources":["../src/interaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dual-output resolution: a human at a terminal gets text, a pipe gets JSON.
|
|
3
|
+
*
|
|
4
|
+
* The agent-facing failure this fixes is mundane and constant — `mj codegen | jq`
|
|
5
|
+
* used to hand `jq` a figlet banner and a spinner, because the machine format was
|
|
6
|
+
* only reachable by remembering `--format=json`. A caller that redirects stdout has
|
|
7
|
+
* already told us it is a machine; nothing further should be required of it.
|
|
8
|
+
*
|
|
9
|
+
* {@link ResolveOutputFormat} is a pure function over injected state so every
|
|
10
|
+
* precedence rule is testable without a real TTY.
|
|
11
|
+
*/
|
|
12
|
+
import type { OutputFormat } from './types.js';
|
|
13
|
+
/** Env var that pins the output format for a whole shell session. */
|
|
14
|
+
export declare const FORMAT_ENV = "MJ_CLI_FORMAT";
|
|
15
|
+
/** Inputs to {@link ResolveOutputFormat}. Every field is injectable for tests. */
|
|
16
|
+
export interface FormatResolutionInput {
|
|
17
|
+
/** Raw `--format` value, if the caller passed one. Accepts the aliases below. */
|
|
18
|
+
formatFlag?: string;
|
|
19
|
+
/** Legacy `--json` boolean, still declared by a few commands. */
|
|
20
|
+
jsonFlag?: boolean;
|
|
21
|
+
/** Defaults to `process.stdout.isTTY`. */
|
|
22
|
+
stdoutIsTTY?: boolean;
|
|
23
|
+
/** Defaults to `process.env`. */
|
|
24
|
+
env?: NodeJS.ProcessEnv;
|
|
25
|
+
}
|
|
26
|
+
/** The resolved format plus the rule that produced it (machine-stable, for tests and `--verbose`). */
|
|
27
|
+
export interface FormatResolution {
|
|
28
|
+
format: OutputFormat;
|
|
29
|
+
reason: 'format-flag' | 'json-flag' | 'env' | 'piped' | 'tty-default';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Canonicalizes the spellings different MJ command families grew independently.
|
|
33
|
+
*
|
|
34
|
+
* `mj test *` shipped `console|json|markdown`, `mj ai *` shipped `compact|json|table`,
|
|
35
|
+
* and the plugin commands shipped `text|json|md`. All three keep working; they just
|
|
36
|
+
* mean the same three things now. Returns `undefined` for an unrecognized value so
|
|
37
|
+
* the caller can fall through rather than silently picking a format.
|
|
38
|
+
*/
|
|
39
|
+
export declare function NormalizeFormatAlias(value: string | undefined): OutputFormat | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Resolves the output format, most explicit signal first:
|
|
42
|
+
*
|
|
43
|
+
* 1. `--format` (any recognized alias)
|
|
44
|
+
* 2. `--json`
|
|
45
|
+
* 3. {@link FORMAT_ENV}
|
|
46
|
+
* 4. stdout is not a TTY → `json` — the pipe *is* the request
|
|
47
|
+
* 5. otherwise `text`
|
|
48
|
+
*/
|
|
49
|
+
export declare function ResolveOutputFormat(input?: FormatResolutionInput): FormatResolution;
|
|
50
|
+
/**
|
|
51
|
+
* True when decorative chrome (banner, spinners, color) should be suppressed:
|
|
52
|
+
* any machine format, or a non-TTY stdout even in text mode.
|
|
53
|
+
*
|
|
54
|
+
* Kept separate from format resolution because a command can legitimately be in
|
|
55
|
+
* text mode while piped (`--format=text > file.txt`) and still want no spinner.
|
|
56
|
+
*/
|
|
57
|
+
export declare function ShouldSuppressChrome(format: OutputFormat, stdoutIsTTY?: boolean): boolean;
|
|
58
|
+
//# sourceMappingURL=output-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-format.d.ts","sourceRoot":"","sources":["../src/output-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,qEAAqE;AACrE,eAAO,MAAM,UAAU,kBAAkB,CAAC;AAE1C,kFAAkF;AAClF,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,aAAa,CAAC;CACvE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAkBxF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,GAAE,qBAA0B,GAAG,gBAAgB,CAevF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAGzF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Env var that pins the output format for a whole shell session. */
|
|
2
|
+
export const FORMAT_ENV = 'MJ_CLI_FORMAT';
|
|
3
|
+
/**
|
|
4
|
+
* Canonicalizes the spellings different MJ command families grew independently.
|
|
5
|
+
*
|
|
6
|
+
* `mj test *` shipped `console|json|markdown`, `mj ai *` shipped `compact|json|table`,
|
|
7
|
+
* and the plugin commands shipped `text|json|md`. All three keep working; they just
|
|
8
|
+
* mean the same three things now. Returns `undefined` for an unrecognized value so
|
|
9
|
+
* the caller can fall through rather than silently picking a format.
|
|
10
|
+
*/
|
|
11
|
+
export function NormalizeFormatAlias(value) {
|
|
12
|
+
if (!value)
|
|
13
|
+
return undefined;
|
|
14
|
+
switch (value.trim().toLowerCase()) {
|
|
15
|
+
case 'text':
|
|
16
|
+
case 'human':
|
|
17
|
+
case 'pretty':
|
|
18
|
+
case 'console':
|
|
19
|
+
case 'compact':
|
|
20
|
+
case 'table':
|
|
21
|
+
return 'text';
|
|
22
|
+
case 'json':
|
|
23
|
+
return 'json';
|
|
24
|
+
case 'md':
|
|
25
|
+
case 'markdown':
|
|
26
|
+
return 'md';
|
|
27
|
+
default:
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolves the output format, most explicit signal first:
|
|
33
|
+
*
|
|
34
|
+
* 1. `--format` (any recognized alias)
|
|
35
|
+
* 2. `--json`
|
|
36
|
+
* 3. {@link FORMAT_ENV}
|
|
37
|
+
* 4. stdout is not a TTY → `json` — the pipe *is* the request
|
|
38
|
+
* 5. otherwise `text`
|
|
39
|
+
*/
|
|
40
|
+
export function ResolveOutputFormat(input = {}) {
|
|
41
|
+
const env = input.env ?? process.env;
|
|
42
|
+
const explicit = NormalizeFormatAlias(input.formatFlag);
|
|
43
|
+
if (explicit)
|
|
44
|
+
return { format: explicit, reason: 'format-flag' };
|
|
45
|
+
if (input.jsonFlag === true)
|
|
46
|
+
return { format: 'json', reason: 'json-flag' };
|
|
47
|
+
const fromEnv = NormalizeFormatAlias(env[FORMAT_ENV]);
|
|
48
|
+
if (fromEnv)
|
|
49
|
+
return { format: fromEnv, reason: 'env' };
|
|
50
|
+
const stdoutIsTTY = input.stdoutIsTTY ?? process.stdout.isTTY === true;
|
|
51
|
+
if (!stdoutIsTTY)
|
|
52
|
+
return { format: 'json', reason: 'piped' };
|
|
53
|
+
return { format: 'text', reason: 'tty-default' };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* True when decorative chrome (banner, spinners, color) should be suppressed:
|
|
57
|
+
* any machine format, or a non-TTY stdout even in text mode.
|
|
58
|
+
*
|
|
59
|
+
* Kept separate from format resolution because a command can legitimately be in
|
|
60
|
+
* text mode while piped (`--format=text > file.txt`) and still want no spinner.
|
|
61
|
+
*/
|
|
62
|
+
export function ShouldSuppressChrome(format, stdoutIsTTY) {
|
|
63
|
+
if (format !== 'text')
|
|
64
|
+
return true;
|
|
65
|
+
return !(stdoutIsTTY ?? process.stdout.isTTY === true);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=output-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-format.js","sourceRoot":"","sources":["../src/output-format.ts"],"names":[],"mappings":"AAaA,qEAAqE;AACrE,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC;AAoB1C;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAyB;IAC5D,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,IAAI,CAAC;QACV,KAAK,UAAU;YACb,OAAO,IAAI,CAAC;QACd;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAA+B,EAAE;IACnE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAErC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAEjE,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAE5E,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACtD,IAAI,OAAO;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAEvD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;IACvE,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAoB,EAAE,WAAqB;IAC9E,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,CAAC,CAAC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -67,6 +67,25 @@ export declare class CLIPluginRegistry {
|
|
|
67
67
|
* Registering the same `command` twice keeps the first declaration, matching the
|
|
68
68
|
* de-duplication rule {@link CLIPluginRegistry.GetAllUsage} applies to plugins.
|
|
69
69
|
*/
|
|
70
|
+
/**
|
|
71
|
+
* Human-authored one-line summaries for the tier-1 domain map, keyed by domain.
|
|
72
|
+
* See {@link CLIPluginRegistry.RegisterDomainSummary}.
|
|
73
|
+
*/
|
|
74
|
+
private static readonly domainSummaries;
|
|
75
|
+
/**
|
|
76
|
+
* Declares the tier-1 summary for a whole domain, overriding the line
|
|
77
|
+
* {@link CLIPluginRegistry.domainSummary} would otherwise synthesize from its
|
|
78
|
+
* commands.
|
|
79
|
+
*
|
|
80
|
+
* Worth having because the synthesized line degrades badly once a domain has more
|
|
81
|
+
* than a couple of commands — `mj test`'s 16 commands would render as one command's
|
|
82
|
+
* summary plus "(+15 more commands)", which tells an agent nothing about what the
|
|
83
|
+
* domain is FOR. A domain with no registered summary keeps the synthesized line, so
|
|
84
|
+
* this is an opt-in improvement rather than a new requirement.
|
|
85
|
+
*
|
|
86
|
+
* First registration wins, matching {@link CLIPluginRegistry.RegisterUsage}.
|
|
87
|
+
*/
|
|
88
|
+
static RegisterDomainSummary(domain: string, summary: string): void;
|
|
70
89
|
static RegisterUsage(usage: PluginUsage): void;
|
|
71
90
|
/**
|
|
72
91
|
* Every command's usage metadata, de-duplicated by command key: the registered
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAErE,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAM5D,kEAAkE;AAClE,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,iFAAiF;IACjF,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,+BAA+B;AAC/B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED,6BAA6B;AAC7B,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAID;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B;;;;;OAKG;WACU,qBAAqB,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+B/F;;;;OAIG;mBACkB,eAAe;IASpC,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAEzE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAQ9C;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,WAAW,EAAE;IAenC,+EAA+E;IAC/E,MAAM,CAAC,cAAc,IAAI,cAAc;IAoBvC,sFAAsF;IACtF,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB;IAQ3D,uEAAuE;IACvE,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW;IAI5E;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAErE,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAM5D,kEAAkE;AAClE,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,iFAAiF;IACjF,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,+BAA+B;AAC/B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED,6BAA6B;AAC7B,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAID;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B;;;;;OAKG;WACU,qBAAqB,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+B/F;;;;OAIG;mBACkB,eAAe;IASpC,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAEzE;;;;;;;;;;;OAWG;IACH;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAA6B;IAEpE;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAMnE,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAQ9C;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,WAAW,EAAE;IAenC,+EAA+E;IAC/E,MAAM,CAAC,cAAc,IAAI,cAAc;IAoBvC,sFAAsF;IACtF,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB;IAQ3D,uEAAuE;IACvE,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW;IAI5E;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAY5B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAQlC"}
|
package/dist/plugin-registry.js
CHANGED
|
@@ -94,6 +94,31 @@ export class CLIPluginRegistry {
|
|
|
94
94
|
* Registering the same `command` twice keeps the first declaration, matching the
|
|
95
95
|
* de-duplication rule {@link CLIPluginRegistry.GetAllUsage} applies to plugins.
|
|
96
96
|
*/
|
|
97
|
+
/**
|
|
98
|
+
* Human-authored one-line summaries for the tier-1 domain map, keyed by domain.
|
|
99
|
+
* See {@link CLIPluginRegistry.RegisterDomainSummary}.
|
|
100
|
+
*/
|
|
101
|
+
static { this.domainSummaries = new Map(); }
|
|
102
|
+
/**
|
|
103
|
+
* Declares the tier-1 summary for a whole domain, overriding the line
|
|
104
|
+
* {@link CLIPluginRegistry.domainSummary} would otherwise synthesize from its
|
|
105
|
+
* commands.
|
|
106
|
+
*
|
|
107
|
+
* Worth having because the synthesized line degrades badly once a domain has more
|
|
108
|
+
* than a couple of commands — `mj test`'s 16 commands would render as one command's
|
|
109
|
+
* summary plus "(+15 more commands)", which tells an agent nothing about what the
|
|
110
|
+
* domain is FOR. A domain with no registered summary keeps the synthesized line, so
|
|
111
|
+
* this is an opt-in improvement rather than a new requirement.
|
|
112
|
+
*
|
|
113
|
+
* First registration wins, matching {@link CLIPluginRegistry.RegisterUsage}.
|
|
114
|
+
*/
|
|
115
|
+
static RegisterDomainSummary(domain, summary) {
|
|
116
|
+
const key = domain.trim().toLowerCase();
|
|
117
|
+
if (!key || !summary)
|
|
118
|
+
return;
|
|
119
|
+
if (!this.domainSummaries.has(key))
|
|
120
|
+
this.domainSummaries.set(key, summary);
|
|
121
|
+
}
|
|
97
122
|
static RegisterUsage(usage) {
|
|
98
123
|
if (!usage?.domain || !usage?.command) {
|
|
99
124
|
throw new Error('RegisterUsage requires a usage object with both domain and command set');
|
|
@@ -157,6 +182,9 @@ export class CLIPluginRegistry {
|
|
|
157
182
|
* use it; otherwise join the command summaries compactly.
|
|
158
183
|
*/
|
|
159
184
|
static domainSummary(domain, cmds) {
|
|
185
|
+
const declared = this.domainSummaries.get(domain.trim().toLowerCase());
|
|
186
|
+
if (declared)
|
|
187
|
+
return declared;
|
|
160
188
|
if (cmds.length === 1)
|
|
161
189
|
return cmds[0].summary;
|
|
162
190
|
// Prefer a command whose key equals the domain (e.g. 'codegen').
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-registry.js","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAiC5D,MAAM,QAAQ,GAAG,6EAA6E,CAAC;AAE/F;;;;;GAKG;AACH,MAAM,OAAO,iBAAiB;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;QACjE,MAAM,MAAM,GAAqB,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAE5D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,OAAO,MAAM,CAAC;QAE/B,IAAI,MAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAqB,CAAC;QAC7E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,sBAAsB,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzI,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAEtC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;gBACjD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,wEAAwE;gBACxE,mEAAmE;gBACnE,0BAA0B;gBAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACK,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,SAAiB,EAAE,SAAiB;QACvE,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvD,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAC9E,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,0EAA0E;IAClE,MAAM,CAAC,UAAU,CAAC,QAAgB;QACxC,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5B,iDAAiD;QACjD,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;YACvD,IAAI,UAAU,CAAC,SAAS,CAAC;gBAAE,OAAO,SAAS,CAAC;YAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YAChC,GAAG,GAAG,MAAM,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;;OAIG;aACqB,oBAAe,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEzE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,aAAa,CAAC,KAAkB;QACrC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;YAAE,OAAO;QACpD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,WAAW;QAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAC/E,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;QACjD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAI,GAAG,CAAC,QAA6C,EAAE,KAAK,CAAC;YACxE,IAAI,KAAK,EAAE,MAAM,IAAI,KAAK,EAAE,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrE,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACpD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,+EAA+E;IAC/E,MAAM,CAAC,cAAc;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACb,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;QAED,MAAM,OAAO,GAAyB,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;aAC1D,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,MAAM;YACN,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC;YACzC,OAAO,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;SACvC,CAAC,CAAC;aACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAEpD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IAED,sFAAsF;IACtF,MAAM,CAAC,iBAAiB,CAAC,MAAc;QACrC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE;aAChC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;aAChD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,uEAAuE;IACvE,MAAM,CAAC,QAAQ,CAAC,OAAe,EAAE,IAA6B;QAC5D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED;;;OAGG;IACK,MAAM,CAAC,aAAa,CAAC,MAAc,EAAE,IAAmB;QAC9D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC9C,iEAAiE;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QACxD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,OAAO,CAAC;QACtC,8EAA8E;QAC9E,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,iBAAiB,CAAC;QACtF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACK,MAAM,CAAC,kBAAkB,CAAC,IAAmB;QACnD,MAAM,KAAK,GAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QAC/E,IAAI,KAAK,GAAyB,MAAM,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QACrF,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC"}
|
|
1
|
+
{"version":3,"file":"plugin-registry.js","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime-host.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { IMJCLIRuntimeHost, LogLevel, MJCLIResult, OutputFormat, PluginUsage } from './types.js';
|
|
2
|
+
/** Construction-time state for {@link MJCLIRuntimeHost}. Injectable so tests need no real TTY. */
|
|
3
|
+
export interface RuntimeHostOptions {
|
|
4
|
+
/** Whether this run may prompt — from `ResolveInteractivity`. Defaults to false (agent-first). */
|
|
5
|
+
interactive?: boolean;
|
|
6
|
+
/** Defaults to `process.stdout.isTTY`. */
|
|
7
|
+
stdoutIsTTY?: boolean;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* Default implementation of {@link IMJCLIRuntimeHost}.
|
|
4
11
|
*
|
|
@@ -13,20 +20,31 @@ import type { IMJCLIRuntimeHost, LogLevel, MJCLIResult, OutputFormat, PluginUsag
|
|
|
13
20
|
* pipeable (plan D4: `mj sync push --format=json | jq .errors`).
|
|
14
21
|
* - **MD mode**: the result is emitted as a fenced ```json block on stdout
|
|
15
22
|
* (forward-looking slot for AI chat UIs, plan D10).
|
|
23
|
+
*
|
|
24
|
+
* Chrome (spinners, color) additionally requires a real TTY, not just text mode:
|
|
25
|
+
* `--format=text > log.txt` should not write spinner escape codes into the file.
|
|
16
26
|
*/
|
|
17
27
|
export declare class MJCLIRuntimeHost implements IMJCLIRuntimeHost {
|
|
18
28
|
readonly Format: OutputFormat;
|
|
19
29
|
readonly Verbose: boolean;
|
|
30
|
+
readonly Interactive: boolean;
|
|
20
31
|
private readonly noBanner;
|
|
32
|
+
/** Whether stdout is a real terminal — gates spinners, color, and pretty-printing. */
|
|
33
|
+
private readonly stdoutIsTTY;
|
|
21
34
|
/** Process-start, used for the "· N total" running clock in text mode. */
|
|
22
35
|
private readonly startTime;
|
|
23
36
|
private spinner;
|
|
24
37
|
private stepBaseMessage;
|
|
25
38
|
private stepStart;
|
|
26
39
|
private ticker;
|
|
27
|
-
constructor(format?: OutputFormat, verbose?: boolean, noBanner?: boolean);
|
|
28
|
-
/**
|
|
40
|
+
constructor(format?: OutputFormat, verbose?: boolean, noBanner?: boolean, options?: RuntimeHostOptions);
|
|
41
|
+
/**
|
|
42
|
+
* Spinners/colors are only appropriate in text mode on a real TTY. A piped text
|
|
43
|
+
* run still logs — it just logs plain lines instead of animating.
|
|
44
|
+
*/
|
|
29
45
|
private get textMode();
|
|
46
|
+
/** Text mode regardless of whether stdout is a terminal — gates plain-line logging. */
|
|
47
|
+
private get plainTextMode();
|
|
30
48
|
private fmtMs;
|
|
31
49
|
private stopTicker;
|
|
32
50
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-host.d.ts","sourceRoot":"","sources":["../src/runtime-host.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-host.d.ts","sourceRoot":"","sources":["../src/runtime-host.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAInG,kGAAkG;AAClG,MAAM,WAAW,kBAAkB;IACjC,kGAAkG;IAClG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,SAAgB,MAAM,EAAE,YAAY,CAAC;IACrC,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,SAAgB,WAAW,EAAE,OAAO,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IAEtC,0EAA0E;IAC1E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IAExC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAA+B;gBAEjC,MAAM,GAAE,YAAqB,EAAE,OAAO,UAAQ,EAAE,QAAQ,UAAQ,EAAE,OAAO,GAAE,kBAAuB;IAW9G;;;OAGG;IACH,OAAO,KAAK,QAAQ,GAEnB;IAED,uFAAuF;IACvF,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,UAAU;IAOlB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAenB,mFAAmF;IACnF,OAAO,CAAC,eAAe;IAIhB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAW9B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAU/B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAiBjD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAgB9C,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,QAAiB,GAAG,IAAI;IAiBpD,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAezC,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;CAYvC"}
|
package/dist/runtime-host.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ora from 'ora-classic';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { SerializeResult } from './serialize.js';
|
|
4
|
+
import { ShouldSuppressChrome } from './output-format.js';
|
|
4
5
|
/**
|
|
5
6
|
* Default implementation of {@link IMJCLIRuntimeHost}.
|
|
6
7
|
*
|
|
@@ -15,9 +16,12 @@ import { SerializeResult } from './serialize.js';
|
|
|
15
16
|
* pipeable (plan D4: `mj sync push --format=json | jq .errors`).
|
|
16
17
|
* - **MD mode**: the result is emitted as a fenced ```json block on stdout
|
|
17
18
|
* (forward-looking slot for AI chat UIs, plan D10).
|
|
19
|
+
*
|
|
20
|
+
* Chrome (spinners, color) additionally requires a real TTY, not just text mode:
|
|
21
|
+
* `--format=text > log.txt` should not write spinner escape codes into the file.
|
|
18
22
|
*/
|
|
19
23
|
export class MJCLIRuntimeHost {
|
|
20
|
-
constructor(format = 'text', verbose = false, noBanner = false) {
|
|
24
|
+
constructor(format = 'text', verbose = false, noBanner = false, options = {}) {
|
|
21
25
|
/** Process-start, used for the "· N total" running clock in text mode. */
|
|
22
26
|
this.startTime = Date.now();
|
|
23
27
|
this.spinner = null;
|
|
@@ -26,13 +30,22 @@ export class MJCLIRuntimeHost {
|
|
|
26
30
|
this.ticker = null;
|
|
27
31
|
this.Format = format;
|
|
28
32
|
this.Verbose = verbose;
|
|
33
|
+
this.Interactive = options.interactive ?? false;
|
|
34
|
+
this.stdoutIsTTY = options.stdoutIsTTY ?? process.stdout.isTTY === true;
|
|
29
35
|
// `--no-banner` is handled globally by the CLI prerun hook (it strips the flag
|
|
30
36
|
// from argv so not-yet-migrated commands don't fail oclif's strict parser) and
|
|
31
37
|
// signalled here via env, so honor either source.
|
|
32
38
|
this.noBanner = noBanner || process.env.MJ_CLI_NO_BANNER === '1';
|
|
33
39
|
}
|
|
34
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Spinners/colors are only appropriate in text mode on a real TTY. A piped text
|
|
42
|
+
* run still logs — it just logs plain lines instead of animating.
|
|
43
|
+
*/
|
|
35
44
|
get textMode() {
|
|
45
|
+
return this.Format === 'text' && !ShouldSuppressChrome(this.Format, this.stdoutIsTTY);
|
|
46
|
+
}
|
|
47
|
+
/** Text mode regardless of whether stdout is a terminal — gates plain-line logging. */
|
|
48
|
+
get plainTextMode() {
|
|
36
49
|
return this.Format === 'text';
|
|
37
50
|
}
|
|
38
51
|
fmtMs(ms) {
|
|
@@ -106,6 +119,9 @@ export class MJCLIRuntimeHost {
|
|
|
106
119
|
else if (this.Format === 'json') {
|
|
107
120
|
this.emitStderrEvent({ event: 'step-done', label, detail });
|
|
108
121
|
}
|
|
122
|
+
else if (this.plainTextMode) {
|
|
123
|
+
process.stdout.write(`${detail ? `${label} ${detail}` : label}\n`);
|
|
124
|
+
}
|
|
109
125
|
}
|
|
110
126
|
FailStep(label, detail) {
|
|
111
127
|
this.stopTicker();
|
|
@@ -121,6 +137,9 @@ export class MJCLIRuntimeHost {
|
|
|
121
137
|
else if (this.Format === 'json') {
|
|
122
138
|
this.emitStderrEvent({ event: 'step-failed', label, detail });
|
|
123
139
|
}
|
|
140
|
+
else if (this.plainTextMode) {
|
|
141
|
+
process.stderr.write(`${detail ? `${label} ${detail}` : label}\n`);
|
|
142
|
+
}
|
|
124
143
|
}
|
|
125
144
|
Log(message, level = 'info') {
|
|
126
145
|
if (this.textMode) {
|
|
@@ -131,6 +150,11 @@ export class MJCLIRuntimeHost {
|
|
|
131
150
|
// eslint-disable-next-line no-console
|
|
132
151
|
(level === 'error' ? console.error : console.log)(painted);
|
|
133
152
|
}
|
|
153
|
+
else if (this.plainTextMode) {
|
|
154
|
+
// Text mode, piped: still the caller's primary output, so keep it on stdout —
|
|
155
|
+
// just uncolored, since escape codes in a redirected file help nobody.
|
|
156
|
+
(level === 'error' ? process.stderr : process.stdout).write(message + '\n');
|
|
157
|
+
}
|
|
134
158
|
else {
|
|
135
159
|
// Keep stdout clean for the JSON/MD result — all human logging → stderr.
|
|
136
160
|
process.stderr.write(message + '\n');
|
|
@@ -145,7 +169,7 @@ export class MJCLIRuntimeHost {
|
|
|
145
169
|
if (this.Format === 'json') {
|
|
146
170
|
this.emitStderrEvent({ event: 'start', command: usage.command, runtime: usage.runtime });
|
|
147
171
|
}
|
|
148
|
-
else if (this.
|
|
172
|
+
else if (this.plainTextMode) {
|
|
149
173
|
const r = usage.runtime;
|
|
150
174
|
const secs = r.typicalSeconds ? `~${r.typicalSeconds}s` : r.class;
|
|
151
175
|
const note = r.note ? ` — ${r.note}` : '';
|
|
@@ -157,7 +181,8 @@ export class MJCLIRuntimeHost {
|
|
|
157
181
|
if (this.spinner?.isSpinning)
|
|
158
182
|
this.spinner.stop();
|
|
159
183
|
if (this.Format === 'json' || this.Format === 'md') {
|
|
160
|
-
|
|
184
|
+
// Pretty only when a human is watching; a pipe gets one compact line.
|
|
185
|
+
process.stdout.write(SerializeResult(result, this.Format, { pretty: this.stdoutIsTTY }) + '\n');
|
|
161
186
|
}
|
|
162
187
|
// Text mode: the plugin is responsible for its own rich human output (via
|
|
163
188
|
// Log/StartStep/SucceedStep). Emit deliberately prints nothing extra so we
|
package/dist/runtime-host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-host.js","sourceRoot":"","sources":["../src/runtime-host.ts"],"names":[],"mappings":"AAAA,OAAO,GAAiB,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-host.js","sourceRoot":"","sources":["../src/runtime-host.ts"],"names":[],"mappings":"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"}
|
package/dist/serialize.d.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type MJCLIResult, type OutputFormat } from './types.js';
|
|
2
|
+
/** Options for {@link SerializeResult}. */
|
|
3
|
+
export interface SerializeOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Pretty-print with 2-space indent. Defaults to false.
|
|
6
|
+
*
|
|
7
|
+
* The caller passes `true` only when a human is looking at the output — i.e.
|
|
8
|
+
* stdout is a TTY. A piped consumer gets one compact line instead: `jq` reads it
|
|
9
|
+
* identically, it appends cleanly to an NDJSON log, and it costs an agent
|
|
10
|
+
* meaningfully fewer tokens to carry in context.
|
|
11
|
+
*/
|
|
12
|
+
pretty?: boolean;
|
|
13
|
+
}
|
|
2
14
|
/**
|
|
3
15
|
* Single source of truth for serializing an {@link MJCLIResult} per format.
|
|
4
16
|
* Both the runtime host's `Emit` and the usage commands call this so JSON/MD
|
|
5
17
|
* envelopes are always rendered identically. Returns the empty string for
|
|
6
18
|
* `text` — in text mode the plugin renders its own human output, not a result
|
|
7
19
|
* blob. No trailing newline; callers add one.
|
|
20
|
+
*
|
|
21
|
+
* Always stamps {@link MJ_CLI_RESULT_VERSION} (respecting an explicit `version`
|
|
22
|
+
* already on the result), so every machine-readable envelope on the wire carries
|
|
23
|
+
* a contract version even though constructing one doesn't require it.
|
|
8
24
|
*/
|
|
9
|
-
export declare function SerializeResult(result: MJCLIResult, format: OutputFormat): string;
|
|
25
|
+
export declare function SerializeResult(result: MJCLIResult, format: OutputFormat, options?: SerializeOptions): string;
|
|
10
26
|
//# sourceMappingURL=serialize.d.ts.map
|
package/dist/serialize.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAErF,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAYjH"}
|
package/dist/serialize.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
|
+
import { MJ_CLI_RESULT_VERSION } from './types.js';
|
|
1
2
|
/**
|
|
2
3
|
* Single source of truth for serializing an {@link MJCLIResult} per format.
|
|
3
4
|
* Both the runtime host's `Emit` and the usage commands call this so JSON/MD
|
|
4
5
|
* envelopes are always rendered identically. Returns the empty string for
|
|
5
6
|
* `text` — in text mode the plugin renders its own human output, not a result
|
|
6
7
|
* blob. No trailing newline; callers add one.
|
|
8
|
+
*
|
|
9
|
+
* Always stamps {@link MJ_CLI_RESULT_VERSION} (respecting an explicit `version`
|
|
10
|
+
* already on the result), so every machine-readable envelope on the wire carries
|
|
11
|
+
* a contract version even though constructing one doesn't require it.
|
|
7
12
|
*/
|
|
8
|
-
export function SerializeResult(result, format) {
|
|
9
|
-
if (format === '
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
export function SerializeResult(result, format, options = {}) {
|
|
14
|
+
if (format === 'text')
|
|
15
|
+
return '';
|
|
16
|
+
// `version` is listed first so it leads the rendered envelope; the spread can carry
|
|
17
|
+
// an explicit `version: undefined`, so re-assert the default after it.
|
|
18
|
+
const versioned = { version: MJ_CLI_RESULT_VERSION, ...result };
|
|
19
|
+
if (!versioned.version)
|
|
20
|
+
versioned.version = MJ_CLI_RESULT_VERSION;
|
|
21
|
+
// `md` is read by a human in a chat UI, so it is always pretty regardless.
|
|
22
|
+
const indent = format === 'md' || options.pretty ? 2 : 0;
|
|
23
|
+
const body = JSON.stringify(versioned, null, indent);
|
|
24
|
+
return format === 'md' ? '```json\n' + body + '\n```' : body;
|
|
14
25
|
}
|
|
15
26
|
//# sourceMappingURL=serialize.js.map
|
package/dist/serialize.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAuC,MAAM,SAAS,CAAC;AAerF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,MAAmB,EAAE,MAAoB,EAAE,UAA4B,EAAE;IACvG,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAEjC,oFAAoF;IACpF,uEAAuE;IACvE,MAAM,SAAS,GAAgB,EAAE,OAAO,EAAE,qBAAqB,EAAE,GAAG,MAAM,EAAE,CAAC;IAC7E,IAAI,CAAC,SAAS,CAAC,OAAO;QAAE,SAAS,CAAC,OAAO,GAAG,qBAAqB,CAAC;IAClE,2EAA2E;IAC3E,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAErD,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -58,11 +58,54 @@ export interface PluginUsage {
|
|
|
58
58
|
examples?: string[];
|
|
59
59
|
runtime: RuntimeHint;
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Version of the {@link MJCLIResult} wire contract. Bump on any breaking change to
|
|
63
|
+
* the envelope so an agent that cached a shape can detect the drift instead of
|
|
64
|
+
* silently mis-parsing. Stamped onto every serialized result by `SerializeResult`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const MJ_CLI_RESULT_VERSION = "1";
|
|
67
|
+
/**
|
|
68
|
+
* Stable, machine-readable error codes. An agent branches on these; the human-facing
|
|
69
|
+
* `message` is free to be reworded without breaking anyone.
|
|
70
|
+
*
|
|
71
|
+
* Add cases here rather than inventing ad-hoc strings at a call site — the whole
|
|
72
|
+
* point is that the set is enumerable and greppable.
|
|
73
|
+
*/
|
|
74
|
+
export declare const MJCLIErrorCodes: {
|
|
75
|
+
/** A needed value was missing and the run wasn't allowed to prompt for it. */
|
|
76
|
+
readonly NonInteractive: "E_NON_INTERACTIVE";
|
|
77
|
+
/** No `mj.config.cjs` (or equivalent) found. */
|
|
78
|
+
readonly NoConfig: "E_NO_CONFIG";
|
|
79
|
+
/** A flag/argument combination the command can't act on. */
|
|
80
|
+
readonly InvalidArguments: "E_INVALID_ARGS";
|
|
81
|
+
/** A referenced entity, directory, or record doesn't exist. */
|
|
82
|
+
readonly NotFound: "E_NOT_FOUND";
|
|
83
|
+
/** Input failed the command's own validation pass. */
|
|
84
|
+
readonly ValidationFailed: "E_VALIDATION_FAILED";
|
|
85
|
+
/** Database connect/query failure. */
|
|
86
|
+
readonly DatabaseError: "E_DATABASE";
|
|
87
|
+
/** Anything not yet categorized. Prefer a specific code. */
|
|
88
|
+
readonly Unknown: "E_UNKNOWN";
|
|
89
|
+
};
|
|
90
|
+
/** Union of the values in {@link MJCLIErrorCodes}. */
|
|
91
|
+
export type MJCLIErrorCode = (typeof MJCLIErrorCodes)[keyof typeof MJCLIErrorCodes];
|
|
61
92
|
/** A single failure, collected (not interleaved) so an agent can read them as a list. */
|
|
62
93
|
export interface MJCLIResultError {
|
|
63
94
|
/** Entity name, file path, phase — whatever is relevant. */
|
|
64
95
|
context?: string;
|
|
65
96
|
message: string;
|
|
97
|
+
/**
|
|
98
|
+
* Stable code from {@link MJCLIErrorCodes}. Optional only so existing call sites
|
|
99
|
+
* keep compiling — new code should always set it, because without one an agent
|
|
100
|
+
* has nothing to branch on but a regex over `message`.
|
|
101
|
+
*/
|
|
102
|
+
code?: MJCLIErrorCode;
|
|
103
|
+
/**
|
|
104
|
+
* Concrete remediation the caller can act on unaided — name the flag, the file,
|
|
105
|
+
* the command to run. "Invalid configuration" is not a suggestion;
|
|
106
|
+
* "Run `mj sync init` in this directory first." is.
|
|
107
|
+
*/
|
|
108
|
+
suggestion?: string;
|
|
66
109
|
}
|
|
67
110
|
/**
|
|
68
111
|
* Universal result shape every plugin returns (plan D6). Command-specific detail
|
|
@@ -70,6 +113,11 @@ export interface MJCLIResultError {
|
|
|
70
113
|
* {@link MJCLIResult.errors} with full detail (not just a count).
|
|
71
114
|
*/
|
|
72
115
|
export interface MJCLIResult {
|
|
116
|
+
/**
|
|
117
|
+
* {@link MJ_CLI_RESULT_VERSION}. Optional on construction — `SerializeResult`
|
|
118
|
+
* stamps it — so it is always present on the wire and never a burden at a call site.
|
|
119
|
+
*/
|
|
120
|
+
version?: string;
|
|
73
121
|
success: boolean;
|
|
74
122
|
/** 'sync:push', 'codegen', 'migrate', etc. */
|
|
75
123
|
command: string;
|
|
@@ -88,6 +136,12 @@ export interface IMJCLIRuntimeHost {
|
|
|
88
136
|
readonly Format: OutputFormat;
|
|
89
137
|
/** Whether `--verbose` was set. */
|
|
90
138
|
readonly Verbose: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Whether this run may prompt — true at a real terminal, false when piped, spawned,
|
|
141
|
+
* or running in CI, unless `--interactive` / `--no-interactive` overrides it. Plugins
|
|
142
|
+
* read this to choose between asking and failing fast with the flag to pass.
|
|
143
|
+
*/
|
|
144
|
+
readonly Interactive: boolean;
|
|
91
145
|
StartStep(label: string): void;
|
|
92
146
|
UpdateStep(label: string): void;
|
|
93
147
|
SucceedStep(label: string, detail?: string): void;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAElD,kDAAkD;AAClD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;IACjD,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,yFAAyF;AACzF,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -5,5 +5,33 @@
|
|
|
5
5
|
* and the {@link IMJCLIRuntimeHost} renders it per the active {@link OutputFormat}.
|
|
6
6
|
* No `ora`, `chalk`, or `console` calls live inside a plugin's business logic.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Version of the {@link MJCLIResult} wire contract. Bump on any breaking change to
|
|
10
|
+
* the envelope so an agent that cached a shape can detect the drift instead of
|
|
11
|
+
* silently mis-parsing. Stamped onto every serialized result by `SerializeResult`.
|
|
12
|
+
*/
|
|
13
|
+
export const MJ_CLI_RESULT_VERSION = '1';
|
|
14
|
+
/**
|
|
15
|
+
* Stable, machine-readable error codes. An agent branches on these; the human-facing
|
|
16
|
+
* `message` is free to be reworded without breaking anyone.
|
|
17
|
+
*
|
|
18
|
+
* Add cases here rather than inventing ad-hoc strings at a call site — the whole
|
|
19
|
+
* point is that the set is enumerable and greppable.
|
|
20
|
+
*/
|
|
21
|
+
export const MJCLIErrorCodes = {
|
|
22
|
+
/** A needed value was missing and the run wasn't allowed to prompt for it. */
|
|
23
|
+
NonInteractive: 'E_NON_INTERACTIVE',
|
|
24
|
+
/** No `mj.config.cjs` (or equivalent) found. */
|
|
25
|
+
NoConfig: 'E_NO_CONFIG',
|
|
26
|
+
/** A flag/argument combination the command can't act on. */
|
|
27
|
+
InvalidArguments: 'E_INVALID_ARGS',
|
|
28
|
+
/** A referenced entity, directory, or record doesn't exist. */
|
|
29
|
+
NotFound: 'E_NOT_FOUND',
|
|
30
|
+
/** Input failed the command's own validation pass. */
|
|
31
|
+
ValidationFailed: 'E_VALIDATION_FAILED',
|
|
32
|
+
/** Database connect/query failure. */
|
|
33
|
+
DatabaseError: 'E_DATABASE',
|
|
34
|
+
/** Anything not yet categorized. Prefer a specific code. */
|
|
35
|
+
Unknown: 'E_UNKNOWN',
|
|
36
|
+
};
|
|
9
37
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4DH;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,8EAA8E;IAC9E,cAAc,EAAE,mBAAmB;IACnC,gDAAgD;IAChD,QAAQ,EAAE,aAAa;IACvB,4DAA4D;IAC5D,gBAAgB,EAAE,gBAAgB;IAClC,+DAA+D;IAC/D,QAAQ,EAAE,aAAa;IACvB,sDAAsD;IACtD,gBAAgB,EAAE,qBAAqB;IACvC,sCAAsC;IACtC,aAAa,EAAE,YAAY;IAC3B,4DAA4D;IAC5D,OAAO,EAAE,WAAW;CACZ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/cli-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.1.0-edge.
|
|
4
|
+
"version": "6.1.0-edge.5",
|
|
5
5
|
"description": "Pluggable MJ CLI core — BaseCLIPlugin, runtime host, and progressive-disclosure usage primitives shared by mj CLI plugins",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"author": "MemberJunction",
|
|
15
15
|
"license": "BUSL-1.1",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@memberjunction/global": "6.1.0-edge.
|
|
17
|
+
"@memberjunction/global": "6.1.0-edge.5",
|
|
18
18
|
"@oclif/core": "^3.27.0",
|
|
19
19
|
"chalk": "^5.6.2",
|
|
20
20
|
"ora-classic": "^5.4.2"
|