icore 1.0.18 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,40 +9,81 @@ Historical entries before this file was introduced were reconstructed from npm
9
9
  publish metadata and local git history. Older entries are intentionally
10
10
  conservative.
11
11
 
12
- Version boundaries between `1.0.12` and `1.0.15` are draft-level and should be
13
- verified against git tags.
12
+ Version boundaries from `1.0.12` through `1.0.19` were checked against npm
13
+ `gitHead` metadata and local git history.
14
14
 
15
15
  ## [Unreleased]
16
16
 
17
+ ## [2.0.0] - 2026-07-14
18
+
17
19
  ### Added
18
20
 
19
- - Added `TerminalApp.runPrepared(...)` for running prepared commands through terminal rendering and output.
21
+ - Added reusable terminal error rendering and exit-code policy with prepare,
22
+ execute, render, write, and external phase context.
23
+ - Added `TerminalApp.reportError(...)` for caller-owned lifecycle flows that
24
+ need the same stderr and exit-code behavior as `run(...)` and
25
+ `runPrepared(...)`.
26
+ - Added `IcoreError.category` to distinguish usage failures from invalid
27
+ command and option definitions.
28
+ - Added the public `IcoreErrorDetailsMap`, generic `IcoreErrorDetails<TCode>`,
29
+ and distributed `AnyIcoreError` contracts for code-specific error details.
30
+ - Added `isIcoreError(...)` overloads for narrowing any `IcoreError` or one
31
+ exact error code while preserving its details type.
20
32
 
21
33
  ### Changed
22
34
 
23
- - Changed `createTerminalApp` typing to accept command registries with void and prepared payloads.
24
- - Updated testing instructions to use `yarn build` and `yarn test`.
35
+ - Clarified that extra positionals after a matched command path are rejected
36
+ during prepare unless the command declares `allowExtraPositionals: true`.
37
+ - Changed `TerminalApp.run(...)` and `TerminalApp.runPrepared(...)` to share the
38
+ configured terminal error policy while preserving the default error text and
39
+ exit code.
40
+ - **Breaking:** changed the `IcoreError` constructor to require code-specific
41
+ `details`; direct callers must now provide the third argument.
42
+ - Added explicit variant discriminators to `UNKNOWN_COMMAND`,
43
+ `UNEXPECTED_ARGUMENT`, `EXPECTED_REQUIRED_ARGUMENT`, and
44
+ `INVALID_OPTION_DEFAULT` details.
25
45
 
26
- ## [1.0.16]
46
+ ## [1.0.19]
27
47
 
28
48
  ### Added
29
49
 
30
- - Added `createTerminalApp()` as the top-level terminal application composition API.
31
- - Added semantic presentation facade: `createPresentation()`.
32
- - Added semantic output facade: `createOutput()` with `output.write(...)` and `output.error(...)`.
33
- - Added terminal-ready command output support: text, async text streams, presentation results, and empty output.
34
- - Added guide-style examples for terminal app, command flow, option schemas, presentation, output, and lower-level mechanics.
50
+ - Added `TerminalApp.writePreparedOutput(...)` for rendering and writing already obtained terminal output.
51
+ - Added `docs/roadmap.md` for directional project decisions that are not release history.
35
52
 
36
53
  ### Changed
37
54
 
38
- - Documentation was reorganized around `command`, `presentation`, and `output`.
39
- - Examples were grouped by usage level: Terminal Application, Layer Toolkit, Primitive Mechanics.
40
- - Public README now positions `icore` as terminal application mechanics, not only argv parsing.
55
+ - Changed `createTerminalApp` typing to allow custom command results when consumers run prepared commands themselves.
56
+ - Documented the caller-owned flow for command execution results that may be
57
+ lifecycle handles before terminal output is written.
58
+ - Documented that terminal string output is written exactly as provided.
41
59
 
42
- ## [1.0.15]
60
+ ## [1.0.18]
43
61
 
44
62
  ### Added
45
63
 
64
+ - Added `TerminalApp.runPrepared(...)` for running prepared commands through terminal rendering and output.
65
+
66
+ ### Changed
67
+
68
+ - Documented the `app.prepare(...)` and `app.runPrepared(...)` flow for applications
69
+ that create and clean up runtime context themselves.
70
+
71
+ ## [1.0.17]
72
+
73
+ ### Changed
74
+
75
+ - Relaxed `createTerminalApp` typing so command registries with commands
76
+ without `prepare()` hooks and with void payloads compile without adapter casts.
77
+
78
+ ## [1.0.16]
79
+
80
+ ### Added
81
+
82
+ - Added `createTerminalApp()` as the top-level terminal application composition API.
83
+ - Added command mechanics facade: `createCommand()`.
84
+ - Added semantic presentation facade: `createPresentation()`.
85
+ - Added semantic output facade: `createOutput()` with `output.write(...)` and `output.error(...)`.
86
+ - Added terminal-ready command output support: text, async text streams, presentation results, and empty output.
46
87
  - Added presentation primitives and renderers:
47
88
  - `renderJson`
48
89
  - `renderCsv`
@@ -54,67 +95,62 @@ verified against git tags.
54
95
  - `createStdoutWriter`
55
96
  - `createStderrWriter`
56
97
  - `createBackpressureTextWriter`
98
+ - Added typed option subset parsing with `parseOptionsSubsetDetailed`.
99
+ - Added guide-style examples for terminal app, command flow, option schemas, presentation, output, and lower-level mechanics.
57
100
 
58
101
  ### Changed
59
102
 
60
- - Extracted generic JSON/CSV/table rendering mechanics from project-specific CLI code.
103
+ - Documentation was reorganized around `command`, `presentation`, and `output`.
104
+ - Examples were grouped by usage level: Terminal Application, Layer Toolkit, Primitive Mechanics.
105
+ - Public README now positions `icore` as terminal application mechanics, not only argv parsing.
106
+ - Source files were reorganized by framework area: argv, command, options,
107
+ presentation, output, and terminal app.
108
+ - Updated tests to run with `fwa --prune`.
109
+ - Restored `CHANGELOG.md` to published package contents.
61
110
 
62
- ## [1.0.14]
111
+ ### Removed
112
+
113
+ - Removed the redundant CLI barrel module.
114
+ - Removed the legacy `git-flow.md` document.
115
+ - Removed the `prepare` package script.
116
+
117
+ ## [1.0.15]
63
118
 
64
119
  ### Added
65
120
 
66
- - Added command mechanics facade: `createCommand()`.
67
- - Added command registry flow:
68
- - `command.define(...)`
69
- - `command.registry(...)`
70
- - `commands.prepare(...)`
71
- - `commands.run(...)`
72
- - `commands.runFromArgs(...)`
73
- - Added lower-level command primitives:
74
- - `defineCommand`
75
- - `defineCommandRegistry`
76
- - `createCommands`
77
- - `resolveCommand`
78
- - `prepareCommandFromArgs`
79
- - `runPreparedCommand`
80
- - `runCommandFromRegistry`
81
- - `runCommand`
121
+ - Added `isPreparedCommandName` for narrowing prepared command unions by command name.
82
122
 
83
123
  ### Changed
84
124
 
85
- - CLI command execution became explicitly two-phase: prepare without runtime context, then run with context.
125
+ - Temporarily excluded `CHANGELOG.md` from published package contents.
126
+
127
+ ## [1.0.14]
128
+
129
+ ### Changed
130
+
131
+ - Preserved prepared command payload correlation when narrowing registry unions.
132
+ - Reformatted `CHANGELOG.md` according to Keep a Changelog.
86
133
 
87
134
  ## [1.0.13]
88
135
 
89
136
  ### Added
90
137
 
91
- - Added typed option schema composition with `mergeOptionsSchema`.
92
- - Added option inference helpers for parsed values and provided metadata.
93
- - Added command-name guards:
94
- - `isCommandName`
95
- - `isPreparedCommandName`
96
- - Added detailed option parsing contracts for cases where caller needs explicit provided/not-provided metadata.
138
+ - Added machine-readable `IcoreError` codes and details.
139
+ - Added strict command resolution mode with `strict: true`.
140
+ - Added strict mode support to direct `runCommand(...)` calls.
141
+ - Added typed prepared command payloads.
142
+ - Added `CHANGELOG.md`.
97
143
 
98
144
  ### Changed
99
145
 
100
- - Boolean option handling was tightened around flag syntax: `--flag` and `--no-flag`.
146
+ - Boolean option handling was tightened to flag syntax only.
101
147
 
102
148
  ## [1.0.12]
103
149
 
104
- ### Added
150
+ ### Changed
105
151
 
106
- - Added core typed CLI option mechanics based on literal schemas:
107
- - `type: 'string'`
108
- - `type: 'boolean'`
109
- - `type: 'number'`
110
- - Added GNU-style argv parsing:
111
- - `--name value`
112
- - `--name=value`
113
- - `--flag`
114
- - short aliases
115
- - `--` terminator
116
- - Added machine-readable `IcoreError`.
117
- - Added initial TypeScript-first public API for command-line mechanics.
152
+ - Replaced the preliminary `flagOnly` boolean option setting with typed
153
+ `syntax: 'flag'`.
118
154
 
119
155
  ## [1.0.11] - 2026-07-02
120
156
 
@@ -266,6 +302,9 @@ verified against git tags.
266
302
  - Detailed changelog entries were not maintained for these releases.
267
303
 
268
304
  [Unreleased]: https://github.com/woodger/icore/commits/develop
305
+ [1.0.19]: https://www.npmjs.com/package/icore/v/1.0.19
306
+ [1.0.18]: https://www.npmjs.com/package/icore/v/1.0.18
307
+ [1.0.17]: https://www.npmjs.com/package/icore/v/1.0.17
269
308
  [1.0.16]: https://www.npmjs.com/package/icore/v/1.0.16
270
309
  [1.0.15]: https://www.npmjs.com/package/icore/v/1.0.15
271
310
  [1.0.14]: https://www.npmjs.com/package/icore/v/1.0.14
@@ -147,6 +147,7 @@ function createDuplicateArgumentError(name) {
147
147
  }
148
148
  function createUnexpectedArgumentError(argument) {
149
149
  return new icore_error_1.IcoreError('UNEXPECTED_ARGUMENT', `Unexpected argument '${argument}'`, {
150
+ reason: 'malformed-option',
150
151
  argument
151
152
  });
152
153
  }
@@ -220,6 +220,7 @@ function resolveCommandPositionals(path, positionals) {
220
220
  if (positionals[index] !== path[index]) {
221
221
  const command = path.join(' ');
222
222
  throw new icore_error_1.IcoreError('UNKNOWN_COMMAND', `Expected command '${command}'`, {
223
+ reason: 'path-mismatch',
223
224
  command,
224
225
  path: [...path],
225
226
  positionals: [...positionals]
@@ -305,12 +306,14 @@ function isOptionBeforeCommand(arg) {
305
306
  function createUnknownCommandError(positionals) {
306
307
  const command = formatCommandPositionals(positionals);
307
308
  return new icore_error_1.IcoreError('UNKNOWN_COMMAND', `Unknown command: ${command}`, {
309
+ reason: 'unresolved',
308
310
  command,
309
311
  positionals: [...positionals]
310
312
  });
311
313
  }
312
314
  function createUnexpectedArgumentError(argument) {
313
315
  return new icore_error_1.IcoreError('UNEXPECTED_ARGUMENT', `Unexpected argument '${argument}'`, {
316
+ reason: 'option-before-command',
314
317
  argument
315
318
  });
316
319
  }
@@ -3,27 +3,150 @@
3
3
  *
4
4
  * Allowed here:
5
5
  * - defining stable error codes;
6
+ * - correlating error codes with structured details;
6
7
  * - preserving human-readable messages on Error instances;
7
8
  * - carrying structured details for application-level handling;
9
+ * - narrowing unknown errors by their stable codes;
8
10
  *
9
11
  * This file must not contain parser, validator, or command resolution logic.
10
12
  */
13
+ type OptionIdentityDetails = {
14
+ argument: string;
15
+ option: string;
16
+ };
17
+ type UnknownCommandDetails = {
18
+ reason: 'unresolved';
19
+ command: string;
20
+ positionals: readonly string[];
21
+ } | {
22
+ reason: 'path-mismatch';
23
+ command: string;
24
+ path: readonly string[];
25
+ positionals: readonly string[];
26
+ };
27
+ type UnexpectedArgumentDetails = {
28
+ reason: 'malformed-option';
29
+ argument: string;
30
+ } | {
31
+ reason: 'unknown-option';
32
+ argument: string;
33
+ option: string;
34
+ } | {
35
+ reason: 'option-before-command';
36
+ argument: string;
37
+ };
38
+ type ExpectedRequiredArgumentDetails = {
39
+ reason: 'option';
40
+ argument: string;
41
+ option: string;
42
+ } | {
43
+ reason: 'positional';
44
+ argument: string;
45
+ positional: string;
46
+ };
47
+ type InvalidOptionTypeDetails = OptionIdentityDetails & ({
48
+ expected: 'string' | 'boolean flag' | 'number';
49
+ value: unknown;
50
+ } | {
51
+ expected: 'integer';
52
+ value: number;
53
+ } | {
54
+ expected: 'minimum';
55
+ min: number;
56
+ value: number;
57
+ } | {
58
+ expected: 'maximum';
59
+ max: number;
60
+ value: number;
61
+ });
62
+ type InvalidOptionDefaultDetails = OptionIdentityDetails & ({
63
+ expected: 'string' | 'boolean' | 'number';
64
+ value: unknown;
65
+ } | {
66
+ expected: 'integer';
67
+ value: number;
68
+ } | {
69
+ expected: 'minimum';
70
+ min: number;
71
+ value: number;
72
+ } | {
73
+ expected: 'maximum';
74
+ max: number;
75
+ value: number;
76
+ } | {
77
+ expected: 'choice';
78
+ choices: readonly (string | number)[];
79
+ value: string | number;
80
+ });
81
+ /** Structured details protocol keyed by every stable `IcoreError` code. */
82
+ export type IcoreErrorDetailsMap = {
83
+ UNKNOWN_COMMAND: UnknownCommandDetails;
84
+ UNEXPECTED_ARGUMENT: UnexpectedArgumentDetails;
85
+ DUPLICATE_ARGUMENT: OptionIdentityDetails;
86
+ EXPECTED_REQUIRED_ARGUMENT: ExpectedRequiredArgumentDetails;
87
+ INVALID_OPTION_TYPE: InvalidOptionTypeDetails;
88
+ INVALID_OPTION_CHOICE: OptionIdentityDetails & {
89
+ choices: readonly (string | number)[];
90
+ value: string | number;
91
+ };
92
+ UNEXPECTED_POSITIONAL: {
93
+ command: string;
94
+ positional: string;
95
+ positionals: readonly string[];
96
+ };
97
+ INVALID_OPTION_ALIAS: OptionIdentityDetails & {
98
+ alias: unknown;
99
+ };
100
+ DUPLICATE_ALIAS: {
101
+ argument: string;
102
+ alias: string;
103
+ };
104
+ INVALID_OPTION_DEFAULT: InvalidOptionDefaultDetails;
105
+ DUPLICATE_COMMAND: {
106
+ command: string;
107
+ };
108
+ };
109
+ /** Stable machine-readable error code for `icore` CLI mechanics errors. */
110
+ export type IcoreErrorCode = keyof IcoreErrorDetailsMap;
111
+ /** Structured details for one exact `IcoreError` code. */
112
+ export type IcoreErrorDetails<TCode extends IcoreErrorCode> = Readonly<IcoreErrorDetailsMap[TCode]>;
11
113
  /**
12
- * Stable machine-readable error code for `icore` CLI mechanics errors.
114
+ * Stable category for distinguishing user input failures from invalid command
115
+ * or option definitions.
13
116
  */
14
- export type IcoreErrorCode = 'UNKNOWN_COMMAND' | 'UNEXPECTED_ARGUMENT' | 'DUPLICATE_ARGUMENT' | 'EXPECTED_REQUIRED_ARGUMENT' | 'INVALID_OPTION_TYPE' | 'INVALID_OPTION_CHOICE' | 'UNEXPECTED_POSITIONAL' | 'INVALID_OPTION_ALIAS' | 'DUPLICATE_ALIAS' | 'INVALID_OPTION_DEFAULT' | 'DUPLICATE_COMMAND';
15
- /**
16
- * Structured context for application-level error handling.
17
- */
18
- export type IcoreErrorDetails = Readonly<Record<string, unknown>>;
117
+ export type IcoreErrorCategory = 'usage' | 'definition';
118
+ declare const icoreErrorCategoryByCode: {
119
+ readonly UNKNOWN_COMMAND: "usage";
120
+ readonly UNEXPECTED_ARGUMENT: "usage";
121
+ readonly DUPLICATE_ARGUMENT: "usage";
122
+ readonly EXPECTED_REQUIRED_ARGUMENT: "usage";
123
+ readonly INVALID_OPTION_TYPE: "usage";
124
+ readonly INVALID_OPTION_CHOICE: "usage";
125
+ readonly UNEXPECTED_POSITIONAL: "usage";
126
+ readonly INVALID_OPTION_ALIAS: "definition";
127
+ readonly DUPLICATE_ALIAS: "definition";
128
+ readonly INVALID_OPTION_DEFAULT: "definition";
129
+ readonly DUPLICATE_COMMAND: "definition";
130
+ };
19
131
  /**
20
132
  * Error thrown by `icore` for CLI parsing, option validation, command
21
133
  * resolution, and schema configuration failures.
22
134
  */
23
- export declare class IcoreError extends Error {
135
+ export declare class IcoreError<TCode extends IcoreErrorCode = IcoreErrorCode> extends Error {
24
136
  /** Stable machine-readable code. */
25
- readonly code: IcoreErrorCode;
137
+ readonly code: TCode;
138
+ /** Stable high-level error category. */
139
+ readonly category: typeof icoreErrorCategoryByCode[TCode];
26
140
  /** Structured error context. */
27
- readonly details: IcoreErrorDetails;
28
- constructor(code: IcoreErrorCode, message: string, details?: IcoreErrorDetails);
141
+ readonly details: IcoreErrorDetails<TCode>;
142
+ constructor(code: TCode, message: string, details: IcoreErrorDetails<TCode>);
29
143
  }
144
+ /** Distributed union preserving the correlation between code and details. */
145
+ export type AnyIcoreError = {
146
+ [TCode in IcoreErrorCode]: IcoreError<TCode>;
147
+ }[IcoreErrorCode];
148
+ /** Checks whether an unknown value is any supported `IcoreError`. */
149
+ export declare function isIcoreError(error: unknown): error is AnyIcoreError;
150
+ /** Checks and narrows an unknown value to one exact `IcoreError` code. */
151
+ export declare function isIcoreError<TCode extends IcoreErrorCode>(error: unknown, code: TCode): error is IcoreError<TCode>;
152
+ export {};
@@ -4,13 +4,29 @@
4
4
  *
5
5
  * Allowed here:
6
6
  * - defining stable error codes;
7
+ * - correlating error codes with structured details;
7
8
  * - preserving human-readable messages on Error instances;
8
9
  * - carrying structured details for application-level handling;
10
+ * - narrowing unknown errors by their stable codes;
9
11
  *
10
12
  * This file must not contain parser, validator, or command resolution logic.
11
13
  */
12
14
  Object.defineProperty(exports, "__esModule", { value: true });
13
15
  exports.IcoreError = void 0;
16
+ exports.isIcoreError = isIcoreError;
17
+ const icoreErrorCategoryByCode = {
18
+ UNKNOWN_COMMAND: 'usage',
19
+ UNEXPECTED_ARGUMENT: 'usage',
20
+ DUPLICATE_ARGUMENT: 'usage',
21
+ EXPECTED_REQUIRED_ARGUMENT: 'usage',
22
+ INVALID_OPTION_TYPE: 'usage',
23
+ INVALID_OPTION_CHOICE: 'usage',
24
+ UNEXPECTED_POSITIONAL: 'usage',
25
+ INVALID_OPTION_ALIAS: 'definition',
26
+ DUPLICATE_ALIAS: 'definition',
27
+ INVALID_OPTION_DEFAULT: 'definition',
28
+ DUPLICATE_COMMAND: 'definition'
29
+ };
14
30
  /**
15
31
  * Error thrown by `icore` for CLI parsing, option validation, command
16
32
  * resolution, and schema configuration failures.
@@ -18,14 +34,21 @@ exports.IcoreError = void 0;
18
34
  class IcoreError extends Error {
19
35
  /** Stable machine-readable code. */
20
36
  code;
37
+ /** Stable high-level error category. */
38
+ category;
21
39
  /** Structured error context. */
22
40
  details;
23
- constructor(code, message, details = {}) {
41
+ constructor(code, message, details) {
24
42
  super(message);
25
43
  this.name = 'IcoreError';
26
44
  this.code = code;
45
+ this.category = icoreErrorCategoryByCode[code];
27
46
  this.details = details;
28
47
  Object.setPrototypeOf(this, new.target.prototype);
29
48
  }
30
49
  }
31
50
  exports.IcoreError = IcoreError;
51
+ function isIcoreError(error, code) {
52
+ return error instanceof IcoreError
53
+ && (code === undefined || error.code === code);
54
+ }
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  */
13
13
  export { parseArgv, type ParsedArgv } from './argv/parser';
14
14
  export { createCommand, createCommands, defineCommand, defineCommandRegistry, isCommandName, isPreparedCommandName, prepareCommandFromArgs, resolveCommand, resolveCommandFromArgs, runCommand, runPreparedCommand, runCommandFromRegistry, type Command, type CommandDefinition, type CommandContext, type CommandInput, type CommandName, type CommandPayload, type CommandRegistry, type CommandResolutionOptions, type CommandResult, type Commands, type PreparedCommand, type PreparedCommandInput, type ResolvedCommand } from './command/mechanics';
15
- export { IcoreError, type IcoreErrorCode, type IcoreErrorDetails } from './errors/icore-error';
15
+ export { IcoreError, isIcoreError, type AnyIcoreError, type IcoreErrorCategory, type IcoreErrorCode, type IcoreErrorDetails, type IcoreErrorDetailsMap } from './errors/icore-error';
16
16
  export { parseOptions, parseOptionsDetailed, parseOptionsSubsetDetailed, type ParseOptionsResult, type ParseOptionsSubsetResult } from './options/parser';
17
17
  export { mergeOptionsSchema, type BooleanOption, type InferOptions, type InferProvidedOptions, type MergeOptionsSchemas, type NumberOption, type OptionDefinition, type OptionsSchema, type RawOptionValue, type StringOption } from './options/schema';
18
18
  export { createPresentation, type Presentation, type PresentationRenderers } from './presentation/facade';
@@ -25,4 +25,4 @@ export { type CsvCell, type CsvRow, type CsvPresentationView, type EmptyPresenta
25
25
  export { createOutput, type Output, type OutputOptions } from './output/facade';
26
26
  export { createStderrWriter, createStdoutWriter } from './output/node-writer';
27
27
  export { createBackpressureTextWriter, type BackpressureTextSink, type TextWriter } from './output/text-writer';
28
- export { createTerminalApp, type TerminalApp, type TerminalAppOptions, type TerminalCommandOutput } from './terminal/app';
28
+ export { createTerminalApp, type TerminalApp, type TerminalAppOptions, type TerminalCommandOutput, type TerminalErrorContext, type TerminalErrorPhase, type TerminalErrorPolicy } from './terminal/app';
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  * This file must not contain parser, validator, or command runtime logic.
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.createTerminalApp = exports.createBackpressureTextWriter = exports.createStdoutWriter = exports.createStderrWriter = exports.createOutput = exports.renderPresentationResult = exports.isPresentationResult = exports.renderTextTable = exports.renderJson = exports.renderCsvRow = exports.renderCsv = exports.presentationFormats = exports.presentationFormatOptions = exports.isPresentationFormat = exports.createPresentation = exports.mergeOptionsSchema = exports.parseOptionsSubsetDetailed = exports.parseOptionsDetailed = exports.parseOptions = exports.IcoreError = exports.runCommandFromRegistry = exports.runPreparedCommand = exports.runCommand = exports.resolveCommandFromArgs = exports.resolveCommand = exports.prepareCommandFromArgs = exports.isPreparedCommandName = exports.isCommandName = exports.defineCommandRegistry = exports.defineCommand = exports.createCommands = exports.createCommand = exports.parseArgv = void 0;
15
+ exports.createTerminalApp = exports.createBackpressureTextWriter = exports.createStdoutWriter = exports.createStderrWriter = exports.createOutput = exports.renderPresentationResult = exports.isPresentationResult = exports.renderTextTable = exports.renderJson = exports.renderCsvRow = exports.renderCsv = exports.presentationFormats = exports.presentationFormatOptions = exports.isPresentationFormat = exports.createPresentation = exports.mergeOptionsSchema = exports.parseOptionsSubsetDetailed = exports.parseOptionsDetailed = exports.parseOptions = exports.isIcoreError = exports.IcoreError = exports.runCommandFromRegistry = exports.runPreparedCommand = exports.runCommand = exports.resolveCommandFromArgs = exports.resolveCommand = exports.prepareCommandFromArgs = exports.isPreparedCommandName = exports.isCommandName = exports.defineCommandRegistry = exports.defineCommand = exports.createCommands = exports.createCommand = exports.parseArgv = void 0;
16
16
  var parser_1 = require("./argv/parser");
17
17
  Object.defineProperty(exports, "parseArgv", { enumerable: true, get: function () { return parser_1.parseArgv; } });
18
18
  var mechanics_1 = require("./command/mechanics");
@@ -30,6 +30,7 @@ Object.defineProperty(exports, "runPreparedCommand", { enumerable: true, get: fu
30
30
  Object.defineProperty(exports, "runCommandFromRegistry", { enumerable: true, get: function () { return mechanics_1.runCommandFromRegistry; } });
31
31
  var icore_error_1 = require("./errors/icore-error");
32
32
  Object.defineProperty(exports, "IcoreError", { enumerable: true, get: function () { return icore_error_1.IcoreError; } });
33
+ Object.defineProperty(exports, "isIcoreError", { enumerable: true, get: function () { return icore_error_1.isIcoreError; } });
33
34
  var parser_2 = require("./options/parser");
34
35
  Object.defineProperty(exports, "parseOptions", { enumerable: true, get: function () { return parser_2.parseOptions; } });
35
36
  Object.defineProperty(exports, "parseOptionsDetailed", { enumerable: true, get: function () { return parser_2.parseOptionsDetailed; } });
@@ -151,7 +151,10 @@ function validateNumberConstraints(name, definition, parsed, source = 'value') {
151
151
  value: parsed
152
152
  });
153
153
  }
154
- throw createExpectedOptionTypeError(name, 'integer', parsed);
154
+ throw createInvalidOptionTypeError(name, `Expected '--${name}' as integer`, {
155
+ expected: 'integer',
156
+ value: parsed
157
+ });
155
158
  }
156
159
  if (definition.min !== undefined && parsed < definition.min) {
157
160
  const message = `Expected '--${name}' to be greater than or equal to ${String(definition.min)}`;
@@ -192,6 +195,7 @@ function assertChoice(name, choices, value, source = 'value') {
192
195
  const message = `Expected '--${name}' as one of: ${choices.join(', ')}`;
193
196
  if (source === 'default') {
194
197
  throw createInvalidOptionDefaultError(name, message, {
198
+ expected: 'choice',
195
199
  choices: [...choices],
196
200
  value
197
201
  });
@@ -200,12 +204,14 @@ function assertChoice(name, choices, value, source = 'value') {
200
204
  }
201
205
  function createUnexpectedArgumentError(name) {
202
206
  return new icore_error_1.IcoreError('UNEXPECTED_ARGUMENT', `Unexpected argument '--${name}'`, {
207
+ reason: 'unknown-option',
203
208
  argument: `--${name}`,
204
209
  option: name
205
210
  });
206
211
  }
207
212
  function createExpectedRequiredArgumentError(name) {
208
213
  return new icore_error_1.IcoreError('EXPECTED_REQUIRED_ARGUMENT', `Expected required argument '--${name}'`, {
214
+ reason: 'option',
209
215
  argument: `--${name}`,
210
216
  option: name
211
217
  });
@@ -5,6 +5,7 @@
5
5
  * - preparing and running command facades;
6
6
  * - rendering presentation results;
7
7
  * - writing command output through the output facade;
8
+ * - reporting terminal errors through caller-configured policy;
8
9
  *
9
10
  * This file must not contain argv tokenization, option validation internals,
10
11
  * domain behavior, or application-specific report mapping.
@@ -15,12 +16,38 @@ import { type Presentation, type PresentationResult } from '../presentation/faca
15
16
  import { type PresentationFormat } from '../presentation/format-options';
16
17
  import { type Output } from '../output/facade';
17
18
  /**
18
- * Supported handler result shapes for the terminal app boundary.
19
+ * Supported terminal output shapes for the terminal app boundary.
19
20
  *
20
- * Domain commands may return ready text, streaming text, a presentation view,
21
- * or no output. Other result shapes are rejected before writing to stdout.
21
+ * Terminal output may be ready text, streaming text, a presentation view, or
22
+ * no output. Other result shapes are rejected before writing to stdout.
22
23
  */
23
24
  export type TerminalCommandOutput = string | AsyncIterable<string> | PresentationResult | undefined;
25
+ /** Terminal operation in which an error was observed. */
26
+ export type TerminalErrorPhase = 'prepare' | 'execute' | 'render' | 'write' | 'external';
27
+ /**
28
+ * Context supplied to terminal error policy callbacks.
29
+ *
30
+ * Prepared command data is guaranteed for command execution and terminal
31
+ * output phases. Errors outside terminal app operations may provide either
32
+ * arguments, prepared command data, or neither.
33
+ */
34
+ export type TerminalErrorContext<TPrepared> = {
35
+ phase: 'prepare';
36
+ args: readonly string[];
37
+ } | {
38
+ phase: 'execute' | 'render' | 'write';
39
+ prepared: TPrepared;
40
+ args?: readonly string[];
41
+ } | {
42
+ phase: 'external';
43
+ args?: readonly string[];
44
+ prepared?: TPrepared;
45
+ };
46
+ /** Caller-owned terminal error rendering and process exit-code policy. */
47
+ export type TerminalErrorPolicy<TPrepared> = {
48
+ renderError?(error: unknown, context: TerminalErrorContext<TPrepared>): string;
49
+ resolveExitCode?(error: unknown, context: TerminalErrorContext<TPrepared>): number;
50
+ };
24
51
  type BivariantCallback<TInput, TOutput> = {
25
52
  bivarianceHack(input: TInput): TOutput;
26
53
  }['bivarianceHack'];
@@ -30,7 +57,7 @@ type TerminalCommandDefinition = {
30
57
  metadata?: unknown;
31
58
  allowExtraPositionals?: boolean;
32
59
  prepare?: BivariantCallback<PreparedCommandInput, unknown | Promise<unknown>>;
33
- handle: BivariantCallback<TerminalCommandInput, TerminalCommandOutput | Promise<TerminalCommandOutput>>;
60
+ handle: BivariantCallback<TerminalCommandInput, unknown | Promise<unknown>>;
34
61
  };
35
62
  type PreparedCommandInput = {
36
63
  options: Record<string, unknown>;
@@ -47,6 +74,8 @@ export type TerminalAppOptions<TCommands extends readonly TerminalCommandDefinit
47
74
  presentation?: Presentation;
48
75
  /** Custom output facade. */
49
76
  output?: Output;
77
+ /** Custom terminal error rendering and exit-code policy. */
78
+ errorPolicy?: TerminalErrorPolicy<PreparedCommand<TCommands[number]>>;
50
79
  /** Resolves output format. */
51
80
  resolveFormat?(prepared: PreparedCommand<TCommands[number]>): PresentationFormat | undefined;
52
81
  };
@@ -54,10 +83,19 @@ export type TerminalApp<TCommands extends readonly TerminalCommandDefinition[]>
54
83
  commands: Commands<TCommands>;
55
84
  presentation: Presentation;
56
85
  output: Output;
86
+ /** Renders an error to stderr and returns its process-style exit code. */
87
+ reportError(error: unknown, context?: TerminalErrorContext<PreparedCommand<TCommands[number]>>): Promise<number>;
57
88
  /** No application context required. */
58
89
  prepare(args: readonly string[], options?: CommandResolutionOptions): Promise<PreparedCommand<TCommands[number]>>;
59
90
  /** Runs an already prepared command through terminal rendering and output. */
60
91
  runPrepared(prepared: PreparedCommand<TCommands[number]>, context: CommandContext<TCommands[number]>): Promise<number>;
92
+ /**
93
+ * Renders and writes already obtained terminal output.
94
+ *
95
+ * String output is written exactly as provided; add a trailing newline in the
96
+ * command result when line output is desired.
97
+ */
98
+ writePreparedOutput(prepared: PreparedCommand<TCommands[number]>, output: TerminalCommandOutput): Promise<void>;
61
99
  /** Returns a process-style exit code. */
62
100
  run(args: readonly string[], context: CommandContext<TCommands[number]>, options?: CommandResolutionOptions): Promise<number>;
63
101
  };