@easbot/terminal 0.3.11

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 houjallen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,238 @@
1
+ [中文](./README.md) | English
2
+
3
+ # @easbot/terminal
4
+
5
+ > Terminal interaction toolkit — unified terminal output, formatting, prompts, and state recovery for EASBOT
6
+
7
+ ## Introduction
8
+
9
+ `@easbot/terminal` is a terminal interaction toolkit for the EASBOT ecosystem. It encapsulates the common capabilities required by CLI / TUI scenarios: themed color output, ANSI handling, OSC-8 hyperlinks, table rendering, styled prompts, safe stream writes, progress-line management, and terminal-state recovery. Every module auto-detects terminal capability (`NO_COLOR` / `FORCE_COLOR` / TTY) and degrades gracefully in non-TTY environments (pipes, redirected files, CI logs).
10
+
11
+ ## Features
12
+
13
+ - **Themed color output** — chalk + Lobster palette with consistent accent / info / success / warning / error colors
14
+ - **Capability detection** — auto-detects TTY, color level, `NO_COLOR` / `FORCE_COLOR`, and degrades to plain text when needed
15
+ - **ANSI utilities** — strips SGR / OSC-8 sequences and computes visible character width (Unicode & emoji safe)
16
+ - **Path helpers** — `~` and `$EASBOT_HOME` shortening for home-directory paths
17
+ - **OSC-8 hyperlinks** — cross-platform terminal hyperlinks with graceful fallback
18
+ - **Table rendering** — `renderTable` with auto-fit columns, Unicode / ASCII / borderless styles, ANSI-safe wrapping
19
+ - **Command output formatting** — success / error / warning / info / heading / key-value / command / list / status / count helpers
20
+ - **Styled prompts** — styled wrappers around `@clack/prompts` (`selectStyled` / `note` / `stylePromptMessage` …)
21
+ - **Safe stream writer** — `createSafeStreamWriter` swallows `EPIPE` / `EIO`, so a closed pipe never throws
22
+ - **Progress line** — register / clear / unregister an active progress line (TTY-only)
23
+ - **Terminal-state recovery** — `restoreTerminalState` resets cursor, mouse tracking, and bracketed paste on exit
24
+ - **CLI JSON output** — `emitJsonOk` / `emitJsonError` implement the EASBOT CLI `--json` contract (`{ ok, data | error }`)
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pnpm add @easbot/terminal
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ### Theme & capability detection
35
+
36
+ ```typescript
37
+ import { theme, isRich, colorize } from '@easbot/terminal';
38
+
39
+ const rich = isRich();
40
+ console.log(colorize(rich, theme.accent, 'Important notice'));
41
+ console.log(colorize(rich, theme.success, '✓ Operation succeeded'));
42
+ console.log(colorize(rich, theme.error, '✗ Operation failed'));
43
+ ```
44
+
45
+ ### Command output formatting
46
+
47
+ ```typescript
48
+ import {
49
+ formatSuccess,
50
+ formatError,
51
+ formatWarning,
52
+ formatInfo,
53
+ formatHeading,
54
+ formatKeyValue,
55
+ formatCommandExample,
56
+ formatListItem,
57
+ formatStatus,
58
+ } from '@easbot/terminal';
59
+
60
+ console.log(formatHeading('Build Output'));
61
+ console.log(formatKeyValue('entry', './dist/index.mjs'));
62
+ console.log(formatKeyValue('format', 'esm / cjs'));
63
+ console.log(formatSuccess('Build complete'));
64
+ console.log(formatError('Missing required flag --name'));
65
+ console.log(formatWarning('Detected uncommitted changes'));
66
+ console.log(formatCommandExample('pnpm build', 'Build all packages'));
67
+ console.log(formatListItem('◇', 'lint', 'biome check .'));
68
+ console.log(formatStatus('running', 'Building...'));
69
+ ```
70
+
71
+ ### Paths & hyperlinks
72
+
73
+ ```typescript
74
+ import { resolveUserPath, resolveConfigDir, displayPath, formatTerminalLink } from '@easbot/terminal';
75
+
76
+ const configDir = resolveConfigDir(); // ~/.openclaw or $OPENCLAW_STATE_DIR
77
+ console.log(displayPath(configDir));
78
+
79
+ console.log(formatTerminalLink('EASBOT repo', 'https://github.com/houjallen/easbot'));
80
+ ```
81
+
82
+ ### Table rendering
83
+
84
+ ```typescript
85
+ import { renderTable } from '@easbot/terminal';
86
+
87
+ console.log(
88
+ renderTable({
89
+ columns: [
90
+ { key: 'name', header: 'Name', align: 'left' },
91
+ { key: 'version', header: 'Version', align: 'left' },
92
+ { key: 'status', header: 'Status', align: 'center' },
93
+ ],
94
+ rows: [
95
+ { name: '@easbot/terminal', version: '0.3.11', status: '✓' },
96
+ { name: '@easbot/note', version: '0.3.11', status: '✓' },
97
+ ],
98
+ style: 'unicode',
99
+ }),
100
+ );
101
+ ```
102
+
103
+ ### Styled prompts
104
+
105
+ ```typescript
106
+ import { selectStyled, note, wrapNoteMessage } from '@easbot/terminal';
107
+
108
+ const choice = await selectStyled({
109
+ message: 'Choose an action',
110
+ options: [
111
+ { value: 'build', label: 'Build', hint: 'Run pnpm build' },
112
+ { value: 'test', label: 'Test', hint: 'Run pnpm test:run' },
113
+ ],
114
+ });
115
+
116
+ note(wrapNoteMessage('Config file saved to ~/.config/app/config.json'), 'Success');
117
+ ```
118
+
119
+ ### Safe stream writes & state recovery
120
+
121
+ ```typescript
122
+ import { createSafeStreamWriter, restoreTerminalState, registerActiveProgressLine } from '@easbot/terminal';
123
+
124
+ const writer = createSafeStreamWriter();
125
+ registerActiveProgressLine(process.stdout);
126
+
127
+ process.on('exit', () => restoreTerminalState('process exit'));
128
+ process.on('SIGINT', () => restoreTerminalState('SIGINT', { exit: true }));
129
+
130
+ // Writing after the pipe closes won't throw EPIPE
131
+ writer.write('first\n');
132
+ writer.write('second\n');
133
+ ```
134
+
135
+ ### CLI `--json` contract
136
+
137
+ ```typescript
138
+ import { emitJsonOk, emitJsonError } from '@easbot/terminal';
139
+
140
+ emitJsonOk({ items: [{ id: 1 }, { id: 2 }] }, { count: 2 });
141
+ // {"ok":true,"data":{"items":[{"id":1},{"id":2}]},"meta":{"count":2}}
142
+
143
+ emitJsonError('E_NOT_FOUND', 'Resource not found');
144
+ // {"ok":false,"error":{"code":"E_NOT_FOUND","message":"Resource not found"}}
145
+ ```
146
+
147
+ ## API Overview
148
+
149
+ ### Theme & styling
150
+
151
+ - `theme` — themed color helpers (`accent`, `info`, `success`, `warn`, `error`, `muted`, `heading`, `command`, `option`)
152
+ - `isRich()` — whether the terminal supports rich color output
153
+ - `colorize(rich, color, value)` — conditional coloring helper
154
+ - `LOBSTER_PALETTE` — raw Lobster palette values
155
+
156
+ ### ANSI utilities
157
+
158
+ - `stripAnsi(input)` — strip SGR / OSC-8 sequences from a string
159
+ - `visibleWidth(input)` — visible character width after stripping ANSI
160
+
161
+ ### Paths & display
162
+
163
+ - `resolveUserPath(input)` — resolve user paths (supports `~`)
164
+ - `resolveConfigDir(env?, homedir?)` — resolve the config dir (supports `OPENCLAW_STATE_DIR` / `CLAWDBOT_STATE_DIR`)
165
+ - `resolveHomeDir()` — resolve the effective home directory
166
+ - `shortenHomePath(input)` / `displayPath(input)` — shorten the home prefix in a single path
167
+ - `shortenHomeInString(input)` / `displayString(input)` — replace every occurrence of the home prefix in a string
168
+ - `resolveEffectiveHomeDir` / `resolveRequiredHomeDir` / `expandHomePrefix` — low-level home helpers
169
+ - `formatTerminalLink(label, url, opts?)` — format an OSC-8 hyperlink
170
+ - `formatDocsLink(path, label?, opts?)` / `formatDocsRootLink(label?)` / `DOCS_ROOT` — docs-link helpers
171
+
172
+ ### Command output formatting
173
+
174
+ - `formatSuccess` / `formatError` / `formatWarning` / `formatInfo`
175
+ - `formatHeading` / `formatKeyValue` / `formatCommandExample` / `formatListItem`
176
+ - `formatStatus` / `formatSeparator` / `formatEmptyMessage` / `formatCount`
177
+
178
+ ### Tables
179
+
180
+ - `TableColumn` / `RenderTableOptions` — column and render-option types
181
+ - `renderTable(opts)` — render a table string
182
+
183
+ ### Styled prompts
184
+
185
+ - `stylePromptMessage` / `stylePromptTitle` / `stylePromptHint` — prompt text styling
186
+ - `selectStyled<T>(params)` — themed select prompt
187
+ - `note(message, title?)` — themed note box
188
+ - `wrapNoteMessage(message, options?)` — auto-wrap a note's message
189
+
190
+ ### CLI JSON output
191
+
192
+ - `emitJsonOk(data, meta?)` — emit `{ ok: true, data, meta? }`
193
+ - `emitJsonError(code, message)` — emit `{ ok: false, error: { code, message } }`
194
+
195
+ ### Streams & state
196
+
197
+ - `SafeStreamWriterOptions` / `SafeStreamWriter` — safe stream-writer types
198
+ - `createSafeStreamWriter(options?)` — create a writer that swallows `EPIPE` / `EIO`
199
+ - `registerActiveProgressLine(stream)` / `clearActiveProgressLine()` / `unregisterActiveProgressLine(stream?)` — progress line management
200
+ - `restoreTerminalState(reason?, options?)` — restore cursor / mouse / bracketed-paste state
201
+
202
+ ### Misc
203
+
204
+ - `styleHealthChannelLine(line, rich)` — themed health-check channel line
205
+
206
+ ## Environment Variables
207
+
208
+ | Variable | Description |
209
+ |----------|-------------|
210
+ | `NO_COLOR` | Disables colors when set (unless `FORCE_COLOR` is also set) — see [no-color.org](https://no-color.org/) |
211
+ | `FORCE_COLOR` | Forces colors when non-empty and not equal to `'0'` |
212
+ | `HOME` / `USERPROFILE` | Fallback sources for home directory resolution |
213
+ | `EASBOT_HOME` | Explicit override for the home directory; changes the display prefix from `~` to `$EASBOT_HOME` |
214
+ | `OPENCLAW_STATE_DIR` / `CLAWDBOT_STATE_DIR` | Override the resolved config directory |
215
+
216
+ ## Development
217
+
218
+ ```bash
219
+ # Install dependencies
220
+ pnpm install
221
+
222
+ # Build
223
+ pnpm build
224
+
225
+ # Test
226
+ pnpm test:run
227
+
228
+ # Type-check
229
+ pnpm type-check
230
+
231
+ # Lint / Format
232
+ pnpm lint
233
+ pnpm format:fix
234
+ ```
235
+
236
+ ## License
237
+
238
+ MIT
package/README.md ADDED
@@ -0,0 +1,238 @@
1
+ [English](./README.en.md) | 中文
2
+
3
+ # @easbot/terminal
4
+
5
+ > 终端交互工具库 — 为 EASBOT 生态提供统一的终端输出、格式化、提示与状态恢复能力
6
+
7
+ ## 简介
8
+
9
+ `@easbot/terminal` 是一个面向 EASBOT 生态的终端交互工具库,封装了命令行 / TUI 场景下常用的能力:终端主题色、ANSI 处理、超链接、表格渲染、提示样式、安全流写入、进度行管理以及终端状态恢复。所有能力都基于终端能力自动检测(`NO_COLOR` / `FORCE_COLOR` / TTY)进行降级,可在管道、文件重定向等非 TTY 场景下安全使用。
10
+
11
+ ## 特性
12
+
13
+ - **终端主题**:基于 chalk + Lobster 调色板,提供统一的强调色 / 信息 / 成功 / 警告 / 错误等样式
14
+ - **终端能力检测**:自动识别 TTY、颜色等级、`NO_COLOR` / `FORCE_COLOR`,不支持富文本时自动降级为纯文本
15
+ - **ANSI 工具**:剥离 SGR / OSC-8 序列,计算可见字符宽度,处理 Unicode / emoji 文本对齐
16
+ - **路径显示**:支持 `~` / `$EASBOT_HOME` 缩短用户主目录路径(`resolveUserPath` / `shortenHomePath` / `displayPath`)
17
+ - **OSC-8 超链接**:跨平台终端超链接,自动检测终端能力,提供降级文本
18
+ - **表格渲染**:`renderTable` 支持自适应列宽、Unicode / ASCII / 无边框三种样式、文本换行、ANSI 样式保持
19
+ - **命令输出格式化**:成功 / 错误 / 警告 / 信息 / 标题 / 键值对 / 命令示例 / 列表项 / 进度状态 / 计数等
20
+ - **提示样式化**:`@clack/prompts` 的样式化封装(`selectStyled` / `note` / `stylePromptMessage` 等)
21
+ - **安全流写入**:`createSafeStreamWriter` 自动处理 `EPIPE` / `EIO`,流关闭后静默忽略后续写入
22
+ - **进度行管理**:注册 / 清除 / 注销活动进度行,仅在 TTY 下生效
23
+ - **终端状态恢复**:`restoreTerminalState` 在退出 / 异常时重置光标、鼠标跟踪、括号粘贴模式
24
+ - **JSON 规范输出**:`emitJsonOk` / `emitJsonError` 实现 CLI `--json` 规范的 `{ ok, data | error }` 协议
25
+
26
+ ## 安装
27
+
28
+ ```bash
29
+ pnpm add @easbot/terminal
30
+ ```
31
+
32
+ ## 快速开始
33
+
34
+ ### 主题与终端能力
35
+
36
+ ```typescript
37
+ import { theme, isRich, colorize } from '@easbot/terminal';
38
+
39
+ const rich = isRich();
40
+ console.log(colorize(rich, theme.accent, '重要提示'));
41
+ console.log(colorize(rich, theme.success, '✓ 操作成功'));
42
+ console.log(colorize(rich, theme.error, '✗ 操作失败'));
43
+ ```
44
+
45
+ ### 命令输出格式化
46
+
47
+ ```typescript
48
+ import {
49
+ formatSuccess,
50
+ formatError,
51
+ formatWarning,
52
+ formatInfo,
53
+ formatHeading,
54
+ formatKeyValue,
55
+ formatCommandExample,
56
+ formatListItem,
57
+ formatStatus,
58
+ } from '@easbot/terminal';
59
+
60
+ console.log(formatHeading('构建产物'));
61
+ console.log(formatKeyValue('入口', './dist/index.mjs'));
62
+ console.log(formatKeyValue('格式', 'esm / cjs'));
63
+ console.log(formatSuccess('构建完成'));
64
+ console.log(formatError('缺少必填参数 --name'));
65
+ console.log(formatWarning('检测到未提交变更'));
66
+ console.log(formatCommandExample('pnpm build', '构建所有包'));
67
+ console.log(formatListItem('◇', 'lint', 'biome check .'));
68
+ console.log(formatStatus('running', '正在执行构建...'));
69
+ ```
70
+
71
+ ### 路径与超链接
72
+
73
+ ```typescript
74
+ import { resolveUserPath, resolveConfigDir, displayPath, formatTerminalLink } from '@easbot/terminal';
75
+
76
+ const configDir = resolveConfigDir(); // ~/.openclaw 或 $OPENCLAW_STATE_DIR
77
+ console.log(displayPath(configDir));
78
+
79
+ console.log(formatTerminalLink('查看文档', 'https://github.com/houjallen/easbot'));
80
+ ```
81
+
82
+ ### 表格渲染
83
+
84
+ ```typescript
85
+ import { renderTable } from '@easbot/terminal';
86
+
87
+ console.log(
88
+ renderTable({
89
+ columns: [
90
+ { key: 'name', header: '名称', align: 'left' },
91
+ { key: 'version', header: '版本', align: 'left' },
92
+ { key: 'status', header: '状态', align: 'center' },
93
+ ],
94
+ rows: [
95
+ { name: '@easbot/terminal', version: '0.3.11', status: '✓' },
96
+ { name: '@easbot/note', version: '0.3.11', status: '✓' },
97
+ ],
98
+ style: 'unicode',
99
+ }),
100
+ );
101
+ ```
102
+
103
+ ### 样式化提示
104
+
105
+ ```typescript
106
+ import { selectStyled, note, wrapNoteMessage } from '@easbot/terminal';
107
+
108
+ const choice = await selectStyled({
109
+ message: '请选择要执行的操作',
110
+ options: [
111
+ { value: 'build', label: '构建', hint: '运行 pnpm build' },
112
+ { value: 'test', label: '测试', hint: '运行 pnpm test:run' },
113
+ ],
114
+ });
115
+
116
+ note(wrapNoteMessage('配置文件已成功保存到 ~/.config/app/config.json'), '成功');
117
+ ```
118
+
119
+ ### 安全流写入与状态恢复
120
+
121
+ ```typescript
122
+ import { createSafeStreamWriter, restoreTerminalState, registerActiveProgressLine } from '@easbot/terminal';
123
+
124
+ const writer = createSafeStreamWriter();
125
+ registerActiveProgressLine(process.stdout);
126
+
127
+ process.on('exit', () => restoreTerminalState('process exit'));
128
+ process.on('SIGINT', () => restoreTerminalState('SIGINT', { exit: true }));
129
+
130
+ // 流断开(如管道关闭)后再次写入不会抛 EPIPE
131
+ writer.write('first\n');
132
+ writer.write('second\n');
133
+ ```
134
+
135
+ ### CLI `--json` 规范输出
136
+
137
+ ```typescript
138
+ import { emitJsonOk, emitJsonError } from '@easbot/terminal';
139
+
140
+ emitJsonOk({ items: [{ id: 1 }, { id: 2 }] }, { count: 2 });
141
+ // {"ok":true,"data":{"items":[{"id":1},{"id":2}]},"meta":{"count":2}}
142
+
143
+ emitJsonError('E_NOT_FOUND', '资源不存在');
144
+ // {"ok":false,"error":{"code":"E_NOT_FOUND","message":"资源不存在"}}
145
+ ```
146
+
147
+ ## API 总览
148
+
149
+ ### 主题与样式
150
+
151
+ - `theme` — 主题颜色对象(accent / info / success / warn / error / muted / heading / command / option)
152
+ - `isRich()` — 判断终端是否支持富文本颜色
153
+ - `colorize(rich, color, value)` — 条件着色工具
154
+ - `LOBSTER_PALETTE` — Lobster 调色板原始色值
155
+
156
+ ### ANSI 工具
157
+
158
+ - `stripAnsi(input)` — 剥离 ANSI SGR / OSC-8 序列,返回纯文本
159
+ - `visibleWidth(input)` — 计算剥离 ANSI 后的可见字符宽度
160
+
161
+ ### 路径与显示
162
+
163
+ - `resolveUserPath(input)` — 解析用户路径(支持 `~` 波浪号)
164
+ - `resolveConfigDir(env?, homedir?)` — 解析配置目录(支持 `OPENCLAW_STATE_DIR` / `CLAWDBOT_STATE_DIR` 覆盖)
165
+ - `resolveHomeDir()` — 解析用户主目录
166
+ - `shortenHomePath(input)` / `displayPath(input)` — 缩短路径中的主目录部分
167
+ - `shortenHomeInString(input)` / `displayString(input)` — 替换字符串中所有匹配的主目录路径
168
+ - `resolveEffectiveHomeDir` / `resolveRequiredHomeDir` / `expandHomePrefix` — 主目录解析工具
169
+ - `formatTerminalLink(label, url, opts?)` — 格式化 OSC-8 终端超链接
170
+ - `formatDocsLink(path, label?, opts?)` / `formatDocsRootLink(label?)` / `DOCS_ROOT` — 文档链接辅助
171
+
172
+ ### 命令输出格式化
173
+
174
+ - `formatSuccess` / `formatError` / `formatWarning` / `formatInfo`
175
+ - `formatHeading` / `formatKeyValue` / `formatCommandExample` / `formatListItem`
176
+ - `formatStatus` / `formatSeparator` / `formatEmptyMessage` / `formatCount`
177
+
178
+ ### 表格
179
+
180
+ - `TableColumn` / `RenderTableOptions` — 表格列配置与渲染选项类型
181
+ - `renderTable(opts)` — 渲染表格字符串
182
+
183
+ ### 提示样式化
184
+
185
+ - `stylePromptMessage` / `stylePromptTitle` / `stylePromptHint` — 提示文本样式化
186
+ - `selectStyled<T>(params)` — 样式化的选择提示
187
+ - `note(message, title?)` — 样式化的注释框
188
+ - `wrapNoteMessage(message, options?)` — 注释消息自动换行
189
+
190
+ ### JSON 规范输出
191
+
192
+ - `emitJsonOk(data, meta?)` — 输出 `{ ok: true, data, meta? }` JSON 响应
193
+ - `emitJsonError(code, message)` — 输出 `{ ok: false, error: { code, message } }` JSON 响应
194
+
195
+ ### 流与状态
196
+
197
+ - `SafeStreamWriterOptions` / `SafeStreamWriter` — 安全流写入器类型
198
+ - `createSafeStreamWriter(options?)` — 创建安全流写入器,自动处理 `EPIPE` / `EIO`
199
+ - `registerActiveProgressLine(stream)` / `clearActiveProgressLine()` / `unregisterActiveProgressLine(stream?)` — 进度行管理
200
+ - `restoreTerminalState(reason?, options?)` — 恢复终端状态(光标 / 鼠标 / 括号粘贴模式)
201
+
202
+ ### 其它
203
+
204
+ - `styleHealthChannelLine(line, rich)` — 健康检查通道行样式化
205
+
206
+ ## 环境变量
207
+
208
+ | 变量 | 作用 |
209
+ |------|------|
210
+ | `NO_COLOR` | 存在时禁用终端颜色(除非同时设置了 `FORCE_COLOR`),遵循 [no-color.org](https://no-color.org/) 规范 |
211
+ | `FORCE_COLOR` | 非空且不为 `'0'` 时强制启用颜色 |
212
+ | `HOME` / `USERPROFILE` | 主目录解析的备选来源(OS 默认值) |
213
+ | `EASBOT_HOME` | 显式指定主目录;设置后路径显示前缀由 `~` 切换为 `$EASBOT_HOME` |
214
+ | `OPENCLAW_STATE_DIR` / `CLAWDBOT_STATE_DIR` | 配置目录覆盖项 |
215
+
216
+ ## 开发
217
+
218
+ ```bash
219
+ # 安装依赖
220
+ pnpm install
221
+
222
+ # 构建
223
+ pnpm build
224
+
225
+ # 测试
226
+ pnpm test:run
227
+
228
+ # 类型检查
229
+ pnpm type-check
230
+
231
+ # Lint / Format
232
+ pnpm lint
233
+ pnpm format:fix
234
+ ```
235
+
236
+ ## 许可证
237
+
238
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,11 @@
1
+ 'use strict';var xe=require('chalk'),Ne=require('fs'),B=require('os'),K=require('path'),utils=require('@easbot/utils'),prompts=require('@clack/prompts');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var xe__default=/*#__PURE__*/_interopDefault(xe);var Ne__default=/*#__PURE__*/_interopDefault(Ne);var B__default=/*#__PURE__*/_interopDefault(B);var K__default=/*#__PURE__*/_interopDefault(K);var de="\\x1b\\[[0-9;]*m",pe="\\x1b\\]8;;.*?\\x1b\\\\|\\x1b\\]8;;\\x1b\\\\",he=new RegExp(de,"g"),ge=new RegExp(pe,"g");function re(e){return !e||e.length===0?"":e.replace(ge,"").replace(he,"")}function O(e){return !e||e.length===0?0:Array.from(re(e)).length}var T={accent:"#FF5A2D",accentBright:"#FF7A3D",accentDim:"#D14A22",info:"#FF8A5B",success:"#2FBF71",warn:"#FFB020",error:"#E23D2D",muted:"#8B7F77"};var Se=typeof process.env.FORCE_COLOR=="string"&&process.env.FORCE_COLOR.trim().length>0&&process.env.FORCE_COLOR.trim()!=="0",z=process.env.NO_COLOR&&!Se?new xe.Chalk({level:0}):xe__default.default,R=e=>z.hex(e),m={accent:R(T.accent),accentBright:R(T.accentBright),accentDim:R(T.accentDim),info:R(T.info),success:R(T.success),warn:R(T.warn),error:R(T.error),muted:R(T.muted),heading:z.bold.hex(T.accent),command:R(T.accentBright),option:R(T.warn)},S=()=>z.level>0,E=(e,r,n)=>e?r(n):n;function Ee(e){let r=S();return E(r,m.success,"\u2713")+` ${e}`}function ke(e){let r=S();return E(r,m.error,"\u2717")+` ${e}`}function ve(e){let r=S();return E(r,m.warn,"\u26A0")+` ${e}`}function $e(e){let r=S();return E(r,m.info,"\u2139")+` ${e}`}function We(e){let r=S();return E(r,m.heading,e)}function we(e,r,n=15){let i=S(),o=e.padEnd(n);return `${E(i,m.muted,o)} ${r}`}function Te(e,r){let n=S(),i=E(n,m.command,e);if(!r)return ` ${i}`;let o=E(n,m.muted,`# ${r}`);return ` ${i} ${o}`}function ye(e,r,n){let i=S(),o=E(i,m.info,e),l=E(i,m.command,r),d=n?` ${E(i,m.muted,n)}`:"";return `${o} ${l}${d}`}function Pe(e,r){let n=S(),i,o;switch(e){case "pending":i="\u25CB",o=m.muted;break;case "running":i="\u25CF",o=m.info;break;case "success":i="\u2713",o=m.success;break;case "error":i="\u2717",o=m.error;break;case "skipped":i="\u25CB",o=m.muted;break}return E(n,o,i)+` ${r}`}function Oe(e=80,r="\u2500"){let n=S();return E(n,m.muted,r.repeat(e))}function Re(e){let r=S();return E(r,m.muted,e)}function Le(e,r,n){let i=S(),o=e===1?r:n||`${r}s`;return `${E(i,m.accent,String(e))} ${o}`}function L(e){let r=e?.trim();return r?utils.Filesystem.toUnixPath(r):void 0}function M(e=process.env,r=B__default.default.homedir){let n=Ce(e,r);return n?utils.Filesystem.resolve(n):void 0}function Ce(e,r){let n=L(e.EASBOT_HOME);if(n){if(n==="~"||n.startsWith("~/")||n.startsWith("~\\")){let l=L(e.HOME)??L(e.USERPROFILE)??te(r);return l?n.replace(/^~(?=$|[\\/])/,l):void 0}return n}let i=L(e.HOME);if(i)return i;let o=L(e.USERPROFILE);return o||te(r)}function te(e){try{return L(e())}catch{return}}function F(e=process.env,r=B__default.default.homedir){return M(e,r)??utils.Filesystem.resolve(process.cwd())}function Y(e,r){if(!e.startsWith("~"))return L(e);let n=process.env.EASBOT_TEST_HOME?.trim();return n||(n=L(r?.home)??M(r?.env??process.env,r?.homedir??B__default.default.homedir)),n?e.replace(/^~(?=$|[\\/])/,n):L(e)}function ne(e){if(!e)return "";let r=e.trim();if(!r)return r;if(r.startsWith("~")){let n=Y(r,{home:F(process.env,B__default.default.homedir),env:process.env,homedir:B__default.default.homedir});return K__default.default.resolve(n)}return K__default.default.resolve(r)}function Ae(e=process.env,r=B__default.default.homedir){let n=e.OPENCLAW_STATE_DIR?.trim()||e.CLAWDBOT_STATE_DIR?.trim();if(n)return ne(n);let i=K__default.default.join(F(e,r),".openclaw");try{if(Ne__default.default.existsSync(i))return i}catch{}return i}function oe(){return M(process.env,B__default.default.homedir)}function ie(){let e=oe();return e?process.env.EASBOT_HOME?.trim()?{home:e,prefix:"$EASBOT_HOME"}:{home:e,prefix:"~"}:void 0}function se(e){if(!e)return e;let r=ie();if(!r)return e;let{home:n,prefix:i}=r;return e===n?i:e.startsWith(`${n}/`)||e.startsWith(`${n}\\`)?`${i}${e.slice(n.length)}`:e}function ce(e){if(!e)return e;let r=ie();return r?e.split(r.home).join(r.prefix):e}function Ie(e){return se(e)}function q(e){return ce(e)}function J(e,r,n){let o=e.replaceAll("\x1B",""),l=r.replaceAll("\x1B","");return (n?.force===true?true:n?.force===false?false:!!process.stdout.isTTY)?`\x1B]8;;${l}\x07${o}\x1B]8;;\x07`:n?.fallback??`${o} (${l})`}var D="https://docs.openclaw.ai";function _e(e,r,n){let i=e.trim(),o=i.startsWith("http")?i:`${D}${i.startsWith("/")?i:`/${i}`}`;return J(r??o,o,{fallback:n?.fallback??o,force:n?.force})}function He(e){return J(e??D,D,{fallback:D})}function Me(e,r){let n={ok:true,data:e};r!==void 0&&(n.meta=r),console.log(JSON.stringify(n,null,2));}function De(e,r){console.log(JSON.stringify({ok:false,error:{code:e,message:r}},null,2));}var G=e=>S()?m.accent(e):e,X=e=>e&&S()?m.heading(e):e,Z=e=>e&&S()?m.muted(e):e;var Be=/^(https?:\/\/|file:\/\/)/i,Je=/^[a-zA-Z]:[\\/]/,je=/^[a-zA-Z0-9._-]+$/;function ae(e,r){if(r<=0)return [e];let n=Array.from(e),i=[];for(let o=0;o<n.length;o+=r)i.push(n.slice(o,o+r).join(""));return i.length>0?i:[e]}function fe(e){return e?Be.test(e)||e.startsWith("/")||e.startsWith("~/")||e.startsWith("./")||e.startsWith("../")||Je.test(e)||e.startsWith("\\\\")||e.includes("/")||e.includes("\\")?true:e.includes("_")&&je.test(e):false}function ze(e,r){if(e.trim().length===0)return [e];if(r<=0)return [e];let n=e.match(/^(\s*)([-*\u2022]\s+)?(.*)$/),i=n?.[1]??"",o=n?.[2]??"",l=n?.[3]??"",d=`${i}${o}`,g=`${i}${o?" ".repeat(o.length):""}`,$=Math.max(10,r-O(d)),W=Math.max(10,r-O(g)),A=l.split(/\s+/).filter(Boolean),y=[],p="",x=d,k=$;for(let b of A){if(!p){if(O(b)>k){if(fe(b)){p=b;continue}let w=ae(b,k),f=w.shift()??"";y.push(x+f),x=g,k=W;for(let u of w)y.push(x+u);continue}p=b;continue}let C=`${p} ${b}`;if(O(C)<=k){p=C;continue}if(y.push(x+p),x=g,k=W,O(b)>k){if(fe(b)){p=b;continue}let w=ae(b,k),f=w.shift()??"";y.push(x+f);for(let u of w)y.push(x+u);p="";continue}p=b;}return (p||A.length===0)&&y.push(x+p),y}function ue(e,r={}){let n=r.columns??process.stdout.columns??80,i=r.maxWidth??Math.max(40,Math.min(88,n-10));return e.split(`
2
+ `).flatMap(o=>ze(o,i)).join(`
3
+ `)}function Ue(e,r){prompts.note(ue(e),X(r));}var _=null;function Ve(e){e.isTTY&&(_=e);}function Q(){_?.isTTY&&_.write("\r\x1B[2K");}function Ye(e){_&&(e&&_!==e||(_=null));}function qe(e){return prompts.select({...e,message:G(e.message),options:e.options.map(r=>r.hint===void 0?r:{...r,hint:Z(r.hint)})})}var Ge="\x1B[0m\x1B[?25h\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004l";function j(e,r,n){let i=n?` (${n})`:"",o=`[terminal] restore ${e} failed${i}: ${String(r)}`;try{process.stderr.write(`${o}
4
+ `);}catch(l){console.error(`[terminal] restore reporting failed${i}: ${String(l)}`);}}function Xe(e,r={}){let n=r.resumeStdinIfPaused??r.resumeStdin??false;try{Q();}catch(o){j("progress line",o,e);}let i=process.stdin;if(i.isTTY&&typeof i.setRawMode=="function"){try{i.setRawMode(!1);}catch(o){j("raw mode",o,e);}if(n&&typeof i.isPaused=="function"&&i.isPaused())try{i.resume();}catch(o){j("stdin resume",o,e);}}if(process.stdout.isTTY)try{process.stdout.write(Ge);}catch(o){j("stdout reset",o,e);}}function Ze(e){let r=e?.code;return r==="EPIPE"||r==="EIO"}function Qe(e={}){let r=false,n=false,i=(g,$)=>{n||(n=true,e.onBrokenPipe?.(g,$));},o=(g,$)=>{if(!Ze(g))throw g;return r=true,i(g,$),false},l=(g,$)=>{if(r)return false;try{e.beforeWrite?.();}catch(W){return o(W,process.stderr)}try{return g.write($),!r}catch(W){return o(W,g)}};return {write:l,writeLine:(g,$)=>l(g,`${$}
5
+ `),reset:()=>{r=false,n=false;},isClosed:()=>r}}function H(e,r){return !Number.isFinite(r)||r<=0?"":e.repeat(r)}function er(e,r,n){let i=O(e);if(i>=r)return e;let o=r-i;if(n==="right")return `${H(" ",o)}${e}`;if(n==="center"){let l=Math.floor(o/2),d=o-l;return `${H(" ",l)}${e}${H(" ",d)}`}return `${e}${H(" ",o)}`}function rr(e,r){if(!e||e.length===0)return [""];if(!Number.isFinite(r)||r<=0)return [e];let n="\x1B",i=[];for(let t=0;t<e.length;){if(e[t]===n){if(e[t+1]==="["){let a=t+2;for(;a<e.length;){let h=e[a];if(h==="m")break;if(h&&h>="0"&&h<="9"){a+=1;continue}if(h===";"){a+=1;continue}break}if(e[a]==="m"){i.push({kind:"ansi",value:e.slice(t,a+1)}),t=a+1;continue}}if(e[t+1]==="]"&&e.slice(t+2,t+5)==="8;;"){let a=e.indexOf(`${n}\\`,t+5);if(a>=0){i.push({kind:"ansi",value:e.slice(t,a+2)}),t=a+2;continue}}}let s=e.codePointAt(t);if(!s)break;let c=String.fromCodePoint(s);i.push({kind:"char",value:c}),t+=c.length;}let o=i.findIndex(t=>t.kind==="char");if(o<0)return [e];let l=-1;for(let t=i.length-1;t>=0;t-=1){let s=i[t];if(s&&s.kind==="char"){l=t;break}}let d=i.slice(0,o).filter(t=>t.kind==="ansi").map(t=>t.value).join(""),g=i.slice(l+1).filter(t=>t.kind==="ansi").map(t=>t.value).join(""),$=i.slice(o,l+1),W=[],A=t=>t===" "||t===" "||t==="/"||t==="-"||t==="_"||t===".",y=t=>t===" "||t===" ",p=false,x=[],k=0,b=null,C=t=>(t??x).map(s=>s.value).join(""),w=t=>t.reduce((s,c)=>s+(c.kind==="char"?1:0),0),f=t=>{let s=t.replace(/\s+$/,"");s.trim().length!==0&&W.push(s);},u=t=>{if(x.length===0)return;if(t==null||t<=0){f(C()),x.length=0,k=0,b=null;return}let s=x.slice(0,t),c=x.slice(t);for(f(C(s));c.length>0;){let a=c[0];if(a?.kind!=="char"||!y(a.value))break;c.shift();}x.length=0,x.push(...c),k=w(x),b=null;};for(let t of $){if(t.kind==="ansi"){x.push(t);continue}let s=t.value;if(!(p&&(p=false,s===`
6
+ `))){if(s===`
7
+ `||s==="\r"){u(x.length),s==="\r"&&(p=true);continue}k+1>r&&k>0&&u(b),x.push(t),k+=1,A(s)&&(b=x.length);}}return u(x.length),W.length===0?[""]:!d&&!g?W:W.map(t=>t&&`${d}${t}${g}`)}function tr(e){if(e!=null&&!(!Number.isFinite(e)||e<=0))return Math.floor(e)}function nr(e){let r=e.rows.map(f=>{let u={};for(let[t,s]of Object.entries(f))u[t]=q(s);return u}),n=e.border??"unicode";if(n==="none"){let f=e.columns;return `${[f.map(s=>s.header).join(" | "),...r.map(s=>f.map(c=>s[c.key]??"").join(" | "))].join(`
8
+ `)}
9
+ `}let i=Math.max(0,e.padding??1),o=e.columns,l=o.map(f=>{let u=O(f.header),t=Math.max(0,...r.map(s=>O(s[f.key]??"")));return {headerW:u,cellW:t}}),d=o.map((f,u)=>{let t=l[u];if(!t)throw new Error(`Internal error: metrics[${u}] is undefined`);let s=Math.max(t.headerW,t.cellW)+i*2,c=f.maxWidth?Math.min(s,f.maxWidth):s;return Math.max(f.minWidth??3,c)}),g=tr(e.width),$=o.length+1,W=d.reduce((f,u)=>f+u,0)+$,A=o.map((f,u)=>{let t=l[u];if(!t)throw new Error(`Internal error: metrics[${u}] is undefined`);return Math.max(f.minWidth??3,t.headerW+i*2,3)}),y=o.map((f,u)=>{let t=l[u];if(!t)throw new Error(`Internal error: metrics[${u}] is undefined`);return Math.max(t.headerW+i*2,3)});if(g&&W>g){let f=W-g,u=o.map((c,a)=>{let h=d[a];if(h===void 0)throw new Error(`Internal error: widths[${a}] is undefined`);return {i:a,w:h}}).filter(({i:c})=>!!o[c]?.flex).toSorted((c,a)=>a.w-c.w).map(c=>c.i),t=o.map((c,a)=>{let h=d[a];if(h===void 0)throw new Error(`Internal error: widths[${a}] is undefined`);return {i:a,w:h}}).filter(({i:c})=>!o[c]?.flex).toSorted((c,a)=>a.w-c.w).map(c=>c.i),s=(c,a)=>{for(;f>0;){let h=false;for(let P of c){let N=d[P],I=a[P];if(!(N===void 0||I===void 0)&&!(N<=I)&&(d[P]=N-1,f-=1,h=true,f<=0))break}if(!h)break}};s(u,A),s(u,y),s(t,A),s(t,y);}if(g){let f=o.length+1,u=d.reduce((s,c)=>s+c,0)+f,t=g-u;if(t>0){let s=o.map((c,a)=>({c,i:a})).filter(({c})=>!!c.flex).map(({i:c})=>c);if(s.length>0){let c=o.map(a=>typeof a.maxWidth=="number"&&a.maxWidth>0?Math.floor(a.maxWidth):Number.POSITIVE_INFINITY);for(;t>0;){let a=false;for(let h of s){let P=d[h],N=c[h];if(!(P===void 0||N===void 0)&&!(P>=N)&&(d[h]=P+1,t-=1,a=true,t<=0))break}if(!a)break}}}}let p=n==="ascii"?{tl:"+",tr:"+",bl:"+",br:"+",h:"-",v:"|",t:"+",ml:"+",m:"+",mr:"+",b:"+"}:{tl:"\u250C",tr:"\u2510",bl:"\u2514",br:"\u2518",h:"\u2500",v:"\u2502",t:"\u252C",ml:"\u251C",m:"\u253C",mr:"\u2524",b:"\u2534"},x=(f,u,t)=>`${f}${d.map(s=>{if(s===void 0)throw new Error("Internal error: width is undefined");return H(p.h,s)}).join(u)}${t}`,k=f=>{let u=d[f];if(u===void 0)throw new Error(`Internal error: widths[${f}] is undefined`);return Math.max(1,u-i*2)},b=H(" ",i),C=(f,u=false)=>{let s=o.map(h=>u?h.header:f[h.key]??"").map((h,P)=>rr(h,k(P))),c=Math.max(...s.map(h=>h.length)),a=[];for(let h=0;h<c;h+=1){let P=s.map((N,I)=>{let le=N[h]??"",ee=o[I];if(!ee)throw new Error(`Internal error: columns[${I}] is undefined`);let me=er(le,k(I),ee.align??"left");return `${b}${me}${b}`});a.push(`${p.v}${P.join(p.v)}${p.v}`);}return a},w=[];w.push(x(p.tl,p.t,p.tr)),w.push(...C({},true)),w.push(x(p.ml,p.m,p.mr));for(let f of r)w.push(...C(f,false));return w.push(x(p.bl,p.b,p.br)),`${w.join(`
10
+ `)}
11
+ `}function or(e,r){if(!r)return e;let n=e.indexOf(":");if(n===-1)return e;let i=e.slice(0,n+1),o=e.slice(n+1).trimStart(),l=o.toLowerCase(),d=(g,$)=>`${i} ${$(o.slice(0,g.length))}${o.slice(g.length)}`;return l.startsWith("failed")?d("failed",m.error):l.startsWith("ok")?d("ok",m.success):l.startsWith("linked")?d("linked",m.success):l.startsWith("configured")?d("configured",m.success):l.startsWith("not linked")?d("not linked",m.warn):l.startsWith("not configured")?d("not configured",m.muted):l.startsWith("unknown")?d("unknown",m.warn):e}exports.DOCS_ROOT=D;exports.LOBSTER_PALETTE=T;exports.clearActiveProgressLine=Q;exports.colorize=E;exports.createSafeStreamWriter=Qe;exports.displayPath=Ie;exports.displayString=q;exports.emitJsonError=De;exports.emitJsonOk=Me;exports.expandHomePrefix=Y;exports.formatCommandExample=Te;exports.formatCount=Le;exports.formatDocsLink=_e;exports.formatDocsRootLink=He;exports.formatEmptyMessage=Re;exports.formatError=ke;exports.formatHeading=We;exports.formatInfo=$e;exports.formatKeyValue=we;exports.formatListItem=ye;exports.formatSeparator=Oe;exports.formatStatus=Pe;exports.formatSuccess=Ee;exports.formatTerminalLink=J;exports.formatWarning=ve;exports.isRich=S;exports.note=Ue;exports.registerActiveProgressLine=Ve;exports.renderTable=nr;exports.resolveConfigDir=Ae;exports.resolveEffectiveHomeDir=M;exports.resolveHomeDir=oe;exports.resolveRequiredHomeDir=F;exports.resolveUserPath=ne;exports.restoreTerminalState=Xe;exports.selectStyled=qe;exports.shortenHomeInString=ce;exports.shortenHomePath=se;exports.stripAnsi=re;exports.styleHealthChannelLine=or;exports.stylePromptHint=Z;exports.stylePromptMessage=G;exports.stylePromptTitle=X;exports.theme=m;exports.unregisterActiveProgressLine=Ye;exports.visibleWidth=O;exports.wrapNoteMessage=ue;
@@ -0,0 +1,131 @@
1
+ import * as chalk from 'chalk';
2
+ import { select } from '@clack/prompts';
3
+
4
+ declare function stripAnsi(input: string): string;
5
+ declare function visibleWidth(input: string): number;
6
+
7
+ declare const LOBSTER_PALETTE: {
8
+ readonly accent: "#FF5A2D";
9
+ readonly accentBright: "#FF7A3D";
10
+ readonly accentDim: "#D14A22";
11
+ readonly info: "#FF8A5B";
12
+ readonly success: "#2FBF71";
13
+ readonly warn: "#FFB020";
14
+ readonly error: "#E23D2D";
15
+ readonly muted: "#8B7F77";
16
+ };
17
+
18
+ declare const theme: {
19
+ readonly accent: chalk.ChalkInstance;
20
+ readonly accentBright: chalk.ChalkInstance;
21
+ readonly accentDim: chalk.ChalkInstance;
22
+ readonly info: chalk.ChalkInstance;
23
+ readonly success: chalk.ChalkInstance;
24
+ readonly warn: chalk.ChalkInstance;
25
+ readonly error: chalk.ChalkInstance;
26
+ readonly muted: chalk.ChalkInstance;
27
+ readonly heading: chalk.ChalkInstance;
28
+ readonly command: chalk.ChalkInstance;
29
+ readonly option: chalk.ChalkInstance;
30
+ };
31
+ declare const isRich: () => boolean;
32
+ declare const colorize: (rich: boolean, color: (value: string) => string, value: string) => string;
33
+
34
+ declare function formatSuccess(message: string): string;
35
+ declare function formatError(message: string): string;
36
+ declare function formatWarning(message: string): string;
37
+ declare function formatInfo(message: string): string;
38
+ declare function formatHeading(title: string): string;
39
+ declare function formatKeyValue(key: string, value: string, keyWidth?: number): string;
40
+ declare function formatCommandExample(command: string, description?: string): string;
41
+ declare function formatListItem(icon: string, text: string, description?: string): string;
42
+ declare function formatStatus(status: 'pending' | 'running' | 'success' | 'error' | 'skipped', message: string): string;
43
+ declare function formatSeparator(width?: number, char?: string): string;
44
+ declare function formatEmptyMessage(message: string): string;
45
+ declare function formatCount(count: number, singular: string, plural?: string): string;
46
+
47
+ declare function resolveUserPath(input: string): string;
48
+ declare function resolveConfigDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
49
+ declare function resolveHomeDir(): string | undefined;
50
+ declare function shortenHomePath(input: string): string;
51
+ declare function shortenHomeInString(input: string): string;
52
+ declare function displayPath(input: string): string;
53
+ declare function displayString(input: string): string;
54
+ declare function formatTerminalLink(label: string, url: string, opts?: {
55
+ fallback?: string;
56
+ force?: boolean;
57
+ }): string;
58
+
59
+ declare function resolveEffectiveHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string | undefined;
60
+ declare function resolveRequiredHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
61
+ declare function expandHomePrefix(input: string, opts?: {
62
+ home?: string;
63
+ env?: NodeJS.ProcessEnv;
64
+ homedir?: () => string;
65
+ }): string;
66
+
67
+ declare const DOCS_ROOT = "https://docs.openclaw.ai";
68
+ declare function formatDocsLink(path: string, label?: string, opts?: {
69
+ fallback?: string;
70
+ force?: boolean;
71
+ }): string;
72
+ declare function formatDocsRootLink(label?: string): string;
73
+
74
+ declare function emitJsonOk(data: unknown, meta?: Record<string, unknown>): void;
75
+ declare function emitJsonError(code: string, message: string): void;
76
+
77
+ declare function wrapNoteMessage(message: string, options?: {
78
+ maxWidth?: number;
79
+ columns?: number;
80
+ }): string;
81
+ declare function note(message: string, title?: string): void;
82
+
83
+ declare function registerActiveProgressLine(stream: NodeJS.WriteStream): void;
84
+ declare function clearActiveProgressLine(): void;
85
+ declare function unregisterActiveProgressLine(stream?: NodeJS.WriteStream): void;
86
+
87
+ declare function selectStyled<T>(params: Parameters<typeof select<T>>[0]): Promise<symbol | T>;
88
+
89
+ declare const stylePromptMessage: (message: string) => string;
90
+ declare const stylePromptTitle: (title?: string) => string | undefined;
91
+ declare const stylePromptHint: (hint?: string) => string | undefined;
92
+
93
+ type RestoreTerminalStateOptions = {
94
+ resumeStdin?: boolean;
95
+ resumeStdinIfPaused?: boolean;
96
+ };
97
+ declare function restoreTerminalState(reason?: string, options?: RestoreTerminalStateOptions): void;
98
+
99
+ type SafeStreamWriterOptions = {
100
+ beforeWrite?: () => void;
101
+ onBrokenPipe?: (err: NodeJS.ErrnoException, stream: NodeJS.WriteStream) => void;
102
+ };
103
+ type SafeStreamWriter = {
104
+ write: (stream: NodeJS.WriteStream, text: string) => boolean;
105
+ writeLine: (stream: NodeJS.WriteStream, text: string) => boolean;
106
+ reset: () => void;
107
+ isClosed: () => boolean;
108
+ };
109
+ declare function createSafeStreamWriter(options?: SafeStreamWriterOptions): SafeStreamWriter;
110
+
111
+ type Align = 'left' | 'right' | 'center';
112
+ type TableColumn = {
113
+ key: string;
114
+ header: string;
115
+ align?: Align;
116
+ minWidth?: number;
117
+ maxWidth?: number;
118
+ flex?: boolean;
119
+ };
120
+ type RenderTableOptions = {
121
+ columns: TableColumn[];
122
+ rows: Array<Record<string, string>>;
123
+ width?: number;
124
+ padding?: number;
125
+ border?: 'unicode' | 'ascii' | 'none';
126
+ };
127
+ declare function renderTable(opts: RenderTableOptions): string;
128
+
129
+ declare function styleHealthChannelLine(line: string, rich: boolean): string;
130
+
131
+ export { DOCS_ROOT, LOBSTER_PALETTE, type RenderTableOptions, type SafeStreamWriter, type SafeStreamWriterOptions, type TableColumn, clearActiveProgressLine, colorize, createSafeStreamWriter, displayPath, displayString, emitJsonError, emitJsonOk, expandHomePrefix, formatCommandExample, formatCount, formatDocsLink, formatDocsRootLink, formatEmptyMessage, formatError, formatHeading, formatInfo, formatKeyValue, formatListItem, formatSeparator, formatStatus, formatSuccess, formatTerminalLink, formatWarning, isRich, note, registerActiveProgressLine, renderTable, resolveConfigDir, resolveEffectiveHomeDir, resolveHomeDir, resolveRequiredHomeDir, resolveUserPath, restoreTerminalState, selectStyled, shortenHomeInString, shortenHomePath, stripAnsi, styleHealthChannelLine, stylePromptHint, stylePromptMessage, stylePromptTitle, theme, unregisterActiveProgressLine, visibleWidth, wrapNoteMessage };
@@ -0,0 +1,131 @@
1
+ import * as chalk from 'chalk';
2
+ import { select } from '@clack/prompts';
3
+
4
+ declare function stripAnsi(input: string): string;
5
+ declare function visibleWidth(input: string): number;
6
+
7
+ declare const LOBSTER_PALETTE: {
8
+ readonly accent: "#FF5A2D";
9
+ readonly accentBright: "#FF7A3D";
10
+ readonly accentDim: "#D14A22";
11
+ readonly info: "#FF8A5B";
12
+ readonly success: "#2FBF71";
13
+ readonly warn: "#FFB020";
14
+ readonly error: "#E23D2D";
15
+ readonly muted: "#8B7F77";
16
+ };
17
+
18
+ declare const theme: {
19
+ readonly accent: chalk.ChalkInstance;
20
+ readonly accentBright: chalk.ChalkInstance;
21
+ readonly accentDim: chalk.ChalkInstance;
22
+ readonly info: chalk.ChalkInstance;
23
+ readonly success: chalk.ChalkInstance;
24
+ readonly warn: chalk.ChalkInstance;
25
+ readonly error: chalk.ChalkInstance;
26
+ readonly muted: chalk.ChalkInstance;
27
+ readonly heading: chalk.ChalkInstance;
28
+ readonly command: chalk.ChalkInstance;
29
+ readonly option: chalk.ChalkInstance;
30
+ };
31
+ declare const isRich: () => boolean;
32
+ declare const colorize: (rich: boolean, color: (value: string) => string, value: string) => string;
33
+
34
+ declare function formatSuccess(message: string): string;
35
+ declare function formatError(message: string): string;
36
+ declare function formatWarning(message: string): string;
37
+ declare function formatInfo(message: string): string;
38
+ declare function formatHeading(title: string): string;
39
+ declare function formatKeyValue(key: string, value: string, keyWidth?: number): string;
40
+ declare function formatCommandExample(command: string, description?: string): string;
41
+ declare function formatListItem(icon: string, text: string, description?: string): string;
42
+ declare function formatStatus(status: 'pending' | 'running' | 'success' | 'error' | 'skipped', message: string): string;
43
+ declare function formatSeparator(width?: number, char?: string): string;
44
+ declare function formatEmptyMessage(message: string): string;
45
+ declare function formatCount(count: number, singular: string, plural?: string): string;
46
+
47
+ declare function resolveUserPath(input: string): string;
48
+ declare function resolveConfigDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
49
+ declare function resolveHomeDir(): string | undefined;
50
+ declare function shortenHomePath(input: string): string;
51
+ declare function shortenHomeInString(input: string): string;
52
+ declare function displayPath(input: string): string;
53
+ declare function displayString(input: string): string;
54
+ declare function formatTerminalLink(label: string, url: string, opts?: {
55
+ fallback?: string;
56
+ force?: boolean;
57
+ }): string;
58
+
59
+ declare function resolveEffectiveHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string | undefined;
60
+ declare function resolveRequiredHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
61
+ declare function expandHomePrefix(input: string, opts?: {
62
+ home?: string;
63
+ env?: NodeJS.ProcessEnv;
64
+ homedir?: () => string;
65
+ }): string;
66
+
67
+ declare const DOCS_ROOT = "https://docs.openclaw.ai";
68
+ declare function formatDocsLink(path: string, label?: string, opts?: {
69
+ fallback?: string;
70
+ force?: boolean;
71
+ }): string;
72
+ declare function formatDocsRootLink(label?: string): string;
73
+
74
+ declare function emitJsonOk(data: unknown, meta?: Record<string, unknown>): void;
75
+ declare function emitJsonError(code: string, message: string): void;
76
+
77
+ declare function wrapNoteMessage(message: string, options?: {
78
+ maxWidth?: number;
79
+ columns?: number;
80
+ }): string;
81
+ declare function note(message: string, title?: string): void;
82
+
83
+ declare function registerActiveProgressLine(stream: NodeJS.WriteStream): void;
84
+ declare function clearActiveProgressLine(): void;
85
+ declare function unregisterActiveProgressLine(stream?: NodeJS.WriteStream): void;
86
+
87
+ declare function selectStyled<T>(params: Parameters<typeof select<T>>[0]): Promise<symbol | T>;
88
+
89
+ declare const stylePromptMessage: (message: string) => string;
90
+ declare const stylePromptTitle: (title?: string) => string | undefined;
91
+ declare const stylePromptHint: (hint?: string) => string | undefined;
92
+
93
+ type RestoreTerminalStateOptions = {
94
+ resumeStdin?: boolean;
95
+ resumeStdinIfPaused?: boolean;
96
+ };
97
+ declare function restoreTerminalState(reason?: string, options?: RestoreTerminalStateOptions): void;
98
+
99
+ type SafeStreamWriterOptions = {
100
+ beforeWrite?: () => void;
101
+ onBrokenPipe?: (err: NodeJS.ErrnoException, stream: NodeJS.WriteStream) => void;
102
+ };
103
+ type SafeStreamWriter = {
104
+ write: (stream: NodeJS.WriteStream, text: string) => boolean;
105
+ writeLine: (stream: NodeJS.WriteStream, text: string) => boolean;
106
+ reset: () => void;
107
+ isClosed: () => boolean;
108
+ };
109
+ declare function createSafeStreamWriter(options?: SafeStreamWriterOptions): SafeStreamWriter;
110
+
111
+ type Align = 'left' | 'right' | 'center';
112
+ type TableColumn = {
113
+ key: string;
114
+ header: string;
115
+ align?: Align;
116
+ minWidth?: number;
117
+ maxWidth?: number;
118
+ flex?: boolean;
119
+ };
120
+ type RenderTableOptions = {
121
+ columns: TableColumn[];
122
+ rows: Array<Record<string, string>>;
123
+ width?: number;
124
+ padding?: number;
125
+ border?: 'unicode' | 'ascii' | 'none';
126
+ };
127
+ declare function renderTable(opts: RenderTableOptions): string;
128
+
129
+ declare function styleHealthChannelLine(line: string, rich: boolean): string;
130
+
131
+ export { DOCS_ROOT, LOBSTER_PALETTE, type RenderTableOptions, type SafeStreamWriter, type SafeStreamWriterOptions, type TableColumn, clearActiveProgressLine, colorize, createSafeStreamWriter, displayPath, displayString, emitJsonError, emitJsonOk, expandHomePrefix, formatCommandExample, formatCount, formatDocsLink, formatDocsRootLink, formatEmptyMessage, formatError, formatHeading, formatInfo, formatKeyValue, formatListItem, formatSeparator, formatStatus, formatSuccess, formatTerminalLink, formatWarning, isRich, note, registerActiveProgressLine, renderTable, resolveConfigDir, resolveEffectiveHomeDir, resolveHomeDir, resolveRequiredHomeDir, resolveUserPath, restoreTerminalState, selectStyled, shortenHomeInString, shortenHomePath, stripAnsi, styleHealthChannelLine, stylePromptHint, stylePromptMessage, stylePromptTitle, theme, unregisterActiveProgressLine, visibleWidth, wrapNoteMessage };
package/dist/index.mjs ADDED
@@ -0,0 +1,11 @@
1
+ import be,{Chalk}from'chalk';import Ae from'fs';import J from'os';import q from'path';import {Filesystem}from'@easbot/utils';import {note,select}from'@clack/prompts';var pe="\\x1b\\[[0-9;]*m",he="\\x1b\\]8;;.*?\\x1b\\\\|\\x1b\\]8;;\\x1b\\\\",ge=new RegExp(pe,"g"),xe=new RegExp(he,"g");function te(e){return !e||e.length===0?"":e.replace(xe,"").replace(ge,"")}function R(e){return !e||e.length===0?0:Array.from(te(e)).length}var y={accent:"#FF5A2D",accentBright:"#FF7A3D",accentDim:"#D14A22",info:"#FF8A5B",success:"#2FBF71",warn:"#FFB020",error:"#E23D2D",muted:"#8B7F77"};var Ee=typeof process.env.FORCE_COLOR=="string"&&process.env.FORCE_COLOR.trim().length>0&&process.env.FORCE_COLOR.trim()!=="0",U=process.env.NO_COLOR&&!Ee?new Chalk({level:0}):be,L=e=>U.hex(e),m={accent:L(y.accent),accentBright:L(y.accentBright),accentDim:L(y.accentDim),info:L(y.info),success:L(y.success),warn:L(y.warn),error:L(y.error),muted:L(y.muted),heading:U.bold.hex(y.accent),command:L(y.accentBright),option:L(y.warn)},S=()=>U.level>0,E=(e,r,n)=>e?r(n):n;function ke(e){let r=S();return E(r,m.success,"\u2713")+` ${e}`}function ve(e){let r=S();return E(r,m.error,"\u2717")+` ${e}`}function $e(e){let r=S();return E(r,m.warn,"\u26A0")+` ${e}`}function We(e){let r=S();return E(r,m.info,"\u2139")+` ${e}`}function we(e){let r=S();return E(r,m.heading,e)}function Te(e,r,n=15){let i=S(),o=e.padEnd(n);return `${E(i,m.muted,o)} ${r}`}function ye(e,r){let n=S(),i=E(n,m.command,e);if(!r)return ` ${i}`;let o=E(n,m.muted,`# ${r}`);return ` ${i} ${o}`}function Pe(e,r,n){let i=S(),o=E(i,m.info,e),l=E(i,m.command,r),d=n?` ${E(i,m.muted,n)}`:"";return `${o} ${l}${d}`}function Oe(e,r){let n=S(),i,o;switch(e){case "pending":i="\u25CB",o=m.muted;break;case "running":i="\u25CF",o=m.info;break;case "success":i="\u2713",o=m.success;break;case "error":i="\u2717",o=m.error;break;case "skipped":i="\u25CB",o=m.muted;break}return E(n,o,i)+` ${r}`}function Re(e=80,r="\u2500"){let n=S();return E(n,m.muted,r.repeat(e))}function Le(e){let r=S();return E(r,m.muted,e)}function Ce(e,r,n){let i=S(),o=e===1?r:n||`${r}s`;return `${E(i,m.accent,String(e))} ${o}`}function C(e){let r=e?.trim();return r?Filesystem.toUnixPath(r):void 0}function D(e=process.env,r=J.homedir){let n=Ne(e,r);return n?Filesystem.resolve(n):void 0}function Ne(e,r){let n=C(e.EASBOT_HOME);if(n){if(n==="~"||n.startsWith("~/")||n.startsWith("~\\")){let l=C(e.HOME)??C(e.USERPROFILE)??ne(r);return l?n.replace(/^~(?=$|[\\/])/,l):void 0}return n}let i=C(e.HOME);if(i)return i;let o=C(e.USERPROFILE);return o||ne(r)}function ne(e){try{return C(e())}catch{return}}function B(e=process.env,r=J.homedir){return D(e,r)??Filesystem.resolve(process.cwd())}function K(e,r){if(!e.startsWith("~"))return C(e);let n=process.env.EASBOT_TEST_HOME?.trim();return n||(n=C(r?.home)??D(r?.env??process.env,r?.homedir??J.homedir)),n?e.replace(/^~(?=$|[\\/])/,n):C(e)}function oe(e){if(!e)return "";let r=e.trim();if(!r)return r;if(r.startsWith("~")){let n=K(r,{home:B(process.env,J.homedir),env:process.env,homedir:J.homedir});return q.resolve(n)}return q.resolve(r)}function Ie(e=process.env,r=J.homedir){let n=e.OPENCLAW_STATE_DIR?.trim()||e.CLAWDBOT_STATE_DIR?.trim();if(n)return oe(n);let i=q.join(B(e,r),".openclaw");try{if(Ae.existsSync(i))return i}catch{}return i}function ie(){return D(process.env,J.homedir)}function se(){let e=ie();return e?process.env.EASBOT_HOME?.trim()?{home:e,prefix:"$EASBOT_HOME"}:{home:e,prefix:"~"}:void 0}function ce(e){if(!e)return e;let r=se();if(!r)return e;let{home:n,prefix:i}=r;return e===n?i:e.startsWith(`${n}/`)||e.startsWith(`${n}\\`)?`${i}${e.slice(n.length)}`:e}function ae(e){if(!e)return e;let r=se();return r?e.split(r.home).join(r.prefix):e}function _e(e){return ce(e)}function G(e){return ae(e)}function j(e,r,n){let o=e.replaceAll("\x1B",""),l=r.replaceAll("\x1B","");return (n?.force===true?true:n?.force===false?false:!!process.stdout.isTTY)?`\x1B]8;;${l}\x07${o}\x1B]8;;\x07`:n?.fallback??`${o} (${l})`}var F="https://docs.openclaw.ai";function He(e,r,n){let i=e.trim(),o=i.startsWith("http")?i:`${F}${i.startsWith("/")?i:`/${i}`}`;return j(r??o,o,{fallback:n?.fallback??o,force:n?.force})}function Me(e){return j(e??F,F,{fallback:F})}function De(e,r){let n={ok:true,data:e};r!==void 0&&(n.meta=r),console.log(JSON.stringify(n,null,2));}function Fe(e,r){console.log(JSON.stringify({ok:false,error:{code:e,message:r}},null,2));}var X=e=>S()?m.accent(e):e,Z=e=>e&&S()?m.heading(e):e,Q=e=>e&&S()?m.muted(e):e;var Je=/^(https?:\/\/|file:\/\/)/i,je=/^[a-zA-Z]:[\\/]/,ze=/^[a-zA-Z0-9._-]+$/;function fe(e,r){if(r<=0)return [e];let n=Array.from(e),i=[];for(let o=0;o<n.length;o+=r)i.push(n.slice(o,o+r).join(""));return i.length>0?i:[e]}function ue(e){return e?Je.test(e)||e.startsWith("/")||e.startsWith("~/")||e.startsWith("./")||e.startsWith("../")||je.test(e)||e.startsWith("\\\\")||e.includes("/")||e.includes("\\")?true:e.includes("_")&&ze.test(e):false}function Ue(e,r){if(e.trim().length===0)return [e];if(r<=0)return [e];let n=e.match(/^(\s*)([-*\u2022]\s+)?(.*)$/),i=n?.[1]??"",o=n?.[2]??"",l=n?.[3]??"",d=`${i}${o}`,g=`${i}${o?" ".repeat(o.length):""}`,W=Math.max(10,r-R(d)),w=Math.max(10,r-R(g)),I=l.split(/\s+/).filter(Boolean),P=[],p="",x=d,k=W;for(let b of I){if(!p){if(R(b)>k){if(ue(b)){p=b;continue}let T=fe(b,k),f=T.shift()??"";P.push(x+f),x=g,k=w;for(let u of T)P.push(x+u);continue}p=b;continue}let N=`${p} ${b}`;if(R(N)<=k){p=N;continue}if(P.push(x+p),x=g,k=w,R(b)>k){if(ue(b)){p=b;continue}let T=fe(b,k),f=T.shift()??"";P.push(x+f);for(let u of T)P.push(x+u);p="";continue}p=b;}return (p||I.length===0)&&P.push(x+p),P}function le(e,r={}){let n=r.columns??process.stdout.columns??80,i=r.maxWidth??Math.max(40,Math.min(88,n-10));return e.split(`
2
+ `).flatMap(o=>Ue(o,i)).join(`
3
+ `)}function Ve(e,r){note(le(e),Z(r));}var H=null;function Ye(e){e.isTTY&&(H=e);}function ee(){H?.isTTY&&H.write("\r\x1B[2K");}function Ke(e){H&&(e&&H!==e||(H=null));}function Ge(e){return select({...e,message:X(e.message),options:e.options.map(r=>r.hint===void 0?r:{...r,hint:Q(r.hint)})})}var Xe="\x1B[0m\x1B[?25h\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004l";function z(e,r,n){let i=n?` (${n})`:"",o=`[terminal] restore ${e} failed${i}: ${String(r)}`;try{process.stderr.write(`${o}
4
+ `);}catch(l){console.error(`[terminal] restore reporting failed${i}: ${String(l)}`);}}function Ze(e,r={}){let n=r.resumeStdinIfPaused??r.resumeStdin??false;try{ee();}catch(o){z("progress line",o,e);}let i=process.stdin;if(i.isTTY&&typeof i.setRawMode=="function"){try{i.setRawMode(!1);}catch(o){z("raw mode",o,e);}if(n&&typeof i.isPaused=="function"&&i.isPaused())try{i.resume();}catch(o){z("stdin resume",o,e);}}if(process.stdout.isTTY)try{process.stdout.write(Xe);}catch(o){z("stdout reset",o,e);}}function Qe(e){let r=e?.code;return r==="EPIPE"||r==="EIO"}function er(e={}){let r=false,n=false,i=(g,W)=>{n||(n=true,e.onBrokenPipe?.(g,W));},o=(g,W)=>{if(!Qe(g))throw g;return r=true,i(g,W),false},l=(g,W)=>{if(r)return false;try{e.beforeWrite?.();}catch(w){return o(w,process.stderr)}try{return g.write(W),!r}catch(w){return o(w,g)}};return {write:l,writeLine:(g,W)=>l(g,`${W}
5
+ `),reset:()=>{r=false,n=false;},isClosed:()=>r}}function M(e,r){return !Number.isFinite(r)||r<=0?"":e.repeat(r)}function rr(e,r,n){let i=R(e);if(i>=r)return e;let o=r-i;if(n==="right")return `${M(" ",o)}${e}`;if(n==="center"){let l=Math.floor(o/2),d=o-l;return `${M(" ",l)}${e}${M(" ",d)}`}return `${e}${M(" ",o)}`}function tr(e,r){if(!e||e.length===0)return [""];if(!Number.isFinite(r)||r<=0)return [e];let n="\x1B",i=[];for(let t=0;t<e.length;){if(e[t]===n){if(e[t+1]==="["){let a=t+2;for(;a<e.length;){let h=e[a];if(h==="m")break;if(h&&h>="0"&&h<="9"){a+=1;continue}if(h===";"){a+=1;continue}break}if(e[a]==="m"){i.push({kind:"ansi",value:e.slice(t,a+1)}),t=a+1;continue}}if(e[t+1]==="]"&&e.slice(t+2,t+5)==="8;;"){let a=e.indexOf(`${n}\\`,t+5);if(a>=0){i.push({kind:"ansi",value:e.slice(t,a+2)}),t=a+2;continue}}}let s=e.codePointAt(t);if(!s)break;let c=String.fromCodePoint(s);i.push({kind:"char",value:c}),t+=c.length;}let o=i.findIndex(t=>t.kind==="char");if(o<0)return [e];let l=-1;for(let t=i.length-1;t>=0;t-=1){let s=i[t];if(s&&s.kind==="char"){l=t;break}}let d=i.slice(0,o).filter(t=>t.kind==="ansi").map(t=>t.value).join(""),g=i.slice(l+1).filter(t=>t.kind==="ansi").map(t=>t.value).join(""),W=i.slice(o,l+1),w=[],I=t=>t===" "||t===" "||t==="/"||t==="-"||t==="_"||t===".",P=t=>t===" "||t===" ",p=false,x=[],k=0,b=null,N=t=>(t??x).map(s=>s.value).join(""),T=t=>t.reduce((s,c)=>s+(c.kind==="char"?1:0),0),f=t=>{let s=t.replace(/\s+$/,"");s.trim().length!==0&&w.push(s);},u=t=>{if(x.length===0)return;if(t==null||t<=0){f(N()),x.length=0,k=0,b=null;return}let s=x.slice(0,t),c=x.slice(t);for(f(N(s));c.length>0;){let a=c[0];if(a?.kind!=="char"||!P(a.value))break;c.shift();}x.length=0,x.push(...c),k=T(x),b=null;};for(let t of W){if(t.kind==="ansi"){x.push(t);continue}let s=t.value;if(!(p&&(p=false,s===`
6
+ `))){if(s===`
7
+ `||s==="\r"){u(x.length),s==="\r"&&(p=true);continue}k+1>r&&k>0&&u(b),x.push(t),k+=1,I(s)&&(b=x.length);}}return u(x.length),w.length===0?[""]:!d&&!g?w:w.map(t=>t&&`${d}${t}${g}`)}function nr(e){if(e!=null&&!(!Number.isFinite(e)||e<=0))return Math.floor(e)}function or(e){let r=e.rows.map(f=>{let u={};for(let[t,s]of Object.entries(f))u[t]=G(s);return u}),n=e.border??"unicode";if(n==="none"){let f=e.columns;return `${[f.map(s=>s.header).join(" | "),...r.map(s=>f.map(c=>s[c.key]??"").join(" | "))].join(`
8
+ `)}
9
+ `}let i=Math.max(0,e.padding??1),o=e.columns,l=o.map(f=>{let u=R(f.header),t=Math.max(0,...r.map(s=>R(s[f.key]??"")));return {headerW:u,cellW:t}}),d=o.map((f,u)=>{let t=l[u];if(!t)throw new Error(`Internal error: metrics[${u}] is undefined`);let s=Math.max(t.headerW,t.cellW)+i*2,c=f.maxWidth?Math.min(s,f.maxWidth):s;return Math.max(f.minWidth??3,c)}),g=nr(e.width),W=o.length+1,w=d.reduce((f,u)=>f+u,0)+W,I=o.map((f,u)=>{let t=l[u];if(!t)throw new Error(`Internal error: metrics[${u}] is undefined`);return Math.max(f.minWidth??3,t.headerW+i*2,3)}),P=o.map((f,u)=>{let t=l[u];if(!t)throw new Error(`Internal error: metrics[${u}] is undefined`);return Math.max(t.headerW+i*2,3)});if(g&&w>g){let f=w-g,u=o.map((c,a)=>{let h=d[a];if(h===void 0)throw new Error(`Internal error: widths[${a}] is undefined`);return {i:a,w:h}}).filter(({i:c})=>!!o[c]?.flex).toSorted((c,a)=>a.w-c.w).map(c=>c.i),t=o.map((c,a)=>{let h=d[a];if(h===void 0)throw new Error(`Internal error: widths[${a}] is undefined`);return {i:a,w:h}}).filter(({i:c})=>!o[c]?.flex).toSorted((c,a)=>a.w-c.w).map(c=>c.i),s=(c,a)=>{for(;f>0;){let h=false;for(let O of c){let A=d[O],_=a[O];if(!(A===void 0||_===void 0)&&!(A<=_)&&(d[O]=A-1,f-=1,h=true,f<=0))break}if(!h)break}};s(u,I),s(u,P),s(t,I),s(t,P);}if(g){let f=o.length+1,u=d.reduce((s,c)=>s+c,0)+f,t=g-u;if(t>0){let s=o.map((c,a)=>({c,i:a})).filter(({c})=>!!c.flex).map(({i:c})=>c);if(s.length>0){let c=o.map(a=>typeof a.maxWidth=="number"&&a.maxWidth>0?Math.floor(a.maxWidth):Number.POSITIVE_INFINITY);for(;t>0;){let a=false;for(let h of s){let O=d[h],A=c[h];if(!(O===void 0||A===void 0)&&!(O>=A)&&(d[h]=O+1,t-=1,a=true,t<=0))break}if(!a)break}}}}let p=n==="ascii"?{tl:"+",tr:"+",bl:"+",br:"+",h:"-",v:"|",t:"+",ml:"+",m:"+",mr:"+",b:"+"}:{tl:"\u250C",tr:"\u2510",bl:"\u2514",br:"\u2518",h:"\u2500",v:"\u2502",t:"\u252C",ml:"\u251C",m:"\u253C",mr:"\u2524",b:"\u2534"},x=(f,u,t)=>`${f}${d.map(s=>{if(s===void 0)throw new Error("Internal error: width is undefined");return M(p.h,s)}).join(u)}${t}`,k=f=>{let u=d[f];if(u===void 0)throw new Error(`Internal error: widths[${f}] is undefined`);return Math.max(1,u-i*2)},b=M(" ",i),N=(f,u=false)=>{let s=o.map(h=>u?h.header:f[h.key]??"").map((h,O)=>tr(h,k(O))),c=Math.max(...s.map(h=>h.length)),a=[];for(let h=0;h<c;h+=1){let O=s.map((A,_)=>{let me=A[h]??"",re=o[_];if(!re)throw new Error(`Internal error: columns[${_}] is undefined`);let de=rr(me,k(_),re.align??"left");return `${b}${de}${b}`});a.push(`${p.v}${O.join(p.v)}${p.v}`);}return a},T=[];T.push(x(p.tl,p.t,p.tr)),T.push(...N({},true)),T.push(x(p.ml,p.m,p.mr));for(let f of r)T.push(...N(f,false));return T.push(x(p.bl,p.b,p.br)),`${T.join(`
10
+ `)}
11
+ `}function ir(e,r){if(!r)return e;let n=e.indexOf(":");if(n===-1)return e;let i=e.slice(0,n+1),o=e.slice(n+1).trimStart(),l=o.toLowerCase(),d=(g,W)=>`${i} ${W(o.slice(0,g.length))}${o.slice(g.length)}`;return l.startsWith("failed")?d("failed",m.error):l.startsWith("ok")?d("ok",m.success):l.startsWith("linked")?d("linked",m.success):l.startsWith("configured")?d("configured",m.success):l.startsWith("not linked")?d("not linked",m.warn):l.startsWith("not configured")?d("not configured",m.muted):l.startsWith("unknown")?d("unknown",m.warn):e}export{F as DOCS_ROOT,y as LOBSTER_PALETTE,ee as clearActiveProgressLine,E as colorize,er as createSafeStreamWriter,_e as displayPath,G as displayString,Fe as emitJsonError,De as emitJsonOk,K as expandHomePrefix,ye as formatCommandExample,Ce as formatCount,He as formatDocsLink,Me as formatDocsRootLink,Le as formatEmptyMessage,ve as formatError,we as formatHeading,We as formatInfo,Te as formatKeyValue,Pe as formatListItem,Re as formatSeparator,Oe as formatStatus,ke as formatSuccess,j as formatTerminalLink,$e as formatWarning,S as isRich,Ve as note,Ye as registerActiveProgressLine,or as renderTable,Ie as resolveConfigDir,D as resolveEffectiveHomeDir,ie as resolveHomeDir,B as resolveRequiredHomeDir,oe as resolveUserPath,Ze as restoreTerminalState,Ge as selectStyled,ae as shortenHomeInString,ce as shortenHomePath,te as stripAnsi,ir as styleHealthChannelLine,Q as stylePromptHint,X as stylePromptMessage,Z as stylePromptTitle,m as theme,Ke as unregisterActiveProgressLine,R as visibleWidth,le as wrapNoteMessage};
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@easbot/terminal",
3
+ "version": "0.3.11",
4
+ "description": "Terminal interaction toolkit for the EASBOT ecosystem — themed colors, ANSI utilities, OSC-8 hyperlinks, command formatting, table rendering, styled prompts, safe stream writes, and terminal-state recovery",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "keywords": [
18
+ "easbot",
19
+ "terminal",
20
+ "cli",
21
+ "tui",
22
+ "ansi",
23
+ "color-theme",
24
+ "table",
25
+ "prompts",
26
+ "hyperlink",
27
+ "progress",
28
+ "typescript"
29
+ ],
30
+ "author": "houjallen",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/houjallen/easbot.git",
35
+ "directory": "packages/terminal"
36
+ },
37
+ "homepage": "https://github.com/houjallen/easbot/tree/main/packages/terminal#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/houjallen/easbot/issues"
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "README.md",
44
+ "README.en.md",
45
+ "LICENSE"
46
+ ],
47
+ "dependencies": {
48
+ "@clack/prompts": "^1.7.0",
49
+ "chalk": "^6.0.0",
50
+ "picocolors": "^1.1.1",
51
+ "@easbot/types": "0.3.11",
52
+ "@easbot/utils": "0.3.11"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^25.6.2",
56
+ "tsup": "^8.5.1",
57
+ "typescript": "^6.0.3",
58
+ "vitest": "^4.1.5"
59
+ },
60
+ "engines": {
61
+ "node": ">=22.22.3"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "scripts": {
67
+ "dev": "tsup --watch --env.NODE_ENV development",
68
+ "build": "tsup --env.NODE_ENV production",
69
+ "test": "vitest",
70
+ "test:run": "vitest run",
71
+ "test:coverage": "vitest run --coverage",
72
+ "lint": "biome check .",
73
+ "lint:fix": "biome check --write .",
74
+ "lint:report": "biome check --reporter=summary .",
75
+ "format": "biome format .",
76
+ "format:fix": "biome format --write .",
77
+ "type-check": "tsc --noEmit",
78
+ "clean": "npx rimraf dist node_modules",
79
+ "publish:npm": "bash scripts/publish.sh",
80
+ "publish:npm:win": "powershell -ExecutionPolicy Bypass -File scripts/publish.ps1"
81
+ }
82
+ }