Metadata-Version: 2.4
Name: wtsh
Version: 26.10.6
Summary: wtsh shell v26
Author-email: wazzge <wazzge920@163.com>
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Shells
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cmd2>=4.2.4
Dynamic: license-file

# wtsh - 基于 cmd2 的通用插件化交互式 Shell

wtsh 是一个基于 Python cmd2 库开发的通用交互式 Shell，允许 **"在当前进程内执行 Python 脚本以修改主程序"** ，将脚本化配置和动态扩展提升到核心地位。

## 托管仓库
- [Gitee](https://gitee.com/wazzge/wtsh)

## 功能特性

- **交互式命令行界面**：基于 cmd2 框架，支持命令自动补全和历史记录
- **通用 Shell 定位**：不绑定任何 Python 版本或虚拟环境策略，是一个纯粹的交互式命令调度框架
- **脚本一等公民**：`run_pyscript` / `py` 命令在当前进程内执行 Python 代码，可直接访问并修改 shell 实例（`self`）
- **文件系统操作**：支持 ls、cat、cd、clear 等基本命令
- **外部提示符支持**：支持接入 Oh-My-Posh 等第三方提示符工具
- **底栏信息展示**：显示用户、路径、插件扩展信息等
- **插件系统**：基于 Python `entry_points` 的 CommandSet 自动发现与加载
- **preloop pyscript 自动加载**：启动时自动扫描并执行全局 / 交互式 Python 初始化脚本

---

## 核心功能

1. **交互式命令行 Shell**
   - 提供用户友好的命令行交互界面
   - 支持命令自动补全和历史记录
   - 彩色提示符显示

2. **Python 脚本执行（一等公民）**
   - `py` - 进入 Python 交互环境，`self` 直接指向 wtsh 实例
   - `run_pyscript <file>` - 在当前进程内执行 Python 脚本，作为 shell 的 "source" 但用 Python 编写
   - 通过脚本可注入/覆盖命令、修改提示符、操控环境变量等
   - `py_restricted_mode` 设置可切换是否在脚本环境暴露 `self`

3. **文件系统操作**
   - `ls` - 列出当前目录下的文件和文件夹
   - `cat` - 显示指定文件的内容
   - `cd` - 切换工作目录
   - `clear` - 清除终端屏幕内容

4. **容器环境检测**
   - `whichcontainer` - 检测当前是否运行在容器环境中
   - 支持检测的容器类型：Docker、Podman、LXC、Host
   - 显示容器运行时和容器名称

5. **系统信息管理**
   - `aboutus` - 显示 wtsh 版本和系统详细信息
   - `restore_prompt` - 还原提示符为默认样式

6. **通用环境变量管理**
   - `export` - 显示或设置环境变量（支持追加 `+=` 和前置 `=:`）
   - `unset` - 删除环境变量（关键变量如 PATH 受保护）
   - `pathrm` - 从 PATH 中移除指定路径片段
   - 不再限制 VIRTUAL_ENV、PYTHONPATH 等虚拟环境相关变量

7. **插件系统**
   - 基于 Python `entry_points` 自动发现与加载
   - CommandSet 机制，扩展命令如同写普通类方法
   - 命令执行黑名单保护核心安全

8. **Oh-My-Posh 提示符接入**
   - 支持接入第三方提示符工具

---

## 安装要求

- Python 3.10+ (Windows7不支持)
- cmd2 v4+ 库

## 快速开始

### 运行方式

```bash
python wtsh.py
```
如果安装后运行：
```bash
wtsh
```

启动后会显示欢迎信息：

```
Python 3.11.2 
Welcome to the wtsh shell! wtsh version 26.9.5. 
==>>
```

如果配置了 Oh-My-Posh 作为提示符后端，效果如下：

```
Python 3.11.2 
Welcome to the wtsh shell! wtsh version 26.9.5. 
Loaded rc file: /home/user/.wtshrc
user@hostname ~/projects/wtsh
❯
```

## 命令列表

### 基础命令

| 命令 | 描述 | 示例 |
|------|------|------|
| `ls` | 列出当前目录下的文件和文件夹 | `ls` |
| `cat <file>` | 显示文件内容 | `cat README.md` |
| `cd <dir>` | 切换目录 | `cd /home/user` |
| `clear` | 清屏 | `clear` |
| `exit` | 退出 Shell | `exit` |

### 系统信息

| 命令 | 描述 |
|------|------|
| `aboutus` | 显示 wtsh 版本和系统信息 |
| `lsplugins` | 列出所有已加载的插件和命令集 |
| `see_blacklist` | 显示命令执行黑名单 |
| `restore_prompt` | 还原提示符为默认样式 |

### Python 脚本执行（一等公民）

| 命令 | 描述 | 示例 |
|------|------|------|
| `py` | 进入 Python 交互环境（`self` 指向 wtsh 实例） | `py` |
| `run_pyscript <file>` | 在当前进程内执行 Python 脚本 | `run_pyscript ~/venv/Scripts/activate.wtsh.py` |
| `run_script <file>` | 在当前进程内执行 shell 脚本（.wtshrc 格式） | `run_script ~/.wtshrc` |

### 环境变量管理

| 命令 | 描述 |
|------|------|
| `export` | 显示或设置环境变量（支持追加 `+=` 和前置 `=:`） |
| `unset` | 删除环境变量（关键变量如 PATH 受保护） |
| `pathrm` | 从 PATH 中移除指定路径片段 |

### 变量展开

命令行中支持 `$VAR` / `${VAR}` 展开，以及特殊变量 `$?`（上一命令返回码）、`$_`（上一参数）、`$0`（shell 名称）。

---

## Python 脚本执行详解（一等公民）

wtsh 的核心理念：**在当前进程内执行 Python 脚本以修改 shell 自身**。这让脚本化配置达到前所未有的灵活度。

### 基础用法

```bash
# 进入 Python 交互环境，self 即为当前 wtsh 实例
py

# 执行 Python 脚本，脚本内同样可以访问 self
run_pyscript my_script.py
```

### self 暴露范围

默认情况下，`py` 和 `run_pyscript` 环境中会暴露 `self`（wtsh 实例）、`app`（同 self）、`cmd` 等对象。可通过 `set py_restricted_mode True` 关闭 self 暴露，脚本将只能使用标准 Python 环境。

### 典型场景：虚拟环境激活

wtsh 不再内置 venv 激活/停用命令，也不再通过 `export` 拦截 VIRTUAL_ENV 等变量。取而代之的是一份标准的 **activate 脚本模板**，你可以把它放在任意 venv 的 `Scripts/`（Windows）或 `bin/`（POSIX）目录下，通过 `run_pyscript` 执行：

```bash
# 把模板脚本复制到目标 venv 的 bin/Scripts 目录
# src/wtsh/pyscript_template/activate.wtsh.py

# 进入 wtsh 后执行
run_pyscript /path/to/venv/Scripts/activate.wtsh.py
```

该脚本会自动完成：
- 将 venv 的 bin/Scripts 前置到 PATH（通过 shell 级 `export PATH=:`）
- 设置 `VIRTUAL_ENV` / `VIRTUAL_ENV_PROMPT`
- 注入 `deactivate` 命令到 shell 实例
- 在提示符前加上 `(venv_name)` 标记
- 切换 venv 时自动回滚 PATH，最终 deactivate 还原一切

### 自定义脚本示例

```python
# my_setup.py - 一个自定义 wtsh 初始化脚本

# 修改提示符
self.prompt = '>>> '

# 注入新命令
def do_hello(self, args):
    """Say hello"""
    self.poutput(f"Hello, {args or 'world'}!")

import types, sys
sys.modules['__main__'].do_hello = do_hello
self.do_hello = types.MethodType(do_hello, self)

# 操作环境变量
self.do_export('MY_CUSTOM_VAR=hello_world')
```

然后在 wtsh 中：
```bash
run_pyscript my_setup.py
hello friend
# -> Hello, friend!
```

### .wtshrc 初始化脚本

`~/.wtshrc` 启动时自动加载，本质是通过 `run_script` 执行的 shell 命令脚本。你也可以在 .wtshrc 中直接调用 `run_pyscript` 来加载 Python 配置：

```bash
# ~/.wtshrc 示例
run_pyscript ~/my_wtsh_setup.py
export PATH+=/my/custom/bin
```

### preloop pyscript 自动加载

除了 `~/.wtshrc`（shell 命令脚本），wtsh 还支持在 **进入命令循环前（preloop 阶段）自动加载 Python 初始化脚本**。这些脚本在 `cmdloop()` 之前执行，比 `.wtshrc` 更"早"，专门用于 Python 级别的预配置。

#### 脚本位置

优先级从高到低：

| 优先级 | 路径 | 说明 |
|--------|------|------|
| 1（最高） | 环境变量 `WTSH_PRELOOP_PYSCRIPT_ROOTPATH` 指向的目录 | 路径需是有效目录，且**不会回退**到默认路径（见下方注意事项） |
| 2（默认） | `~/.wtsh/pyscript.d/` | 用户目录下的默认位置 |

路径值会依次经过 `expanduser`（展开 `~`）和 `expandvars`（展开 `$VAR` / `${VAR}`）处理，因此以下写法都有效：

```bash
export WTSH_PRELOOP_PYSCRIPT_ROOTPATH=$HOME/.wtsh/pyscript.d
export WTSH_PRELOOP_PYSCRIPT_ROOTPATH=~/.wtsh/pyscript.d
export WTSH_PRELOOP_PYSCRIPT_ROOTPATH=/opt/wtsh/preloop
```

> ⚠️ **重要**：如果设置了 `WTSH_PRELOOP_PYSCRIPT_ROOTPATH` 但路径无效（目录不存在），wtsh 会直接跳过 preloop 加载，**不会自动回退到 `~/.wtsh/pyscript.d`**。这是刻意设计（环境变量优先级意味着"用户明确指定了位置"）。排查 preloop 不加载问题时，请先确认该环境变量是否存在且有效。

#### 脚本命名与加载规则

目录内查找两个固定文件名，按顺序执行：

| 文件名 | 作用范围 | 加载条件 |
|--------|----------|----------|
| `base.wtsh.py` | **全局** | 文件存在即加载，任何模式下都执行 |
| `interactive.wtsh.py` | **仅交互式** | 文件存在 **且** 当前 stdin 为 TTY（即终端交互模式）时加载 |

执行顺序：`base.wtsh.py` → `interactive.wtsh.py`

```
# 典型目录结构
~/.wtsh/pyscript.d/
├── base.wtsh.py           # 全局脚本（必加载）
└── interactive.wtsh.py    # 交互式脚本（仅 TTY 模式加载）
```

#### 跳过条件

满足以下任一条件时，整个 preloop pyscript 加载流程会被 **跳过**（不会有任何提示输出）：

- `py_restricted_mode` 为 `True`（严格模式下 self 不可用，脚本无意义）
- 根目录无法解析（环境变量无效路径 + 默认路径不存在）
- 目录下既没有 `base.wtsh.py` 也没有 `interactive.wtsh.py`

#### 异常处理

如果 preloop 脚本执行时抛出异常，wtsh 会：
1. 通过 `perror` 打印 **脚本路径 + 异常类型 + 异常消息**
2. 立即调用 `sys.exit(1)` **退出整个程序**（不会进入命令循环）

```
Preloop pyscript error in /home/user/.wtsh/pyscript.d/base.wtsh.py: NameError: name 'xxx' is not defined
```

这是刻意设计的——preloop 脚本是启动流程的关键环节，出错应尽早暴露。

#### 使用示例

```bash
# 创建目录
mkdir -p ~/.wtsh/pyscript.d

# 编写全局脚本 —— 任何模式下都执行
# ~/.wtsh/pyscript.d/base.wtsh.py
self.do_export('MY_APP_HOME=/opt/myapp')
self.poutput('Loaded base preloop pyscript')

# 编写交互式脚本 —— 仅 TTY 终端加载
# ~/.wtsh/pyscript.d/interactive.wtsh.py
self.prompt = '==>> '  # 自定义提示符
self.poutput('Welcome back, interactive user!')
```

或者通过环境变量自定义路径：

```bash
# 在 .bashrc / .zshrc 中
export WTSH_PRELOOP_PYSCRIPT_ROOTPATH=/etc/wtsh/preloop
```

#### 与 .wtshrc 的关系

两者在不同阶段执行，互补而非替代：

| 特性 | preloop pyscript | .wtshrc |
|------|------------------|---------|
| 执行时机 | `cmdloop()` 之前（preloop） | `__init__` 中（更早） |
| 语言 | Python | shell 命令 |
| 暴露 self | 是（默认模式） | 否 |
| 交互式判断 | 支持（interactive.wtsh.py） | 不支持 |
| 错误行为 | 打印错误 + 退出程序 | 打印警告 + 继续 |

推荐策略：**Python 级配置放 preloop pyscript，shell 命令放 .wtshrc**。

## 命令详解

### ls

列出当前目录下的所有文件和目录：

```bash
==>> ls
Documents
Downloads
Desktop
```

### cat

显示指定文件的内容：

```bash
==>> cat example.txt
Hello, wtsh!
```

### cd

切换到指定目录：

```bash
==>> cd Documents
==>> 
```

### clear

清除终端屏幕内容。

### exit

退出 wtsh Shell，返回系统命令行。

### aboutus

显示 wtsh 的版本信息和运行时平台：

```bash
==>> aboutus
wtsh version: 26.9.5
wtsh plugin protocol version: 7.2.0
wtsh plugin protocol platform: entry_points
wtsh plugin entry_points: wtsh.plugins
wtsh main runtime platform(OS platform): linux
supported plugin types: entrypoints+cmd2.commandset --by cmd2
cmd2 version: 4.0.0
```

### lsplugins

列出所有已加载的插件和命令集：

```bash
==>> lsplugins
plugin_name (entry_point)
```

### see_blacklist

显示命令执行黑名单（这些命令被禁止执行）：

```bash
==>> see_blacklist
dd
format
```

### restore_prompt

将提示符恢复为默认样式。

### export

显示或设置环境变量。wtsh 作为通用 Shell，不再对 VIRTUAL_ENV、PYTHONHOME、PYTHONPATH 等虚拟环境相关变量做任何拦截或限制：

```bash
# 显示所有环境变量
export

# 显示指定变量
export PATH

# 设置变量
export MYVAR=hello

# 设置带空格的值（需要引号）
export MYVAR="hello world"

# 追加到变量（适用于 PATH 等）
export PATH+=/new/bin

# 前置到变量开头
export PATH=:/priority/bin

# 自由设置 venv 相关变量
export VIRTUAL_ENV=/path/to/venv
export PYTHONPATH+=/my/modules
```

### unset

删除环境变量（关键变量如 PATH、HOME 等受保护，无法删除）：

```bash
unset MYVAR
```

### pathrm

从 PATH 中移除指定路径片段：

```bash
pathrm /usr/local/bin
```

## 初始化文件

wtsh 支持在用户目录下使用 `.wtshrc` 文件作为初始化脚本。启动时会自动执行该文件中的命令。

初始化文件位置：`~/.wtshrc`

如果初始化文件加载成功，会显示：
```
Loaded rc file: /home/user/.wtshrc
```

如果文件不存在，会显示警告信息。

## Oh-My-Posh 提示符接入

wtsh 支持接入 Oh-My-Posh 等第三方提示符工具，提供更丰富的提示符样式。

### 配置方法

```bash
# 设置 Oh-My-Posh 作为主提示符
set main_prompt_provider 'oh-my-posh print primary'

# 刷新提示符
restore_prompt
```

### 效果预览

**启用 Oh-My-Posh 后：**

```
┌─────────────────────────────────────────────────────────────────┐
│ user@hostname ~/projects/wtsh                                   │
│ ❯                                                               │
└─────────────────────────────────────────────────────────────────┘
```

**原生提示符模式：**

```
┌─────────────────────────────────────────────────────────────────┐
│ ==>> ls                                                         │
│ Documents  Downloads  Desktop                                   │
└─────────────────────────────────────────────────────────────────┘
```

### 安全限制

为防止命令注入攻击，`main_prompt_provider` 配置项禁止包含以下危险字符：
- `;` - 命令分隔符
- `&`, `|` - 管道符
- `>`, `<` - 重定向符
- `` ` `` - 反引号命令执行
- `$(` - 子shell命令执行

### 底栏行为

- **原生提示符模式**：底栏显示完整信息（用户、路径、解释器）
- **Oh-My-Posh 模式**：底栏只显示解释器信息（用户和路径由 Oh-My-Posh 显示）

## 插件系统

wtsh 支持通过插件机制扩展功能，采用 Python `entry_points` 作为插件发现机制。

### 插件机制

wtsh 在启动时会自动扫描 `wtsh.plugins` 组下的所有 entry points，并动态加载：

```python
for ep in entry_points(group="wtsh.plugins"):
    cls = ep.load()
    if inspect.isclass(cls) and issubclass(cls, cmd2.CommandSet):
        self.register_command_set(cls())
        print(f'Loaded plugin {ep.name}')
```

### 插件协议信息

- **插件协议名称**：`wtsh.plugins`
- **插件协议版本**：7.2.0
- **插件平台**：`entry_points`
- **支持的插件类型**：`entrypoints+cmd2.commandset`

### 插件开发

开发 wtsh 插件需要：

1. 创建一个继承自 `cmd2.CommandSet` 的类
2. 在 `pyproject.toml` 中注册 entry point：

```toml
[project.entry-points."wtsh.plugins"]
my_plugin = "my_package.my_module:MyCommandSet"
```

3. 实现自定义命令方法（使用 `@with_category` 装饰器分类）

### 插件加载

插件会在 wtsh 启动时自动加载，加载成功后会显示：

```
Loaded plugin plugin_name
```

如果没有找到插件或加载失败，会显示相应的提示信息。

### 插件管理命令

| 命令 | 描述 |
|------|------|
| `lsplugins` | 列出所有已加载的插件和命令集 |

### 安全限制

- 命令执行黑名单（`dd`、`format`）对插件命令同样生效
- 插件无法修改主程序的 `__BLACKLIST` 变量

## 支持的平台

wtsh 可以在以下操作系统上运行：

- Linux
- Windows
- macOS
- KaihongOS （docker容器内运行）

## AI 辅助开发说明

坦白说，这个项目的代码有不少是我（人类）和 AI 一起写的。我负责想"要做什么"和"为什么这么做"，比如设计整体架构、定义项目理念、把关安全性；而 AI 则帮我把想法变成具体的代码实现，还能优化代码结构、写文档示例。

这种合作模式很高效：我抛出一个需求，AI 给出初步实现，我再审核、修改、打磨，最终形成可用的功能。但请放心，项目的核心思想、安全策略和关键决策都是我来把控的，AI 只是个给力的助手。

## 许可证

Apache License 2.0

## 版本历史

- **26.9.5**：wtsh 转向通用 Shell 定位；将"在当前进程内执行 Python 脚本以修改主程序"提升为一等公民（`py`/`run_pyscript` 默认暴露 `self`，新增 `py_restricted_mode` 可切换）；移除 pipw 子命令和 runpy + subprocess_interpreter 体系（移入 `wtsh.DEPRECATED/`）；export 解除对 VIRTUAL_ENV、PYTHONHOME、PYTHONPATH 等 venv 相关变量的所有拦截限制；新增标准 activate.wtsh.py 模板脚本，通过 `run_pyscript` 实现 venv 的激活/停用；新增 `$VAR` / `${VAR}` 变量展开和 `$?`/`$_`/`$0` 特殊变量；`.wtshrc` 改用 `run_script` 加载；新增 preloop pyscript 自动加载机制（`base.wtsh.py` 全局 + `interactive.wtsh.py` 仅交互式，支持环境变量 `WTSH_PRELOOP_PYSCRIPT_ROOTPATH` 自定义路径，严格模式或目录无效时自动跳过，脚本出错则打印并退出程序）
- **26.7.21**：新增 Oh-My-Posh 提示符接入支持；优化底栏显示逻辑，外部提示符模式下仅显示解释器信息；添加命令注入安全限制；移除废弃命令 `py_venv_activate`、`py_venv_exit` 和 `import_all_commandsets_from_an_independent_py`
- **26.7.18**：新增环境变量管理命令（export、unset、pathrm），支持环境变量的设置、追加、前置和删除；彻底抛弃 venv 的 activate/deactivate 体系；保护关键环境变量（PATH、HOME等）不被误删
- **26.6.28**：新增命令执行黑名单（__BLACKLIST），commandset不可修改；提供统一的插件接口类libwtsh_utils
- **26.6.18**：添加初步的底栏支持，主提示符精简，添加右提示符
- **26.5.30**：升级到cmd2-v4、新增虚拟环境管理功能、初始化文件支持（.wtshrc）、distrobox容器内执行宿主机命令（dexec）、优化清屏功能支持Windows、新增cmd2版本显示
- **26.5.17**：优化whl打包、docker镜像和容器检测功能，容器检测功能移除"自动附加到提示符"以防止信息泄露
- **26.5.0**：初始版本，包含基础文件操作和容器检测功能
