ErisPulse-TerminalAdapter 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,301 @@
1
+ """TerminalAdapter:把命令行标准输入/输出作为消息通道,用于本地开发调试。
2
+
3
+ 终端输入的每一行即一条私聊消息,Bot 的回复通过 SendDSL 打印到终端。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import sys
10
+ import time
11
+ import uuid
12
+ from dataclasses import dataclass, field
13
+ from typing import Any
14
+
15
+ from ErisPulse.Core import BaseAdapter, SendDSL
16
+ from ErisPulse.Core.Bases import BaseConfig, BaseI18n, I18nKey
17
+
18
+
19
+ class TerminalAdapter(BaseAdapter):
20
+ """终端适配器:命令行即聊天会话,用于本地开发调试。"""
21
+
22
+ _platform = "terminal"
23
+
24
+ @dataclass
25
+ class ConfigClass(BaseConfig):
26
+ bot_id: str = field(
27
+ default="terminal_bot",
28
+ metadata={
29
+ "description": "Bot 的用户 ID",
30
+ "ui": {"widget": "text", "group": "basic", "order": 1},
31
+ },
32
+ )
33
+ bot_name: str = field(
34
+ default="TerminalBot",
35
+ metadata={
36
+ "description": "Bot 昵称",
37
+ "ui": {"widget": "text", "group": "basic", "order": 2},
38
+ },
39
+ )
40
+ user_id: str = field(
41
+ default="terminal_user",
42
+ metadata={
43
+ "description": "模拟用户的 ID(与 Bot 对话的终端用户)",
44
+ "ui": {"widget": "text", "group": "basic", "order": 3},
45
+ },
46
+ )
47
+ user_name: str = field(
48
+ default="User",
49
+ metadata={
50
+ "description": "模拟用户昵称",
51
+ "ui": {"widget": "text", "group": "basic", "order": 4},
52
+ },
53
+ )
54
+ prompt: str = field(
55
+ default="> ",
56
+ metadata={
57
+ "description": "输入提示符",
58
+ "ui": {"widget": "text", "group": "ui", "order": 5},
59
+ },
60
+ )
61
+ reply_prefix: str = field(
62
+ default="[Bot] ",
63
+ metadata={
64
+ "description": "Bot 回复的行前缀(留空则不加前缀)",
65
+ "ui": {"widget": "text", "group": "ui", "order": 6},
66
+ },
67
+ )
68
+ echo_input: bool = field(
69
+ default=False,
70
+ metadata={
71
+ "description": "是否回显用户输入(管道输入场景下开启)",
72
+ "ui": {"widget": "switch", "group": "ui", "order": 7},
73
+ },
74
+ )
75
+
76
+ class I18nClass(BaseI18n):
77
+ welcome: I18nKey = I18nKey(
78
+ default="Terminal adapter started. Type a message to chat with the Bot. Ctrl+C / EOF to quit.",
79
+ zh_CN="终端适配器已启动。直接输入消息即可与 Bot 对话,Ctrl+C 或 EOF 退出。",
80
+ zh_TW="終端介面卡已啟動。直接輸入訊息即可與 Bot 對話,Ctrl+C 或 EOF 退出。",
81
+ en="Terminal adapter started. Type a message to chat with the Bot. Ctrl+C / EOF to quit.",
82
+ ja="ターミナルアダプターが起動しました。メッセージを入力して Bot と会話できます。Ctrl+C / EOF で終了。",
83
+ ru="Терминальный адаптер запущен. Введите сообщение для общения с ботом. Ctrl+C / EOF — выход.",
84
+ )
85
+ goodbye: I18nKey = I18nKey(
86
+ default="Terminal adapter stopped.",
87
+ zh_CN="终端适配器已停止。",
88
+ zh_TW="終端介面卡已停止。",
89
+ en="Terminal adapter stopped.",
90
+ ja="ターミナルアダプターを停止しました。",
91
+ ru="Терминальный адаптер остановлен.",
92
+ )
93
+ input_hint: I18nKey = I18nKey(
94
+ default="Use /help to list commands.",
95
+ zh_CN="输入 /help 查看可用命令。",
96
+ zh_TW="輸入 /help 查看可用指令。",
97
+ en="Use /help to list commands.",
98
+ ja="/help でコマンド一覧を表示。",
99
+ ru="Введите /help для списка команд.",
100
+ )
101
+
102
+ class Send(SendDSL):
103
+ """终端发送 DSL:把 OB12 消息段渲染为文本打印到 stdout。"""
104
+
105
+ def Raw_ob12(self, message, **kwargs):
106
+
107
+ async def _do_send():
108
+ segments = self._apply_modifiers(message)
109
+ text = self._adapter._render_segments(segments)
110
+ self._adapter._output(text)
111
+ return self._adapter.make_response(
112
+ message_id=str(uuid.uuid4()),
113
+ data={"text": text, **self.send_context},
114
+ )
115
+
116
+ return asyncio.create_task(_do_send())
117
+
118
+ def __init__(self, sdk=None):
119
+ super().__init__(sdk)
120
+ self._running = False
121
+ self._read_task: asyncio.Task | None = None
122
+
123
+ async def start(self) -> None:
124
+ """启动适配器:上线 Bot、打印欢迎语、启动 stdin 读取循环"""
125
+ cfg = self.cfg
126
+ self._running = True
127
+
128
+ await self.emit_meta("connect", cfg.bot_id, user_name=cfg.bot_name, avatar="")
129
+
130
+ try:
131
+ from ErisPulse import i18n
132
+
133
+ say = i18n.t
134
+ except Exception:
135
+
136
+ def say(key, default=None):
137
+ return default or key
138
+
139
+ self._write_raw("\n")
140
+ self._output_raw(say("TerminalAdapter.welcome"))
141
+ self._output_raw(say("TerminalAdapter.input_hint"))
142
+ self._write_raw("\n")
143
+
144
+ self._read_task = asyncio.create_task(self._read_loop())
145
+ self.logger.info("TerminalAdapter 已启动")
146
+
147
+ async def shutdown(self) -> None:
148
+ """关闭适配器:停止读取、下线 Bot"""
149
+ self._running = False
150
+ if self._read_task and not self._read_task.done():
151
+ self._read_task.cancel()
152
+ try:
153
+ await self._read_task
154
+ except (asyncio.CancelledError, Exception):
155
+ pass
156
+
157
+ cfg = self.cfg
158
+ try:
159
+ from ErisPulse import i18n
160
+
161
+ self._output_raw(i18n.t("TerminalAdapter.goodbye"))
162
+ except Exception:
163
+ pass
164
+
165
+ await self.emit_meta("disconnect", cfg.bot_id)
166
+ self.logger.info("TerminalAdapter 已关闭")
167
+
168
+ def on_config_update(self, old_config, new_config):
169
+ """配置热更新回调"""
170
+ self.logger.info("TerminalAdapter 配置已热更新")
171
+
172
+ async def call_api(self, endpoint: str, **params: Any) -> dict:
173
+ """模拟常用平台 API,使框架标准动作可用。"""
174
+ cfg = self.cfg
175
+
176
+ if endpoint == "get_self_info":
177
+ return self.make_response(data={"user_id": cfg.bot_id, "user_name": cfg.bot_name, "platform": "terminal"})
178
+ if endpoint == "get_user_info":
179
+ uid = str(params.get("user_id", cfg.user_id))
180
+ is_bot = uid == cfg.bot_id
181
+ return self.make_response(
182
+ data={
183
+ "user_id": uid,
184
+ "user_name": cfg.bot_name if is_bot else cfg.user_name,
185
+ "user_displayname": cfg.bot_name if is_bot else cfg.user_name,
186
+ "platform": "terminal",
187
+ }
188
+ )
189
+ if endpoint in ("get_friend_list", "get_user_list"):
190
+ return self.make_response(data=[{"user_id": cfg.user_id, "user_name": cfg.user_name}])
191
+ if endpoint == "get_group_list":
192
+ return self.make_response(data=[]) # 终端无群组
193
+ if endpoint in ("get_group_info", "get_group_member_info", "get_group_member_list"):
194
+ return self.make_error(retcode=10002, message="终端适配器不支持群组操作")
195
+ if endpoint == "send_message":
196
+ return self.make_response(message_id=str(uuid.uuid4()))
197
+ if endpoint == "delete_message":
198
+ return self.make_response() # 终端无法撤回,返回成功
199
+
200
+ return self.make_error(retcode=10002, message=f"终端适配器不支持 {endpoint}")
201
+
202
+ async def _read_loop(self) -> None:
203
+ """异步读取 stdin:每行作为一条私聊消息 emit 给框架。"""
204
+ loop = asyncio.get_running_loop()
205
+ cfg = self.cfg
206
+
207
+ while self._running:
208
+ try:
209
+ self._write_raw(cfg.prompt)
210
+ line = await loop.run_in_executor(None, sys.stdin.readline)
211
+ if not line:
212
+ # EOF(无更多输入)
213
+ break
214
+ text = line.rstrip("\r\n")
215
+ if not text:
216
+ continue
217
+ if cfg.echo_input:
218
+ self._output_raw(f"< {text}")
219
+ await self._handle_input(text)
220
+ except asyncio.CancelledError:
221
+ break
222
+ except Exception as e:
223
+ self.logger.warning(f"读取 stdin 失败: {e}")
224
+ await asyncio.sleep(0.5)
225
+
226
+ async def _handle_input(self, text: str) -> None:
227
+ """把一行文本构造为 OB12 message 事件并 emit"""
228
+ cfg = self.cfg
229
+ try:
230
+ from ErisPulse.Core.adapter import adapter as adapter_mgr
231
+ except ImportError:
232
+ self.logger.error("无法访问 adapter manager")
233
+ return
234
+
235
+ event = {
236
+ "id": str(uuid.uuid4()),
237
+ "time": int(time.time()),
238
+ "type": "message",
239
+ "detail_type": "private",
240
+ "platform": "terminal",
241
+ "self": {
242
+ "platform": "terminal",
243
+ "user_id": cfg.bot_id,
244
+ "user_name": cfg.bot_name,
245
+ },
246
+ "user_id": cfg.user_id,
247
+ "message": [{"type": "text", "data": {"text": text}}],
248
+ "alt_message": text,
249
+ "terminal_raw": {"text": text},
250
+ "terminal_raw_type": "stdin_line",
251
+ }
252
+ await adapter_mgr.emit(event)
253
+
254
+ @staticmethod
255
+ def _render_segments(segments: list[dict]) -> str:
256
+ parts: list[str] = []
257
+ for seg in segments:
258
+ seg_type = seg.get("type", "")
259
+ data = seg.get("data", {}) or {}
260
+ if seg_type == "text":
261
+ parts.append(str(data.get("text", "")))
262
+ elif seg_type == "image":
263
+ parts.append(f"[image: {data.get('file', '')}]")
264
+ elif seg_type == "audio":
265
+ parts.append(f"[voice: {data.get('file', '')}]")
266
+ elif seg_type == "video":
267
+ parts.append(f"[video: {data.get('file', '')}]")
268
+ elif seg_type == "file":
269
+ parts.append(f"[file: {data.get('file', '')}]")
270
+ elif seg_type == "mention":
271
+ parts.append(f"@{data.get('user_id', '')}")
272
+ elif seg_type == "mention_all":
273
+ parts.append("@all")
274
+ elif seg_type == "reply":
275
+ parts.append(f"[reply:{data.get('message_id', '')}]")
276
+ else:
277
+ parts.append(f"[{seg_type}]")
278
+ return "".join(parts)
279
+
280
+ def _output(self, text: str) -> None:
281
+ """带 Bot 前缀地输出一段文本(多行逐行加前缀)"""
282
+ prefix = self.cfg.reply_prefix or ""
283
+ for line in str(text).split("\n"):
284
+ self._write_raw(prefix + line + "\n")
285
+
286
+ def _output_raw(self, text: str) -> None:
287
+ """原样输出一段文本(不加前缀,自动换行)"""
288
+ if text:
289
+ self._write_raw(str(text) + "\n")
290
+
291
+ @staticmethod
292
+ def _write_raw(s: str) -> None:
293
+ """底层写 stdout"""
294
+ try:
295
+ sys.stdout.write(s)
296
+ sys.stdout.flush()
297
+ except Exception:
298
+ pass
299
+
300
+
301
+ __all__ = ["TerminalAdapter"]
@@ -0,0 +1,3 @@
1
+ from .Core import TerminalAdapter
2
+
3
+ __all__ = ["TerminalAdapter"]
@@ -0,0 +1,219 @@
1
+ Metadata-Version: 2.4
2
+ Name: ErisPulse-TerminalAdapter
3
+ Version: 1.0.0
4
+ Summary: ErisPulse TerminalAdapter - 终端适配器
5
+ Project-URL: homepage, https://github.com/ErisPulse/ErisPulse-TerminalAdapter
6
+ Project-URL: repository, https://github.com/ErisPulse/ErisPulse-TerminalAdapter
7
+ Project-URL: ErisPulse, https://github.com/ErisPulse/ErisPulse
8
+ Author: ErisDev
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 ErisPulse
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: adapter,cli,debug,erispulse,terminal
32
+ Requires-Python: >=3.10
33
+ Requires-Dist: erispulse>=2.7.0
34
+ Description-Content-Type: text/markdown
35
+
36
+ <div align="center">
37
+
38
+ <img src=".github/assets/logo.png" width="180" alt="ErisPulse TerminalAdapter" />
39
+
40
+ # ErisPulse TerminalAdapter
41
+
42
+ **The terminal is the chat — develop and test your Bot with zero platform setup.**
43
+
44
+ A terminal adapter for [ErisPulse](https://github.com/ErisPulse/ErisPulse). Each line you type in the terminal is emitted as a private message, and the bot's replies are printed back to stdout. Handy for developing and testing handlers without registering a real platform.
45
+
46
+ <p>
47
+ <a href="https://pypi.org/project/ErisPulse-TerminalAdapter/"><img src="https://img.shields.io/pypi/v/ErisPulse-TerminalAdapter?style=for-the-badge&logo=pypi&logoColor=white" alt="PyPI"></a>
48
+ <a href="https://pypi.org/project/ErisPulse-TerminalAdapter/"><img src="https://img.shields.io/badge/Python-3.10+-FFD43B?style=for-the-badge&logo=python&logoColor=blue" alt="Python"></a>
49
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue?style=for-the-badge" alt="License"></a>
50
+ <a href="https://github.com/ErisPulse/ErisPulse-TerminalAdapter"><img src="https://img.shields.io/github/stars/ErisPulse/ErisPulse-TerminalAdapter?style=for-the-badge&logo=github&color=brightgreen" alt="Stars"></a>
51
+ <a href="https://pepy.tech/project/ErisPulse-TerminalAdapter"><img src="https://img.shields.io/pepy/dt/ErisPulse-TerminalAdapter?style=for-the-badge&color=blue" alt="Downloads"></a>
52
+ <a href="https://github.com/ErisPulse/ErisPulse"><img src="https://img.shields.io/badge/Powered_by-ErisPulse-FF6B9D?style=for-the-badge&logo=bookstack&logoColor=white" alt="ErisPulse"></a>
53
+ </p>
54
+
55
+ [English](#english) | [简体中文](#简体中文)
56
+
57
+ </div>
58
+
59
+ ---
60
+
61
+ <a id="english"></a>
62
+
63
+ ## English
64
+
65
+ ### Features
66
+
67
+ - **Zero config** — no platform account or token needed, install and run
68
+ - **One line, one message** — every line typed in the terminal becomes a private message that triggers command / module handlers
69
+ - **Replies printed to stdout** — the bot's SendDSL replies are printed with a `[Bot]` prefix
70
+ - **Standard actions work** — `get_user_info` / `get_self_info` / `get_friend_list` return mock data so framework standard actions keep working
71
+ - **Readable rendering** — non-text segments (image / voice / file / mention ...) render as readable placeholders
72
+ - **i18n aware** — welcome / goodbye / hint messages follow the framework's `i18n` language
73
+
74
+ ### Install
75
+
76
+ ```bash
77
+ pip install ErisPulse-TerminalAdapter
78
+ ```
79
+
80
+ Requires ErisPulse >= 2.7.0.
81
+
82
+ ### Configuration
83
+
84
+ `config.toml`:
85
+
86
+ ```toml
87
+ [TerminalAdapter]
88
+ bot_id = "terminal_bot"
89
+ bot_name = "TerminalBot"
90
+ user_id = "terminal_user"
91
+ user_name = "User"
92
+ prompt = "> "
93
+ reply_prefix = "[Bot] "
94
+ echo_input = false
95
+ ```
96
+
97
+ | Field | Default | Description |
98
+ |------|---------|-------------|
99
+ | `bot_id` | `terminal_bot` | Bot user ID |
100
+ | `bot_name` | `TerminalBot` | Bot nickname |
101
+ | `user_id` | `terminal_user` | Mocked user ID (the terminal user chatting with the bot) |
102
+ | `user_name` | `User` | Mocked user nickname |
103
+ | `prompt` | `> ` | Input prompt |
104
+ | `reply_prefix` | `[Bot] ` | Prefix prepended to each bot reply line (empty for none) |
105
+ | `echo_input` | `false` | Echo user input (useful for piped input) |
106
+
107
+ The adapter registers under platform name `terminal` and exposes a single private-chat session (no groups).
108
+
109
+ ### Usage
110
+
111
+ After `epsdk run`, the terminal becomes the chat:
112
+
113
+ ```
114
+ > Terminal adapter started. Type a message to chat with the Bot. Ctrl+C / EOF to quit.
115
+ > Use /help to list commands.
116
+
117
+ > /hello
118
+ [Bot] Hello, User!
119
+ > ping
120
+ [Bot] ...
121
+ ```
122
+
123
+ You can also pipe input in, which is handy for automated testing:
124
+
125
+ ```bash
126
+ echo "/hello" | epsdk run main.py
127
+ ```
128
+
129
+ Non-text segments render as placeholders (`[image: url]`, `[voice: url]`, `@user_id`, ...). Group-related actions are unsupported (no groups in a terminal).
130
+
131
+ ### Notes
132
+
133
+ - `stdin` is read in a worker thread, so on shutdown the reader only returns after the next line or EOF (Ctrl+D / Ctrl+Z).
134
+ - Welcome / goodbye / hint messages follow the framework's `i18n` language setting.
135
+
136
+ ---
137
+
138
+ <a id="简体中文"></a>
139
+
140
+ ## 简体中文
141
+
142
+ ### 特性
143
+
144
+ - **零配置即用** —— 不需要注册任何平台账号、不需要 token,装上就能跑
145
+ - **一行一消息** —— 终端里每输入一行即一条私聊消息,直接触发命令 / 模块处理器
146
+ - **回复即打印** —— Bot 通过 SendDSL 回复的内容带 `[Bot]` 前缀打印到 stdout
147
+ - **标准动作可用** —— `get_user_info` / `get_self_info` / `get_friend_list` 等返回模拟数据,框架标准动作照常工作
148
+ - **多段渲染** —— 非文本消息段(图片 / 语音 / 文件 / @ 等)渲染成可读占位符
149
+ - **i18n 跟随** —— 欢迎语 / 退出语跟随框架 `i18n` 语言设置
150
+
151
+ ### 安装
152
+
153
+ ```bash
154
+ pip install ErisPulse-TerminalAdapter
155
+ ```
156
+
157
+ 需要 ErisPulse >= 2.7.0。
158
+
159
+ ### 配置
160
+
161
+ `config.toml`:
162
+
163
+ ```toml
164
+ [TerminalAdapter]
165
+ bot_id = "terminal_bot"
166
+ bot_name = "TerminalBot"
167
+ user_id = "terminal_user"
168
+ user_name = "User"
169
+ prompt = "> "
170
+ reply_prefix = "[Bot] "
171
+ echo_input = false
172
+ ```
173
+
174
+ | 字段 | 默认值 | 说明 |
175
+ |------|--------|------|
176
+ | `bot_id` | `terminal_bot` | Bot 的用户 ID |
177
+ | `bot_name` | `TerminalBot` | Bot 昵称 |
178
+ | `user_id` | `terminal_user` | 模拟用户的 ID(与 Bot 对话的终端用户)|
179
+ | `user_name` | `User` | 模拟用户昵称 |
180
+ | `prompt` | `> ` | 输入提示符 |
181
+ | `reply_prefix` | `[Bot] ` | Bot 回复的行前缀(留空则不加前缀)|
182
+ | `echo_input` | `false` | 是否回显用户输入(管道输入场景下开启)|
183
+
184
+ 适配器注册的平台名为 `terminal`,只有一个私聊会话,没有群组概念。
185
+
186
+ ### 使用
187
+
188
+ `epsdk run` 启动后,终端就是聊天窗口:
189
+
190
+ ```
191
+ > 终端适配器已启动。直接输入消息即可与 Bot 对话,Ctrl+C 或 EOF 退出。
192
+ > 输入 /help 查看可用命令。
193
+
194
+ > /hello
195
+ [Bot] Hello, User!
196
+ > ping
197
+ [Bot] ...
198
+ ```
199
+
200
+ 也可以通过管道喂入,便于自动化测试:
201
+
202
+ ```bash
203
+ echo "/hello" | epsdk run main.py
204
+ ```
205
+
206
+ 非文本消息段会渲染成占位符(`[image: url]`、`[voice: url]`、`@user_id` 等)。群组相关操作不支持(终端无群组)。
207
+
208
+ ### 说明
209
+
210
+ - `stdin` 在独立线程中读取,关闭时需等到下一行或 EOF(Ctrl+D / Ctrl+Z)才会退出。
211
+ - 欢迎语 / 退出语 / 提示语跟随框架 `i18n` 语言设置。
212
+
213
+ ---
214
+
215
+ <div align="center">
216
+
217
+ **Related** · [ErisPulse](https://github.com/ErisPulse/ErisPulse) · [Documentation](https://www.erisdev.com) · [Issues](https://github.com/ErisPulse/ErisPulse-TerminalAdapter/issues)
218
+
219
+ </div>
@@ -0,0 +1,7 @@
1
+ TerminalAdapter/Core.py,sha256=fAYtWkQEBzqn_f8WEZrNSjYp5z9rmvZScQu6pRNDiXE,11540
2
+ TerminalAdapter/__init__.py,sha256=sHIRa0KwCO9CYX-64uh54PFHP2g2Ce5KZKm67vZjBCc,65
3
+ erispulse_terminaladapter-1.0.0.dist-info/METADATA,sha256=incdjH2WTL6ML0rPX4ZuPtcfKR0UTU0zUpVBqDAZcvA,8270
4
+ erispulse_terminaladapter-1.0.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
5
+ erispulse_terminaladapter-1.0.0.dist-info/entry_points.txt,sha256=I92EU7dtLXBtuONFzOiYDCBz2CH2jFHZ_vvxZpZdb_g,63
6
+ erispulse_terminaladapter-1.0.0.dist-info/licenses/LICENSE,sha256=x-M-f1_UtTUReGL_ZHkep-yEwmFtH1fPXpMBIN-MHvU,1066
7
+ erispulse_terminaladapter-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [erispulse.adapter]
2
+ terminal = TerminalAdapter:TerminalAdapter
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ErisPulse
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.