@alcyone-labs/arg-parser 2.10.1 → 2.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -10
- package/dist/index.cjs +60 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.min.mjs +1249 -1221
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +60 -2
- package/dist/index.mjs.map +1 -1
- package/dist/ui/components/ScrollArea.d.ts +3 -0
- package/dist/ui/components/ScrollArea.d.ts.map +1 -1
- package/dist/ui/utils/ansi-utils.d.ts +17 -0
- package/dist/ui/utils/ansi-utils.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,6 +77,8 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
|
|
|
77
77
|
- [Typical Errors](#typical-errors)
|
|
78
78
|
- [System Flags & Configuration](#system-flags--configuration)
|
|
79
79
|
- [Changelog](#changelog)
|
|
80
|
+
- [v2.10.2](#v2102)
|
|
81
|
+
- [v2.10.1](#v2101)
|
|
80
82
|
- [v2.10.0](#v2100)
|
|
81
83
|
- [v2.8.2](#v282)
|
|
82
84
|
- [v2.8.1](#v281)
|
|
@@ -117,15 +119,64 @@ A modern, type-safe command line argument parser with built-in MCP (Model Contex
|
|
|
117
119
|
|
|
118
120
|
## OpenTUI: Reactive Rich Terminal Interfaces
|
|
119
121
|
|
|
120
|
-
ArgParser
|
|
122
|
+
ArgParser includes **OpenTUI**, a standardized framework for building deep, multi-layered terminal applications with minimal boilerplate. It features a stack-based navigation system (`StackNavigator`), mouse wheel support, and a reactive theming engine.
|
|
121
123
|
|
|
122
124
|
### Core TUI Features
|
|
123
125
|
|
|
124
126
|
- **Standardized Navigation**: `Enter` / `Right` to dive into details, `Esc` / `Left` to go back.
|
|
125
|
-
- **Reactive Theming**: Cycle through built-in themes (`Default`, `Ocean`, `Monokai`) or create your own
|
|
126
|
-
- **Mouse & Scroll Performance**: Built-in SGR mouse reporting support with smooth scrolling and
|
|
127
|
+
- **Reactive Theming**: Cycle through built-in themes (`Default`, `Ocean`, `Monokai`) or create your own.
|
|
128
|
+
- **Mouse & Scroll Performance**: Built-in SGR mouse reporting support with smooth scrolling and high-performance rendering.
|
|
127
129
|
- **Component Based**: Reusable `List`, `ScrollArea`, `Input`, and `SplitLayout` components.
|
|
128
130
|
|
|
131
|
+
### Component Reference
|
|
132
|
+
|
|
133
|
+
#### `App`
|
|
134
|
+
|
|
135
|
+
The main entry point for TUI applications. It handles TTY raw mode, mouse reporting, and ensures clean terminal restoration on exit or crash.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const app = new UI.App();
|
|
139
|
+
app.run(rootComponent);
|
|
140
|
+
// Exit manually
|
|
141
|
+
app.stop();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### `ScrollArea`
|
|
145
|
+
|
|
146
|
+
A container for long text blocks with automatic scrollbars and mouse-wheel support.
|
|
147
|
+
|
|
148
|
+
- `content`: The text to display (supports ANSI colors).
|
|
149
|
+
- `wrapText`: (New in v2.10.2) If true, automatically wraps long lines to fit the area width.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const details = new UI.ScrollArea({
|
|
153
|
+
content: "Long text...",
|
|
154
|
+
wrapText: true,
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### `StackNavigator`
|
|
159
|
+
|
|
160
|
+
Manages a stack of components, perfect for "Drill-down" interfaces.
|
|
161
|
+
|
|
162
|
+
- Handles `Esc` and `Left Arrow` automatically to return to the previous view.
|
|
163
|
+
- Resizes restore components to the correct dimensions.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const nav = new UI.StackNavigator({ initialComponent: homeList });
|
|
167
|
+
nav.push(detailsView); // Drill down
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### `ThemeManager`
|
|
171
|
+
|
|
172
|
+
Allows real-time theme switching without affecting application logic.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
UI.ThemeManager.setTheme("Ocean");
|
|
176
|
+
const t = UI.ThemeManager.current;
|
|
177
|
+
console.log(t.accent("Statically colored text"));
|
|
178
|
+
```
|
|
179
|
+
|
|
129
180
|
### Quick TUI Example
|
|
130
181
|
|
|
131
182
|
```typescript
|
|
@@ -135,14 +186,18 @@ const app = new UI.App();
|
|
|
135
186
|
|
|
136
187
|
// Create components
|
|
137
188
|
const list = new UI.List({
|
|
138
|
-
items: [
|
|
189
|
+
items: [
|
|
190
|
+
{ label: "Help", value: "help" },
|
|
191
|
+
{ label: "Exit", value: "exit" },
|
|
192
|
+
],
|
|
139
193
|
onSubmit: (item) => {
|
|
140
194
|
if (item.value === "exit") app.stop();
|
|
141
|
-
}
|
|
195
|
+
},
|
|
142
196
|
});
|
|
143
197
|
|
|
144
|
-
const details = new UI.ScrollArea({
|
|
145
|
-
content: "Select an item to see more..."
|
|
198
|
+
const details = new UI.ScrollArea({
|
|
199
|
+
content: "Select an item to see more...",
|
|
200
|
+
wrapText: true,
|
|
146
201
|
});
|
|
147
202
|
|
|
148
203
|
// Build layout
|
|
@@ -150,10 +205,9 @@ const layout = new UI.SplitLayout({
|
|
|
150
205
|
direction: "horizontal",
|
|
151
206
|
first: list,
|
|
152
207
|
second: details,
|
|
153
|
-
|
|
208
|
+
splitRatio: 0.3,
|
|
154
209
|
});
|
|
155
210
|
|
|
156
|
-
// Run with automatic TTY cleanup
|
|
157
211
|
app.run(layout);
|
|
158
212
|
```
|
|
159
213
|
|
|
@@ -635,20 +689,23 @@ interface DxtOptions {
|
|
|
635
689
|
ArgParser provides universal support for environment variables across all commands.
|
|
636
690
|
|
|
637
691
|
**Features:**
|
|
692
|
+
|
|
638
693
|
1. **Automatic Fallback**: If a flag is not provided via CLI, ArgParser looks for configured environment variables.
|
|
639
694
|
2. **Priority Handling**: `CLI Flag` > `Environment Variable` > `Default Value`.
|
|
640
695
|
3. **Reverse Sync**: Once a flag value is resolved (whether from CLI or Env), it is automatically written back to `process.env`. This ensures downstream code accessing `process.env` sees the consistent, final value.
|
|
641
696
|
4. **Array Support**: You can specify multiple env vars for a single flag; the first one found is used.
|
|
642
697
|
|
|
643
698
|
**Example:**
|
|
699
|
+
|
|
644
700
|
```typescript
|
|
645
701
|
parser.addFlag({
|
|
646
702
|
name: "apiKey",
|
|
647
703
|
type: "string",
|
|
648
704
|
env: ["MY_APP_API_KEY", "LEGACY_API_KEY"], // First match wins
|
|
649
|
-
defaultValue: "dev-key"
|
|
705
|
+
defaultValue: "dev-key",
|
|
650
706
|
});
|
|
651
707
|
```
|
|
708
|
+
|
|
652
709
|
- If passed `--api-key val`: `apiKey` is "val", and `process.env.MY_APP_API_KEY` becomes "val".
|
|
653
710
|
- If not passed, but `MY_APP_API_KEY` exists: `apiKey` uses the env value.
|
|
654
711
|
- If neither: `apiKey` is "dev-key", and `process.env.MY_APP_API_KEY` is set to "dev-key".
|
|
@@ -2203,6 +2260,17 @@ ArgParser includes built-in `--s-*` flags for development, debugging, and config
|
|
|
2203
2260
|
|
|
2204
2261
|
## Changelog
|
|
2205
2262
|
|
|
2263
|
+
### v2.10.2
|
|
2264
|
+
|
|
2265
|
+
- **OpenTUI Improvements**:
|
|
2266
|
+
- **Soft Wrapping**: Added `wrapText` (boolean) to `ScrollArea` component. When enabled, text automatically reflows to fit the container width (preventing clipping).
|
|
2267
|
+
- **ANSI Preservation**: Soft-wrapping logic is ANSI-aware; color and style states are correctly carried over to wrapped lines.
|
|
2268
|
+
|
|
2269
|
+
### v2.10.1
|
|
2270
|
+
|
|
2271
|
+
- **Bug Fixes**:
|
|
2272
|
+
- Fixed a crash in `Terminal.moveCursor` when running in certain environments where `node:readline` utilities were inaccessible. Switched to direct ANSI escape codes for cursor positioning.
|
|
2273
|
+
|
|
2206
2274
|
### v2.10.0 - OpenTUI integration + IFlag "env" property now first-class citizen
|
|
2207
2275
|
|
|
2208
2276
|
#### OpenTUI Integration
|
package/dist/index.cjs
CHANGED
|
@@ -9343,12 +9343,61 @@ class List extends Component {
|
|
|
9343
9343
|
}
|
|
9344
9344
|
}
|
|
9345
9345
|
}
|
|
9346
|
+
function stripAnsi(str) {
|
|
9347
|
+
return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
|
|
9348
|
+
}
|
|
9349
|
+
function visualLength(str) {
|
|
9350
|
+
return stripAnsi(str).length;
|
|
9351
|
+
}
|
|
9352
|
+
function wrapText(text, width) {
|
|
9353
|
+
if (width <= 0) return [text];
|
|
9354
|
+
const result = [];
|
|
9355
|
+
const lines = text.split("\n");
|
|
9356
|
+
for (const line of lines) {
|
|
9357
|
+
if (visualLength(line) <= width) {
|
|
9358
|
+
result.push(line);
|
|
9359
|
+
continue;
|
|
9360
|
+
}
|
|
9361
|
+
let currentLine = "";
|
|
9362
|
+
let currentVisibleLength = 0;
|
|
9363
|
+
let activeAnsiCodes = [];
|
|
9364
|
+
const tokenRegex = /(\u001b\[(?:\d{1,3}(?:;\d{1,3})*)?[mK])|([\s\S])/g;
|
|
9365
|
+
let match;
|
|
9366
|
+
while ((match = tokenRegex.exec(line)) !== null) {
|
|
9367
|
+
const ansiCode = match[1];
|
|
9368
|
+
const char = match[2];
|
|
9369
|
+
if (ansiCode) {
|
|
9370
|
+
currentLine += ansiCode;
|
|
9371
|
+
if (ansiCode === "\x1B[0m") {
|
|
9372
|
+
activeAnsiCodes = [];
|
|
9373
|
+
} else if (ansiCode.endsWith("m")) {
|
|
9374
|
+
activeAnsiCodes.push(ansiCode);
|
|
9375
|
+
}
|
|
9376
|
+
} else if (char) {
|
|
9377
|
+
if (currentVisibleLength >= width) {
|
|
9378
|
+
result.push(currentLine + "\x1B[0m");
|
|
9379
|
+
currentLine = activeAnsiCodes.join("") + char;
|
|
9380
|
+
currentVisibleLength = 1;
|
|
9381
|
+
} else {
|
|
9382
|
+
currentLine += char;
|
|
9383
|
+
currentVisibleLength++;
|
|
9384
|
+
}
|
|
9385
|
+
}
|
|
9386
|
+
}
|
|
9387
|
+
if (currentLine.length > 0) {
|
|
9388
|
+
result.push(currentLine + "\x1B[0m");
|
|
9389
|
+
}
|
|
9390
|
+
}
|
|
9391
|
+
return result;
|
|
9392
|
+
}
|
|
9346
9393
|
class ScrollArea extends Component {
|
|
9347
9394
|
constructor(config) {
|
|
9348
9395
|
super(config);
|
|
9349
9396
|
this.contentLines = [];
|
|
9350
9397
|
this.scrollOffset = 0;
|
|
9398
|
+
this.wrapText = false;
|
|
9351
9399
|
this.content = config.content;
|
|
9400
|
+
this.wrapText = !!config.wrapText;
|
|
9352
9401
|
this.updateContentLines();
|
|
9353
9402
|
}
|
|
9354
9403
|
setContent(content) {
|
|
@@ -9356,8 +9405,18 @@ class ScrollArea extends Component {
|
|
|
9356
9405
|
this.scrollOffset = 0;
|
|
9357
9406
|
this.updateContentLines();
|
|
9358
9407
|
}
|
|
9408
|
+
resize(x, y, width, height) {
|
|
9409
|
+
super.resize(x, y, width, height);
|
|
9410
|
+
if (this.wrapText) {
|
|
9411
|
+
this.updateContentLines();
|
|
9412
|
+
}
|
|
9413
|
+
}
|
|
9359
9414
|
updateContentLines() {
|
|
9360
|
-
this.
|
|
9415
|
+
if (this.wrapText && this.width > 0) {
|
|
9416
|
+
this.contentLines = wrapText(this.content, Math.max(1, this.width - 2));
|
|
9417
|
+
} else {
|
|
9418
|
+
this.contentLines = this.content.split("\n");
|
|
9419
|
+
}
|
|
9361
9420
|
}
|
|
9362
9421
|
render() {
|
|
9363
9422
|
const lines = [];
|
|
@@ -9372,7 +9431,6 @@ class ScrollArea extends Component {
|
|
|
9372
9431
|
const maxTop = this.height - scrollbarHeight;
|
|
9373
9432
|
scrollbarTop = Math.floor(scrollPercent * maxTop);
|
|
9374
9433
|
}
|
|
9375
|
-
const stripAnsi = (str) => str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
|
|
9376
9434
|
for (let i = 0; i < this.height; i++) {
|
|
9377
9435
|
const lineContent = visibleLines[i] || "";
|
|
9378
9436
|
let prefix = "";
|