Metadata-Version: 2.4
Name: damnatiox-agent
Version: 0.4.0
Summary: A terminal-first Python coding agent with a bounded model-tool harness.
Author: jame100101
Project-URL: Repository, https://github.com/jame100101/damnatioX-agent
Project-URL: Issues, https://github.com/jame100101/damnatioX-agent/issues
Keywords: agent,cli,deepseek,rag,tools,tui
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.14
Description-Content-Type: text/markdown
Requires-Dist: numpy<3,>=2.5.1
Requires-Dist: openai<3,>=2.47
Requires-Dist: prompt-toolkit<4,>=3.0.52
Requires-Dist: PyYAML<7,>=6.0.3
Requires-Dist: rich<16,>=15
Provides-Extra: rag
Requires-Dist: sentence-transformers<6,>=5.6; extra == "rag"
Provides-Extra: dev
Requires-Dist: build<2,>=1.3; extra == "dev"
Requires-Dist: pytest<10,>=9.1; extra == "dev"
Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
Requires-Dist: setuptools>=77; extra == "dev"
Requires-Dist: twine<7,>=6; extra == "dev"
Requires-Dist: wheel; extra == "dev"

<p align="center">
  <img src="https://github.com/jame100101/damnatioX-agent/raw/refs/heads/main/docs/assets/damnatiox-wordmark.png" alt="DamnatioX" width="560" />
</p>

<h1 align="center">DamnatioX Agent</h1>

<p align="center">
  <a href="#安装"><img alt="Python 3.14" src="https://img.shields.io/badge/PYTHON-3.14-3776AB?style=for-the-badge&logo=python&logoColor=white"></a>
  <a href="frontend/"><img alt="React 19" src="https://img.shields.io/badge/REACT-19-20232A?style=for-the-badge&logo=react&logoColor=61DAFB"></a>
  <a href="frontend/"><img alt="TypeScript" src="https://img.shields.io/badge/TYPESCRIPT-7-3178C6?style=for-the-badge&logo=typescript&logoColor=white"></a>
  <a href="#完整运行链路"><img alt="Harness V2" src="https://img.shields.io/badge/HARNESS-V2-8B5CF6?style=for-the-badge"></a>
  <a href="#react--ink-终端界面"><img alt="Local TUI" src="https://img.shields.io/badge/TUI-REACT%20%7C%20INK-EC4899?style=for-the-badge"></a>
</p>

<p align="center"><strong>简体中文</strong> · Local-first · Session persistence · Tool runtime</p>

DamnatioX Agent 是终端优先的本地 Coding Agent。当前版本由 Python Harness V2
负责 Session、模型、工具、权限、预算和持久化，由 React + TypeScript + Ink
负责默认全屏终端界面；Rich / prompt-toolkit 界面继续作为兼容入口。

## 安装

需要 Python 3.14。发布包提供三种常用安装方式：

```bash
# 推荐：隔离安装 CLI
pipx install damnatiox-agent

# uv tool
uv tool install damnatiox-agent

# 普通 pip / 虚拟环境
python -m pip install --upgrade damnatiox-agent
```

Windows 上若 pip 提示用户级 `Scripts` 目录不在 `PATH`，执行一次以下命令并
重新打开终端：

```powershell
$scripts = Join-Path (python -m site --user-base) 'Python314\Scripts'
$path = [Environment]::GetEnvironmentVariable('Path', 'User')
[Environment]::SetEnvironmentVariable('Path', "$path;$scripts", 'User')
```

默认安装保持 CLI 与 Harness 依赖轻量。需要本地 embedding 模型和语义
知识库工具时，安装 `rag` extra：

```bash
pipx install 'damnatiox-agent[rag]'
# 或
python -m pip install 'damnatiox-agent[rag]'
```

安装后可在任意已有目录启动：

```bash
cd /path/to/project
damnatioX
```

`damnatioX` 与 `damnatiox` 均为正式 CLI 入口。

启动目录就是本次 Agent 的 Workspace；文件工具和命令始终绑定到该目录。
Session、Attempt、Event 与 Artifact 按 Workspace 隔离；Workspace 可写时沿用
`<workspace>/.damnatiox`，只读目录（例如 `C:\Windows\System32`）自动使用
`~/.damnatiox/workspaces/<workspace>-<hash>`。首次运行会直接进入 React TUI 的
`Config → model-config` 页面：填写 OpenAI-compatible Base URL 与 API Key，获取模型列表，
再选择模型。也可预先设置：

```bash
export OPENAI_API_KEY="..."
export OPENAI_BASE_URL="https://provider.example/v1"
```

Windows PowerShell：

```powershell
$env:OPENAI_API_KEY = "..."
$env:OPENAI_BASE_URL = "https://provider.example/v1"
```

交互式输入的 Key 保存到用户目录 `~/.damnatiox/config.json`。首次设置只通过
本机 Node→Python stdio RPC 传递一次，输入全程掩码且服务端不回显；后续启动由
Python gateway 从环境或配置读取；旧的 `DEEPSEEK_API_KEY` / `DEEPSEEK_BASE_URL` 仍兼容。
`/config` 打开设置页，可重新获取端点模型并切换 Base URL、API Key 与当前模型。

React gateway 独占 stdin 作为本机 NDJSON 控制通道；Workspace 的 Git 元数据与
Diff 探测使用独立的空输入流，因此从普通目录或非 Git 目录启动也不会阻塞模型
Turn。若升级前已有卡在 `Preparing turn` 的进程，退出后用新版本重新启动即可。

### CLI

```text
damnatiox                         新 Session，默认 --ui auto
damnatiox --continue              恢复当前 Workspace 最近的 Session
damnatiox -c / -continue          上一项的短写与单横线兼容写法
damnatiox -s / -session           打开历史 Session 选择器
damnatiox --resume SESSION_ID     恢复指定 Session
damnatiox --manual-approval       React 界面中在写入与独占工具前显示审批框
damnatiox --ui react              明确使用 React / Ink
damnatiox --ui rich               使用 Rich 兼容界面
damnatiox --ui-info               检查前端 manifest、SHA256 和 Node 运行时
damnatiox --frontend-smoke        无 API Key 前端渲染 smoke
damnatiox --version
```

`--ui auto` 优先选择经过 manifest SHA256 校验的 React 前端：

- 平台 wheel 使用包内 Node 24.14.0；
- 通用 wheel 使用系统 Node 22 或更高版本；
- 通用 wheel 找不到兼容 Node 时进入 Rich 界面；
- stdin/stdout 被重定向时，`auto` 保留 Rich 的线性输入输出路径；
- `--ui react` 的资源、完整性或运行时错误使用稳定的 `DX-UI-*` 错误码。

React 启动前不打印 Rich banner，因此 React / Ink 独占 TTY。`--ui-info` 和
`--frontend-smoke` 都不读取 API Key。

## React / Ink 终端界面

默认界面沿用原 Rich TUI 的信息层次，而不是把 Harness 状态拼成普通日志：

```text
Header
├── Model / reasoning effort / Session / Workspace / Git
Transcript
├── User turn
├── Thinking（可隐藏）
├── ToolActivity（queued / running / approval / result）
└── Assistant response
Composer
├── 支持粘贴与中文 IME 光标定位
└── 输入 `/` 弹出可搜索 slash command / option palette
Approval
├── tool、参数名称与有界脱敏预览
└── Y / N / Esc
Status
└── 动态等待特效、当前阶段、思考/总耗时、Token、诊断
```

主要快捷键：

```text
Enter          发送
↑ / ↓ / Tab    选择或补全 slash command、模型与表单字段
← / → / Tab    在 Config 首页切换 Settings / Status / Config / Usage / Stats
Mouse click     直接切换 Config 顶部 Settings / Status / Config / Usage / Stats
Ctrl+C         第一次中断活动 Turn/提示退出；2 秒内第二次强制退出 TUI
Y / N / Esc    处理当前工具审批
Mouse wheel    每次上下滚动 Transcript 3 行
PageUp/Down    按页浏览 Transcript
Ctrl+Home/End  跳到 Transcript 顶部/尾部
Shift+drag     在鼠标捕获开启时选择终端文字
Ctrl+Shift+V   使用终端原生粘贴；多行内容在输入栏显示为 ↵
```

界面支持 `/help`、`/status`、`/tools`、`/skills`、`/sessions`、`/new`、
`/resume`、`/history [count]`、`/context`、`/content`、`/compact`（兼容
`/compress`）、`/config`、`/diff`、`/model`、`/effort`、`/thinking`、`/copy`、`/clear`
和 `/exit`。`/context` 只检查上下文 Token 估算、阈值和上轮用量；`/content`
预览下一次请求会沿用的结构化摘要与最近消息，不再是 `/context` 的别名。

输入 `/` 后，命令面板显示可选命令；`/model`、`/effort`、`/thinking`、
`/resume`、`/history` 与 `/skills` 会继续进入对应选项面板。`/model` 直接进入模型选择器，
显示当前端点模型及其上下文长度；切换结果会持久化到 Workspace 运行设置并立即更新
Session 的 prompt、输出预留与 compaction 阈值。
所有 slash command 的结果都使用面向终端阅读的摘要、列表或对齐字段展示，
不会把 RPC JSON 直接写入对话记录。
Reasoning 流会显示详细内容、实时 `Thinking for …` 计时和 Braille 等待动画；
最终回答中的 Markdown 表格会按 CJK/emoji 终端 cell 宽度整理为对齐表格。

默认鼠标滚轮由 TUI 捕获，每次滚动三行。Windows Terminal 等终端可按住 Shift
拖选文字；也可执行 `/copy` 暂停鼠标捕获，使用终端原生选择/复制，再执行一次
`/copy` 恢复 Transcript 滚轮。输入组件使用 Ink 的真实 cursor API，因此中文
IME 组合文本和候选窗通过实际 Ink 布局坐标锚定在当前输入框光标右侧，而不是依赖
固定终端行号；slash 面板、配置字段和终端缩放都不会把光标推到其他区域。配置页与
命令面板会在窄终端中切换紧凑布局，长字段保持在可视边界内。

前端源码位于 `frontend/`，生产 bundle 位于
`damnatiox_agent/ui/assets/app.mjs`。Python launcher 会先校验
`assets/manifest.json` 中记录的 SHA256，再使用包内或系统 Node 启动它。

## 完整运行链路

```mermaid
flowchart TD
    CLI["damnatiox：Python CLI launcher"]
    NODE["Node 24 / Node >= 22"]
    REACT["React + TypeScript + Ink TUI"]
    RPC["NDJSON framed JSON-RPC 2.0 over stdio"]
    GW["tui_gateway"]
    API["LocalAgentAPI"]
    APP["AgentApplication"]
    TURN["TurnService"]
    LOOP["AgentLoop"]
    CTX["ContextBuilder / CompletionPolicy / TurnBudget"]
    MODEL["ModelGateway"]
    DISCOVERY["OpenAI-compatible /models + ModelProfile limits"]
    RUNTIME["ToolRuntime"]
    EXEC["ToolExecutor / Sandbox / ProcessRunner"]
    STORE["Session / Attempt / Event / Artifact Stores"]
    EXT["Skills / Workspace Facts / Attempt Facts"]

    CLI --> NODE
    NODE --> REACT
    REACT <--> RPC
    RPC <--> GW
    GW --> API
    API --> APP
    APP --> TURN
    TURN --> LOOP
    LOOP --> CTX
    LOOP <--> MODEL
    GW --> DISCOVERY
    DISCOVERY --> APP
    LOOP <--> RUNTIME
    RUNTIME --> EXEC
    TURN <--> STORE
    LOOP --> STORE
    EXT --> CTX
```

线性表示：

```text
CLI Python launcher
→ Node React/Ink
→ NDJSON JSON-RPC stdio
→ damnatiox_agent.interfaces.tui_gateway
→ LocalAgentAPI / AgentApplication
→ TurnService / AgentLoop
→ ModelGateway / ToolRuntime
→ AgentEvent / Turn result
→ JSON-RPC notification
→ React reducer 与终端组件
```

Node 前端占用终端 stdin/stdout，并启动独立 Python gateway 子进程。Gateway 的
stdout 只写一行一条的 JSON-RPC；诊断写 stderr。请求读取保留在主线程，Turn 和
Compaction 在 worker 中运行，因此 `turn/interrupt` 和工具审批在模型或工具运行
期间仍可响应。

## RPC 与前后端边界

`tui_gateway` 只负责协议校验、序列化、worker 调度和进程关闭；模型、工具、
Session 和文件访问仍位于 `LocalAgentAPI` 与 `AgentApplication` 后方。

主要 RPC：

| 领域 | 方法或通知 |
|---|---|
| 初始化 / 配置 | `initialize`、`config/read`、`config/discoverModels`、`config/applyModelEndpoint`、`config/setApiKey`（兼容）、`runtime/status`、`shutdown` |
| Session | `session/read`、`session/list`、`session/create`、`session/resume`、`session/save`、`session/history` |
| Attempt / Events | `attempt/list`、`attempt/read`、`events/list` |
| Turn | `turn/start`、`turn/interrupt`、`turn/result` |
| 流式事件 | `agent/event` |
| 审批 | `tool/resolveApproval` |
| Context | `context/read`、`context/compact`、`context/compacted` |
| Workspace | `workspace/read`、`workspace/diff` |
| 能力 | `tool/list`、`skill/list`、`skill/update`、`model/list`、`model/update` |

`initialize` 协商 protocol version。缺少凭据时先返回 `credentialRequired` 和
脱敏配置元数据，React 显示密码输入界面；配置完成后返回 capability、当前 Session
的有界尾部快照、Workspace、模型、reasoning effort、命令表和事件 cursor。更早的 Session
历史使用 `session/history` 分页读取，界面会显示已省略的 Turn 数量。
Session 元数据持久化创建时间与最后关闭时间；`-s`/`-session` 的启动选择器和
`/resume` 面板都会展示这两个时间。`AgentEvent` 包含 `session_id`、
`attempt_id`、`sequence`、`timestamp`、kind、text 和 details；前端按 cursor
去重和恢复，不假定 sequence 连续。

API Key 只在 `config/discoverModels`（或兼容的 `config/setApiKey`）本机 stdio 请求中出现，
且不进入响应、事件或日志；配置页只回显掩码。OpenAI-compatible client、ToolExecutor
和可变 Session 对象不穿过 RPC。
审批事件仅传工具身份、参数名称与有界脱敏预览；原始完整值留在
ToolRuntime 一侧，EventStore 不持久化该预览。

## Harness V2 分层

| 层 | 代码位置 | 职责 |
|---|---|---|
| CLI / UI | `damnatiox_agent/cli.py`、`damnatiox_agent/ui/`、`frontend/`、`tui/` | UI 选择、TTY、React 渲染、Rich 兼容 |
| Transport | `damnatiox_agent/interfaces/tui_gateway.py`、`python_api.py` | JSON-RPC、NDJSON、DTO、stream、cancel、approval |
| Application | `damnatiox_agent/application/` | Composition root、Session 选择、Turn 生命周期、Compaction |
| Agent Core | `damnatiox_agent/agent/` | 单一模型—工具循环、上下文、预算、取消、完成检查、事件 |
| Model | `damnatiox_agent/model/` | timeout、retry、backoff、stream、usage、cost |
| Tools | `damnatiox_agent/tools/`、`tool/` | ToolSpec、参数校验、权限、执行、Sandbox、进程树、结果 |
| Workspace | `damnatiox_agent/workspace/` | 路径边界和 Mutation Journal |
| Persistence | `context/session_store.py`、`damnatiox_agent/persistence/` | Session、Attempt、Event、Artifact 原子保存和恢复 |
| Extensions | `damnatiox_agent/extensions/` | Skills、Workspace Facts、Attempt Facts、ToolProvider 接缝 |
| Evals | `damnatiox_agent/evals/`、`evals/tasks.json` | declarative baseline 与 Application runner |

默认 composition root 是
`damnatiox_agent.application.bootstrap.build_agent_application`。Router、独立
Planner、LLM Validator、Replanner 和 Answer Repair 仍只存在于 legacy 源码，
不进入默认 React、Rich 或 Python API 热路径。

## Agent Loop

核心实现为 `damnatiox_agent/agent/loop.py::AgentLoop.run`：

```python
while True:
    cancel_token.raise_if_cancelled()
    budget.check()

    context = context_builder.build(session, attempt, tool_registry.schemas())
    context = context_builder.fit_to_budget(
        context,
        budget.remaining_input_tokens,
    )
    response = model_gateway.generate(context, budget, cancel_token)
    attempt.append_assistant_message(response.message)

    if not response.tool_calls:
        completion_policy.validate(response.content, attempt, budget)
        return response.content

    tool_runtime.execute_calls(
        response.tool_calls,
        budget,
        cancel_token,
        tool_result_sink=append_and_checkpoint,
    )
```

Harness 负责权限、Workspace、预算、timeout、API retry、取消、执行和停止；模型
决定是否调用工具以及收到结果后的下一步。确定性的 schema、路径、退出码和完成
条件由代码判断。

主 Agent 的默认表达是批判优先、直球、一针见血的严厉教官/教练/师父风格；可以
嘴臭，但骂完必须紧跟事实、改法和执行，不得用空喷替代把任务做完。角色规则保持在
单一紧凑的主提示词中，不扩散到 Router、摘要器或其他确定性组件。

### 模型发现与上下文硬上限

所有模型仍走 OpenAI-compatible Chat Completions 接口。`/config` 先调用端点的
`GET /models`：若端点返回 `context_window`、`context_length`、`max_model_len` 等扩展字段，
Harness 直接采用端点值；内置模型可使用本地 catalog；标准 `/models` 未携带上下文元数据的
未知模型要求用户明确填写，不按名称猜测。配置保存在 `~/.damnatiox/config.json`。
DeepSeek 模型保留其 reasoning/thinking 扩展参数；其他 OpenAI-compatible 模型默认只发送
标准 Chat Completions 字段，避免把供应商私有参数硬塞给所有端点。

选择模型后，Harness 从该模型窗口确定性派生四个限制：`model_context_tokens`、
`max_prompt_tokens`、`compression_trigger_tokens`、`compression_target_tokens`。
`ContextBuilder` 只在 prompt 上限内组装历史，`AgentLoop` 同时限制
`max_output_tokens <= model_context_tokens - fitted_input_tokens`。因此 256K 模型只使用
256K 窗口，1M 模型可使用 1M 窗口；切换模型不会沿用旧模型的阈值。

### 中断与继续

第一次 `Ctrl+C` 只发出 `turn/interrupt`，UI 保持 `Cancelling turn`，直到收到持久化后的
`turn/result`；2 秒内第二次 `Ctrl+C` 才关闭 TUI。取消会传播到模型 stream、Agent Loop 和
进程工具；已经完成的工具副作用不回滚，未完成操作不标记成功。Turn、Attempt、Event 与
已完成工具结果会先 checkpoint，并在同一 Session 写入 `resume_pending/resume_reason` 标记。
后续输入“继续”时，模型会看到原请求、中断记录和当前 Workspace 事实；成功完成下一轮后清除
pending 标记。这是会话级继续，不会自动重放未完成的工具调用。

有限默认预算：

| 资源 | 默认值 |
|---|---:|
| Turn 总墙钟 | 600 秒 |
| 单次模型 API timeout | 60 秒 |
| 模型请求 | 24 |
| 工具调用 | 96 |
| 输入 Token | Turn 上限 1,000,000，且受模型 prompt 硬上限约束 |
| 输出 Token | Turn 上限 200,000，且受模型剩余窗口/输出上限约束 |
| 估算费用 | 5 USD |

### Token 与费用口径

- `/context` 展示的是**会话基础上下文估算**：system prompt、结构化 summary 与
  recent turns。它使用轻量算法估算（ASCII 约 4 字符/Token，非 ASCII 约
  1 字符/Token，并加消息开销）；工具 schema、动态 Workspace/Skill 块和下一条
  用户消息会在真正构建请求时再加入。
- 状态栏的 `tok` 累加当前 Turn 内每次模型请求的 usage。兼容端点返回
  `prompt_tokens` / `completion_tokens` 时直接采用；流式请求显式要求
  `include_usage`。端点不返回 usage 时，输入按完整 messages + tool schemas 的
  序列化结果估算，输出按规范化 assistant message 估算。
- 每次启动或进入 Session 时，后台会从 LiteLLM 公共 JSON catalog 发起有超时、大小上限
  和 ETag/Last-Modified 条件缓存的价格刷新；失败时使用上次成功缓存，DeepSeek V4 Flash /
  Pro 另有内置兜底价。当前模型的输入、输出、缓存命中单价和数据来源可在
  `/status` 或 `Config → Usage` 查看。
- 本地估算公式为
  `cost = (非缓存输入 × input_price + 缓存输入 × cache_read_price + 输出 × output_price) / 1,000,000`，
  并累加工具循环中的所有模型请求。Token 优先采用端点返回的 usage；端点没有 usage 时才使用
  Harness 的确定性 Token 估算。价格目录是估算口径，不替代服务商最终账单。
- 可用内置脚本单独检查实时匹配结果：
  `python -m damnatiox_agent.model.pricing MODEL --base-url BASE_URL`。

模型 SDK 自带 retry 关闭，重试和预算由 `ModelGateway` 统一控制。
`CancellationToken` 会停止后续 Loop、关闭 stream，并把取消传播给进程工具；
`ProcessRunner` 负责终止子进程树。

## 工具、上下文和持久化

`ToolRuntime` 在现有 `ToolExecutor` 外统一处理：

1. Tool 注册与 JSON/schema 参数；
2. PermissionPolicy 和 WorkspacePathPolicy；
3. TurnBudget、timeout 与 cancellation；
4. 读并行与写/独占 barrier；
5. ToolResult、Verification、Mutation 和 Artifact 标准化；
6. 每个 barrier 结果立即 checkpoint。

RAG 是模型按需选择的 `search_knowledge_base` 普通工具，本地 embedding 模型由
`damnatiox-agent[rag]` extra 提供；`read_artifact` 对超长
结果执行有界读取。Skills、Workspace Facts 和 Attempt Facts 以 ContextBlock
注入，不在 Loop 内增加路由分支。

Workspace 可写时的状态布局：

```text
.damnatiox/
├── sessions/*.json
├── attempts/<session_id>/<attempt_id>.json
├── events/<session_id>/<attempt_id>.json
├── events/<session_id>/.sequence-high-water
└── artifacts/<session_id>/<attempt_id>/*
```

只读 Workspace 使用相同子目录结构，根目录切换到
`~/.damnatiox/workspaces/<workspace>-<hash>/`；文件工具的 Workspace 边界保持不变。

Turn 开始即保存 `running` Attempt；assistant message、tool call/result、usage、
verification 和 mutation 按 checkpoint 更新。重启会终态化遗留 Attempt、补齐
terminal event，并恢复 completed Turn。超长 ToolResult 保存为 Artifact，上下文
只携带预览、hash 和引用。

ContextBuilder 估算 system、summary、历史、Skills、工具 schema、当前
ToolResult、Evidence 和工程事实。Compaction 在回答返回后使用独立预算和单 worker
运行，避免阻塞主回答路径。

## Python API

不使用 TUI 时可直接嵌入：

```python
import os
from rich.console import Console

from damnatiox_agent.application import build_agent_application
from damnatiox_agent.interfaces import LocalAgentAPI

application = build_agent_application(
    Console(),
    api_key=os.environ["DEEPSEEK_API_KEY"],
    workspace=".",
)
api = LocalAgentAPI(application)
session = api.create_session()
result = api.start_turn(session["session_id"], "检查当前仓库")
```

React gateway 和 Python 调用方共享同一个 `AgentApplication`、Attempt 格式与
AgentEvent 协议。

## 开发、构建与测试

Python：

```bash
python -m pip install -e ".[dev]"
python -m ruff format --check .
python -m ruff check .
python -m compileall -q chain context damnatiox_agent rag skill tool tui validation
python -m pytest -q
python -m build
python -m twine check dist/*
```

React / TypeScript：

```bash
cd frontend
npm ci
npm run typecheck
npm test
npm run build
cd ..

damnatiox --ui-info
damnatiox --frontend-smoke
```

`npm run build` 使用 esbuild 生成单一 Node ESM bundle 和 SHA256 manifest。
测试覆盖 JSON-RPC、gateway 并发、stream/cancel/approval、React reducer、
slash commands、布局组件、launcher 完整性、Session 恢复和 Harness Loop。
`--frontend-smoke` 同时验证静态 Ink 渲染和 Node → Python 隔离模式的
initialize / approval / cancel / shutdown 桥接。

Declarative eval：

```bash
python -m damnatiox_agent.evals --tasks evals/tasks.json --pretty
```

默认 eval runner 用 scripted steps 检查 schema、指标和阈值，不代表在线模型质量；
`AgentApplicationTurnRunner` 用于受控的真实 Application 评测。

## Wheel 与 GitHub Actions

发布产物分为：

| 产物 | React 运行时 |
|---|---|
| sdist / `py3-none-any` 通用 wheel | 包含 React bundle；使用系统 Node >= 22，`auto` 可进入 Rich |
| Linux x64 platform wheel | 内置校验后的 Node 24.14.0 |
| Windows x64 platform wheel | 内置校验后的 Node 24.14.0 |
| macOS x64 platform wheel | 内置校验后的 Node 24.14.0 |
| macOS arm64 platform wheel | 内置校验后的 Node 24.14.0 |

Node 下载 URL、archive SHA256、目标和 wheel tag 固定在
`scripts/node-runtime-lock.json`。平台构建再次校验 archive，提取 Node executable
与 LICENSE，并将 runtime manifest 写入 wheel；launcher 在执行包内 Node 前校验
executable SHA256。不在源码树中提交 Node 二进制。

`.github/workflows/ci.yml` 在每次 branch push 及针对 `main` 的 Pull Request 上，于
Ubuntu、Windows、macOS 使用 Python 3.14 和
Node 24.14.0，执行 npm typecheck/test/build、Ruff、compileall、pytest、Python
构建、Twine 检查，并在干净环境从仓库外目录运行 `--version`、`--ui-info` 和
`--frontend-smoke`。

`.github/workflows/publish.yml` 继续由 GitHub Release `published` 触发：

1. 校验 tag 与 Python 包版本；
2. 构建 sdist、通用 wheel 和四个平台 wheel；
3. 对前端、Node archive、wheel 和干净安装执行检查；
4. 汇总并核对发布产物集合；
5. 使用 PyPI Trusted Publishing（OIDC）发布。

## Codex / Hermes 的结构借鉴

本项目借鉴的是结构，而非复制实现：

- Codex 的 App Server 思路：前端通过结构化 request/response/notification 与
  后端通信，不解析 CLI 文本；
- Codex 的 UI/backend 分工：Session、Turn、权限、工具和持久化归 Harness，
  TUI 只维护展示与输入状态；
- Hermes 的 facade/gateway 思路：不同入口共享统一 Agent 生命周期和事件；
- 两者共同体现的稳定 ID、事件 cursor、工具审批和前后端协议边界。

DamnatioX 当前仍使用自己的 Python Harness、LocalAgentAPI、NDJSON gateway、
React reducer、Workspace 策略和持久化格式。Rich 兼容层保留用于显式回退；
后续高级能力继续以真实评测和失败案例为前提加入。
