Release v1.125.0

This commit is contained in:
coso
2026-08-09 19:53:30 +08:00
parent f929f4c3f8
commit 8647d18fa3
295 changed files with 19716 additions and 16831 deletions
+43
View File
@@ -73,6 +73,19 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --config.node-linker=hoisted
- name: Run Windows Agent Plugin path contract tests
shell: bash
run: |
set -euo pipefail
cargo test \
--manifest-path "lime-rs/Cargo.toml" \
-p lime-mcp \
--lib \
agent_plugin_config \
-- \
--nocapture \
2>&1 | tee "windows-plugin-mcp-contract-tests.log"
- name: Prepare sherpa-onnx runtime
shell: bash
run: |
@@ -158,6 +171,18 @@ jobs:
--n-minus-one-version "$N_MINUS_ONE_VERSION" \
--version "$VERSION"
- name: Run installed Windows Agent Plugin Gate B
shell: bash
run: |
set -euo pipefail
VERSION="$(node -p "require('./package.json').version")"
PLUGIN_GATE_EXECUTABLE="$(node -e "const fs=require('node:fs');const summary=JSON.parse(fs.readFileSync('.lime/qc/windows-squirrel-rc/$VERSION/summary.json','utf8'));const executable=summary.evidence?.installation?.executable;if(!executable)throw new Error('Windows Squirrel evidence is missing the installed executable');process.stdout.write(executable);")"
npm run smoke:plugin-package-electron-gate-b -- \
--electron-executable "$PLUGIN_GATE_EXECUTABLE" \
--evidence-dir ".lime/qc/gui-evidence/plugin-package-electron-gate-b-windows" \
--prefix "plugin-package-electron-gate-b-windows" \
--timeout-ms 600000
- name: Upload Windows Squirrel RC evidence
if: ${{ always() }}
uses: actions/upload-artifact@v4
@@ -167,6 +192,15 @@ jobs:
retention-days: ${{ github.event.inputs.retention_days || 7 }}
path: .lime/qc/windows-squirrel-rc
- name: Upload Windows Agent Plugin Gate B evidence
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: lime-windows-agent-plugin-gate-b-evidence
if-no-files-found: warn
retention-days: ${{ github.event.inputs.retention_days || 7 }}
path: .lime/qc/gui-evidence/plugin-package-electron-gate-b-windows
- name: Upload Windows test package
uses: actions/upload-artifact@v4
with:
@@ -174,3 +208,12 @@ jobs:
if-no-files-found: error
retention-days: ${{ github.event.inputs.retention_days || 7 }}
path: windows-test-package/*
- name: Upload Windows Agent Plugin path contract log
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: lime-windows-agent-plugin-path-contract-tests
if-no-files-found: error
retention-days: ${{ github.event.inputs.retention_days || 7 }}
path: windows-plugin-mcp-contract-tests.log
+3
View File
@@ -340,6 +340,9 @@ jobs:
- name: Test Windows file browser directory creation
run: cargo test --manifest-path lime-rs/Cargo.toml -p lime-services create_directory_creates_nested_directory_from_platform_path -- --test-threads=1
- name: Test Windows Agent Plugin MCP parity
run: cargo test --manifest-path lime-rs/Cargo.toml -p lime-mcp agent_plugin_config --lib -- --test-threads=1
results:
name: Quality results
runs-on: ubuntu-latest
+11 -20
View File
@@ -1,6 +1,6 @@
<div align="center"><a name="readme-top"></a>
<img src="./docs/images/readme-hero-en.png" alt="Lime README hero banner: Spark ideas with a touch of green" width="100%" />
<img src="./docs/images/readme-hero-en.png" alt="Lime README hero banner: An agent that can actually finish the work" width="100%" />
# Lime
@@ -8,9 +8,9 @@
**Open-source full-stack desktop AI agent**
Full-stack AI agent for coding, files, terminals, tools, research, content, multimodal work, and multi-agent workflows.
Full-stack AI agent for coding, files, terminals, tools, research, content, multimodal work, and multi-agent workflows worldwide.
[简体中文](./README.md) · **English** · [Docs](./docs/README.md) · [Release Notes](./RELEASE_NOTES.en.md) · [Issues](https://github.com/limecloud/lime/issues)
[简体中文](./README.zh-CN.md) · **English** · [Docs](./docs/README.md) · [Release Notes](./RELEASE_NOTES.en.md) · [Issues](https://github.com/limecloud/lime/issues)
<p>
<a href="https://github.com/limecloud/lime/releases"><img src="https://img.shields.io/github/v/release/limecloud/lime?label=release" alt="Lime GitHub Release" /></a>
@@ -21,7 +21,7 @@ Full-stack AI agent for coding, files, terminals, tools, research, content, mult
Lime is more than a chat box: it understands context, calls tools, edits files, runs commands, organizes material, creates deliverables, and keeps moving a task forward from one desktop workspace.
<sub>The Simplified Chinese README is the primary version. This English page is a companion for international readers.</sub>
<sub>The Chinese and English READMEs are maintained together for users worldwide.</sub>
</div>
@@ -48,9 +48,9 @@ Lime is more than a chat box: it understands context, calls tools, edits files,
## What is Lime?
Lime is an open-source full-stack AI agent for the desktop. It brings the Agent loop, filesystem, terminal processes, code changes, tool calls, MCP, Skills, multimodal input and output, model routing, and multi-agent collaboration into one traceable task chain.
Lime is an open-source full-stack desktop AI agent for users and teams worldwide. It brings the Agent loop, filesystem, terminal processes, code changes, tool calls, MCP, Skills, multimodal input and output, model routing, and multi-agent collaboration into one traceable task chain.
It belongs to the same category of hands-on agents as Claude Code, WorkBuddy, and Codex, while emphasizing a desktop GUI, visual workspace, configurable providers, and mixed engineering, research, and content workflows for Chinese users.
It belongs to the same category of hands-on agents as Claude Code, WorkBuddy, and Codex, while emphasizing a desktop GUI, visual workspace, configurable providers, and mixed engineering, research, and content workflows for global users and teams.
Lime works by:
@@ -69,7 +69,8 @@ Use Lime as an engineering partner, research assistant, content collaborator, or
- **Terminal and process operations**: run scripts, builds, tests, dependency commands, long-running processes, and inspect their output within controlled permissions.
- **Files and workspaces**: read and write text or structured files, organize directories, and create documents, reports, web drafts, and other artifacts.
- **Tools, MCP, and Skills**: discover capabilities, call external tools or local Skills, and turn repeatable procedures into reusable execution units.
- **Research and content delivery**: work with references, screenshots, images, and multi-turn context from analysis through publish-ready output.
- **Multimodal understanding and generation**: work with text, code, images, screenshots, audio, video, PDFs, tables, and structured data in one task, then create images, audio, video, documents, charts, and other artifacts.
- **Research and content delivery**: work with web pages, references, screenshots, images, audio, video, and multi-turn context from analysis through publish-ready output.
- **Multi-agent and long-running work**: split subtasks, make progress in parallel, preserve state, and resume complex work in the same Thread.
- **Provider and model control**: choose models per task and manage capability catalogs, credentials, routing, retries, and failure boundaries.
@@ -135,7 +136,9 @@ Lime does not lock you to one model service. Configure providers, models, and cr
## Product positioning
Lime belongs to the full-stack AI agent, coding agent, desktop AI agent, and terminal agent category. It handles code tasks as well as research, writing, material organization, automation, and multimodal delivery; the goal is a set of verifiable actions, not just a generated paragraph.
Lime belongs to the full-stack AI agent, coding agent, desktop AI agent, and terminal agent category for users and teams worldwide. It handles code tasks as well as research, writing, material organization, automation, and multimodal delivery; the goal is a set of verifiable actions, not just a generated paragraph.
Multimodality is a core Agent workflow, not a separate attachment feature. One Thread can combine a written brief, a codebase, images and screenshots, voice or video material, PDFs, and spreadsheets so the Agent can cross-understand them, call tools, and produce delivery-ready results.
---
@@ -211,15 +214,3 @@ No. Describe the goal, constraints, context, and acceptance criteria. Reusable p
This project is provided for learning and research purposes only. Users are responsible for their own use and risk.
Lime does not directly provide AI model services. Model capabilities are provided by third-party AI service providers configured by the user.
---
<div align="center">
### WeChat Community
<img src="./docs/images/coso.jpg" alt="Lime WeChat community QR code" width="180" />
Scan the QR code and mention `Lime` to join the discussion group.
</div>
+104 -112
View File
@@ -1,16 +1,16 @@
<div align="center"><a name="readme-top"></a>
<img src="./docs/images/readme-hero.png" alt="Lime README 主视觉:青柠一下,灵感即来" width="100%" />
<img src="./docs/images/readme-hero-en.png" alt="Lime README hero banner: An agent that can actually finish the work" width="100%" />
# Lime
### 让 Agent 真正把事情做完
### An agent that can actually finish the work
**开源、全栈、桌面端 AI Agent**
**Open-source full-stack desktop AI agent**
Full-stack AI agent for coding, files, terminals, tools, research, content, multimodal work, and multi-agent workflows.
Full-stack AI agent for coding, files, terminals, tools, research, content, multimodal work, and multi-agent workflows worldwide.
**简体中文** · [English](./README.en.md) · [文档](./docs/README.md) · [发布记录](./RELEASE_NOTES.md) · [问题反馈](https://github.com/limecloud/lime/issues)
[简体中文](./README.zh-CN.md) · **English** · [Docs](./docs/README.md) · [Release Notes](./RELEASE_NOTES.en.md) · [Issues](https://github.com/limecloud/lime/issues)
<p>
<a href="https://github.com/limecloud/lime/releases"><img src="https://img.shields.io/github/v/release/limecloud/lime?label=release" alt="Lime GitHub Release" /></a>
@@ -19,204 +19,196 @@ Full-stack AI agent for coding, files, terminals, tools, research, content, mult
<img src="https://img.shields.io/badge/license-GPLv3-2F4F4F" alt="Lime GPLv3 license" />
</p>
Lime 不只是回答问题的聊天框,而是可以理解上下文、调用工具、修改文件、运行命令、整理资料、生成交付物并持续推进任务的桌面 AI Agent。
Lime is more than a chat box: it understands context, calls tools, edits files, runs commands, organizes material, creates deliverables, and keeps moving a task forward from one desktop workspace.
</div>
---
<details>
<summary><kbd>目录</kbd></summary>
<summary><kbd>Table of Contents</kbd></summary>
- [Lime 是什么](#lime-是什么)
- [全栈 Agent 能做什么](#全栈-agent-能做什么)
- [一次任务如何推进](#一次任务如何推进)
- [核心能力](#核心能力)
- [适合谁](#适合谁)
- [产品定位](#产品定位)
- [快速开始](#快速开始)
- [技术栈与平台](#技术栈与平台)
- [常见问题](#常见问题)
- [开源协议](#开源协议)
- [免责声明](#免责声明)
- [What is Lime?](#what-is-lime)
- [What the full-stack agent can do](#what-the-full-stack-agent-can-do)
- [How a task moves forward](#how-a-task-moves-forward)
- [Core capabilities](#core-capabilities)
- [Who Lime is for](#who-lime-is-for)
- [Product positioning](#product-positioning)
- [Quick Start](#quick-start)
- [Tech Stack and Platforms](#tech-stack-and-platforms)
- [FAQ](#faq)
- [License](#license)
- [Disclaimer](#disclaimer)
</details>
---
## Lime 是什么
## What is Lime?
Lime 是一个开源的全栈 AI Agent 桌面应用。它把 Agent loop、文件系统、终端进程、代码修改、工具调用、MCPSkills、多模态输入输出、多模型路由和多 Agent 协作放进同一条可追踪的任务链。
Lime is an open-source full-stack desktop AI agent for users and teams worldwide. It brings the Agent loop, filesystem, terminal processes, code changes, tool calls, MCP, Skills, multimodal input and output, model routing, and multi-agent collaboration into one traceable task chain.
它和 Claude CodeWorkBuddy、Codex 属于同一类“能动手完成任务”的 Agent 产品,但 Lime 更强调桌面 GUI、可视化工作区、可配置 Provider,以及面向中文用户的研究、创作和工程混合场景。
It belongs to the same category of hands-on agents as Claude Code, WorkBuddy, and Codex, while emphasizing a desktop GUI, visual workspace, configurable providers, and mixed engineering, research, and content workflows for global users and teams.
Lime 的基本工作方式是:
Lime works by:
- 先理解目标、仓库、文件、历史会话和约束,再给出可执行计划
- 根据权限执行读写文件、搜索、补丁、终端命令、测试和其他工具调用
- 将过程投影为 ThreadTurnItem 和可复用 artifact,方便中断、恢复、审阅和继续
- 让你选择自己的 Provider 和模型,在不同任务中切换能力而不改变工作上下文
- Understanding the goal, repository, files, history, and constraints before proposing an executable plan.
- Reading and writing files, searching, applying patches, running terminal commands, testing, and calling tools within granted permissions.
- Projecting work as Thread, Turn, Item, and reusable artifacts so tasks can be paused, reviewed, restored, and continued.
- Letting you choose providers and models without losing the surrounding task context.
你可以把 Lime 当作一个坐在桌面上的工程搭档、研究助理、内容合作者和自动化执行器:你给出目标和边界,它负责把目标拆成动作并留下可检查的结果。
Use Lime as an engineering partner, research assistant, content collaborator, or automation executor: you provide the goal and boundaries, and it turns them into inspectable actions and results.
---
## 全栈 Agent 能做什么
## What the full-stack agent can do
- **代码理解与修改**:浏览仓库、定位问题、跨文件实现功能、重构、补测试、生成 patch 并解释变更
- **终端与进程操作**:在受控权限下运行脚本、构建、测试、安装依赖、观察输出和管理长任务
- **文件与工作区协作**:读写文本和结构化文件,整理目录,生成文档、报告、网页草稿和其他 artifact
- **工具、MCP 与 Skills**:发现可用能力,调用外部工具或本地 Skill,把重复流程变成可复用的执行单元
- **研究与内容交付**:处理资料、截图、图片和多轮对话,完成从分析、写作到发布准备的连续工作
- **多 Agent 与长任务**:拆分子任务、并行推进、保留状态,在同一 Thread 中恢复和继续复杂工作
- **模型与 Provider 控制**:按任务选择模型,管理能力目录、凭证、路由、重试和故障边界
- **Code understanding and changes**: inspect repositories, locate bugs, implement cross-file features, refactor, add tests, produce patches, and explain diffs.
- **Terminal and process operations**: run scripts, builds, tests, dependency commands, long-running processes, and inspect their output within controlled permissions.
- **Files and workspaces**: read and write text or structured files, organize directories, and create documents, reports, web drafts, and other artifacts.
- **Tools, MCP, and Skills**: discover capabilities, call external tools or local Skills, and turn repeatable procedures into reusable execution units.
- **Multimodal understanding and generation**: work with text, code, images, screenshots, audio, video, PDFs, tables, and structured data in one task, then create images, audio, video, documents, charts, and other artifacts.
- **Research and content delivery**: work with web pages, references, screenshots, images, audio, video, and multi-turn context from analysis through publish-ready output.
- **Multi-agent and long-running work**: split subtasks, make progress in parallel, preserve state, and resume complex work in the same Thread.
- **Provider and model control**: choose models per task and manage capability catalogs, credentials, routing, retries, and failure boundaries.
---
## 一次任务如何推进
## How a task moves forward
### 1. 修复一个真实 Bug
### 1. Fix a real bug
你把仓库和报错交给 Lime。Agent 会先读取相关文件和配置,定位调用链,说明假设,再修改实现、运行相关测试并展示 diff
Give Lime a repository and an error. The Agent reads the relevant files and configuration, traces the call path, states its assumptions, changes the implementation, runs focused tests, and shows the diff.
你可以在同一个 Thread 里继续追问“为什么这样改”“还有哪些边界”“把修复同步到文档”,每一步都有状态和结果可回看。
Continue in the same Thread with questions such as "why this change?" or "what are the edge cases?" Every step remains visible and reviewable.
### 2. 从需求交付一个全栈功能
### 2. Ship a full-stack feature
需求进入后,Lime 可以先拆分前端、App ServerRust runtime、协议和测试,再按依赖顺序执行。你可以批准每个高风险动作,也可以随时暂停、修改计划或回滚未提交改动。
Lime can split a requirement across the frontend, App Server, Rust runtime, protocol, and tests, then execute in dependency order. Approve risky actions, pause, revise the plan, or inspect uncommitted changes at any point.
### 3. 把资料变成可交付内容
### 3. Turn material into a deliverable
将网页、笔记、截图、会议记录和历史结果放入任务,Agent 可以整理结构、指出缺口、生成报告、脚本、方案或发布稿,并保留引用上下文供你复核。
Add web pages, notes, screenshots, meeting records, and prior results. The Agent can structure them, identify gaps, produce a report, script, plan, or launch draft, and keep context for review.
### 4. 把重复流程变成 Skill
### 4. Turn a repeated procedure into a Skill
把常用的检查、发布、研究或团队规范写成 Skill,Agent 在需要时发现并执行它。工具通过 MCP 或受控能力接入,不需要把全部步骤重新写进每次提示词。
Encode a recurring check, release step, research method, or team rule as a Skill. The Agent can discover and run it through MCP or controlled capabilities instead of repeating every instruction in every prompt.
### 5. 多 Agent 协作处理大任务
### 5. Coordinate multiple agents
将研究、实现、测试、文档等子任务交给不同 Agent,主 Thread 汇总结果并保持统一上下文、权限和审阅边界。
Delegate research, implementation, testing, and documentation to different agents. The main Thread keeps shared context, permissions, and review boundaries while it collects the results.
---
## 核心能力
## Core capabilities
### 从一个目标开始
### Start from one goal
<img src="./docs/images/readme-feature-start.png" alt="Lime 从一个任务开始功能图" />
<img src="./docs/images/readme-feature-start-en.png" alt="Lime start from one task feature image" />
输入一句目标、一个仓库、一个目录或一组资料。Agent 会先建立上下文,再提出计划和需要你确认的边界。
Enter a goal, repository, directory, or set of materials. The Agent establishes context first, then proposes a plan and the boundaries that need your approval.
### 在同一个工作区里执行和审阅
### Execute and review in one workspace
<img src="./docs/images/readme-feature-workspace.png" alt="Lime 同一空间持续打磨功能图" />
<img src="./docs/images/readme-feature-workspace-en.png" alt="Lime refine in one workspace feature image" />
对话、计划、文件变更、命令输出、工具结果和生成物都围绕同一个 Thread 展示。你能逐步批准、拒绝、重试、继续或恢复任务。
Conversation, plans, file changes, command output, tool results, and artifacts stay around the same Thread. Approve, reject, retry, continue, or restore work step by step.
### 连接自己的模型和工具
### Connect your models and tools
<img src="./docs/images/readme-feature-provider.png" alt="Lime 使用自己的 AI 服务功能图" />
<img src="./docs/images/readme-feature-provider-en.png" alt="Lime use your own AI services feature image" />
Lime 不绑定单一模型服务。你可以配置 Provider、模型和凭证,并通过 MCPSkills 和受控工具扩展 Agent 的执行范围。
Lime does not lock you to one model service. Configure providers, models, and credentials, then extend the Agent through MCP, Skills, and controlled tools.
---
## 适合谁
## Who Lime is for
- 需要读代码、改代码、跑测试和交付功能的开发者
- 需要同时处理产品、设计、数据、文档和自动化的全栈团队
- 需要本地资料、终端工具和多轮推理的研究者与内容创作者
- 希望把团队规范、检查流程和工具能力沉淀为 Skills 的团队
- 想在桌面 GUI 中获得类似 Claude CodeWorkBuddy、Codex 工作方式的用户
- Developers who need to read code, change code, run tests, and ship features.
- Full-stack teams handling product, design, data, documentation, and automation together.
- Researchers and creators who need local material, terminal tools, and long-running reasoning.
- Teams that want to encode rules, checks, and tools as reusable Skills.
- Users who want a desktop GUI with the working style of Claude Code, WorkBuddy, or Codex.
---
## 产品定位
## Product positioning
Lime 属于全栈 AI Agent / coding agent / desktop AI agent / terminal agent 这一产品类别。它可以承担代码任务,也可以承担研究、写作、资料整理、自动化和多模态交付;重点不是生成一段文本,而是围绕目标完成一组可验证的动作。
Lime belongs to the full-stack AI agent, coding agent, desktop AI agent, and terminal agent category for users and teams worldwide. It handles code tasks as well as research, writing, material organization, automation, and multimodal delivery; the goal is a set of verifiable actions, not just a generated paragraph.
Multimodality is a core Agent workflow, not a separate attachment feature. One Thread can combine a written brief, a codebase, images and screenshots, voice or video material, PDFs, and spreadsheets so the Agent can cross-understand them, call tools, and produce delivery-ready results.
---
## 快速开始
## Quick Start
### 下载安装
### Download and install
[Releases](https://github.com/limecloud/lime/releases) 下载对应平台安装包。
Download the installer for your platform from [Releases](https://github.com/limecloud/lime/releases).
- macOS 用户下载 `.dmg` 或使用 Homebrew 安装
- Windows 用户下载 `Lime_*_x64-setup.exe`
- 当前仅提供 macOS Windows 发布包,Linux 桌面端已暂停支持
- 如果 Windows 出现 SmartScreen 提示,通常是未签名或签名信誉不足导致,不代表安装包一定损坏
- macOS users can download the `.dmg` package or install with Homebrew.
- Windows users can download `Lime_*_x64-setup.exe`.
- Lime currently publishes macOS and Windows builds only. Linux desktop builds are paused.
- If Windows SmartScreen appears, it usually means the installer is unsigned or has not built enough signing reputation. It does not necessarily mean the installer is broken.
会使用 Homebrew 的 macOS 用户也可以运行:
macOS users who use Homebrew can run:
```bash
brew tap aiclientproxy/tap
brew install --cask lime
```
### 第一次使用
### First run
1. 打开 Lime,进入 Provider 配置页并测试模型连接
2. 选择一个工作区或项目目录,确认文件和终端权限
3. 新建 Agent Thread,写下目标、约束和验收标准
4. 先让 Agent 给出计划,再按需批准文件、命令和外部工具调用
5. 检查 diff、测试结果和生成物,继续追问或结束任务
1. Open Lime, configure a Provider, and test a model connection.
2. Choose a workspace or project directory and confirm file and terminal permissions.
3. Create an Agent Thread with a goal, constraints, and acceptance criteria.
4. Ask for a plan first, then approve file changes, commands, or external tool calls as needed.
5. Inspect the diff, test results, and artifacts; continue the task or close it.
---
## 技术栈与平台
## Tech Stack and Platforms
- 桌面框架:ElectronRust App ServerApp Server JSON-RPC
- Agent runtimeThread / Turn / Item projection、工具生命周期、SkillsMCP、多 Agent 和历史恢复
- 前端技术:ReactTypeScriptVite
- 本地能力:文件系统、进程、工作区、artifact 和持久化状态
- 支持平台:macOSWindows
- 开源协议:GPLv3
- Desktop framework: Electron, Rust App Server, App Server JSON-RPC.
- Agent runtime: Thread / Turn / Item projection, tool lifecycle, Skills, MCP, multi-agent work, and history restoration.
- Frontend: React, TypeScript, Vite.
- Local capabilities: filesystem, processes, workspaces, artifacts, and persisted state.
- Supported platforms: macOS, Windows.
- License: GPLv3.
---
## 常见问题
## FAQ
### Lime 会提供 AI 模型吗?
### Does Lime provide AI models?
不会。Lime Agent 宿主和工作区,不直接销售模型服务。你需要配置可用的 Provider、模型和凭证。
No. Lime is an Agent host and workspace, not a model vendor. Configure an available Provider, model, and credential.
### Agent 能修改代码和运行命令吗?
### Can the Agent edit code and run commands?
可以。在你授予的权限范围内,Agent 可以读取和修改文件、执行终端命令、运行测试并调用工具;高风险动作应先审阅或批准。
Yes. Within the permissions you grant, the Agent can read and edit files, run terminal commands, run tests, and call tools. Review or approve high-risk actions.
### 我的资料会全部上传吗?
### Will all my materials be uploaded?
项目资料、会话历史和配置优先保存在本机。调用模型或外部工具时,相关输入会发送到你配置的 Provider 或目标服务;敏感资料请按对应服务商政策判断。
Project materials, conversation history, and configuration are kept locally by default. Inputs needed for model or external-tool calls are sent to the Provider or target service you configured; follow the relevant service policy for sensitive material.
### 它和普通聊天工具有什么不同?
### How is Lime different from a normal chat tool?
普通聊天工具主要返回文本。Lime 会理解工作区上下文,实际操作文件、进程和工具,保留执行状态与结果,并允许你在同一任务中继续推进。
Normal chat mainly returns text. Lime understands workspace context, operates files, processes, and tools, retains execution state and results, and lets you keep moving in the same task.
### 需要会写复杂提示词吗?
### Do I need advanced prompt-writing skills?
不需要。直接描述目标、约束、上下文和验收方式即可;可复用的做法可以沉淀为 Skill,复杂任务也可以让 Agent 先规划再执行。
No. Describe the goal, constraints, context, and acceptance criteria. Reusable procedures can become Skills, and complex tasks can start with an Agent-generated plan.
---
## 开源协议
## License
[GNU General Public License v3 (GPLv3)](https://www.gnu.org/licenses/gpl-3.0)
## 免责声明
## Disclaimer
本项目仅供学习研究使用,用户需自行承担使用风险。
本项目不直接提供 AI 模型服务,模型能力由第三方服务商提供。
This project is provided for learning and research purposes only. Users are responsible for their own use and risk.
---
<div align="center">
### 微信交流
<img src="./docs/images/coso.jpg" alt="Lime 微信交流群二维码" width="180" />
扫码加微信,备注 `Lime`,拉你进群讨论。
</div>
Lime does not directly provide AI model services. Model capabilities are provided by third-party AI service providers configured by the user.
+112
View File
@@ -0,0 +1,112 @@
<div align="center"><a name="readme-top"></a>
<img src="./docs/images/readme-hero.png" alt="Lime README 主视觉:青柠一下,灵感即来" width="100%" />
# Lime
### 一个真正能把事情推进下去的 Agent
**面向全球用户的开源全栈桌面 AI Agent**
代码、文件、终端、工具、研究、内容、多模态和多 Agent 协作,都在同一个可恢复的任务空间里完成。
[English](./README.md) · **简体中文** · [文档](./docs/README.md) · [发布记录](./RELEASE_NOTES.md) · [问题反馈](https://github.com/limecloud/lime/issues)
<p>
<a href="https://github.com/limecloud/lime/releases"><img src="https://img.shields.io/github/v/release/limecloud/lime?label=release" alt="Lime GitHub Release" /></a>
<img src="https://img.shields.io/badge/platform-macOS%20%7C%20Windows-246B45" alt="Lime supports macOS and Windows" />
<img src="https://img.shields.io/badge/desktop-Electron-24C8DB" alt="Lime is an Electron desktop app" />
<img src="https://img.shields.io/badge/license-GPLv3-2F4F4F" alt="Lime GPLv3 license" />
</p>
</div>
---
## Lime 是什么
Lime 是一个全栈桌面 AI Agent。它能理解目标和工作区,读取和修改文件,运行终端命令,调用工具、MCP 和 Skills,处理多模态输入,生成可交付 artifact,并把整个过程保留在 Thread / Turn / Item 中。
它和 Claude Code、WorkBuddy、Codex 属于同一类“能动手完成任务”的 Agent 产品,同时提供桌面 GUI、可视化工作区、Provider 选择和跨工程/研究/内容的统一工作流。
## 能力一览
| 能力 | 可以完成的工作 |
| --- | --- |
| 代码与工程 | 理解仓库、定位问题、跨文件修改、运行测试、解释 diff |
| 文件与终端 | 读写文件、搜索目录、启动进程、查看输出、管理长任务 |
| 工具与扩展 | 使用 MCP、Skills、浏览器和受控工具扩展执行范围 |
| 多模态 | 理解文本、代码、图片、截图、音频、视频、PDF、表格和结构化数据 |
| 生成与交付 | 生成文档、图片、音频、视频、图表、网页草稿和结构化 artifact |
| 协作与恢复 | 多 Agent 分工、权限审批、取消/重试、历史恢复和持续执行 |
## 一次任务如何工作
1. 写下目标、约束和验收标准,选择工作区或项目目录。
2. Agent 读取必要上下文,先给出计划和需要确认的边界。
3. 在授权范围内修改文件、运行命令、调用工具和生成结果。
4. 检查 diff、命令输出、测试结果和 artifact,继续追问或结束任务。
## 核心工作区
### 从一个目标开始
<img src="./docs/images/readme-feature-start.png" alt="Lime 从一个任务开始功能图" />
从一句话、一个仓库、一组资料或一张截图开始,Agent 会先建立上下文,而不是直接猜答案。
### 执行与审阅在同一个 Thread
<img src="./docs/images/readme-feature-workspace.png" alt="Lime 同一空间持续打磨功能图" />
对话、计划、文件变更、终端输出、工具结果和生成物都可回看。高风险动作可以逐项批准、拒绝、重试或暂停。
### 连接自己的模型与工具
<img src="./docs/images/readme-feature-provider.png" alt="Lime 使用自己的 AI 服务功能图" />
Lime 不绑定单一模型服务。配置 Provider、模型和凭证后,可以按任务切换能力,并通过 MCP 与 Skills 扩展 Agent。
## 快速开始
从 [Releases](https://github.com/limecloud/lime/releases) 下载 macOS 或 Windows 安装包。
1. 打开 Lime,配置 Provider 并测试模型连接。
2. 选择工作区,确认文件和终端权限。
3. 新建 Agent Thread,写下目标和验收标准。
4. 让 Agent 先规划,再批准需要执行的动作。
macOS 也可以使用 Homebrew
```bash
brew tap aiclientproxy/tap
brew install --cask lime
```
## 数据与权限
项目资料、会话历史和配置默认保存在本机。调用模型或外部工具时,相关输入会发送到你配置的 Provider 或目标服务。文件修改、终端命令和外部工具调用遵循权限与审批边界。
## 文档与社区
- [文档](./docs/README.md)
- [发布记录](./RELEASE_NOTES.md)
- [GitHub Issues](https://github.com/limecloud/lime/issues)
## 开源协议
[GNU General Public License v3 (GPLv3)](https://www.gnu.org/licenses/gpl-3.0)
本项目仅供学习研究使用,用户需自行承担使用风险。模型能力由用户配置的第三方服务提供。
---
<div align="center">
### 微信交流
<img src="./docs/images/coso.jpg" alt="Lime 微信交流群二维码" width="180" />
扫码加微信,备注 `Lime`,拉你进群讨论。
</div>
+17 -18
View File
@@ -1,39 +1,38 @@
## Lime v1.124.0
## Lime v1.125.0
Simplified Chinese release notes are the primary version.
### New Features
- Upgraded Lime's public positioning to a full-stack AI agent covering code, files, terminals, tools, MCP, Skills, multimodal work, Providers, and long-running multi-agent tasks.
- Added current App Server v2 filesystem and process capabilities for directory/file operations, watching, terminal process startup, output streams, stdin, termination, and status restoration.
- Connected the Agent workspace, Thread/Turn/Item projection, artifacts, and desktop GUI through one traceable execution chain for a task-oriented workflow similar to Claude Code, WorkBuddy, and Codex.
- Added current Plugin package assets plus Gate B packaging and runtime verification entry points.
- Aligned the plugin package path with Agent Plugins v1.0.0: root `plugin.json`, direct-child Skills, and root `mcp.json`.
- Added the Codex Apps extension adapter, standard Apps JSON catalog, and typed `app/list`, `app/read`, and `app/installed` flow.
- Added typed App Server JSON-RPC and GUI integration for `command/exec` and `review/start`.
### Fixes
- Fixed projection drift for files, processes, background terminals, and Agent task state across App Server, Electron host, gateway, and GUI.
- Fixed lifecycle boundaries for long-running work, cancellation, output streams, and history restoration while preserving fail-closed permissions and review semantics.
- Fixed protocol schema, generated client, and model/Provider capability drift during the v2 migration so non-executable models cannot enter Agent routes.
- Fixed Thread/Turn/Item, filesystem, process, background terminal, review, and Agent state projection drift across App Server, Electron, and GUI.
- Fixed MCP Plugin placeholder lowering, path containment, HTTP header filtering, sibling isolation, and persistent `PLUGIN_DATA` behavior.
- Fixed protocol schema, generated client, model capability, and provider lowering drift.
### Improvements and Refactoring
- Physically removed retired Plugin runtimes, workers, legacy v0 filesystem/process/plugin wires, and detached Electron/Renderer facades without production mock fallbacks or compatibility dual paths.
- Converged the App Server v2 protocol, schema registry, Rust/TypeScript typed clients, runtime owners, and GUI gateways around the single `Electron Desktop Host -> App Server JSON-RPC -> RuntimeCore -> Thread/Turn/Item projection -> GUI` product chain.
- Returned filesystem, process, tools, Skills, MCP, Plugin, and multi-agent capabilities to their current owners, reducing duplicate entry points and cross-layer state copies.
- Physically removed the retired Plugin package, worker, manager, renderer runtime, v0 filesystem/process/plugin wires, and detached facades.
- Converged business capabilities on the single `Electron Desktop Host -> App Server JSON-RPC -> RuntimeCore -> Thread/Turn/Item projection -> GUI` chain.
- Removed retired Plugin Lab/sidebar copy, old technical Plugin standards, and zero-reference governance surfaces; return paths are guarded.
### Testing and Quality
- Added Rust, TypeScript, public JSON-RPC, and real Electron regression coverage for filesystem, process, background terminal, Agent runtime, Plugin package, and protocol v2 flows.
- Expanded current Agent fixtures, tool/Skills/MCP scenarios, Gate B packaging evidence, history restoration, and cancellation/retry paths.
- Synchronized generated protocol schemas/types, command contracts, legacy return guards, script governance, five-locale GUI regressions, and README positioning docs.
- Passed protocol contracts, Rust related tests, governance scans, docs boundary checks, Agent fixtures, GUI smoke, and macOS Electron Gate B.
- Added Windows runner coverage for environment variables, UNC/extended paths, junction/reparse containment, data persistence, and Squirrel Gate B.
- Windows runner artifacts remain a release gate; macOS and historical Windows evidence are not substituted.
### Documentation
- Rewrote the Chinese and English root READMEs to present Lime as a full-stack desktop AI agent similar to Claude Code, WorkBuddy, and Codex while retaining the existing product images.
- Updated App Server filesystem/process boundaries, the Agent runtime chain, Plugin current ownership, governance roadmap, and v2 protocol documentation.
- Updated architecture, command boundaries, Plugin v3 contract, Codex parity matrix, cleanup ledger, and release workflow documentation.
- Made the root README the English canonical entry while retaining a standalone Chinese page.
### Other
- Bumped the root app, CLI npm package, Rust workspace, and Cargo.lock versions to `1.124.0`.
- Bumped the root app, CLI npm package, Rust workspace, and Cargo.lock versions to `1.125.0`.
**Full changes**: `v1.123.0` -> `v1.124.0`
**Full changes**: `v1.124.0` -> `v1.125.0`
+17 -18
View File
@@ -1,37 +1,36 @@
## Lime v1.124.0
## Lime v1.125.0
### 新功能
- 将 Lime 的产品定位升级为全栈 AI Agent:统一覆盖代码、文件、终端、工具、MCP、Skills、多模态、Provider 和多 Agent 长任务
- 新增 current App Server v2 文件系统与进程能力,支持目录/文件读写、复制、删除、监听、终端进程启动、输出流、stdin、终止与状态恢复
- 将 Agent 工作区、Thread/Turn/Item 投影、artifact 和桌面 GUI 连接到同一条可追踪执行链,面向类似 Claude Code、WorkBuddy、Codex 的任务型 Agent 使用方式
- 补齐 current Plugin package、Browser 能力资产和 Gate B 打包/运行验证入口。
- 对齐 Agent Plugins v1.0.0 标准包:根 `plugin.json`、直接子目录 Skills 和根 `mcp.json`
- 新增 Codex Apps extension adapter、标准 Apps JSON catalog 与 `app/list``app/read``app/installed` 主链
- 补齐 App Server `command/exec``review/start` 的 typed JSON-RPC、事件投影和 GUI 接入
### 修复
- 修复文件、进程、后台终端和 Agent 任务状态在 App Server、Electron host、gateway 与 GUI 之间的投影不一致
- 修复 current runtime 在长任务、取消、输出流和历史恢复场景中的生命周期边界,保持失败关闭和权限审阅语义
- 修复协议 schema、生成客户端模型/Provider 能力目录在 v2 迁移后的漂移,避免不可执行模型进入 Agent 路由
- 修复 Thread/Turn/Item、文件、进程、后台终端、审核和 Agent 状态在 App Server、Electron 与 GUI 之间的投影漂移
- 修复 MCP Plugin placeholder、路径 containment、HTTP header 过滤、失败隔离和 `PLUGIN_DATA` 持久化行为
- 修复协议 schema、生成客户端模型能力与 provider lowering 的一致性问题
### 优化与重构
- 物理删除已退役的 Plugin runtime、旧 worker、旧 v0 文件/进程/插件 wire 与脱离构建图的 Electron/Renderer facade,不保留生产 mock fallback 或兼容双轨
- 收敛 App Server v2 protocol、schema registry、Rust/TypeScript typed client、runtime owner 与 GUI gateway,保持 `Electron Desktop Host -> App Server JSON-RPC -> RuntimeCore -> Thread/Turn/Item projection -> GUI` 单一产品链。
- 将文件、进程、工具、Skills、MCP、Plugin 和多 Agent 能力归回各自 current owner,减少重复入口和跨层状态复制
- 物理删除 Plugin package、worker、manager、renderer runtime、旧 v0 filesystem/process/plugin wire 和 detached facade
- 将业务能力收敛到 `Electron Desktop Host -> App Server JSON-RPC -> RuntimeCore -> Thread/Turn/Item projection -> GUI` 单一产品链。
- 清理旧 Plugin Lab/sidebar 文案、旧技术标准文档和无引用治理 surface,禁止旧路径回流
### 测试与质量
- 新增文件系统、进程、后台终端、Agent runtime、Plugin package 和协议 v2 的 Rust、TypeScript、JSON-RPC 与真实 Electron 回归
- 扩展 current Agent fixture、工具/Skills/MCP 场景、Gate B 打包验证、历史恢复和取消/重试路径证据
- 同步 generated protocol schema/types、命令契约、legacy 回流守卫、脚本治理、五语言 GUI 回归与 README 定位文档
- 通过协议 contracts、Rust related tests、治理扫描、文档边界、Agent fixture、GUI smoke 和 macOS Electron Gate B
- 增加 Windows runner 的环境变量、UNC/extended path、junction/reparse、数据持久化与 Squirrel Gate B 验证入口
- 发布门禁持续跟踪 Windows runner artifact,未用 macOS 或旧 Windows 证据替代
### 文档
- 重写中英文根 README,明确 Lime 是类似 Claude Code、WorkBuddy、Codex 的全栈桌面 AI Agent,并保留原有产品图片
- 更新 App Server 文件/进程边界、Agent runtime 主链、Plugin current owner、治理路线图和 v2 协议说明
- 更新架构、命令边界、Plugin v3 合同、Codex parity matrix、清理账本和发布流程文档
- 根 README 采用英文 canonical 入口,并保留中文独立页面
### 其他
- 将根应用、CLI npm 包、Rust workspace 与 Cargo.lock 版本统一提升到 `1.124.0`
- 将根应用、CLI npm 包、Rust workspace 与 Cargo.lock 版本统一提升到 `1.125.0`
**完整变更**: `v1.123.0` -> `v1.124.0`
**完整变更**: `v1.124.0` -> `v1.125.0`
+1 -6
View File
@@ -43,13 +43,10 @@ import { AppServerDynamicToolHost } from "./appServerDynamicToolHost";
const DEFAULT_APP_SERVER_REQUEST_TIMEOUT_MS = 30_000;
const APP_SERVER_BACKEND_TIMEOUT_GRACE_MS = 30_000;
const APP_SERVER_TURN_START_METHOD = "turn/start";
const APP_SERVER_PROJECT_SHELL_DRAIN_EVENTS_METHOD =
"projectShell/session/drainEvents";
const APP_SERVER_CONVERSATION_IMPORT_THREAD_COMMIT_METHOD =
"conversationImport/thread/commit";
const APP_SERVER_CONVERSATION_IMPORT_JOB_READ_METHOD =
"conversationImport/job/read";
const APP_SERVER_PROJECT_SHELL_DRAIN_EVENTS_TIMEOUT_MS = 3_000;
const APP_SERVER_CONVERSATION_IMPORT_THREAD_COMMIT_TIMEOUT_MS = 180_000;
const APP_SERVER_CONVERSATION_IMPORT_SCAN_TIMEOUT_MS = 120_000;
const APP_SERVER_CONVERSATION_IMPORT_PREVIEW_TIMEOUT_MS = 120_000;
@@ -1040,9 +1037,7 @@ function resolveAppServerRequestTimeoutMs(
}
function resolveDefaultAppServerRequestTimeoutMs(method: string): number {
if (method === APP_SERVER_PROJECT_SHELL_DRAIN_EVENTS_METHOD) {
return APP_SERVER_PROJECT_SHELL_DRAIN_EVENTS_TIMEOUT_MS;
}
if (method === "command/exec") return 600_000;
if (method === APP_SERVER_CONVERSATION_IMPORT_THREAD_COMMIT_METHOD) {
return APP_SERVER_CONVERSATION_IMPORT_THREAD_COMMIT_TIMEOUT_MS;
}
-95
View File
@@ -35,12 +35,6 @@ const {
showOpenDialogMock,
showItemInFolderMock,
openProjectPathWithLocalToolMock,
projectShellHostDisposeForShutdownMock,
projectShellHostKillSessionMock,
projectShellHostResizeSessionMock,
projectShellHostRunCommandMock,
projectShellHostStartSessionMock,
projectShellHostWriteSessionMock,
systemUtilityHostGetBrowserBackendPolicyMock,
systemUtilityHostGetBrowserBackendsStatusMock,
systemUtilityHostGetBrowserConnectorInstallStatusMock,
@@ -127,12 +121,6 @@ const {
showOpenDialogMock: vi.fn(),
showItemInFolderMock: vi.fn(),
openProjectPathWithLocalToolMock: vi.fn(),
projectShellHostDisposeForShutdownMock: vi.fn(),
projectShellHostKillSessionMock: vi.fn(),
projectShellHostResizeSessionMock: vi.fn(),
projectShellHostRunCommandMock: vi.fn(),
projectShellHostStartSessionMock: vi.fn(),
projectShellHostWriteSessionMock: vi.fn(),
systemUtilityHostGetBrowserBackendPolicyMock: vi.fn(),
systemUtilityHostGetBrowserBackendsStatusMock: vi.fn(),
systemUtilityHostGetBrowserConnectorInstallStatusMock: vi.fn(),
@@ -205,17 +193,6 @@ vi.mock("./fileShellHost", () => ({
})),
}));
vi.mock("./projectShellHost", () => ({
ProjectShellHost: vi.fn(() => ({
disposeForShutdown: projectShellHostDisposeForShutdownMock,
killSession: projectShellHostKillSessionMock,
resizeSession: projectShellHostResizeSessionMock,
runCommand: projectShellHostRunCommandMock,
startSession: projectShellHostStartSessionMock,
writeSession: projectShellHostWriteSessionMock,
})),
}));
vi.mock("./systemUtilityHost", () => ({
SystemUtilityHost: vi.fn(() => ({
getBrowserBackendPolicy: systemUtilityHostGetBrowserBackendPolicyMock,
@@ -916,78 +893,6 @@ describe("ElectronHostCommands local file shell facade", () => {
);
});
it("项目 Shell 命令应只分发到 ProjectShellHost", async () => {
projectShellHostRunCommandMock.mockResolvedValueOnce({
command: "pwd",
exitCode: 0,
});
projectShellHostStartSessionMock.mockResolvedValueOnce({
sessionId: "project-shell-1",
tty: true,
});
projectShellHostWriteSessionMock.mockResolvedValueOnce({});
projectShellHostResizeSessionMock.mockResolvedValueOnce({});
projectShellHostKillSessionMock.mockResolvedValueOnce({});
const userDataDir = await createTempUserDataDir();
const host = createHost(userDataDir);
const runArgs = {
rootPath: "/tmp/project",
command: " pwd ",
timeoutMs: 10,
};
await expect(
host.invoke("run_project_shell_command", runArgs),
).resolves.toMatchObject({ command: "pwd", exitCode: 0 });
const startArgs = {
rootPath: "/tmp/project",
cols: 120,
rows: 14,
};
await expect(
host.invoke("project_shell_session_start", startArgs),
).resolves.toMatchObject({
sessionId: "project-shell-1",
tty: true,
});
const writeArgs = {
sessionId: "project-shell-1",
data: "ls\r",
};
await expect(
host.invoke("project_shell_session_write", writeArgs),
).resolves.toEqual({});
const resizeArgs = {
sessionId: "project-shell-1",
cols: 100,
rows: 20,
};
await expect(
host.invoke("project_shell_session_resize", resizeArgs),
).resolves.toEqual({});
const killArgs = {
sessionId: "project-shell-1",
};
await expect(
host.invoke("project_shell_session_kill", killArgs),
).resolves.toEqual({});
expect(projectShellHostRunCommandMock).toHaveBeenCalledWith(runArgs);
expect(projectShellHostStartSessionMock).toHaveBeenCalledWith(startArgs);
expect(projectShellHostWriteSessionMock).toHaveBeenCalledWith(writeArgs);
expect(projectShellHostResizeSessionMock).toHaveBeenCalledWith(resizeArgs);
expect(projectShellHostKillSessionMock).toHaveBeenCalledWith(killArgs);
});
it("disposeProjectShellSessionsForShutdown 应委托 ProjectShellHost", async () => {
const userDataDir = await createTempUserDataDir();
const host = createHost(userDataDir);
host.disposeProjectShellSessionsForShutdown();
expect(projectShellHostDisposeForShutdownMock).toHaveBeenCalledOnce();
});
});
describe("ElectronHostCommands app config persistence", () => {
-20
View File
@@ -36,7 +36,6 @@ import {
import { showDesktopNotification } from "./desktopNotificationHost";
import { FileShellHost } from "./fileShellHost";
import { LayeredDesignProjectHost } from "./layeredDesignProjectHost";
import { ProjectShellHost } from "./projectShellHost";
import { openResourceManagerWindow } from "./resourceManagerWindowHost";
import { SystemUtilityHost } from "./systemUtilityHost";
import { VoiceModelHost } from "./voiceModelHost";
@@ -77,7 +76,6 @@ export class ElectronHostCommands {
readonly #emit: HostEventEmitter;
readonly #fileShellHost = new FileShellHost();
readonly #layeredDesignProjectHost = new LayeredDesignProjectHost();
readonly #projectShellHost: ProjectShellHost;
readonly #systemUtilityHost: SystemUtilityHost;
readonly #voiceModelHost: VoiceModelHost;
readonly #appConfigHost: AppConfigHost;
@@ -94,11 +92,6 @@ export class ElectronHostCommands {
this.#userDataDir = userDataDir;
this.#emit = emit;
this.#appConfigHost = new AppConfigHost(userDataDir);
this.#projectShellHost = new ProjectShellHost(
<T>(method: string, params: AppServerParams = {}) =>
this.#appServerRequest<T>(method, params),
emit,
);
this.#systemUtilityHost = new SystemUtilityHost({
appDataRoot,
readConfig: () => this.#readConfig(),
@@ -132,16 +125,6 @@ export class ElectronHostCommands {
return await this.#fileShellHost.openWithDefaultApp(args);
case "open_project_path_with_tool":
return await this.#openProjectPathWithTool(args);
case "run_project_shell_command":
return await this.#projectShellHost.runCommand(args);
case "project_shell_session_start":
return await this.#projectShellHost.startSession(args);
case "project_shell_session_write":
return await this.#projectShellHost.writeSession(args);
case "project_shell_session_resize":
return await this.#projectShellHost.resizeSession(args);
case "project_shell_session_kill":
return await this.#projectShellHost.killSession(args);
case "save_exported_document":
return await this.#saveExportedDocument(args);
case "save_layered_design_project_export":
@@ -601,9 +584,6 @@ export class ElectronHostCommands {
);
}
disposeProjectShellSessionsForShutdown(): void {
this.#projectShellHost.disposeForShutdown();
}
}
function readRecord(
+5 -5
View File
@@ -148,11 +148,11 @@ describe("electron/ipcChannels", () => {
expect(isElectronHostCommand("open_system_settings_url")).toBe(true);
expect(isElectronHostCommand("open_with_default_app")).toBe(true);
expect(isElectronHostCommand("open_project_path_with_tool")).toBe(true);
expect(isElectronHostCommand("run_project_shell_command")).toBe(true);
expect(isElectronHostCommand("project_shell_session_start")).toBe(true);
expect(isElectronHostCommand("project_shell_session_write")).toBe(true);
expect(isElectronHostCommand("project_shell_session_resize")).toBe(true);
expect(isElectronHostCommand("project_shell_session_kill")).toBe(true);
expect(isElectronHostCommand("run_project_shell_command")).toBe(false);
expect(isElectronHostCommand("project_shell_session_start")).toBe(false);
expect(isElectronHostCommand("project_shell_session_write")).toBe(false);
expect(isElectronHostCommand("project_shell_session_resize")).toBe(false);
expect(isElectronHostCommand("project_shell_session_kill")).toBe(false);
expect(isElectronHostCommand("reveal_in_finder")).toBe(true);
expect(isElectronHostCommand("save_exported_document")).toBe(true);
expect(isElectronHostCommand("save_layered_design_project_export")).toBe(
-5
View File
@@ -53,11 +53,6 @@ export const ELECTRON_HOST_COMMANDS = [
"recognize_layered_design_text",
"reveal_in_finder",
"open_project_path_with_tool",
"run_project_shell_command",
"project_shell_session_start",
"project_shell_session_write",
"project_shell_session_resize",
"project_shell_session_kill",
"report_frontend_crash",
"report_frontend_debug_log",
"save_config",
-1
View File
@@ -1452,7 +1452,6 @@ app.on("activate", () => {
app.on("before-quit", () => {
isQuitting = true;
globalShortcut.unregisterAll();
hostCommands.disposeProjectShellSessionsForShutdown();
tray?.destroy();
tray = null;
devHttpBridge?.stop();
-280
View File
@@ -1,280 +0,0 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import {
METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS,
METHOD_PROJECT_SHELL_SESSION_KILL,
METHOD_PROJECT_SHELL_SESSION_RESIZE,
METHOD_PROJECT_SHELL_SESSION_START,
METHOD_PROJECT_SHELL_SESSION_WRITE,
} from "@limecloud/app-server-client";
const { runProjectShellCommandMock } = vi.hoisted(() => ({
runProjectShellCommandMock: vi.fn(),
}));
vi.mock("./projectToolsHost", async (importOriginal) => {
const actual = await importOriginal<typeof import("./projectToolsHost")>();
return {
...actual,
runProjectShellCommand: runProjectShellCommandMock,
};
});
import { ProjectShellHost } from "./projectShellHost";
type AppServerRequestMock = (
method: string,
params?: unknown,
) => Promise<unknown>;
function createProjectShellHost(
request: AppServerRequestMock = async () => {
throw new Error("App Server should not be called");
},
emit: (event: string, payload?: unknown) => void = () => undefined,
) {
return new ProjectShellHost(
<T>(method: string, params?: Record<string, unknown>) =>
request(method, params) as Promise<T>,
emit,
);
}
afterEach(() => {
vi.useRealTimers();
vi.clearAllMocks();
});
describe("ProjectShellHost", () => {
it("runCommand 应走项目 Shell current 封装并归一化 timeout", async () => {
runProjectShellCommandMock.mockResolvedValueOnce({
command: "pwd",
cwd: "/tmp/project",
exitCode: 0,
stdout: "/tmp/project\n",
stderr: "",
durationMs: 10,
timedOut: false,
});
const host = createProjectShellHost();
await expect(
host.runCommand({
rootPath: "/tmp/project",
command: " pwd ",
timeoutMs: 10,
}),
).resolves.toMatchObject({ command: "pwd", exitCode: 0 });
expect(runProjectShellCommandMock).toHaveBeenCalledWith({
cwd: "/tmp/project",
command: "pwd",
timeoutMs: 1000,
});
});
it("session 方法应委托 App Server PTY current 通道", async () => {
vi.useFakeTimers();
const request = vi.fn(async (method: string) => {
if (method === METHOD_PROJECT_SHELL_SESSION_START) {
return {
sessionId: "project-shell-1",
cwd: "/tmp/project",
shell: "/bin/zsh",
title: "Shell: project",
localEcho: false,
tty: true,
pid: 123,
};
}
return {};
});
const host = createProjectShellHost(request);
await expect(
host.startSession({
rootPath: "/tmp/project",
cols: 120,
rows: 14,
}),
).resolves.toMatchObject({
sessionId: "project-shell-1",
tty: true,
});
await expect(
host.writeSession({
sessionId: "project-shell-1",
data: "ls\r",
}),
).resolves.toEqual({});
await expect(
host.resizeSession({
sessionId: "project-shell-1",
cols: 100,
rows: 20,
}),
).resolves.toEqual({});
await expect(
host.killSession({
sessionId: "project-shell-1",
}),
).resolves.toEqual({});
expect(request).toHaveBeenCalledWith(METHOD_PROJECT_SHELL_SESSION_START, {
rootPath: "/tmp/project",
cols: 120,
rows: 14,
});
expect(request).toHaveBeenCalledWith(METHOD_PROJECT_SHELL_SESSION_WRITE, {
sessionId: "project-shell-1",
data: "ls\r",
});
expect(request).toHaveBeenCalledWith(METHOD_PROJECT_SHELL_SESSION_RESIZE, {
sessionId: "project-shell-1",
cols: 100,
rows: 20,
});
expect(request).toHaveBeenCalledWith(METHOD_PROJECT_SHELL_SESSION_KILL, {
sessionId: "project-shell-1",
});
});
it("event drain 应转发到前端事件通道", async () => {
vi.useFakeTimers();
const emit = vi.fn();
const request = vi.fn(async (method: string) => {
if (method === METHOD_PROJECT_SHELL_SESSION_START) {
return {
sessionId: "project-shell-1",
cwd: "/tmp/project",
shell: "/bin/zsh",
title: "Shell: project",
localEcho: false,
tty: true,
pid: 123,
};
}
if (method === METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS) {
return {
events: [
{
type: "data",
sessionId: "project-shell-1",
stream: "stdout",
data: "hello",
},
{
type: "exit",
sessionId: "project-shell-1",
exitCode: 0,
signal: null,
},
],
};
}
return {};
});
const host = createProjectShellHost(request, emit);
await host.startSession({
rootPath: "/tmp/project",
cols: 120,
rows: 14,
});
await vi.advanceTimersByTimeAsync(100);
expect(request).toHaveBeenCalledWith(
METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS,
{ sessionId: "project-shell-1", limit: 200 },
);
expect(emit).toHaveBeenCalledWith("project-shell-session-event", {
type: "data",
sessionId: "project-shell-1",
stream: "stdout",
data: "hello",
});
});
it("写入后应主动 drain 并转发输出", async () => {
vi.useFakeTimers();
const emit = vi.fn();
const request = vi.fn(async (method: string) => {
if (method === METHOD_PROJECT_SHELL_SESSION_START) {
return {
sessionId: "project-shell-1",
cwd: "/tmp/project",
shell: "/bin/zsh",
title: "coso@host: project",
localEcho: false,
tty: true,
pid: 123,
};
}
if (method === METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS) {
return {
events: [
{
type: "data",
sessionId: "project-shell-1",
stream: "stdout",
data: "__lime_shell_e2e__\n",
},
],
};
}
return {};
});
const host = createProjectShellHost(request, emit);
await host.startSession({
rootPath: "/tmp/project",
cols: 120,
rows: 14,
});
await host.writeSession({
sessionId: "project-shell-1",
data: "printf '__lime_shell_e2e__\\n'\r",
});
expect(request).toHaveBeenCalledWith(
METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS,
{ sessionId: "project-shell-1", limit: 200 },
);
expect(emit).toHaveBeenCalledWith("project-shell-session-event", {
type: "data",
sessionId: "project-shell-1",
stream: "stdout",
data: "__lime_shell_e2e__\n",
});
});
it("disposeForShutdown 应结束 App Server PTY 会话", async () => {
vi.useFakeTimers();
const request = vi.fn(async (method: string) => {
if (method === METHOD_PROJECT_SHELL_SESSION_START) {
return {
sessionId: "project-shell-1",
cwd: "/tmp/project",
shell: "/bin/zsh",
title: "Shell: project",
localEcho: false,
tty: true,
pid: 123,
};
}
return {};
});
const host = createProjectShellHost(request);
await host.startSession({
rootPath: "/tmp/project",
cols: 120,
rows: 14,
});
host.disposeForShutdown();
expect(request).toHaveBeenCalledWith(METHOD_PROJECT_SHELL_SESSION_KILL, {
sessionId: "project-shell-1",
});
});
});
-267
View File
@@ -1,267 +0,0 @@
import {
METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS,
METHOD_PROJECT_SHELL_SESSION_KILL,
METHOD_PROJECT_SHELL_SESSION_RESIZE,
METHOD_PROJECT_SHELL_SESSION_START,
METHOD_PROJECT_SHELL_SESSION_WRITE,
} from "@limecloud/app-server-client";
import path from "node:path";
import {
normalizeProjectShellTimeout,
runProjectShellCommand,
type ProjectShellCommandResult,
} from "./projectToolsHost";
type HostArgs = Record<string, unknown> | null | undefined;
type AppServerParams = Record<string, unknown>;
type AppServerRequest = <T>(
method: string,
params?: AppServerParams,
) => Promise<T>;
type HostEventEmitter = (event: string, payload?: unknown) => void;
type ProjectShellSessionStartResult = {
sessionId: string;
cwd: string;
shell: string;
title: string;
localEcho: boolean;
tty: boolean;
pid: number | null;
};
type ProjectShellSessionEvent =
| {
type: "data";
sessionId: string;
stream: "stdout" | "stderr";
data: string;
}
| {
type: "exit";
sessionId: string;
exitCode: number | null;
signal: string | null;
}
| {
type: "error";
sessionId: string;
message: string;
};
type ProjectShellSessionDrainEventsResponse = {
events: ProjectShellSessionEvent[];
};
const PROJECT_SHELL_SESSION_EVENT = "project-shell-session-event";
const PROJECT_SHELL_EVENT_POLL_INTERVAL_MS = 80;
const PROJECT_SHELL_EVENT_DRAIN_LIMIT = 200;
export class ProjectShellHost {
readonly #appServerRequest: AppServerRequest;
readonly #emit: HostEventEmitter;
readonly #sessions = new Set<string>();
#eventPoller: ReturnType<typeof setInterval> | null = null;
#eventDrainInFlight = false;
constructor(
appServerRequest: AppServerRequest,
emit: HostEventEmitter = () => undefined,
) {
this.#appServerRequest = appServerRequest;
this.#emit = emit;
}
async runCommand(args: HostArgs): Promise<ProjectShellCommandResult> {
const request = readRequest(args);
const rootPath = readRequiredAbsolutePath(request, "rootPath");
const command = readRequiredRawString(request, "command").trim();
if (!command) {
throw new Error("Shell 命令不能为空");
}
return await runProjectShellCommand({
cwd: rootPath,
command,
timeoutMs: normalizeProjectShellTimeout(readNumber(request, "timeoutMs")),
});
}
async startSession(args: HostArgs): Promise<ProjectShellSessionStartResult> {
const request = readRequest(args);
const response =
await this.#appServerRequest<ProjectShellSessionStartResult>(
METHOD_PROJECT_SHELL_SESSION_START,
{
rootPath: readRequiredAbsolutePath(request, "rootPath"),
cols: readNumber(request, "cols") ?? 120,
rows: readNumber(request, "rows") ?? 16,
},
);
this.#sessions.add(response.sessionId);
this.#ensureEventPoller();
void this.#drainEvents();
return response;
}
async writeSession(args: HostArgs): Promise<Record<string, never>> {
const request = readRequest(args);
await this.#appServerRequest(METHOD_PROJECT_SHELL_SESSION_WRITE, {
sessionId: readRequiredString(request, "sessionId"),
data: readRequiredRawString(request, "data"),
});
void this.#drainEvents();
setTimeout(() => {
void this.#drainEvents();
}, 30);
setTimeout(() => {
void this.#drainEvents();
}, 120);
return {};
}
async resizeSession(args: HostArgs): Promise<Record<string, never>> {
const request = readRequest(args);
await this.#appServerRequest(METHOD_PROJECT_SHELL_SESSION_RESIZE, {
sessionId: readRequiredString(request, "sessionId"),
cols: readNumber(request, "cols") ?? 120,
rows: readNumber(request, "rows") ?? 16,
});
return {};
}
async killSession(args: HostArgs): Promise<Record<string, never>> {
const request = readRequest(args);
const sessionId = readRequiredString(request, "sessionId");
await this.#appServerRequest(METHOD_PROJECT_SHELL_SESSION_KILL, {
sessionId,
});
this.#sessions.delete(sessionId);
this.#stopEventPollerIfIdle();
return {};
}
disposeForShutdown(): void {
if (this.#eventPoller) {
clearInterval(this.#eventPoller);
this.#eventPoller = null;
}
const sessionIds = Array.from(this.#sessions);
this.#sessions.clear();
for (const sessionId of sessionIds) {
void this.#appServerRequest(METHOD_PROJECT_SHELL_SESSION_KILL, {
sessionId,
}).catch(() => undefined);
}
}
#ensureEventPoller(): void {
if (this.#eventPoller) {
return;
}
this.#eventPoller = setInterval(() => {
void this.#drainEvents();
}, PROJECT_SHELL_EVENT_POLL_INTERVAL_MS);
}
#stopEventPollerIfIdle(): void {
if (this.#sessions.size > 0 || !this.#eventPoller) {
return;
}
clearInterval(this.#eventPoller);
this.#eventPoller = null;
}
async #drainEvents(): Promise<void> {
if (this.#eventDrainInFlight) {
return;
}
if (this.#sessions.size === 0) {
this.#stopEventPollerIfIdle();
return;
}
this.#eventDrainInFlight = true;
try {
for (const sessionId of Array.from(this.#sessions)) {
const response =
await this.#appServerRequest<ProjectShellSessionDrainEventsResponse>(
METHOD_PROJECT_SHELL_SESSION_DRAIN_EVENTS,
{ sessionId, limit: PROJECT_SHELL_EVENT_DRAIN_LIMIT },
);
for (const event of response.events ?? []) {
if (event.type === "exit" || event.type === "error") {
this.#sessions.delete(event.sessionId);
}
this.#emit(PROJECT_SHELL_SESSION_EVENT, event);
}
}
} catch (error) {
console.warn("[electron-host] project shell event drain failed", error);
} finally {
this.#eventDrainInFlight = false;
this.#stopEventPollerIfIdle();
}
}
}
function readRequest(value: unknown): Record<string, unknown> {
return readRecord(value, "request") ?? toRecord(value) ?? {};
}
function readRecord(
value: unknown,
key: string,
): Record<string, unknown> | null {
const record = toRecord(value);
if (!record) {
return null;
}
const next = record[key];
return next && typeof next === "object" && !Array.isArray(next)
? (next as Record<string, unknown>)
: null;
}
function readRequiredString(value: unknown, key: string): string {
const next = readString(value, key);
if (!next) {
throw new Error(`Missing required string field: ${key}`);
}
return next;
}
function readRequiredRawString(value: unknown, key: string): string {
const record = toRecord(value);
const next = record?.[key];
if (typeof next !== "string") {
throw new Error(`Missing required string field: ${key}`);
}
return next;
}
function readRequiredAbsolutePath(value: unknown, key: string): string {
const next = readRequiredString(value, key);
if (!path.isAbsolute(next)) {
throw new Error(`${key} 必须是绝对路径`);
}
return next;
}
function readString(value: unknown, key: string): string | null {
const record = toRecord(value);
const next = record?.[key];
if (typeof next !== "string") {
return null;
}
const trimmed = next.trim();
return trimmed || null;
}
function readNumber(value: unknown, key: string): number | null {
const record = toRecord(value);
const next = record?.[key];
return typeof next === "number" && Number.isFinite(next) ? next : null;
}
function toRecord(value: unknown): Record<string, unknown> | null {
return value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: null;
}
-91
View File
@@ -4,16 +4,6 @@ import path from "node:path";
export type ProjectPathOpenTool = "vscode" | "cursor" | "terminal" | "finder";
export interface ProjectShellCommandResult {
command: string;
cwd: string;
exitCode: number | null;
stdout: string;
stderr: string;
durationMs: number;
timedOut: boolean;
}
export async function openProjectPathWithLocalTool(
targetPath: string,
tool: Exclude<ProjectPathOpenTool, "finder">,
@@ -24,71 +14,6 @@ export async function openProjectPathWithLocalTool(
});
}
export function normalizeProjectShellTimeout(value: number | null): number {
if (!Number.isFinite(value ?? NaN)) {
return 30_000;
}
return Math.min(Math.max(Math.trunc(value ?? 30_000), 1_000), 120_000);
}
export async function runProjectShellCommand({
cwd,
command,
timeoutMs,
}: {
cwd: string;
command: string;
timeoutMs: number;
}): Promise<ProjectShellCommandResult> {
const resolved = resolveProjectShellCommand(command);
const startedAt = Date.now();
return await new Promise<ProjectShellCommandResult>((resolve, reject) => {
const child = spawn(resolved.executable, resolved.args, {
cwd,
stdio: ["ignore", "pipe", "pipe"],
windowsHide: true,
});
let stdout = "";
let stderr = "";
let settled = false;
let timedOut = false;
const settle = (result: ProjectShellCommandResult) => {
if (settled) return;
settled = true;
clearTimeout(timer);
resolve(result);
};
const timer = setTimeout(() => {
timedOut = true;
child.kill();
}, timeoutMs);
child.stdout?.on("data", (chunk: Buffer) => {
stdout += chunk.toString("utf8");
});
child.stderr?.on("data", (chunk: Buffer) => {
stderr += chunk.toString("utf8");
});
child.on("error", (error) => {
if (settled) return;
settled = true;
clearTimeout(timer);
reject(new Error(`Shell 命令启动失败: ${error.message}`));
});
child.on("close", (code) => {
settle({
command,
cwd,
exitCode: timedOut ? null : code,
stdout,
stderr,
durationMs: Date.now() - startedAt,
timedOut,
});
});
});
}
function resolveProjectPathOpenCommand(
targetPath: string,
tool: Exclude<ProjectPathOpenTool, "finder">,
@@ -137,22 +62,6 @@ function resolveProjectPathOpenCommand(
};
}
function resolveProjectShellCommand(command: string): {
executable: string;
args: string[];
} {
if (process.platform === "win32") {
return {
executable: "cmd.exe",
args: ["/d", "/s", "/c", command],
};
}
return {
executable: process.env.SHELL?.trim() || "/bin/sh",
args: ["-lc", command],
};
}
async function runProjectPathOpenCommand(
executable: string,
args: string[],
+2 -2
View File
@@ -41,7 +41,7 @@
- `../tests/lime-agent-qc-rollout-plan.md` - Lime 样本产品的 Agent 运营级测试落地计划
- `command-runtime.md` - `@` / `/` / 轻卡 / viewer / 功能方案包实施手册
- `skill-standard.md` - 统一技能标准、skill / adapter / runtime binding 边界
- `../tech/plugin/README.md` - Lime Plugin Package v1、Agent Skills 目录契约、worker / workbench / hooks / CLI / connector 打包标准
- `../roadmap/plugin/v3/README.md` - Agent Plugins v1.0.0 portable 包、Skills/MCP 固定目录、Codex extension 与 Lime current owner 边界
- `site-adapter-standard.md` - 站点适配器标准、来源导入边界、运行时收敛规则
- `web-browser-scene-skill.md` - 网页 / 浏览器场景技能设计提案,说明如何把外部 web skill 思路收敛到 Lime 主线
- `project-heatmap.md` - 仓库热力图与治理候选分析
@@ -93,7 +93,7 @@
- **碰到 `src/lib/dev-bridge/**`**:先读 `commands.md``governance.md`;保留 current renderer bridge 传输,按命令组清 `commandPolicy``mockPriorityCommands`、旧 smoke、负向测试和 contract guard,把删不动的旧 policy 登记到对应执行计划;跨命令组长期 residual 必须同步回挂 `../exec-plans/tech-debt-tracker.md``CCD-012`
- **改 `@` / `/` / 轻卡 / viewer / ServiceSkill 场景**:先读 `command-runtime.md`
- **改 Claw 技能 / Service Skill / 统一 Skills 标准**:先读 `skill-standard.md`
- **改插件包 / Plugin 包结构 / `plugin.json` / `app.runtime.yaml` / `skills/**/SKILL.md`**:先读 `../tech/plugin/README.md`,再看 `skill-standard.md``governance.md`
- **改插件包 / Plugin 包结构 / `plugin.json` / `mcp.json` / `skills/**/SKILL.md`**:先读 `../roadmap/plugin/v3/README.md``../roadmap/plugin/v3/01-target-contract.md`,再看 `skill-standard.md``governance.md`
- **改站点适配器 / 导入外部 adapter**:先读 `site-adapter-standard.md`,再看 `web-browser-scene-skill.md``quality-workflow.md`
- **做网页登录态访问 / 网页导出 / Markdown 落盘场景**:先读 `web-browser-scene-skill.md`
- **改 Workspace / GUI 壳 / 主路径**:先读 `workspace.md``quality-workflow.md``playwright-e2e.md`
+252 -25
View File
@@ -130,7 +130,10 @@ App Server 是 Renderer、Electron、CLI、Plugin 与 runtime 的唯一跨应用
App Server 的 request dispatcher 必须先把各 method handler future 装箱,再在单一 await 点执行;禁止让大型 async `match` 把所有分支 future 内联进同一个 poll 栈。stdio transport 在 `initialize` 完成前保持顺序执行;初始化后每个 client request 由独立 transport task 调度,notification/response 继续内联,并由 request id 关联响应、由 serialization scope 保证同一资源的共享/独占顺序。长 turn、MCP 或宿主 I/O 不得阻塞无冲突的 list/read request。
Project Shell/Git 等宿主子进程必须有确定性测试注入和生产 deadline。测试不得读取真实用户 shell rc;plain directory 的 Git status 先通过 `.git` ancestor preflight 返回,仓库内 Git 命令使用异步 process、`kill_on_drop` 和 5 秒上限,不得在 async handler 中调用无界 `std::process::Command::output`
Desktop command/exec 与 Git 等宿主子进程必须有确定性测试注入和生产 deadline。测试不得读取真实用户 shell rc;
plain directory 的 Git status 先通过 `.git` ancestor preflight 返回,仓库内 Git 命令使用异步 process、`kill_on_drop`
和 5 秒上限,不得在 async handler 中调用无界 `std::process::Command::output`。交互终端必须复用 App Server
`CommandExecServer`Electron 不得持有第二套 session 状态。
Server-originated request 使用与 client request 分离的 `serverRequest` catalog kind,并按以下方向流动:
@@ -1776,8 +1779,8 @@ thread identity fail closed in the current Agent Chat path. The generic protocol
lifecycle. Full cold reads and limited projection-summary reads derive the warning beside canonical items from the same
event log, preserving message, sequence and localization code without a second store. Live raw `agentSession/event`
warning wrappers are `dead / forbidden-to-restore` and covered only by negative tests. `guardianWarning` stays `planned`
because Lime has no Guardian review runtime producer; a schema-only or Renderer-fixture implementation would not make it
current.
because Lime has no independent high-priority Guardian warning producer; a schema-only or Renderer-fixture implementation
would not make it current.
Architecture impact: major because a live notification and recovery surface moved from the deprecated raw side channel
to the v2 protocol/projector/Renderer boundary. The product direction remains Electron Desktop Host -> App Server
@@ -1887,33 +1890,40 @@ CODEX_HOME/config.toml + <cwd>/.codex/config.toml + active Plugin catalog
-> Agent sampling step / command gate
-> AgentEvent hook.started / hook.completed
-> App Server v2 hook notifications
-> canonical ThreadItemPayload::Hook (item_<hookRunId>)
-> Thread/read + thread/items/list + Renderer timeline
-> Renderer transient Hook timeline projection
canonical Thread/Turn/Item materializer
-> excludes hook.started / hook.completed
-> thread/read + thread/items/list contain no Hook lifecycle Item
```
`hooks/list` is the sole public discovery contract. `tool-runtime` owns source loading, stable key/hash, trust and
execution; Agent runtime owns lifecycle events; App Server owns JSON-RPC dispatch, notification projection, durable
materialization and read-model lowering; the Renderer only validates and displays the canonical Hook Item. Started and
completed notifications must carry the same run id and the same `item_<hookRunId>` identity. Terminal status is mapped
to completed, failed or interrupted without creating a second generic item lifecycle.
event append and public read-model exclusion; the Renderer validates the typed notification and may display a transient
timeline row. Started and completed notifications must carry the same run id, but they do not create or update a
canonical Item. This follows Codex's separate `hook/started` and `hook/completed` notifications and its ThreadItem union,
which contains `HookPrompt` but no Hook lifecycle Item.
The v2 protocol/schema/generated Rust and TypeScript clients, public JSON-RPC `hooks/list`, Hook event projector,
canonical history materializer and five-locale timeline row are `current`. The former raw hook config shape,
`known_unprojected` Hook drift path, bare run-id item identity and production mock/fallback execution are
`dead / deleted / forbidden-to-restore`; no compatibility owner was added. Lime remains a compact Electron Desktop
GUI and does not copy Codex TUI surfaces. Provider/model/media behavior remains owned by the Grok-aligned
`model-provider` control plane.
canonical history exclusion and five-locale transient timeline row are `current`. The former canonical
`ThreadItemPayload::Hook`, `item_<hookRunId>` identity, public history recovery path, raw hook config shape,
`known_unprojected` Hook drift path and production mock/fallback execution are `dead / deleted / forbidden-to-restore`;
no compatibility owner was added. Lime remains a compact Electron Desktop GUI and does not copy Codex TUI surfaces.
Provider/model/media behavior remains owned by the Grok-aligned `model-provider` control plane.
Architecture impact: major because this adds a cross-layer protocol, lifecycle event, durable Item and recovery path.
Architecture diagram updated: this section and the App Server notification -> Thread/Turn/Item projection path above.
Responsible developer confirmation: root, 2026-08-07. Confirmation content: 已核对目录归属、数据流、依赖方向、协议边界和验证门禁。
Architecture impact: major because the Hook lifecycle boundary is a typed live notification rather than a durable
Thread Item and recovery contract. Architecture diagram updated: this section and the App Server notification versus
Thread/Turn/Item projection split above. Responsible developer confirmation: root, 2026-08-09. Confirmation content:
已核对 Codex notification/ThreadItem 边界、Lime EventStore 分类、公共历史排除、Renderer transient 投影和验证门禁。
## 31. Apps Catalog And Readiness Owner
Apps/connectors 只有一个 catalog owner,并保持 Desktop 与 Codex TUI 的产品边界分离:
```text
installed Plugin manifests with apps capability
standard Agent Plugin root manifest
-> explicit Codex extension `apps: "./config.json"`
-> independent `apps.{name}.{id,category?}` config
-> App Server PluginDataSource / local plugin_catalog
-> RuntimeCore app/list | app/read | app/installed
-> App Server JSON-RPC
@@ -1927,11 +1937,14 @@ successful plugin/install | plugin/uninstall | plugin/enabled/set
-> Renderer typed watcher -> fresh Apps read
```
`app/list` uses the installed Plugin manifest `apps` capability and keeps pagination in the same catalog. `app/read`
deduplicates ids while preserving first-request order and returns `missingAppIds`; the processor rejects more than 100 ids
with `INVALID_PARAMS`. Optional `threadId` on list/installed is validated against the loaded canonical Thread and fails
closed with `SESSION_NOT_FOUND`. The local registry is read fresh on every request, so `forceRefetch` and `forceRefresh`
never fabricate a hosted cache refresh.
`app/list` never reads a portable top-level `apps` field. It follows Codex's explicit client extension adapter:
`extensions.com.openai.apps`, with `.codex-plugin/plugin.json` only as the overlay fallback, must be a package-relative
path to a separate Apps JSON document. Connector `id` is the catalog identity; inline Apps objects fail closed and an
invalid Apps component is isolated from Skills/MCP and package installation. `app/read` deduplicates ids while preserving
first-request order and returns `missingAppIds`; the processor rejects more than 100 ids with `INVALID_PARAMS`. Optional
`threadId` on list/installed is validated against the loaded canonical Thread and fails closed with `SESSION_NOT_FOUND`.
The local registry is read fresh on every request, so `forceRefetch` and `forceRefresh` never fabricate a hosted cache
refresh.
`callable` is a readiness boundary, not an install flag. Until a local Plugin app has a committed hosted connector
model-visible tool snapshot, enabled local apps report `callable=false` and Desktop readiness remains false. No UI or
@@ -1944,17 +1957,27 @@ owner; Apps are projected inside the selected Plugin detail sidebar instead of c
source. The consumer reads `app/list + app/installed`, renders `ready / disabled / pending`, and reruns the same fresh
read after typed `app/list/updated` arrives through the App Server event bus.
The Apps-specific Electron Gate B uses isolated app data and a local Plugin manifest with an `apps` capability. It
proved real Electron renderer/preload/IPC, `app_server_handle_json_lines`, `plugin/list -> plugin/install`, exact
The Apps-specific Electron Gate B runner now uses isolated app data, a standard root Agent Plugins manifest and a Codex
extension path to an independent Apps JSON. Its prior 2026-08-07 artifact used the retired inline manifest shape and is
historical only. The migrated runner passed on 2026-08-09 and proved the transport/UI flow across real Electron
renderer/preload/IPC, `app_server_handle_json_lines`, `plugin/list -> plugin/install`, exact
`app/list` / `app/read` / `app/installed`, GUI `plugin/enabled/set`, the subsequent fresh Apps read and the same visible
row changing from `enabled=true / callable=false / pending` to `disabled`. Console, page, invoke, trace, legacy command
and production mock fallback counts were all zero. Evidence:
`.lime/qc/project-gates/standalone-apps-catalog-20260807T152703394Z-702520/apps-catalog-gate-b/apps-catalog-gate-b-summary.json`.
`.lime/qc/project-gates/standalone-apps-catalog-20260809T054741397Z-147740/apps-catalog-gate-b/apps-catalog-gate-b-summary.json`.
All seven required methods were observed; install notification and pending-to-disabled fresh read succeeded; console,
page, invoke, trace, mock fallback and legacy command counts were zero.
There is no second Apps catalog, `window` custom-event fact source, TUI-style Apps surface, compatibility wrapper or
production mock fallback. Hosted connector model-visible tool snapshot and a real `callable=true` provider path remain
open capability work; the local Gate B does not claim either one.
Architecture impact: existing cross-layer Apps owner corrected in place; no second runtime or storage owner added.
Architecture diagram updated: this section now distinguishes the portable Agent Plugins manifest from the explicit
Codex Apps extension path and independent config file.
Responsible developer confirmation: root, 2026-08-09. Confirmation content: 已核对 portable/extension
边界、Apps identity、失败隔离、JSON-RPC 数据流与 Gate B 重验要求。
Architecture impact: major because this adds a cross-layer catalog/readiness contract and live invalidation path while
reusing the existing Plugin catalog owner. The product direction remains Electron Desktop Host -> App Server JSON-RPC
-> RuntimeCore -> Thread/Turn/Item projection -> GUI; provider/model/media behavior remains owned by the Grok-aligned
@@ -2035,6 +2058,41 @@ owner -> Thread/Turn/Item projection -> GUI; process control does not create a s
confirmation: root, 2026-08-08. Confirmation content: 已核对 connection/Thread owner 分界、目录归属、数据流、依赖方向、
协议与 notification 顺序、删除边界和验证门禁。
### 33.1 Exact Command Exec Owner
Codex standalone `command/exec` 是 Desktop coding terminal 的唯一 current owner;它与 Thread-owned command Item、
Codex TUI 的 `process/*` 控制面分开,但共享 `tool-runtime` 本地进程 supervisor
```text
Renderer commandExec gateway
-> typed App Server client
-> command/exec
-> App Server CommandExecServer keyed by (ConnectionId, processId)
-> tool-runtime LocalExecutionProcessHandle
command/exec/write|resize|terminate
-> same (ConnectionId, processId)
command/exec/outputDelta
-> same owner connection, raw bytes as deltaBase64
```
一次性命令 response 保留 UTF-8 聚合 stdout/stderr;开启流式输出时,所有 delta 在最终 response 前按顺序投影,
response 的 stdout/stderr 为空。`command/exec``outputBytesCap``timeoutMs` 使用 Codex exact 三态字段,默认
output cap 为 1 MiB,超时退出码为 `124`;PTY resize 只允许正数尺寸,stdin close 后非空写入失败。`processId` 可以由
客户端提供,也可由服务端生成,但只在 originating ConnectionId 内有效;断连和终止都会清理 session。
Desktop terminal 只消费 `src/lib/api/commandExec.ts`,通过 xterm 展示真实 outputDelta,不在 Renderer 伪造 prompt、
session reconnect、明文 stdin 或 fallback output。Electron 仅承担既有 JSONL sidecar 转发职责。
v2 protocol/schema、CommandExecServer、connection cleanup、typed client、Renderer gateway、GUI terminal 和负向回流
guard 为 `current`;旧 `project_shell_*``run_project_shell_command`、Project Shell v0 DTO/schema、旧 gateway 与
Electron host 为 `dead / deleted / forbidden-to-restore``compat``deprecated` 均为空。
Architecture impact: major because a public JSON-RPC command family replaced the private Project Shell IPC/session owner.
Architecture map updated: sections 6.1, 33.1 and command boundary document. Responsible developer confirmation: root,
2026-08-08. Confirmation content: 已核对 Desktop/App Server/runtime owner、ConnectionId 隔离、notification 顺序、
raw bytes lowering、删除边界和 GUI/contract 验证门禁。
## 34. Exact Filesystem Owner
Codex exact filesystem contract 由 App Server 独立 `FsServer` 承接,Desktop 只消费 typed wire 并投影富 GUI
@@ -2075,3 +2133,172 @@ exact v2 owner. The product direction remains Electron Desktop Host -> App Serve
Thread/Turn/Item projection -> GUI; filesystem IO does not create a second Electron backend or copy Codex TUI. Responsible
developer confirmation: root, 2026-08-08. Confirmation content: 已核对目录归属、绝对路径/base64 边界、connection watcher
owner、Desktop GUI 投影、旧 owner 删除与验证门禁。
## 35. Review Lifecycle Owner
Desktop review 复用 RuntimeCore 的异步 turn admission 和 Thread/Turn/Item canonical lifecycle;它不复制 Codex TUI
的 review UI 或后台入口:
```text
Desktop review gateway
-> App Server JSON-RPC review/start
-> RuntimeCore::start_review
-> admitted Turn (inProgress)
-> enteredReviewMode Extension Item
-> provider/backend review turn
-> exitedReviewMode Extension Item
-> turn.completed
-> v2 ThreadItem projection / GUI timeline
```
`review/start` 是 inline Desktop action。`threadId` 必须命中已加载 sessionactive turn、空 branch/sha/instructions
`delivery=detached` 均 fail closeddetached review 明确不属于 Lime Desktop。base branch、commit sha/title 和 custom
instructions 在 prompt 构造前统一 trim/校验,canonical boundary 与恢复数据只保存规范化后的 target,避免 prompt 与 read
model 分叉。
review admission 立即返回 v2 `turn.status=inProgress`,实际 backend 在 session loop 中异步执行。durable 事件至少保持
`item.started(enteredReviewMode) -> turn.accepted -> item.completed(exitedReviewMode) -> turn.completed` 的 review-specific
顺序;review 输出优先从 assistant message/item 事件聚合,没有输出时使用稳定的 user-facing hint。两个 Extension Item
分别投影为 v2 `ThreadItem::EnteredReviewMode``ThreadItem::ExitedReviewMode`,未知 Extension 继续 fail closed。
v2 protocol/schema、App Server review handler、RuntimeCore review context、canonical/read-model projection、Rust/TypeScript
clients 与 review 定向测试为 `current`。Desktop review gateway 可消费该 current methodElectron 只转发 JSONL,不承接
review runtime。Codex TUI 的 detached/background review、旧 raw side-channel 和未被 Desktop 消费的兼容入口为
`dead / deleted / forbidden-to-restore``compat``deprecated` 均为空。
Architecture impact: major because review now has one cross-layer asynchronous admission, durable boundary Item and v2
projection contract. The product direction remains Electron Desktop Host -> App Server JSON-RPC -> RuntimeCore ->
Thread/Turn/Item projection -> GUI; model/provider behavior remains owned by the Grok-aligned `model-provider` control plane.
Responsible developer confirmation: root, 2026-08-09. Confirmation content: 已核对 review owner、target 规范化、事件顺序、
Desktop/TUI 边界、删除分类和 Rust/contract 验证门禁。真实 Electron Gate B review evidence 已建立:
`.lime/qc/gui-evidence/code-artifact-workbench-electron-fixture/code-artifact-workbench-electron-fixture-summary.json`
证据确认真实 Electron preload/IPC 命中 `app_server_handle_json_lines` 与 typed `review/start`backend `turnId`
raw v2 `enteredReviewMode`/`exitedReviewMode` 及 canonical `thread/read` 同一身份;GUI 显示“代码审查完成:未发现阻塞性问题”
和“审查已完成”,内部 Review prompt 不进入页面文本,生产 mock fallback 命中为零。共享壳证据为
`.lime/qc/project-gates/standalone-shell-01-20260808231556-70202/shell-01-electron-smoke/summary.json`
## 36. Existing Current Method Classification Audit
本轮不新增平行实现,只修正产品范围矩阵中把 current owner 混入 planned 组的分类漂移。以下 13 个 exact method 已有
同方向 generated manifest、真实 owner、typed client/projection 和可追踪证据:
```text
PluginCatalogPage
-> typed pluginCatalog gateway
-> plugin/list | plugin/read | plugin/install | plugin/uninstall | plugin/installed
-> App Server Plugin processor / RuntimeCore PluginDataSource
-> local plugin_catalog
RuntimeCore waiter
-> currentTime/read | item/permissions/requestApproval | item/tool/call
-> Electron Desktop Host / unified PendingInteraction exact responder
-> validated response identity
-> canonical continuation / permission grant / DynamicToolCall Item
runtime.warning | runtime.error | command terminal interaction fact
-> App Server warning | error | item/commandExecution/terminalInteraction
-> typed client / canonical read model / Renderer projection
update_plan completion
-> durable turn.plan.updated fact
-> App Server turn/plan/updated v2 notification
-> typed client / Renderer projection
apply_patch exact Turn delta
-> durable turn.diff.updated fact
-> App Server turn/diff/updated v2 notification
-> typed client / canonical conversation Turn unified_diff
-> Desktop Changes previous-conversation projection
```
基础 Plugin catalog 五个方法已经由 Plugin v3 current owner 承接,并在真实 Electron fixture 中经过
`app_server_handle_json_lines`;这不等于 Plugin share、`plugin/skill/read`、remote catalog watcher 或 hosted connector
readiness 已完成。`currentTime/read` 仍只读取 Host 时钟;`item/permissions/requestApproval` 仍经 tool-runtime
permission parser、App Server exact waiter 和统一 PendingInteractionController 返回 scope-bound grant`item/tool/call`
仍只响应冻结的 Desktop dynamic-tool binding,不开放任意 Electron IPC。typed `warning` / `error` 继续由 durable
runtime fact 和 canonical read model 承接,terminal interaction 只保留 bounded redacted summary。
`turn/plan/updated` 只投影 RuntimeCore producer 的 typed plan fact,不把 Renderer 本地 checklist 或 Tool Item 变成第二事实源。
`turn/diff/updated` 只投影 `apply_patch` 在当前 Turn 内聚合出的精确 unified diff;连续 patch 由 RuntimeCore coding event tracker
校验并合并,未知或不连续 mutation 发送空 diff 清理旧快照。App Server projector 与 typed client 严格拒绝额外字段,Renderer
只把它归并到 canonical conversation Turn 的 `unified_diff`Desktop Changes 在 previous-conversation 模式直接读取该字段。
空字符串是有效 net-zero 结果,不得回退到由 GUI items 拼装的第二份 patch。该链路不复制 Codex TUI,也不改变 provider owner
多模型、多模态 sampling 和媒体 lowering 继续归 Grok-aligned `model-provider`
矩阵中的 `plugin/share/*``plugin/skill/read``guardianWarning` 与其余 review notifications 继续为 `planned`
`item/autoApprovalReview/*` 已由 Guardian current owner 承接;`turn/moderationMetadata` 由下一节 current
主链接管。没有新增 `compat`
`deprecated`;旧 Plugin 私有协议、Renderer 伪造 reverse request、raw diagnostic side-channel、未脱敏 terminal
interaction 和生产 mock fallback 继续为 `dead / deleted / forbidden-to-restore`
`deprecationNotice` 已按 Desktop 产品范围裁决为 `product-scope-excluded`:它是 Codex 开发/设置诊断,不进入
对话通知链;旧实现无外部兼容负担时直接替换或删除,不恢复同名通知包装。
Architecture impact: major; 本节新增了从 Turn-scoped 精确 delta producer、durable event、v2 notification、canonical Turn
到 Desktop Changes 的跨层数据流,并明确空 diff 清理与唯一事实源边界。Responsible developer confirmation: root,
2026-08-09. Confirmation content: 已核对 `apply_patch` 连续 mutation 校验、EventLog/projector 顺序、typed client 严格
解码、canonical Turn 恢复、Desktop/TUI 分界,以及多模型/多模态仍由 Grok-aligned `model-provider` 承接。
## 37. Turn Moderation Metadata Projection
Lime 只从 trusted first-party Responses transport 读取
`response.metadata.openai_chatgpt_moderation_metadata`,不接受第三方兼容端点伪造该字段。SSE 与 WebSocket 共用同一
Responses reducer,产生 provider-neutral `CanonicalLlmEvent::TurnModerationMetadata`Agent runtime 不对该事件去重,
每次 sampling 更新都生成 durable `turn.moderation_metadata` fact。App Server 按事件顺序投影 exact
`turn/moderationMetadata { threadId, turnId, metadata }`,缺少 thread、turn 或 metadata 时 fail closed;显式 `null`
仍是有效 metadata。
```text
trusted first-party Responses response.metadata
-> model-provider CanonicalLlmEvent::TurnModerationMetadata
-> agent-runtime CurrentProviderTurnEvent / AgentEvent
-> durable turn.moderation_metadata
-> App Server turn/moderationMetadata
-> typed client signal router
-> Renderer canonical Turn.moderation_metadata
```
`metadata` 是 opaque JSON value,可以是 object、array、scalar 或 `null`。各层不得猜测供应商私有字段、生成第二份
typed schema 或直接展示 raw JSONRenderer reducer 仅做 last-write-wins,后续不含该字段的 Turn snapshot 必须保留已有
值,cold/hydrate reader 也读取同一 canonical Turn 字段。Codex TUI 当前忽略该通知,Lime Desktop 不复制 TUI UI
Electron 继续只转发 App Server JSONL,不新增 IPC 或第二业务后端。OpenAI moderation metadata 的可信 transport lowering
`model-provider`,但多模型 catalog、默认选择、model switch、provider capability/readiness、retry/circuit breaker 与
多模态 sampling/media lowering 仍由 Grok-aligned control plane 承接。
Architecture impact: major; 本节新增 first-party provider metadata 到 durable Turn projection 的跨层数据流,并固定
opaque JSON、无去重、last-write-wins 与 Desktop/TUI 分界。Responsible developer confirmation: root, 2026-08-09.
Confirmation content: 已核对 SSE/WS 共用 reducer、first-party trust gate、App Server exact wire、canonical Turn 恢复、
Electron 无新增业务边界,以及 Grok-aligned 多模型/多模态 owner 不变。
## 38. Guardian Auto Approval Review Projection
严格自动审查只在当前工具决策已经判定为 `strictAutoReview` 的 shell/`exec_command` 路径触发真实 Guardian
reviewer;它不是用户审批的重命名,也不复制 Codex TUI 的 detached review UI。reviewer 复用当前 session 的
`model-provider` 路由,以无工具结构化采样读取一次风险判断;provider 未就绪、取消、超时、非法 JSON 或不确定结果
均 fail closed 为拒绝。
```text
strictAutoReview tool decision
-> agent-runtime Guardian reviewer (same session model-provider, no tools)
-> AgentEvent guardian_review_started/completed
-> App Server durable event projector
-> item/autoApprovalReview/started|completed
-> typed app-server client / Renderer sequence gate
-> ConversationProjection pending_interactions
```
started 以 `reviewId` 建立 `kind: guardian_review` 的 pending interaction,并携带目标 Item、action 和风险审查快照;
completed 只接受 `agent` decision source 与 `approved|denied|timedOut|aborted` 终态,分别投影为
`resolved|declined|cancelled`。缺失 start、错 thread/turn、额外字段或非终态 completion 均 fail closedReducer 不创建
第二份审批 Item、Message synthesis 或独立 pending store。审查 rationale 是内部 bounded payloadGUI 不展示 provider
原始 JSON 或 prompt。
Electron 继续只转发 App Server JSONL,不新增 IPC 或第二业务后端。Codex TUI 的 detached/background review 不属于
Lime Desktop 产品面;`guardianWarning` 仍是没有真实 producer 的独立 planned notification。Guardian 风险 lowering 归
`model-provider`,而 Grok-aligned 多模型 catalog/default/model switch/provider capability/readiness/retry/circuit
breaker 与多模态 sampling/media lowering owner 不变。
Architecture impact: major;本节新增 Guardian review 从工具决策、provider sampling、durable AgentEvent、v2 notification
到 GUI pending projection 的跨层数据流,并固定 fail-closed 与 Desktop/TUI 边界。Responsible developer confirmation:
root, 2026-08-09。Confirmation content: 已核对 strictAutoReview producer 范围、session provider 复用、超时/取消/非法响应
拒绝语义、App Server typed wire、Renderer pending 状态、Electron 无新增 IPC,以及 Grok-aligned 多模型/多模态 owner
不变。
+89 -2
View File
@@ -85,8 +85,11 @@ Apps/connectors 只允许走同一个 Plugin catalog owner
`src/lib/api/apps.ts -> AppServerClient.request(...) -> app_server_handle_json_lines -> App Server app/* -> RuntimeCore -> PluginDataSource -> local plugin_catalog`
current method 为 `app/list``app/read``app/installed``app/list/updated``app/list` 从已安装 Plugin manifest 的
`apps` capability 构建分页 catalog`app/read` 最多接收 100 个 id,去重并保持首次请求顺序,未知 id 放入
current method 为 `app/list``app/read``app/installed``app/list/updated`Portable
Agent Plugins manifest 不允许顶层 `apps``app/list` 只从显式 Codex
`extensions.com.openai.apps`(或 overlay fallback)指向的独立 Apps JSON 构建分页 catalog
配置项的 connector `id` 是 catalog identity。旧内联 Apps object fail closed;非法 Apps
配置只禁用该组件。`app/read` 最多接收 100 个 id,去重并保持首次请求顺序,未知 id 放入
`missingAppIds`;携带 `threadId` 时必须命中已加载 canonical Thread。`app/installed` 只报告有效 enabled/runtime
state;本地 Plugin 没有 hosted connector model-visible tool snapshot 时,`callable` 强制为 `false`Desktop 不得
把安装或启用状态冒充模型 readiness。`forceRefetch` / `forceRefresh` 在本地 registry 上只是 fresh read,不伪造
@@ -111,6 +114,22 @@ root 并重建受管目录,不删除 Thread/Turn/Item、event log、projection
`memoryStore/reset``MemoryStoreResetParams/Response`、typed client 与设置页调用均为
`dead / deleted / forbidden-to-restore`workspace memory reset 不再作为未被产品消费的平级公开能力保留。
## Command Exec 主链
Codex exact 独立命令执行与 Desktop 交互终端只允许走 connection-scoped App Server JSON-RPC
`src/lib/api/commandExec.ts -> typed App Server client -> command/exec -> App Server CommandExecServer -> tool-runtime local process supervisor`
一次性命令通过 `command/exec` 返回 `exitCode/stdout/stderr`;流式命令通过
`command/exec/outputDelta` 投影 raw bytes 的 `deltaBase64`,并由同一连接内的 `processId` 过滤。交互终端的
输入、PTY 尺寸和终止分别使用 `command/exec/write``command/exec/resize``command/exec/terminate`
`outputBytesCap``timeoutMs` 保持 omitted/null/value 语义;stdin close 后的非空写入、非 TTY resize、零值尺寸、
未知 process id 和同一连接重复 active id 均 fail closed。断连、response 发送失败或 notification writer 失败都清理该
连接拥有的进程。Electron 只转发 App Server JSONL,不持有第二套终端会话、轮询 drain 或 renderer mock fallback。
`project_shell_*``run_project_shell_command`、Project Shell v0 DTO/schema、旧 API gateway 和 Electron 私有
session host 均为 `dead / deleted / forbidden-to-restore`;没有 compat/deprecated wrapper。
## Process Control 主链
Codex exact 子进程控制只允许走 connection-scoped App Server 主链:
@@ -153,3 +172,71 @@ Office/PDF 文本提取不属于 `fs/readFile`;若产品继续需要,应在
`src/lib/api/browserRuntime.ts -> AppServerClient.request(...) -> app_server_handle_json_lines -> App Server browserSession/* -> BrowserRuntimeManager`
Settings 的浏览器页只消费 `browserSession/target/list``browserSession/open``browserSession/read``browserSession/close`Renderer 只展示带 debugger endpoint 的 `page` target。旧 connector install、Chrome relay endpoint、backend priority 与静态 Electron diagnostic facade 不得回到 Settings 产品面。Browser Workspace 尚未迁完的旧 facade 属于 PAGE-08 blocker,不能作为 Settings 或 Browser Runtime current evidence。
## Review 主链
Desktop code review 只允许走 current `review/start`
`src/lib/api/review.ts -> typed App Server client -> app_server_handle_json_lines -> App Server review/start -> RuntimeCore::start_review -> Thread/Turn/Item projection`
请求必须携带真实 `threadId` 和 typed `target``uncommittedChanges``baseBranch``commit``custom`)。App Server
拒绝 detached deliveryRuntimeCore 先检查 session/active turn,再规范化 target 字段并提交异步 turn。响应立即返回
`reviewThreadId``turn.status=inProgress`review 结果通过同一 thread 的 canonical events/read model 回流 GUI。
review boundary 使用 `enteredReviewMode` / `exitedReviewMode` Extension Item,分别投影为 v2 `EnteredReviewMode` /
`ExitedReviewMode`,并在 turn terminal 前完成退出 item。Renderer 不扫描工作区猜测 review 状态,不创建第二套
review transcript,也不把 Codex TUI detached/background review 伪装成 Desktop 能力。
旧 review facade、raw `agentSession/event` review side-channel、detached/background 入口和生产 mock fallback 均为
`dead / deleted / forbidden-to-restore`;没有 compat/deprecated wrapper。该边界的最低验证是
`cargo test -p app-server processor::thread::projection::tests``cargo test -p app-server processor::tests::review`
`npm run test:contracts`。真实 Electron Gate B evidence 已建立于
`.lime/qc/gui-evidence/code-artifact-workbench-electron-fixture/code-artifact-workbench-electron-fixture-summary.json`
证明 preload/IPC 命中 `app_server_handle_json_lines``review/start` 与 backend turn identity 绑定,GUI 可见终态与
内部 prompt 隔离,且无生产 mock fallback;不得用 TUI 或浏览器投影冒充该证据。
## Host Reverse Requests, Plan And Diff Notifications
`currentTime/read``item/permissions/requestApproval``item/tool/call` 使用同一 App Server server-request dispatcher
```text
RuntimeCore waiter
-> App Server JSON-RPC server-request
-> Electron Desktop Host / PendingInteraction responder
-> exact response id
-> RuntimeCore continuation
```
`currentTime/read` 只能由 Electron Host 读取系统时钟,App Server 负责 thread scope、超时和响应校验;它不创建
Thread Item,也不提供 Renderer 时钟 API。`item/permissions/requestApproval` 只接受 tool-runtime 规范化后的
permission profile 和 canonical session/thread/turn/item/environment identity;统一 `PendingInteractionController`
只能返回 turn/session-scoped grant 或空 grant,不能扩大请求权限。`item/tool/call` 只能命中
`thread/start`/`thread/resume` 后冻结的 Desktop dynamic-tool binding,调用 identity、namespace、tool 和参数必须逐项
匹配;结果由 canonical DynamicToolCall Item 投影,Renderer 不得伪造 server request 或直接执行宿主能力。
`turn/plan/updated` 是 RuntimeCore `update_plan` producer 生成的 server notification,经 App Server v2 projector、
typed client 和 Renderer projection 进入同一 Thread/Turn/Item read model。计划 snapshot 的权威 owner 是 canonical
Plan ItemRenderer 本地 checklist 只做投影,不得替代 durable plan fact。
`turn.diff.updated` 是 RuntimeCore `apply_patch` coding event producer 在 Turn 范围内聚合精确 mutation 后生成的 durable
fact,经 App Server JSON-RPC projector 投影为 exact `turn/diff/updated { threadId, turnId, diff }`,再由 typed client
和 Renderer conversation reducer 写入 canonical Turn 的 `unified_diff`。Desktop Changes 的 previous-conversation 模式只
消费该字段;空字符串是有效 net-zero 清除信号,不得回退到本地 patch 拼装或第二份 diff store。Renderer 不承接 Codex
TUI 的 review surfaceElectron 只做既有 Desktop Host JSONL 转发,不新增业务后端。
这条通知的 owner 是 App Server JSON-RPC + RuntimeCore durable event 链,不是 Electron IPC、旧 facade 或 provider。
多模型 catalog、model switch、provider capability/readiness、retry/circuit breaker 和多模态 sampling/media lowering
继续归 Grok-aligned `model-provider`Codex 对齐只覆盖 Agent loop、Thread/Turn/Item、工具生命周期和 GUI 投影边界。
`turn.moderation_metadata` 是 trusted first-party Responses metadata producer 生成的 durable fact,经 App Server
JSON-RPC projector 投影为 exact
`turn/moderationMetadata { threadId, turnId, metadata }``metadata` 必须原样保持 JSON valueobject、array、scalar 与
`null` 都有效,缺失字段或 wrapper 额外字段 fail closed。该事件不去重,每次更新都经 typed client signal router 写入
canonical Turn 的 `moderation_metadata`Renderer 只做 last-write-wins 且不展示 raw JSON。Electron 不新增 IPCCodex
TUI 忽略该通知的行为不复制为 Desktop UI;多模型与多模态控制面仍由 Grok-aligned `model-provider` 承接。
runtime diagnostics 与 command terminal interaction 只允许走 typed server notification`runtime.warning` / `runtime.error`
由 App Server 分别投影为 `warning` / `error`live 与 cold read 共用 durable event owner`error.willRetry` 不直接生成
Turn terminal。`item/commandExecution/terminalInteraction` 只发送脱敏、bounded summary,并与 canonical
CommandExecution read model 合并。raw diagnostic side-channel、未脱敏 stdin/stdout 和 Renderer 自建 terminal history
均为 `dead / forbidden-to-restore`
@@ -3732,3 +3732,324 @@ Plugin/Workflow 实现。分类与进度:exact `fs/*`、FsServer、connection-
3. `agentSession`/`protocol/v0`/`lime-providers` 不再是 production current surface
4. 所有产品范围内的 transport、method、Item、MCP、Multi-Agent、environment 和 evidence contract 有实现与验证,排除项有明确删除守卫;
5. Gate A/B、workspace compile、治理扫描和回流 guard 全部通过。
### 2026-08-08 Codex exact `command/exec*` current slice
目标:将 Codex standalone `command/exec``command/exec/{write,resize,terminate}`
`command/exec/outputDelta` 接入 Lime Desktop 的 App Server JSON-RPC current 主链。该能力不是
Thread/TUI 专属:Desktop coding terminal 需要独立、connection-scoped 的 PTY/stdio 控制,但不得
继续使用 Electron `project_shell_*`、旧 v0 DTO 或轮询 drain 协议。
窄写集:`app-server-protocol` v2 command schema/envelope、App Server command processor 与
connection notification hook、typed package/Renderer gateway、Electron command forwarder、旧
Project Shell UI/bridge 删除、产品范围矩阵、架构与治理回流守卫。避让发布、provider、Plugin、OEM
与其它并行未完成写集。
退出条件:
1. exact command request/response/notification shape 与 Codex 当前协议一致;process id 只在
originating ConnectionId 内有效,断连终止进程,output notification 在最终 response 前发出。
2. Desktop terminal 只通过 App Server JSON-RPC current gateway 工作;生产代码零引用
`project_shell_*``run_project_shell_command`、旧 project shell v0 method。
3. protocol schema/generated client、App Server lifecycle、Renderer/Electron contract 和
negative governance guard 同步,矩阵四个 client method 与 notification 从 `planned` 移入
`implemented`
4. 定向 Rust/TypeScript/contract/governance/GUI smoke 验证通过;若某项受环境阻断,记录具体原因。
完成结果:Codex exact `command/exec``command/exec/write``command/exec/resize``command/exec/terminate`
`command/exec/outputDelta` 已进入 v2 protocol/schema、App Server `CommandExecServer`、连接生命周期清理、typed
package client、Renderer `commandExec` gateway 和 Desktop xterm terminal。一次性 stdout/stderr、流式 raw bytes、
stdin close、PTY resize、terminate、连接隔离、重复 id、output cap 与 timeout 均有 Rust owner 测试;timeout 退出码固定
`124`。Renderer 仅发送 base64 stdin,按 processId 过滤 outputDelta,卸载时终止 originating connection 的进程。
直接替换结果:旧 Project Shell Rust DTO/processor/schema、Electron 私有 IPC/host、Renderer gateway、session reconnect
语义、明文 stdin 和相关正向 fixture 已物理删除;未新增 compat/deprecated wrapper。旧命令名只保留在负向回流 guard、
历史 execution plan 和 immutable evidence。
验证证据:`cargo check -p app-server-protocol``cargo check -p app-server`、App Server command/exec Rust 定向测试
(含 output cap/timeout)通过;`npx vitest run "src/components/agent/chat/components/TaskCenterUtilityToolbar.integration.test.tsx" "src/lib/api/commandExec.test.ts"`
`36/36``npm run typecheck` 通过。相关 `npm run test:related` 的 smart runner 曾因把 `electron/` 目录误作输入触发
Vite `EISDIR`,已改用直接文件 runner;该 runner 错误不计为产品测试失败。contracts、治理、GUI smoke 和全量 fmt/diff
仍是本刀收尾门禁。
分类与进度:exact command/exec protocol、App Server owner、connection cleanup、typed clients、Renderer gateway、
Desktop terminal 和负向 guard 为 `current``compat``deprecated` 均为空;旧 Project Shell surface 为
`dead / deleted / forbidden-to-restore`。产品范围矩阵由 `108 implemented / 77 planned / 35 product-scope-excluded`
更新为 `113 implemented / 72 planned / 35 product-scope-excluded`,产品范围完成度 `113 / 185 = 61.1%`。架构影响:重大;
`internal/aiprompts/architecture.md` 第 6.1、33.1 节与 `internal/aiprompts/commands.md` 已同步,责任开发者 root
确认唯一 owner、跨层数据流、ConnectionId 边界、协议顺序、删除边界和验证门禁。
下一刀回到剩余 P1 current owner,优先 review lifecycle 或 hosted connector readiness;不得恢复 Project Shell、旧
`executionProcess/*`,也不得把 connection-scoped processId 与 Thread command item identity 混用。
### 2026-08-09 Codex exact `review/start` Desktop lifecycle slice
目标:继续按 Codex review lifecycle 对齐 Lime Desktop 的 `review/start`,保留 Desktop GUI 形态,不复制 Codex TUI
detached/background review;多模型与多模态控制面仍分别归 Grok-aligned `model-provider` 和 canonical content lowering。
窄写集:RuntimeCore review admission/context、App Server review handler、canonical/read-model/v2 ThreadItem projection、
Rust processor/runtime tests,以及 architecture/commands 事实源。Electron 只作为既有 JSONL Desktop Host 转发边界;不新增
第二 runtime、review transcript store、provider fallback 或 compat wrapper。
完成结果:`review/start` 先校验真实 thread/session 和 active turn,规范化 branch/sha/title/instructions 后异步提交
turn,立即返回 v2 `inProgress`。detached delivery 在 Desktop 明确 fail closed。review boundary 以
`enteredReviewMode` / `exitedReviewMode` Extension Item 写入 canonical event logreview output 优先收集 assistant
message/item 文本,没有输出时回退稳定 hintv2 projection 分别返回 `EnteredReviewMode``ExitedReviewMode`
未知 Extension 保持 fail closed,不被 review-specific 缺字段错误遮蔽。
根因与修复:GUI 监听建立晚于快速 Review 终态导致结果丢失;Workspace admission 后本地 `starting` 未复位;内部
Review prompt 被错误投影为普通用户消息。`src/lib/api/review.ts` 现在在 admission 前订阅同 thread 的
`agentSession/event/<threadId>`,捕获 `turn_completed`/`turn_failed`/`turn_canceled`、快速终态、请求失败和超时并解除
监听;Workspace 两个 Review 调用点在 admission 与 terminal 都刷新 canonical read modelCodeReviewSummaryPanel 与
Canvas Changes panel admission 后复位 `starting`RuntimeCore 通过内部 `review.input``visibility=agent_only`
`source=review`)把 prompt 留在 provider history,不生成普通 `user_visible message.created`。Electron fixture 增加
Review 专用 `message.delta -> message.completed -> turn.completed` 序列和 prompt 不可见、raw v2 boundary 与 backend
`turnId` 绑定断言。
定向验证:`cargo test -p app-server processor::thread::projection::tests` `20/20`
`cargo test -p app-server processor::tests::review` `4/4`、Review gateway `9/9`、CodeReviewSummaryPanel `20/20`
Canvas Workbench coding `10/10`、Electron fixture guard `8/8`、聚合 Vitest `47/47``npm run typecheck`
`node --check``cargo fmt --manifest-path "lime-rs/Cargo.toml" --all -- --check` 均通过。最终协议/治理门禁
`npm run check:protocol-types``npm run test:contracts`301 checks)、`npm run governance:legacy-report`2112 文件,
零引用候选/分类漂移/边界违规均为 0)、`npm run governance:scripts` 均通过。`npm run smoke:agent-runtime-current-fixture`
全量通过,`liveProviderUsed=false``npm run verify:gui-smoke` 通过,证据为
`.lime/qc/project-gates/standalone-shell-01-20260808231556-70202/shell-01-electron-smoke/summary.json`
专项 Review Gate B 证据为
`.lime/qc/gui-evidence/code-artifact-workbench-electron-fixture/code-artifact-workbench-electron-fixture-summary.json`
真实 Electron/preload/IPC 命中 `app_server_handle_json_lines``review/start`canonical session/turn identity、
`enteredReviewMode`/`exitedReviewMode`、backend terminal、GUI 审查结果和内部 prompt 隔离断言全部通过,mock fallback 为零。
早期 `npm run test:related` smart runner 将 `electron/` 目录当文件导致 `EISDIR`,已改用精确 Vitest 文件 runner;不属于
Review 用例失败。
分类与进度:review/start v2 method、RuntimeCore admission、canonical boundary、read model/v2 projection、typed clients、
Desktop GUI gateway 与 Gate B evidence 为 `current``compat``deprecated` 均为空;旧 detached/background/raw
review side-channel 与未消费 facade 为 `dead / deleted / forbidden-to-restore`。command/exec 旧 Project Shell surface
同样保持 `dead / deleted / forbidden-to-restore`。产品范围矩阵已同步为 `114 implemented / 71 planned / 35
product-scope-excluded`,完成度 `114 / 185 = 61.6%`。架构影响:重大;architecture 第 35 节已记录真实 Gate B
证据、进程边界、identity 绑定和无 mock fallback,责任开发者 root 已确认。
下一刀:回到剩余 P1 current owner,优先 hosted connector model-visible tool snapshot / `callable=true` provider
readiness;不得恢复 TUI detached review、旧 raw review side-channel、Project Shell 或 compat wrapper。
### 2026-08-09 existing current method classification audit
目标与窄写集:继续清点 Codex exact method 矩阵,纠正已经存在 current owner、同名 generated manifest、typed
client/projection 与真实证据,却仍混在 planned 组中的分类漂移。本刀只修改产品矩阵、架构/命令事实源和本执行记录;
不改 Plugin/Provider/Workspace 业务热区,不新增 Electron backend、TUI surface 或 compat wrapper。
核验结果:
1. `plugin/list``plugin/read``plugin/install``plugin/uninstall``plugin/installed` 已接入 App Server Plugin
processor、RuntimeCore PluginDataSource、local `plugin_catalog`、typed package/Renderer gateway,并由真实 Electron
`mcp-elicitation-gate-b` 覆盖完整 list/install/read/installed/uninstall 生命周期。
2. `currentTime/read` 已接入 v2 server-request manifest、App Server exact-id waiter、Electron Host clock responder、
timeout/range/invalid-response Rust 测试和 Host drain 隔离测试;它不暴露 Renderer clock API。
3. `item/tool/call` 已接入 v2 dynamic-tool contract、RuntimeCore waiter、冻结的 Desktop `desktop.appInfo` binding、
canonical DynamicToolCall Item/read model 和 Electron Gate Breverse request 不泄漏到 Renderer。
4. `turn/plan/updated` 已由 RuntimeCore `update_plan` producer 生成 durable fact,经 App Server v2 projector、typed
package notification、Renderer projection 与 current fixture 投递。
5. `item/permissions/requestApproval` 已接入 tool-runtime permission parser、App Server exact-id waiter、RuntimeCore
grant response 和统一 PendingInteractionControllerprofile、cwd、environment 与 response identity 均 fail closed。
6. `warning` / `error` 已接入 durable runtime producer、App Server v2 projector、canonical read model、typed client 和
Renderer projectiontyped error 的 retry success/failure 已有真实 Electron fixture guard。
7. `item/commandExecution/terminalInteraction` 已接入 command completion producer、脱敏摘要、v2 notification、cold
read merge 与 Renderer bounded projection。
矩阵拆组后,基础 Plugin catalog 五个方法、三个 reverse request、typed `warning`/`error`、command terminal
interaction 和 `turn/plan/updated``planned` 移入 `implemented`Plugin share/skill-read、deprecation/Guardian、
auto-approval review、`turn/diff/updated``turn/moderationMetadata` 继续保持 planned。计数从
`114 implemented / 71 planned / 35 product-scope-excluded` 更新为
`126 implemented / 59 planned / 35 product-scope-excluded`,产品范围完成度为 `126 / 185 = 68.1%`
验证结果:产品范围矩阵、Plugin gateway、Electron current-time/dynamic-tool Host 与 Renderer plan projection 的精确
Vitest `57/57`Apps/Plugin Electron fixture guard 与 current agent fixture guard `86/86`permission/error/terminal/matrix
五组回归 `137/137`。Rust App Server `current_time` `5/5``turn_plan` `6/6``dynamic_tool_server_request` `1/1`
permission request `1/1`tool-runtime permission `2/2`agent-runtime permission `3/3`runtime warning `3/3`、error
`5/5`、terminal interaction `2/2``app-server-protocol` 全量 `110/110`
`item/commandExecution/terminalInteraction` 原有 producer、projector、typed client 与 Renderer projection,但
`v2::NOTIFICATION_METHODS` 中央 catalog 漏列 exact method,导致 generated manifest 未覆盖该 notification;本刀已补入
catalog,并重新生成 schema bundle 与 TypeScript protocol types。严格串行执行 `npm run generate:protocol-types`
`npm run check:protocol-types` 后确认 generated file 无 drift;最终 `npm run test:contracts` 全通过(App Server client
`301 checks`command、modality、scripts、Electron release、cleanup 与 docs boundary 全绿)。
`npm run governance:legacy-report` 扫描 `2112` 个 current 文件与 `1376` 个测试文件,零引用候选、分类漂移和边界违规
均为 `0``git diff --check` 通过。本刀没有改变 GUI、Bridge 或 Runtime 行为,因此不重复运行 `verify:gui-smoke`
真实 Electron coverage 复用并由 tracked guard 锁定的 Apps/Plugin 与 MCP elicitation Gate B。
早期使用 Node 原生 test runner 执行三个 Vitest 文件触发 runner state 错误,已用正确的 Vitest runner 重跑并全部通过;
另一次并行运行 protocol generator/check 触发 generated file 恢复竞态,改为严格串行生成与检查后消除。两者均属于
执行入口问题,不是产品失败。
分类:上述 12 个 exact method、current owners、typed clients/projections 与现有 Gate B/fixture 为 `current`;无新增
`compat``deprecated`;旧 Plugin 私有协议、Renderer 伪造 reverse request 与生产 mock fallback 继续为
`dead / deleted / forbidden-to-restore`。架构影响:无,本刀只让矩阵与既有架构一致;architecture 第 36 节已记录
核验边界,责任开发者 root 确认。下一刀回到真正未完成的 P1 surface,优先 deprecation/Guardian、auto-approval
review 或 remaining review notification;多模型和多模态继续由
Grok-aligned `model-provider` catalog/capability/readiness/sampling owner 承接。
### 2026-08-09 `turn/diff/updated` Desktop Changes slice
目标与窄写集:把 Codex Turn 级精确代码变更事件接入 Lime Desktop 唯一主链,完成
`apply_patch -> durable turn.diff.updated -> v2 turn/diff/updated -> typed client -> canonical Turn -> Desktop Changes`
闭环。本刀只修改 `tool-runtime` apply-patch metadata 与 App Server coding-event/projector、v2 protocol/schema、typed
package client、Renderer canonical conversation projection、Changes 工作台接线、产品范围矩阵和架构/命令事实源;不修改
Electron Host 业务边界、Provider、Command Exec、Review、Plugin/MCP 热区,不恢复 Codex TUI,也不新增 compat wrapper。
实现结果:
1. `apply_patch` 为 Add/Delete/Update/Move 记录内部 Turn-scoped mutation metadatatracker 校验连续 old/new 内容并在
Turn 内聚合精确 unified diff,支持纯 rename 与 net-zero。未知或不连续 mutation 会 invalidate 并发送空 diff 清理旧快照;
原始 tool item 持久化前剥离内部 metadata。
2. Runtime durable `turn.diff.updated` 经 App Server v2 projector 发出严格 Codex shape
`turn/diff/updated { threadId, turnId, diff }`。typed client、schema、Renderer notification parser 与 sequence gate 已同步,
额外字段 fail closed。
3. Renderer 将通知归并为 canonical conversation `Turn.unified_diff`;后续 `turn_started`/`turn_completed` 快照缺少 diff
时保留已有值,空字符串保留为精确 net-zero。runtime handler 只回写 canonical Turn,不创建第二份 diff store。
4. Desktop Changes 从当前 canonical Turn 读取 `turnDiff`。previous-conversation 复制 `git apply` 时只要该字段已定义就
优先使用精确 diff,即使为空也不回退到组件根据 item 拼装的 patchGit branch/commit/unstaged 基准继续读取 Git backend。
事实源分类:`tool-runtime` coding tracker、App Server durable/projector、v2 protocol/schema、typed client、canonical Turn
projection 与 Desktop Changes 为 `current`;旧组件级 patch 拼装仅作为无 canonical diff 的历史 fixture fallback,不能覆盖已
定义的空 diff;不存在 compat/deprecated 新路径。Codex TUI review/diff UI、Renderer 第二 diff store 和生产 mock fallback
属于 `dead / deleted / forbidden-to-restore`。多模型、多模态控制面仍由 Grok-aligned `model-provider` owner 承接。
矩阵同步:将 `turn/diff/updated``review-notification-planned` 拆出为 `turn-diff-notification-current`,计数更新为
`127 implemented / 58 planned / 35 product-scope-excluded`,产品范围完成度 `127 / 185 = 68.6%``turn/moderationMetadata`
仍为 planned。
验证与退出条件:
- Rust 定向:`tool-runtime` apply-patch 回归、App Server coding tracker/projector/notification tests 通过。
- Protocol/schematurn-diff round-trip、schema registry、`npm run generate:protocol-types``npm run check:protocol-types` 通过。
- Typed/Rendererapp-server-client 85/85`npm run typecheck`V2 notification/drift/conversation projection 与工作台 view-model
回归通过;补 previous-conversation 精确 diff 优先级测试。
- 本轮收尾门禁:`npm run test:contracts``npm run test:rust:related -- <turn-diff paths>`
`npm run smoke:agent-runtime-current-fixture``npm run governance:legacy-report``npm run verify:gui-smoke`;若 GUI
fixture 环境阻塞,记录具体原因,不以浏览器投影替代 Gate B。
下一刀:回到 remaining P1 review surface,优先 `turn/moderationMetadata` 或 deprecation/Guardian/auto-approval review
notifications;不得恢复 TUI detached review、旧 raw side-channel 或 provider 平行 owner。
### 2026-08-09 `turn/moderationMetadata` canonical Turn slice
主目标与窄写集:把 Codex trusted first-party Responses moderation metadata 接入 Lime Desktop 唯一 Agent 主链,完成
`Responses metadata -> model-provider canonical event -> agent-runtime -> durable event -> App Server exact notification ->
typed client -> canonical Turn`。本刀只修改 provider/runtime/agent 事件、App Server v2 protocol/projector/schema、typed
package client、Renderer canonical projection、产品矩阵和架构/命令事实源;不新增 Electron IPC、TUI UI、raw metadata
展示、provider 平行 owner、mock fallback 或 compat wrapper。
实现结果:
1. `model-provider` 仅在 trusted first-party Responses route 读取
`response.metadata.openai_chatgpt_moderation_metadata`。SSE 与 WebSocket 复用同一 reducer;第三方兼容 route 不产生
moderation event。metadata 保持任意 JSON,包括 object、array、scalar 和 `null`
2. `CanonicalLlmEvent::TurnModerationMetadata``CurrentProviderTurnEvent``AgentEvent` 映射为 durable
`turn.moderation_metadata`。该事件跨 sampling step 不去重,每次更新均保留;provider proxy 的 OpenAI/Anthropic 输出
转换器明确忽略它,不泄漏 raw metadata。
3. App Server 投影 exact
`turn/moderationMetadata { threadId, turnId, metadata }`;缺少 identity/metadata fail closedwrapper 额外字段被拒绝,
`null` 是有效值。typed client signal router、direct notification routing、sequence gate 和 drift catalog 已同步。
4. Renderer 将 opaque metadata 归并到 canonical `Turn.moderation_metadata`,按 last-write-wins 更新。后续未携带该字段的
Turn snapshot 不覆盖既有值,cold/hydrate reader 使用同一字段;没有新增用户可见 raw JSON surface。
事实源分类:trusted Responses lowering、provider-neutral event、Agent durable event、App Server exact protocol/projector、
typed client 与 canonical Turn projection 为 `current``compat``deprecated` 均为空;第三方 metadata 冒充、TUI
surface、Electron 第二业务后端、raw side-channel 与生产 mock fallback 为 `dead / forbidden-to-restore`。Grok-aligned
`model-provider` 继续拥有多模型 catalog/default/model switch/capability/readiness/retry/circuit breaker 与多模态 sampling。
矩阵同步:`turn/moderationMetadata` 从 planned 移入 implemented,更新为
`128 implemented / 57 planned / 35 product-scope-excluded`,产品范围完成度 `128 / 185 = 69.2%`。整体 Codex 对齐仍未
完成,本刀不关闭总执行计划。
验证结果与退出条件:
- Rust`model-provider` reducer `7/7``agent-runtime` metadata sampling `1/1``lime-agent` serde `1/1`、App Server
moderation projector `2/2``app-server-protocol` `112/112` 通过;`cargo check -p lime-server` 通过。
- Protocol/schemaschema 先生成到临时目录,与仓库 schema 树逐文件一致;`npm run generate:protocol-types`
`npm run typecheck` 通过。
- Typed/Rendererapp-server-client `113/113`moderation notification/drift/timeline 三文件 `47/47` 通过。
- 执行入口记录:Node 原生 test runner 无法运行 Vitest 文件,改用 package 正式入口后通过;`test:related` smart runner
因把 `electron/` 目录当文件读取而报 `EISDIR`,改用精确 Vitest 文件 runner 后通过,均非产品断言失败。
- 收尾门禁已完成:`npm run test:contracts` 全绿(App Server client `301 checks`)、相关 Rust related layer 全绿(含
`lime-server` 的 provider metadata non-leak 分支)、`npm run smoke:agent-runtime-current-fixture` 通过且
`liveProviderUsed=false``npm run governance:legacy-report` 扫描 `2112`/`1376` 文件并保持零引用候选/分类漂移/边界违规、
`npm run verify:gui-smoke` 通过并生成真实 Electron/App Server evidence。矩阵守卫 `4/4``git diff --check` 也通过;GUI
本刀无新增可见 surfaceGate B 复用现有 Electron/App Server current 主链。
架构影响:重大;`internal/aiprompts/architecture.md` 第 37 节已记录跨层数据流与边界。Responsible developer
confirmation: root, 2026-08-09. 已确认 first-party trust、SSE/WS、opaque JSON、无去重、last-write-wins、Desktop/TUI
分界、Electron 无新增 IPC,以及 Grok-aligned 多模型/多模态 owner 不变。
下一刀:继续 remaining planned method,优先 deprecation/Guardian/auto-approval review notification;不得恢复旧 raw
metadata 通道、TUI review UI、Provider 平行 owner 或兼容包装。
### 2026-08-09 `deprecationNotice` Desktop 产品范围清退
本轮先处理下一项候选中的分类漂移,而不是为没有 runtime producer 的诊断通知造协议壳。Codex 的
`deprecationNotice` 是开发/设置诊断;V2 投影事实源已经将它标为 `product-scope-excluded`Lime Desktop
没有对话或全局通知消费者,也没有外部兼容负担。`guardianWarning` 仍因缺少真实 Guardian review producer
保持 `planned``item/autoApprovalReview/*` 也不借现有用户审批或 `strictAutoReview` 标记冒充。
改动:将 V1 fixture 的 diagnostics planned 组拆为 `guardian-notification-planned`
`deprecation-notification-excluded`,同步 `inventory.byStatus`、产品范围矩阵和架构事实源。当前分类为
`128 implemented / 56 planned / 36 product-scope-excluded`,产品范围完成度仍按
`128 / (128 + 56) = 69.6%` 计算;总上游 inventory 仍为 220 个方向化 identity。无新增 `current``compat`
`deprecated` 路径;deprecation surface 为 `product-scope-excluded`,现有旧实现若出现则按
`dead / deleted / forbidden-to-restore` 处理。
验证退出条件:V1 method scope boundary、`npm run test:contracts``npm run governance:legacy-report`
`git diff --check` 通过;本轮未新增运行时/GUI 行为,不重复执行 Electron Gate B。下一刀回到有真实
producer 的 current owner,优先先完成 Guardian review producer/lifecycle,再接
`item/autoApprovalReview/{started,completed}` 的 exact Codex wire;不得恢复 TUI detached review 或兼容包装。
### 2026-08-09 V2 投影事实源漂移复核
本轮只收文档事实源,不新增协议或 compat surface。`internal/refactor/v2/EVENT-PROJECTIONS.md` 已同步
current owner`hook/started``hook/completed` 是 Tool runtime 的 paired transient lifecycle,不创建
canonical ThreadItem`turn/diff/updated` 是 Lime exact Turn diff,经 canonical Turn/Changes 共用快照;
`turn/moderationMetadata` 已由 trusted first-party Responses metadata 完成 `model-provider -> AgentEvent ->
durable event -> v2 notification -> typed client -> canonical Turn` 主链。`guardianWarning` 与
`item/autoApprovalReview/{started,completed}` 仍为 `planned`:当前没有 Guardian 第二模型 reviewer、风险决策、
取消/超时状态或真实 producer,现有用户审批和 `strictAutoReview` 不得冒充。
分类:文档修正为 `current` 的 Hook/Turn diff/moderation 继续由既有 owner 承接;无新增 `compat`
`deprecated``dead` surface。验证:`git diff --check`;后续涉及实现时必须回到 tool-runtime +
model-provider + agent-runtime + App Server 这条唯一 Guardian 主链,并补 Rust owner 集成、typed protocol/client、
Renderer pending/timeline 与 Electron Gate B 证据后才能更新矩阵状态。
### 2026-08-09 Guardian auto-approval review current owner 收口
本轮完成上一条计划中的 Guardian auto-approval review 主链,产品目标仍是 Lime DesktopCodex TUI 的 detached/background
review、raw side-channel 和第二套 Electron 业务后端不进入产品。唯一事实源为:
`strictAutoReview -> agent-runtime Guardian reviewer -> current session model-provider -> AgentEvent -> App Server v2 notification -> typed client -> Renderer ConversationProjection`
实现结果:
1. `agent-runtime` 新增真实 Guardian reviewer,复用当前 session 的 `model-provider` 做无工具结构化采样;provider 不可用、取消、30 秒超时、非法 JSON 和不确定结果均 fail closed。结果只允许 `approved`/`denied`,并带风险、授权、rationale 和 action 摘要。
2. durable `guardian_review_started/completed` AgentEvent 经 App Server v2 projector 投影为 exact
`item/autoApprovalReview/started``item/autoApprovalReview/completed`typed protocol/schema、manifest、generated
TypeScript、strict decoder、lifecycle union、drift registry 和 sequence gate 同步更新。
3. Renderer `ConversationProjection` 将 started 投影为 `pending_interactions`approved/denied/timedOut/aborted
分别投影为 resolved/declined/cancelledcompleted `inProgress` 被 App Server projector 拒绝。可选 Guardian 字段现在
对“字段存在但类型非法”与“字段缺失”严格区分,前者 fail closed。
4. V1 方法矩阵将两个 `item/autoApprovalReview/*``planned` 移入 `implemented`,当前统计为
`130 implemented / 54 planned / 36 product-scope-excluded`,产品范围完成度 `130 / 184 = 70.7%``guardianWarning`
仍为 `planned`,因为没有独立的高优先级 warning producer,不能由 Guardian review lifecycle 冒充。
分类:Guardian reviewer、AgentEvent、App Server v2 projector、typed client、Renderer pending/timeline projection 为
`current`;无 `compat` 或新增 `deprecated`TUI detached review、raw side-channel、生产 mock fallback 和旧审批冒充
Guardian 均为 `dead / deleted / forbidden-to-restore`。Grok-aligned `model-provider` 继续拥有多模型 catalog/default/model
switch/capability/readiness/retry/circuit breaker 与多模态 sampling,不复制 Codex TUI 控制面。
本轮退出条件已全部通过:`npm run check:protocol-types`、app-server-client build、`npm run typecheck`、Guardian/Rust/Renderer
定向回归、`npm run test:rust:related -- lime-rs/crates/app-server-protocol lime-rs/crates/app-server lime-rs/crates/agent lime-rs/crates/agent-runtime lime-rs/crates/model-provider lime-rs/crates/tool-runtime`
`npm run test:contracts`301 checks)、`npm run governance:legacy-report`0 引用候选/分类漂移/边界违规)、
`git diff --check``npm run smoke:agent-runtime-current-fixture``liveProviderUsed=false`)与
`npm run verify:gui-smoke`standalone shell evidence`.lime/qc/project-gates/standalone-shell-01-20260809110637-94994/shell-01-electron-smoke/summary.json`)。
矩阵守卫最初拦截了 manifest 漏列 `item/autoApprovalReview/completed`;已补入 v2 `NOTIFICATION_METHODS` 中央 catalog
重新生成 manifest/schema/generated TypeScript 后矩阵守卫 `4/4` 与协议 `112/112` 通过。
下一刀:回到 remaining planned producer/consumer,优先补 `guardianWarning` 的独立真实 producer 或其他 P1 current owner
不得恢复 TUI detached review、旧 raw side-channel、生产 mock fallback 或 compat wrapper。
@@ -0,0 +1,41 @@
# Lime v1.125.0 发布执行计划
状态:release-candidate
日期:2026-08-09
目标版本:`1.125.0`
目标 tag`v1.125.0`
## 主目标
在不覆盖已发布的 `v1.124.0` tag 的前提下,发布当前工作树中的 Agent runtime、App Server/protocol、Plugin v3、GUI、文档与质量治理改动。
## Release Candidate
- `release metadata`:根 `package.json``packages/lime-cli-npm/package.json``lime-rs/Cargo.toml``lime-rs/Cargo.lock``RELEASE_NOTES.md``RELEASE_NOTES.en.md`、本计划。
- `candidate changes`:当前工作树全部已跟踪和未跟踪改动,包括 Agent runtime、App Server/protocol、Plugin v3、Electron/GUI、测试、治理和文档。
- `excluded changes`:无;用户已明确确认当前工作树整体纳入。
## 退出条件
-`README.md` 为英文 canonical 入口,英文页面无二维码,中文页面保留二维码。
- 版本事实源与双语 release notes 统一到 `1.125.0`,不覆盖 `v1.124.0`
- 通过版本一致性、typecheck、docs boundary、contracts、GUI smoke 或明确记录环境限制。
- 完成 release commit、`v1.125.0` tag、`main`/tag 推送和远端复核。
- 针对发布 commit SHA 触发 `.github/workflows/build-windows-test.yml`,轮询 Windows runner 直至完成并保存 artifact 结果。
## 验证记录
- `npm run verify:app-version`:通过,所有版本事实源为 `1.125.0`
- `npm run typecheck`:通过。
- Guardian projection Vitest`54/54` 通过。
- `npm run test:contracts`:通过。
- `npm run docs:boundary`:通过。
- `npm run governance:legacy-report`:通过,零引用候选、分类漂移、边界违规均为 `0`
- `npm run governance:scripts`:通过。
- `npm run governance:electron-release-workflow`:通过。
- `npm run verify:gui-smoke`:通过;Electron evidence `standalone-shell-01-20260809113946-74365`App Server `1.125.0`
- `npm run test:rust:related -- lime-rs/crates/app-server lime-rs/crates/mcp lime-rs/crates/skills lime-rs/crates/runtime-core lime-rs/crates/tool-runtime`:通过,`311 passed; 0 failed`
- `npm run smoke:agent-runtime-current-fixture`:通过,覆盖当前 Agent runtime 全部 fixture;报告 `liveProviderUsed=false`
- `git diff --check`:通过。
- Release commit/tag/push:待执行。
- Windows runner:待触发并轮询。
@@ -17,12 +17,12 @@ legacy 同义命令冒充协议对齐。矩阵覆盖 `clientRequest`、`serverRe
## 当前盘点
| 状态 | 数量 | 裁决 |
| ------------------------ | ---: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `implemented` | 108 | 连接握手、核心 Thread/Turn/Item、durable ordered Thread Section、thread subscription/lifecycle/content search/raw item injection/background terminals/elicitation/Guardian continuation、Plugin Search、Hook discovery/lifecycle notifications、Skills list/config/extra roots/watcher、Apps exact catalog/read/installed 与 typed `app/list/updated` watcher、exact memory reset、connection-scoped process lifecycle、exact fs IO/watch、exact MCP resource/tool request/lifecycle notifications、typed approval/MCP server request 与 model control plane |
| `planned` | 77 | 其余 Plugins、config、review 与 Windows sandbox |
| `product-scope-excluded` | 35 | Codex account/commerce、attestation、remote control、test-only、internal raw response、deprecated surface,以及只表达单一全局 Provider 的 capability read |
| 合计 | 220 | `136` client request、`11` server request、`72` server notification、`1` client notification |
| 状态 | 数量 | 裁决 |
| ------------------------ | ---: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `implemented` | 130 | 连接握手、核心 Thread/Turn/Item、durable ordered Thread Section、thread subscription/lifecycle/content search/raw item injection/background terminals/elicitation/Guardian continuation、基础 Plugin cataloglist/read/install/uninstall/installed)与 Plugin Search、Hook discovery/lifecycle notifications、Skills list/config/extra roots/watcher、Apps exact catalog/read/installed 与 typed `app/list/updated` watcher、exact memory reset、connection-scoped process lifecycle、exact fs IO/watch、exact command/exec lifecycle、inline review/start 与 entered/exitedReviewMode boundary、`currentTime/read``item/permissions/requestApproval``item/tool/call`、typed `error`/`warning``item/commandExecution/terminalInteraction``item/autoApprovalReview/{started,completed}``turn/plan/updated`、精确 `turn/diff/updated``turn/moderationMetadata`、exact MCP resource/tool request/lifecycle notifications、typed approval/MCP server request 与 model control plane |
| `planned` | 54 | Plugin share/skill-read、`guardianWarning` 与其余 review notifications、config、Realtime 与 Windows sandbox |
| `product-scope-excluded` | 36 | Codex account/commerce、attestation、remote control、test-only、internal raw response、deprecated surface、Desktop 不消费的开发/设置 deprecation notice,以及只表达单一全局 Provider 的 capability read |
| 合计 | 220 | `136` client request、`11` server request、`72` server notification、`1` client notification |
`implemented` 只说明 method boundary 已存在并接入 current owner,不代表字段、恢复、GUI 或 Gate B 已全面 parity。
字段和 lifecycle 缺口继续由 Item inventory、gap register 与对应执行切片管理。
@@ -32,17 +32,25 @@ legacy 同义命令冒充协议对齐。矩阵覆盖 `clientRequest`、`serverRe
1. Codex/ChatGPT account、billing、attestation 和 remote-control client administration 不进入 Lime;不建 compat。
2. `applyPatchApproval``execCommandApproval``thread/rollback``item/fileChange/outputDelta``thread/compacted` 为 deprecated,禁止恢复。
3. `rawResponse/*` 绕过 canonical Thread/Turn/Item,保持 internal/excluded。
4. `executionProcess/*``fileSystem/*`、旧 skill/plugin method 即使功能相似,也不能算 Codex method parity。
5. Realtime、review 与 Windows sandbox 属于产品范围,当前标 `planned`,后续只能在既有 owner 补齐。
4. `executionProcess/*``fileSystem/*`、旧 skill/plugin method 即使功能相似,也不能算 Codex method parity;只有 generated manifest 中同名、同方向且接入 current owner 的 Plugin catalog 方法才计入
5. Realtime 与 Windows sandbox 属于产品范围,当前标 `planned`,后续只能在既有 owner 补齐Desktop review 已由 inline `review/start` current owner 承接,Codex TUI detached/background review 不进入 Lime
6. `modelProvider/capabilities/read` 读取 Codex 单一全局 ProviderLime 的 provider/model 选择绑定 Thread route。该空参数方法没有产品消费者,不能把静态全局值冒充当前 route truth,归入 excluded;能力继续由 executable model catalog、resolved route 与 provider lowering 承接。
7. Codex HEAD 的 durable ordered Thread Section 已进入 Lime current 主链:section/store/order、五个 exact method、typed client、冷启动恢复与 Desktop 分组/置顶均消费同一事实源。旧 `isPinned` metadata、Renderer 时间重排与 localStorage 收藏为 `dead / deleted / forbidden-to-restore`
8. `plugin/search` 已使用 exact Codex method、params/result wire、typed client 与公共 JSON-RPC 证据接入本地 Plugin catalog ownerCodex remote catalog、share、watcher 和 readiness 仍由其余 planned method 承接,不由该 method 冒充完成。
8. `plugin/list``plugin/read``plugin/install``plugin/uninstall``plugin/installed``plugin/search` 已使用 exact Codex method、params/result wire、typed client 与公共 JSON-RPC/Electron 证据接入本地 Plugin catalog ownerCodex remote catalog、share、skill-read、watcher 和 readiness 仍由 planned method 承接,不由这些基础方法冒充完成。
9. `hooks/list` 已接入 `tool-runtime` 唯一 discovery/trust owner、exact v2 contract、公共 JSON-RPC、command Hook sampling lifecycle、canonical Hook Item 恢复与真实 Electron Gate B;旧 raw config、默认信任、空 reporter 和 Renderer drift fallback 为 `dead / deleted / forbidden-to-restore`
10. `skills/list` 已接入 `lime-skills::AgentSkillSnapshot` 唯一 discovery owner、exact `cwds + forceReload -> data[{cwd,skills,errors}]` contract、公共 JSON-RPC、typed clients 与 Renderer catalog projection`skills/changed {}` 通过真实 Electron Gate B 驱动 GUI 自动刷新。singular `skill/list``SkillListResponse``get_local_skills_for_app``dead / deleted / forbidden-to-restore`
11. `skills/config/write``skills/extraRoots/set` 已接入 exact v2 contract、公共 JSON-RPC、typed clients 与同一 `lime-skills::AgentSkillSnapshot` owner。Desktop 将用户级启停配置持久化到 Lime YAML `skills.config`extra roots 只做进程级原子替换;成功设置 roots 发送 `skills/changed {}`。两者不引入 Codex TUI 或第二套管理 catalog。
12. `app/list``app/read``app/installed``app/list/updated` 已接入 exact v2 contract、公共 JSON-RPC、typed package client 和 Desktop Apps gateway。Apps catalog 唯一复用 Plugin catalog;本地 Plugin 没有 hosted connector 的 model-visible tool snapshot 时,`callable` 必须为 `false`,不能冒充 readiness 或模型可调用能力。
13. `process/spawn``process/writeStdin``process/resizePty``process/kill``process/outputDelta``process/exited` 已接入 exact connection-scoped contract、真实 local supervisor 和 typed package client。Desktop Workspace 继续通过 `thread/backgroundTerminals/*` 投影 Thread-owned 终止能力,不复制 Codex TUI,也不把 Thread item id 冒充 connection process handle;旧 `executionProcess/*``dead / deleted / forbidden-to-restore`
14. `fs/readFile``fs/writeFile``fs/createDirectory``fs/getMetadata``fs/readDirectory``fs/remove``fs/copy``fs/watch``fs/unwatch``fs/changed` 已接入 exact v2 contract、App Server `FsServer`、typed clients 和公共 JSON-RPC 证据。raw bytes 始终使用 base64,路径必须为绝对路径,watch id 按 connection 隔离;Desktop 文件浏览/预览只做 GUI 投影。旧 `fileSystem/*`、v0 DTO/schema 和 file browser Rust owner 为 `dead / deleted / forbidden-to-restore`
15. `currentTime/read` 由 Electron Desktop Host 唯一读取系统时钟,App Server waiter 负责 canonical thread scope、响应校验和超时;它不创建 Thread Item,也不暴露 Renderer 时钟 API。`item/tool/call` 由冻结的 Desktop dynamic-tool binding 响应,RuntimeCore waiter 与 canonical DynamicToolCall Item 负责生命周期和恢复,Renderer 不能伪造调用。两者均有同名 generated manifest、typed contract、边界单测和 Electron Gate B 证据。
16. `turn/plan/updated` 由 RuntimeCore `update_plan` producer 生成 durable `turn.plan.updated` fact,经 App Server v2 projector、typed package notification 和 Renderer projection 投递;Plan snapshot 仍由 canonical Plan Item/read model 承担,不能用本地 GUI 状态或 Tool Item 冒充。
17. `item/permissions/requestApproval``tool-runtime` 解析并收紧 permission profileApp Server exact-id waiter 传递 canonical session/thread/turn/item/environment identityRenderer 统一 `PendingInteractionController` 返回 turn/session grant 或 fail-closed 空 grant;相对路径、越界 profile、重复和迟到响应均被拒绝。
18. `warning``error` 由 runtime durable event producer、App Server v2 projector、canonical read model、typed client 和 Renderer 共同承接;`error.willRetry` 不伪造 Turn terminal`warning.code` 只用于五语言展示。`item/commandExecution/terminalInteraction` 由 command completion producer 生成脱敏摘要,live notification、cold read 和 GUI 都消费同一 bounded typed projection。
19. `turn/diff/updated``apply_patch` 的 Turn-scoped 精确 delta producer 生成 durable `turn.diff.updated` fact,经 App Server v2 projector、typed client 和 canonical conversation Turn 投影;Desktop Changes previous-conversation 只读取该 Turn 的 `unified_diff`,空字符串表示 net-zero 清除,不回退到第二套本地 patch 拼装。
20. `turn/moderationMetadata` 只接受 trusted first-party Responses `response.metadata.openai_chatgpt_moderation_metadata`,经 `model-provider` canonical event、Agent runtime durable `turn.moderation_metadata`、App Server exact v2 notification 和 Renderer canonical Turn 投影。metadata 保持任意 JSON,不猜字段、不展示 raw JSON;每次更新均投递并按 last-write-wins 合并,`null` 是有效覆盖值。Codex TUI 当前忽略该通知,Lime Desktop 不复制 TUI surface,也不新增 Electron IPC 或改变 Grok-aligned 多模型/多模态 owner。
21. `deprecationNotice` 属于 Codex 开发/设置诊断,不进入 Lime Desktop 对话或通知事实源。Lime 对无外部兼容负担的退役实现直接替换/删除,不新增同名兼容通知;`guardianWarning` 只有在独立的高优先级 warning producer 落地后才重新评估。
## 守卫
@@ -58,23 +66,23 @@ legacy 同义命令冒充协议对齐。矩阵覆盖 `clientRequest`、`serverRe
`thread/inject_items` 已对齐 exact method/shape、Codex current `ResponseItem` validation union、active Turn
session actor delivery、durable provider-only history、Responses exact lowering 与非 Responses fail-closed。
Guardian reviewer producer/lifecycle elicitation provider active-time pause consumer 仍是 runtime lifecycle
blocker,但不影响这两个 method boundary 的 implemented 分类。多模型控制平面的
Guardian reviewer producer/lifecycle 已进入 current 主链;elicitation provider active-time pause consumer 仍是 runtime lifecycle
blocker,但不影响已实现的 Guardian method boundary。多模型控制平面的
`model/verification``model/rerouted` 已接入可信 Responses metadata producer、Turn 级去重、exact v2
notification、schema 与 generated client。reroute 只接受 first-party requested/server mismatch,使用
`highRiskCyberActivity`,并通过 transient sink 实时投影而不进入 EventLog/resume item replay;普通 provider
fallback 继续只产生 `routing.fallback.applied`。下一刀处理 provider adapter/hosted tool 闭环、
Plugins/Apps watcher/readiness。每完成一个
Plugin share/skill-read、`guardianWarning` 与 remaining review notifications 和 Apps watcher/readiness。`deprecationNotice`
已按 Desktop 产品范围裁决为 excluded。每完成一个
method,必须同步 exact protocol、handler、typed client、fixture/evidence,再将其移入 `implemented`
Codex 已明确将 `thread/rollback` 标记为即将删除,Lime 不新增该公开方法。当前产品范围完成度为
`108 / 185 = 58.4%`。本切片新增 9 个 exact fs client request 与 1 个 fs server notification,并物理删除旧 `fileSystem/*` public surface;此前切片新增 4 个 exact process client request 与 2 个 process server notification,并物理删除旧 `executionProcess/*` public surface;再前一切片新增 exact `memory/reset` client request,并收口已有 Hook lifecycle 与 MCP lifecycle notification 的中央 catalog/产品裁决;相对更早切片新增 Apps 的三个 client request 与一个 server notification,以及
`130 / 184 = 70.7%`。本切片`item/autoApprovalReview/{started,completed}` 接入真实 Guardian reviewer 到 Desktop pending interaction 的完整 current 主链;此前切片`turn/moderationMetadata` 接入 trusted first-party Responses metadata 到 Desktop canonical Turn 的完整 current 主链,并将 `deprecationNotice` 按 Desktop 产品范围移入 excluded;更早已将基础 Plugin catalog 五个方法、`currentTime/read``item/permissions/requestApproval``item/tool/call``warning``error``item/commandExecution/terminalInteraction``turn/plan/updated``turn/diff/updated` 从混合 planned 组拆出;`review/start` client request、`enteredReviewMode`/`exitedReviewMode` canonical boundary 与 Desktop Gate B evidence,以及 command/exec、fs、process 与 memory slices 也已同步进入 current owner,并物理删除对应旧 public surface;再前一切片收口已有 Hook lifecycle 与 MCP lifecycle notification 的中央 catalog/产品裁决;相对更早切片新增 Apps 的三个 client request 与一个 server notification,以及
`mcpServer/resource/read``mcpServer/tool/call` 两个 client request
均有 exact contract、公共 JSON-RPC 和 typed client evidence。resource read 的 `threadId` 可选;存在时只读取
对应 Session-owned MCP runtime。tool call 强制真实 `threadId`,经 `ExecutionBackend -> AgentRuntimeState ->
McpThreadRuntime` 执行,不经过全局 management manager。Settings 只浏览工具,不伪造 Thread owner。
此前相对注册表基线新增的 `13` 个方向已全部进入 `implemented`:五个 durable Thread Section
管理/移动 method、exact `plugin/search``hooks/list`、三个 Apps client request、Apps notification 与这两个 MCP method。现有自定义 Plugin
list/read/install 仍不能冒充其余 Codex Plugin method parity。
此前相对注册表基线新增的 `28` 个方向已全部进入 `implemented`:五个 durable Thread Section
管理/移动 method、基础 Plugin catalog 五个方法、exact `plugin/search``hooks/list`、三个 Apps client request、Apps notification、三个 Host/product reverse requests、typed `warning`/`error`、command terminal interaction、`turn/plan/updated``turn/diff/updated`、两个 MCP method、`turn/moderationMetadata` 与两个 Guardian auto-approval review notifications。Plugin share/skill-read、`guardianWarning` 与其余 review notifications 仍保持 planned`deprecationNotice` 已按 Desktop 产品范围移入 excluded。
Gemini GenerateContent transport 虽已完成 request/stream/tool/history
闭环,但没有新增 exact Codex App Server method,因此不改变本矩阵计数;不得把 `37.8%` 解释成多模型或
闭环,但没有新增 exact Codex App Server method,因此不改变本矩阵计数;不得把 `70.7%` 解释成多模型或
整个 Codex 对齐工程的完成度。
@@ -20,9 +20,9 @@
"clientNotification": 1
},
"byStatus": {
"implemented": 108,
"product-scope-excluded": 35,
"planned": 77
"implemented": 130,
"product-scope-excluded": 36,
"planned": 54
}
},
"groups": [
@@ -352,15 +352,22 @@
"methods": ["collaborationMode/list"]
},
{
"id": "command-planned",
"id": "command-current",
"direction": "clientRequest",
"productArea": "command",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "tool-runtime + app-server command processor",
"counterpartRule": "none",
"gap": "Legacy executionProcess/projectShell names cannot stand in for Codex command/exec lifecycle.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/command_exec.rs",
"lime-rs/crates/app-server/src/processor/command_exec.rs",
"lime-rs/crates/app-server/src/command_exec.rs",
"lime-rs/crates/app-server/src/command_exec/tests.rs",
"packages/app-server-client/src/request-client-methods.ts",
"src/lib/api/commandExec.ts",
"src/lib/api/commandExec.test.ts"
],
"methods": [
"command/exec",
"command/exec/resize",
@@ -591,27 +598,47 @@
"methods": ["plugin/search"]
},
{
"id": "plugins-planned",
"id": "plugin-catalog-current",
"direction": "clientRequest",
"productArea": "plugins",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "plugin registry + app-server",
"counterpartRule": "none",
"gap": "Legacy plugin methods do not satisfy Codex manifest, share, watcher, and readiness semantics.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"owner": "App Server Plugin catalog + local plugin_catalog",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/plugin.rs",
"lime-rs/crates/app-server/src/processor/plugin.rs",
"lime-rs/crates/app-server/src/runtime/plugins.rs",
"lime-rs/crates/app-server/src/local_data_source/plugin_catalog.rs",
"packages/app-server-client/src/request-client-methods.ts",
"src/lib/api/pluginCatalog.ts",
"scripts/electron/mcp-elicitation-gate-b.mjs"
],
"methods": [
"plugin/install",
"plugin/installed",
"plugin/list",
"plugin/read",
"plugin/uninstall"
]
},
{
"id": "plugins-share-planned",
"direction": "clientRequest",
"productArea": "plugins",
"status": "planned",
"priority": "P1",
"owner": "Plugin share and skill catalog owner",
"counterpartRule": "none",
"gap": "Plugin share mutations and plugin skill body reads still lack current Desktop lifecycle and evidence.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"methods": [
"plugin/share/checkout",
"plugin/share/delete",
"plugin/share/list",
"plugin/share/save",
"plugin/share/updateTargets",
"plugin/skill/read",
"plugin/uninstall"
"plugin/skill/read"
]
},
{
@@ -638,16 +665,22 @@
]
},
{
"id": "review-planned",
"id": "review-current",
"direction": "clientRequest",
"productArea": "review",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "agent-runtime review lifecycle + app-server",
"counterpartRule": "none",
"gap": "Review items project internally, but review/start is not a public current method with recovery evidence.",
"counterpartRule": "same-name",
"evidence": [
"packages/agent-runtime-projection/tests/reviewStartItem.test.mjs"
"lime-rs/crates/app-server-protocol/src/protocol/v2/review.rs",
"lime-rs/crates/app-server/src/processor/review.rs",
"lime-rs/crates/app-server/src/processor/tests/review.rs",
"lime-rs/crates/app-server/src/runtime/review.rs",
"src/lib/api/review.ts",
"src/lib/api/review.test.ts",
"scripts/electron/code-artifact-workbench-fixture-smoke.mjs",
"scripts/electron/code-artifact-workbench-fixture-smoke.test.mjs"
],
"methods": ["review/start"]
},
@@ -700,28 +733,59 @@
"methods": ["windowsSandbox/readiness", "windowsSandbox/setupStart"]
},
{
"id": "client-clock-planned",
"id": "client-clock-current",
"direction": "serverRequest",
"productArea": "client-capability",
"status": "planned",
"status": "implemented",
"priority": "P4",
"owner": "app-server server-request registry",
"counterpartRule": "none",
"gap": "External client clock request and capability gate are not implemented.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"owner": "Electron Desktop Host clock responder + App Server waiter",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/current_time.rs",
"lime-rs/crates/app-server/src/current_time.rs",
"lime-rs/crates/app-server/src/current_time_tests.rs",
"electron/appServerCurrentTimeHost.ts",
"electron/appServerHost.test.ts",
"lime-rs/crates/app-server-protocol/schema/json/manifest.json"
],
"methods": ["currentTime/read"]
},
{
"id": "item-server-request-planned",
"id": "permissions-approval-current",
"direction": "serverRequest",
"productArea": "item-approval",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "app-server server-request registry + tool-runtime",
"counterpartRule": "none",
"gap": "Granular permission approval and client dynamic tool dispatch have no current typed lifecycle.",
"evidence": ["internal/refactor/v1/10-item-inventory-skeleton.md"],
"methods": ["item/permissions/requestApproval", "item/tool/call"]
"owner": "tool-runtime permission policy + App Server waiter + Renderer PendingInteractionController",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/request_permissions.rs",
"lime-rs/crates/tool-runtime/src/request_permissions.rs",
"lime-rs/crates/agent-runtime/src/request_permissions.rs",
"lime-rs/crates/app-server/src/permission_server_request.rs",
"src/lib/api/agentRuntime/pendingInteractionController.ts",
"src/lib/api/agentRuntime/pendingInteractionController.test.ts",
"internal/research/refactor/v2/13-evidence/2026-07-30-v2-04-host-capabilities-gate-b.md"
],
"methods": ["item/permissions/requestApproval"]
},
{
"id": "dynamic-tool-call-current",
"direction": "serverRequest",
"productArea": "dynamic-tools",
"status": "implemented",
"priority": "P1",
"owner": "Electron Desktop Host dynamic tool binding + App Server RuntimeCore waiter",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/dynamic_tool.rs",
"lime-rs/crates/app-server/src/dynamic_tool_server_request.rs",
"electron/appServerDynamicToolHost.ts",
"electron/appServerDynamicToolHost.test.ts",
"src/lib/api/agentRuntime/appServerCanonicalItemReader.ts",
"scripts/electron/mcp-elicitation-gate-b.mjs"
],
"methods": ["item/tool/call"]
},
{
"id": "apps-notification-current",
@@ -741,28 +805,69 @@
"methods": ["app/list/updated"]
},
{
"id": "command-notification-planned",
"id": "command-notification-current",
"direction": "serverNotification",
"productArea": "command",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "tool-runtime + app-server command processor",
"counterpartRule": "none",
"gap": "command/exec output streaming is not exposed as the Codex notification contract.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/command_exec.rs",
"lime-rs/crates/app-server/src/processor/command_exec.rs",
"lime-rs/crates/app-server/src/command_exec.rs",
"lime-rs/crates/app-server/src/command_exec/tests.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/commandExec.test.ts"
],
"methods": ["command/exec/outputDelta"]
},
{
"id": "diagnostics-notification-planned",
"id": "guardian-notification-planned",
"direction": "serverNotification",
"productArea": "diagnostics",
"status": "planned",
"priority": "P1",
"owner": "app-server notification projector",
"owner": "app-server notification projector + Guardian runtime owner",
"counterpartRule": "none",
"gap": "Generic error/warning/deprecation and guardian warning shapes are not aligned to Codex.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"methods": ["deprecationNotice", "error", "guardianWarning", "warning"]
"gap": "Lime has no Guardian review runtime producer that can emit a distinct high-priority warning.",
"evidence": [
"internal/refactor/v1/08-third-audit-gap-register.md",
"internal/refactor/v2/EVENT-PROJECTIONS.md"
],
"methods": ["guardianWarning"]
},
{
"id": "deprecation-notification-excluded",
"direction": "serverNotification",
"productArea": "diagnostics",
"status": "product-scope-excluded",
"priority": "none",
"owner": "product-scope",
"counterpartRule": "none",
"rationale": "Deprecation notices are Codex development/settings diagnostics, not Desktop conversation state; Lime removes retired surfaces directly and does not need a compatibility notification.",
"evidence": ["internal/refactor/v2/EVENT-PROJECTIONS.md"],
"methods": ["deprecationNotice"]
},
{
"id": "runtime-diagnostics-current",
"direction": "serverNotification",
"productArea": "diagnostics",
"status": "implemented",
"priority": "P1",
"owner": "App Server runtime diagnostics projector + canonical read model",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/notification.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications/warning.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications/error.rs",
"lime-rs/crates/app-server/src/processor/tests/event_notifications.rs",
"lime-rs/crates/app-server/src/runtime/read_model/runtime_items.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/agentRuntime/appServerV2Notification.ts",
"scripts/agent-runtime/claw-chat-current-fixture-typed-error.mjs"
],
"methods": ["error", "warning"]
},
{
"id": "external-agent-config-notification-planned",
@@ -828,21 +933,48 @@
"methods": ["hook/completed", "hook/started"]
},
{
"id": "item-notification-planned",
"id": "item-guardian-review-notification-current",
"direction": "serverNotification",
"productArea": "item",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "tool-runtime + app-server v2 notification projector",
"counterpartRule": "none",
"gap": "Auto-approval review and terminal interaction lack runtime source events and typed projection.",
"evidence": ["internal/refactor/v1/10-item-inventory-skeleton.md"],
"owner": "agent-runtime Guardian reviewer + App Server v2 notification projector + Renderer ConversationProjection",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/agent/src/guardian_review.rs",
"lime-rs/crates/app-server/src/runtime/thread_guardian.rs",
"lime-rs/crates/app-server/src/processor/thread/guardian.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications/guardian.rs",
"lime-rs/crates/app-server-protocol/src/protocol/v2/item.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/agentRuntime/appServerV2Notification.ts",
"src/lib/api/agentRuntime/conversationProjection/reducer.ts",
"src/lib/api/agentRuntime/appServerV2Notification.test.ts"
],
"methods": [
"item/autoApprovalReview/completed",
"item/autoApprovalReview/started",
"item/commandExecution/terminalInteraction"
"item/autoApprovalReview/started"
]
},
{
"id": "command-terminal-interaction-current",
"direction": "serverNotification",
"productArea": "item",
"status": "implemented",
"priority": "P1",
"owner": "tool-runtime command lifecycle + App Server v2 notification projector",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/item.rs",
"lime-rs/crates/app-server/src/runtime_backend/coding_events.rs",
"lime-rs/crates/app-server/src/runtime_backend/coding_events/tests.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications/command.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/agentRuntime/appServerV2Notification.ts",
"src/lib/api/agentRuntime/appServerV2Notification.test.ts"
],
"methods": ["item/commandExecution/terminalInteraction"]
},
{
"id": "mcp-notification-current",
"direction": "serverNotification",
@@ -982,20 +1114,62 @@
]
},
{
"id": "review-notification-planned",
"id": "turn-moderation-metadata-notification-current",
"direction": "serverNotification",
"productArea": "review",
"status": "planned",
"status": "implemented",
"priority": "P1",
"owner": "agent-runtime review lifecycle + app-server",
"counterpartRule": "none",
"gap": "Review/plan/diff updates are not all represented by durable public notifications.",
"evidence": ["internal/refactor/v1/08-third-audit-gap-register.md"],
"methods": [
"turn/diff/updated",
"turn/moderationMetadata",
"turn/plan/updated"
]
"owner": "model-provider trusted Responses metadata + agent-runtime + App Server canonical Turn",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/model-provider/src/current_client/stream.rs",
"lime-rs/crates/agent-runtime/src/provider_turn.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications.rs",
"lime-rs/crates/app-server-protocol/src/protocol/v2/model.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/agentRuntime/appServerV2Notification.ts",
"src/lib/api/agentRuntime/conversationProjection/reducer.ts"
],
"methods": ["turn/moderationMetadata"]
},
{
"id": "turn-diff-notification-current",
"direction": "serverNotification",
"productArea": "coding-review",
"status": "implemented",
"priority": "P1",
"owner": "RuntimeCore coding event producer + App Server v2 notification projection + canonical Turn",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/tool-runtime/src/apply_patch.rs",
"lime-rs/crates/app-server/src/runtime_backend/coding_events/turn_diff.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications/turn_diff.rs",
"lime-rs/crates/app-server-protocol/src/protocol/v2/notification.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/agentRuntime/appServerV2Notification.ts",
"src/lib/api/agentRuntime/conversationProjection/reducer.ts",
"src/components/agent/chat/workspace/workspaceConversationCodingViews.tsx"
],
"methods": ["turn/diff/updated"]
},
{
"id": "turn-plan-notification-current",
"direction": "serverNotification",
"productArea": "plan",
"status": "implemented",
"priority": "P1",
"owner": "RuntimeCore plan producer + App Server v2 notification projection",
"counterpartRule": "same-name",
"evidence": [
"lime-rs/crates/app-server-protocol/src/protocol/v2/notification.rs",
"lime-rs/crates/app-server/src/processor/v2_notifications/turn_plan.rs",
"lime-rs/crates/app-server/src/processor/tests/event_notifications.rs",
"lime-rs/crates/app-server/src/runtime_backend/plan_events.rs",
"packages/app-server-client/src/server-notifications.ts",
"src/lib/api/agentRuntime/appServerV2Notification.ts",
"scripts/agent-runtime/claw-chat-current-fixture-turn-plan-update.mjs"
],
"methods": ["turn/plan/updated"]
},
{
"id": "windows-sandbox-notification-planned",
+8 -8
View File
@@ -13,7 +13,7 @@
出口代码:TL 时间线,TP Turn 面板,PI pending interactionHS Header/状态区,GN 应用通知,DX 仅开发诊断。
实施快照:direct `item/started -> item/commandExecution/outputDelta* -> item/completed` 通过 typed adapter 和共享 reducerproduction `thread/resume` 安装同一 replay reducer,后续 live notification 继续复用。completed snapshot 权威覆盖 delta 草稿,输出限制为 256 KiB。`write_stdin` 复用原始 `exec_command` Item identitytyped terminal interaction 与 canonical cold read 只保留 `sent N chars` 脱敏摘要。`turn.plan.updated` 由 canonical `update_plan``ToolOutput.structured_content` 派生,实时与 canonical cold read 共用 checklist 投影;`update_plan` 工具项保留在 read model,但不生成 `ThreadItem.plan` 或 Plan UI。unknown Item 已沿 canonical typed payload、v2 `thread/read`、Renderer 终态合并与 direct TurnTimeline fail-visible,只保留 upstream type 和脱敏字段名,并有专项 Electron Gate Bunknown/known-unprojected notification drift recorder 仍只提供诊断,不能把 72 notification 中的 planned surface 标记完成。
实施快照:direct `item/started -> item/commandExecution/outputDelta* -> item/completed` 通过 typed adapter 和共享 reducerproduction `thread/resume` 安装同一 replay reducer,后续 live notification 继续复用。completed snapshot 权威覆盖 delta 草稿,输出限制为 256 KiB。`write_stdin` 复用原始 `exec_command` Item identitytyped terminal interaction 与 canonical cold read 只保留 `sent N chars` 脱敏摘要。`turn.plan.updated` 由 canonical `update_plan``ToolOutput.structured_content` 派生,实时与 canonical cold read 共用 checklist 投影;`update_plan` 工具项保留在 read model,但不生成 `ThreadItem.plan` 或 Plan UI。Hook lifecycle 由 current Hook runtime 产生 paired `hook.started`/`hook.completed`,只做 transient timeline 投影,不创建 canonical ThreadItem。trusted first-party Responses 的 moderation metadata 已走 `model-provider -> AgentEvent -> durable event -> v2 turn/moderationMetadata -> typed client -> canonical Turn`,保持 opaque JSON 与 last-write-wins。strictAutoReview 的 shell/`exec_command` 触发真实 Guardian reviewer,经同 session `model-provider` 无工具结构化采样生成 durable `guardian.review.started/completed`,再投影为 typed `item/autoApprovalReview/*` 与 Renderer `pending_interactions`;provider 不可用、取消、超时和非法响应全部拒绝。unknown Item 已沿 canonical typed payload、v2 `thread/read`、Renderer 终态合并与 direct TurnTimeline fail-visible,只保留 upstream type 和脱敏字段名,并有专项 Electron Gate Bunknown/known-unprojected notification drift recorder 仍只提供诊断,不能把 72 notification 中的 planned surface 标记完成。
## 1. Thread、Turn 与 Hook
@@ -35,10 +35,10 @@
| 14 | thread/settings/updated | HS | current | 下一 Turn model、reasoning、permission 摘要 |
| 15 | thread/tokenUsage/updated | TP/HS | current | 本 Turn/总用量,节流更新 |
| 16 | turn/started | TL/TP | current | 建立 Turn 与原始 Item 顺序 |
| 17 | hook/started | TL/HS | planned | Hook activityrun id 保留 |
| 17 | hook/started | TL/HS | current | current Hook producer 的 transient activityrun id 保留 |
| 18 | turn/completed | TL/TP | current | 权威 Turn 终态并清理 pending |
| 19 | hook/completed | TL | planned | Hook status、duration、entries 与阻断结果 |
| 20 | turn/diff/updated | DX | product-scope-excluded | Codex raw unified diffLime 以 canonical FileChange 为唯一事实源 |
| 19 | hook/completed | TL | current | paired Hook producer 的 transient status,不写入 canonical Item |
| 20 | turn/diff/updated | DX | current | Lime exact Turn diffcanonical Turn/Changes 使用同一快照 |
| 21 | turn/plan/updated | TP | current | canonical update_plan checklist,实时/冷恢复一致 |
## 2. Item 生命周期、流与进程
@@ -46,8 +46,8 @@
| # | Method | 目标出口 | 当前裁决 | v2 投影 |
| --: | ----------------------------------------- | -------- | ---------------------- | ----------------------------------------------------------- |
| 22 | item/started | TL | current | 按 typed 联合建立 Item;未知安全 fail visible |
| 23 | item/autoApprovalReview/started | PI/TL | planned | 目标 Item 的 Guardian review 进行中 |
| 24 | item/autoApprovalReview/completed | PI/TL | planned | approved/denied/timedOut/aborted 与风险摘要 |
| 23 | item/autoApprovalReview/started | PI/TL | current | 目标 Item 的 Guardian review 进行中 |
| 24 | item/autoApprovalReview/completed | PI/TL | current | approved/denied/timedOut/aborted 与风险摘要 |
| 25 | item/completed | TL | current | Item 权威终态覆盖流式草稿 |
| 26 | rawResponseItem/completed | DX | product-scope-excluded | 不参与正式 Item 或终态合成 |
| 27 | rawResponse/completed | DX | product-scope-excluded | 不进入普通时间线 |
@@ -87,7 +87,7 @@
| --: | -------------------------------- | -------- | ---------------------- | ------------------------------------------------------------ |
| 52 | model/rerouted | TL/HS | current | from/to 与 allowlisted reason;不改变 route owner |
| 53 | model/verification | HS/DX | current | 脱敏验证结论 |
| 54 | turn/moderationMetadata | DX | product-scope-excluded | 只驱动受审核 policy |
| 54 | turn/moderationMetadata | DX | current | trusted first-party metadataopaque Turn statelast-write-wins |
| 55 | model/safetyBuffering/updated | HS | current | 安全缓冲提示,不伪造模型选择 |
| 56 | warning | HS/GN | current | typed threadId/message/code?;实时去重 toast 与冷读恢复 |
| 57 | guardianWarning | HS/TL | planned | 高优先级安全 warning,不被普通 warning 吞掉 |
@@ -112,7 +112,7 @@
| 71 | windowsSandbox/setupCompleted | GN/PI | planned | setup success/error 与下一步 |
| 72 | account/login/completed | GN/PI | product-scope-excluded | credential 流程不进入对话 |
v2 的实现门槛不是把所有 planned method 同时实现,而是首先将这张表固化为类型检查的 coverage map。新增 Codex method 时,CI 必须要求它先获得裁决,不能落入 default silent return。`turn/diff/updated``process/outputDelta``process/exited` 虽保留在 upstream method inventory 和 drift recorder 中,但明确为 `product-scope-excluded`:不得进入 Lime current protocol、Renderer projector、时间线或用户级通知;对应 standalone `process/spawn` 控制面与 raw unified diff 不能借 planned 名义回流。
v2 的实现门槛不是把所有 planned method 同时实现,而是首先将这张表固化为类型检查的 coverage map。新增 Codex method 时,CI 必须要求它先获得裁决,不能落入 default silent return。standalone `process/outputDelta``process/exited` 虽保留在 upstream method inventory 和 drift recorder 中,但明确为 `product-scope-excluded`:不得进入 Lime current protocol、Renderer projector、时间线或用户级通知;对应 standalone `process/spawn` 控制面不能借 planned 名义回流。Lime exact `turn/diff/updated` 已由 `apply_patch -> durable fact -> v2 projector -> canonical Turn/Changes` current owner 承接,不等同于 Codex TUI 的 raw diff surface
## 6. Lime-owned 扩展事件
+38 -6
View File
@@ -6,7 +6,7 @@
当前阶段:V2-05 notification、host capability 与 recoveryV2-00、V2-01、V2-02、V2-03、V2-04 已关闭,direct TurnTimeline、production replay、session history、长列表性能、MCP elicitation、Multi-Agent、三项 product-scope reverse request、media read v2、unknown Item fail-visible recovery、`skills/changed` catalog invalidation、typed `error` retry/terminal、`turn/plan/updated` checklist、`mcpServer/oauthLogin/completed``mcpServer/startupStatus/updated` 与 unified exec terminal interaction Gate B 已通过
下一刀:V2-05 已关闭 media transient bypass、unknown Item fail-visible recovery、`configWarning` owner 迁移、thread-scoped `warning` typed/recovery、`skills/changed` catalog invalidation、typed `error` retry/terminal、`turn/plan/updated` checklist、MCP OAuth completion、MCP startup statusunified exec terminal interaction typed/recovery 链;`turn/diff/updated` standalone `process/*` 已裁决为 product-scope-excluded。继续审计具备真实 producer/consumer 的 planned notification、host capability 或 recovery`guardianWarning` 在 Guardian runtime producer 落地前保持 planned。不重复改写已关闭 owner,也不恢复 raw unified diff、unsandboxed process/spawn、Message synthesis、unknown null drop、extension fallback、v0 media/config owner、旧 MCP Desktop lifecycle event、旧 Team 工具、第二 pending store、第二 Skill catalog owner、Plan ThreadItem、独立 `write_stdin` Tool Item 或由 error 抢占 Turn terminal 的旁路状态机。
下一刀:V2-05 已关闭 media transient bypass、unknown Item fail-visible recovery、`configWarning` owner 迁移、thread-scoped `warning` typed/recovery、`skills/changed` catalog invalidation、typed `error` retry/terminal、`turn/plan/updated` checklist、MCP OAuth completion、MCP startup statusunified exec terminal interaction、Hook lifecycle、`turn/diff/updated` typed/recovery 与 Guardian auto-approval review typed/recovery 链;standalone `process/*` 为 product-scope-excluded。继续审计具备真实 producer/consumer 的 planned notification、host capability 或 recovery`guardianWarning` 因仍没有独立真实 producer 保持 planned。不重复改写已关闭 owner,也不恢复 raw unified diff、unsandboxed process/spawn、Message synthesis、unknown null drop、extension fallback、v0 media/config owner、旧 MCP Desktop lifecycle event、旧 Team 工具、第二 pending store、第二 Skill catalog owner、Plan ThreadItem、独立 `write_stdin` Tool Item 或由 error 抢占 Turn terminal 的旁路状态机。
## 1. 约束与非目标
@@ -197,9 +197,9 @@
动作:
1. 按 EVENT-PROJECTIONS 逐项补 Hook、environment、warning、fuzzy search、realtime、Windows sandbox 等仍在产品范围内的 planned surface`turn/diff/updated` standalone `process/*` 已裁决为 product-scope-excluded,不得恢复为 current。
1. 按 EVENT-PROJECTIONS 逐项补 environment、warning、fuzzy search、realtime、Windows sandbox 等仍在产品范围内的 planned surfaceHook 与 `turn/diff/updated` 已有 current ownerstandalone `process/*` 为 product-scope-excluded,不得恢复为第二套 current。
2. 每项先补 App Server typed protocol 和 producer,再补 Electron gateway、projection、renderer 和 Gate B;不能由前端先造状态。
3. 维护已落地的 unknown notification drift recorderknown-but-excluded 发 DXunknown notification fail visible`turn/diff/updated` `process/*` 只保留脱敏字段名诊断,不进入 Rendererunknown reverse request fail closed。
3. 维护已落地的 unknown notification drift recorderknown-but-excluded 发 DXunknown notification fail visiblestandalone `process/*` 只保留脱敏字段名诊断,不进入 Renderer;current `turn/diff/updated` 走 canonical Turn/Changesunknown reverse request fail closed。
4. 移除已被 direct ItemRenderer 替代的旧 Message hydration、stream merge、legacy event parser、compat DTO 和测试夹具。
5. 在同一变更集中更新 internal/aiprompts/architecture.md,记录 Renderer read path 从 Message synthesis 收敛到 ConversationProjection,并完成架构图确认。
@@ -254,13 +254,13 @@ Gate B 最少场景:Agent Markdown、Reasoning、Plan、Search、Shell output
| 分类 | v2 裁决 |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| current | App Server v2 主链、ConversationProjection、direct TurnTimeline、bounded restored Turn window、canonical long-message preview、production replay、统一 PendingInteraction、thread-scoped media read、typed unknown Item live/cold fail-visible 与专项 Gate B、typed `configWarning` producer/GUI、thread-scoped typed `warning` 与 durable recovery、typed `skills/changed` catalog invalidation 与 GUI 自动重读、typed `error` live/durable recovery 与 Turn terminal ownership、`turn/plan/updated` canonical checklist 与 cold recovery、typed `mcpServer/oauthLogin/completed` 与 GUI 自动刷新、typed `mcpServer/startupStatus/updated` 与 MCP 连接态投影、unified exec terminal interaction typed/cold recovery、六工具 AgentControl、canonical SubAgent activity、parent-owned child direct-input policy、`currentTime/read``item/permissions/requestApproval``item/tool/call`、typed DynamicToolCall、model-provider 多模型/多模态 owner |
| current | App Server v2 主链、ConversationProjection、direct TurnTimeline、bounded restored Turn window、canonical long-message preview、production replay、统一 PendingInteraction、thread-scoped media read、typed unknown Item live/cold fail-visible 与专项 Gate B、typed `configWarning` producer/GUI、thread-scoped typed `warning` 与 durable recovery、typed `skills/changed` catalog invalidation 与 GUI 自动重读、typed `error` live/durable recovery 与 Turn terminal ownership、`turn/plan/updated` canonical checklist 与 cold recovery、typed `mcpServer/oauthLogin/completed` 与 GUI 自动刷新、typed `mcpServer/startupStatus/updated` 与 MCP 连接态投影、Hook transient lifecycle、`turn/diff/updated` canonical Turn/Changes、unified exec terminal interaction typed/cold recovery、Guardian auto-approval review lifecycle/pending projection、六工具 AgentControl、canonical SubAgent activity、parent-owned child direct-input policy、`currentTime/read``item/permissions/requestApproval``item/tool/call`、typed DynamicToolCall、model-provider 多模型/多模态 owner |
| compat | 不保留长期生产 compat;仅可存在一次性迁移测试夹具 |
| product-scope-excluded | `turn/diff/updated` raw unified diff、standalone unsandboxed `process/outputDelta` / `process/exited`;只保留 upstream inventory 与脱敏 drift 诊断,不进入 current protocol 或 Renderer |
| product-scope-excluded | standalone unsandboxed `process/outputDelta` / `process/exited`;只保留 upstream inventory 与脱敏 drift 诊断,不进入 current protocol 或 Renderer |
| deprecated | fileChange outputDelta、thread/compacted 与尚未完成 current producer 的旧 notification 裁决;只允许迁出 |
| dead / deleted | canonical Item -> Message tool/agent/reasoning 合成、首帧无界历史挂载、canonical 长正文绕过 preview、unknown Item null drop、ContextCompaction hide、通用 extension fallback、重复 pending store、v0 media/config notification owner、media transient notification/raw subscription/live-drain 旁路、旧 MCP OAuth/start/stop/error Desktop event、裸旧 Team 工具、raw output 状态推断与生产 mock fallback |
计划完成度:保守估算 97%。该数字按 V2-00 至 V2-05 六个阶段退出条件与剩余风险折算:V2-00、V2-01、V2-02、V2-03、V2-04 已关闭,V2-05 的 media transient bypass、unknown Item fail-visible recovery、`configWarning` typed owner、thread-scoped `warning` typed/recovery、`skills/changed` catalog invalidation、typed `error` retry/terminal、`turn/plan/updated` canonical checklist、MCP OAuth completion、MCP startup status 与 unified exec terminal interaction typed/recovery 链已关闭;`turn/diff/updated` standalone `process/*` 已明确排除出 Lime 产品范围,其余 planned notification、host capability 与全面 recovery 仍未完成。该估算不表示 v2 已可整体交付或 release-ready。
计划完成度:保守估算 97%。该数字按 V2-00 至 V2-05 六个阶段退出条件与剩余风险折算:V2-00、V2-01、V2-02、V2-03、V2-04 已关闭,V2-05 的 media transient bypass、unknown Item fail-visible recovery、`configWarning` typed owner、thread-scoped `warning` typed/recovery、`skills/changed` catalog invalidation、typed `error` retry/terminal、`turn/plan/updated` canonical checklist、MCP OAuth completion、MCP startup status、Hook lifecycle 与 unified exec terminal interaction`turn/diff/updated` canonical Turn/Changes 链已关闭;standalone `process/*` 已明确排除出 Lime 产品范围,其余 planned notification、host capability 与全面 recovery 仍未完成。该估算不表示 v2 已可整体交付或 release-ready。
## 6. 执行台账
@@ -773,3 +773,35 @@ Gate B 证据:
治理分类:unified exec、canonical terminal interactions、typed notification、Renderer live/historical projection 与 Gate B fixture 为 `current`;无 `compat`;原始 stdin、独立 `write_stdin` Tool Item、retired Bash/PowerShell tools 与生产 mock fallback 为 `dead / forbidden-to-restore`。本切片未改变 public owner、唯一产品链或依赖方向,无需改写 `internal/aiprompts/architecture.md`。责任开发者确认:root2026-08-01。
下一刀:其余 planned notification 在当前工作树仍缺少完整 producer、consumer、持久化语义与 Gate B,保持 planned;不得为提高完成度新增协议 facade、compat 或生产 mock。v2 总体完成度保守估算仍为 97%,仍非 release-ready。
### 2026-08-09V2-05 Guardian auto-approval review lifecycle
状态:该垂直切片 `completed`V2-05 与 v2 总体仍为 `in-progress`,不得标记 release-ready。
本轮实现:
- `strictAutoReview` 不再转成人工审批;当前 shell/`exec_command` tool decision 会复用同一 session 的
`model-provider` 做无工具结构化 Guardian sampling30 秒超时、取消、provider 不可用、非法 JSON 或不确定结果全部
fail closed 为拒绝。没有为未接入的 MCP、patch、network 或 permission 生产假 review producer。
- AgentEvent 新增 `guardian_review_started/completed`App Server projector 生成 exact
`item/autoApprovalReview/started|completed` typed v2 notification;协议 schema、manifest、generated TypeScript、client
lifecycle union 与 strict decoder 同步,completed 严格拒绝 `inProgress`、未知 action、额外字段和非 `agent` decision source。
- Renderer v2 route、drift registry 与 sequence gate 接受同一 thread/turn identitystarted 建立
`pending_interactions[id=reviewId, kind=guardian_review]`completed 将 approved/denied/timedOut/aborted 映射为
resolved/declined/cancelled,并保留 action/review 快照。缺失 started 的 completion 只记录诊断,不创建第二份 pending store。
- Electron 只转发 App Server JSONL;没有 TUI detached/background review UI、raw provider JSON、额外 IPC、兼容 wrapper 或
production mock fallback。多模型 catalog/default/switch/capability/readiness/retry/circuit breaker 与多模态 sampling/media
lowering 继续归 Grok-aligned `model-provider`
验证:`cargo test -p app-server-protocol --lib` 112/112App Server Guardian projector 2/2app-server-client build 与
strict notification tests 14/14Renderer Guardian/projection 定向套件 50/50`npm run typecheck``npm run test:contracts`
301 checks)与 `npm run governance:legacy-report`2112/1376 文件,0 候选、0 漂移、0 边界违规)通过。当前尚未单独运行
Guardian 专项 Electron Gate B 或 live provider evidence;聚合 `smoke:agent-runtime-current-fixture` 仍是下一步验证,不把
浏览器投影冒充真实桌面证据。
治理分类:Guardian agent/provider/App Server/typed client/ConversationProjection 为 `current`;无 `compat`
`deprecated`;旧人工审批冒充 auto review、raw side-channel、TUI detached review、生产 mock fallback 与未接入 producer
的 Guardian 扩展为 `dead / forbidden-to-restore``guardianWarning` 继续 `planned`
架构确认:已同步 `internal/aiprompts/architecture.md` 第 38 节;责任开发者确认:root,2026-08-09。下一刀回到剩余
planned producer/consumer 或补 Guardian 真实 Electron Gate B,不恢复旧双轨。
@@ -70,7 +70,7 @@
{ "method": "hook/started", "outlets": ["timeline", "header"] },
{ "method": "turn/completed", "outlets": ["timeline", "turnPanel"] },
{ "method": "hook/completed", "outlets": ["timeline"] },
{ "method": "turn/diff/updated", "outlets": ["diagnostics"] },
{ "method": "turn/diff/updated", "outlets": ["changes"] },
{ "method": "turn/plan/updated", "outlets": ["turnPanel"] },
{ "method": "item/started", "outlets": ["timeline"] },
{
+17 -17
View File
@@ -2,11 +2,11 @@
更新时间:2026-06-30
状态:In Progress
主线:Lime 插件包标准下的内容工厂写文章闭环
主线:Agent Plugins v1.0.0 标准下的内容工厂写文章闭环
## 1. 目标
Writing 的目标很简单:用户在 Claw 里发起“写一篇文章”,Lime 应该启动已安装的内容工厂插件,通过 Lime 插件包标准声明的 workflow、子智能体、skills、CLI、连接器和 hooks 完成资料搜索、结构策划、正文写作、审稿和配图规划。对话区任务卡和对话流过程态留在对话流里,最终文章成熟后再进入独立 `ArtifactFrame`。文章类 `ArtifactFrame` 内部使用 `articleArtifacts` renderer,可流式输出最终文章;`ArtifactFrame` 注册链已抽成通用扩展点,后续其他产物只需新增 renderer;点击框头或打开按钮后,按 `../rightsurface/README.md` 的 dock / tab 标准展开右侧 Article Editor 可编辑画布。
Writing 的目标很简单:用户在 Claw 里发起“写一篇文章”,Lime 应该启动已安装的内容工厂插件,通过标准包提供的 Skills 与 MCP 能力完成资料搜索、结构策划、正文写作、审稿和配图规划。workflow、子智能体、CLI、连接器和 hooks 属于 App Server/runtime 的产品投影,不再扩展 portable manifest。对话区任务卡和对话流过程态留在对话流里,最终文章成熟后再进入独立 `ArtifactFrame`。文章类 `ArtifactFrame` 内部使用 `articleArtifacts` renderer,可流式输出最终文章;点击框头或打开按钮后,按 `../rightsurface/README.md` 的 dock / tab 标准展开右侧 Article Editor 可编辑画布。
```text
@写文章 / @写作
@@ -23,19 +23,19 @@ Writing 的目标很简单:用户在 Claw 里发起“写一篇文章”,Lim
| 结论 | 口径 |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Lime 形成自己的插件包标准 | 入口、能力、运行、工作台和资源都按 Lime Plugin Package v1 组织,不再把外部产品格式当发布目标。 |
| 写作不是宿主内置能力 | `@写文章`、workflow、subagents、skills、CLI 和 hooks 都来自已安装内容工厂插件包。 |
| 采用 Agent Plugins portable 标准 | 包根只保留 `plugin.json``mcp.json``skills/<skill>/SKILL.md`;Lime 私有运行时字段不进入包合同。 |
| 写作不是宿主内置能力 | `@写文章`、workflow、subagents、Skills、CLI 和 hooks 都来自已安装包的 typed activation projection。 |
| 产物有独立框架 | 普通 assistant message 不承载整篇文章;过程态先在对话区回显,最终文章在独立 `ArtifactFrame` 内流式输出,右侧 Article Editor 负责编辑和深加工。 |
| 旧 Profile 路径已删除 | Article Workspace 是右侧产物事实源,Article Editor 是唯一文章编辑界面;旧 Profile 路径不再保留。 |
| 右侧布局归宿主 | 右侧 dock / tab / pane 规则统一遵循 `../rightsurface/README.md`;内容工厂只贡献 contract / article renderer / workflow。 |
| 右侧布局归宿主 | 右侧 dock / tab / pane 规则统一遵循 `../rightsurface/README.md`;内容工厂只贡献结果与 renderer 投影。 |
| 不登录也能用本地已安装插件 | 云端 marketplace 登录失败不能阻断本地 installed catalog 和本地插件激活。 |
| 旧临时 manifest 不是主路径 | 旧说明文档只给人读;机器事实源迁到 Lime 插件包 manifest 和分层能力文件。 |
| 运行时投影不伪装成包合同 | workflow、evidence、Article Workspace 和 renderer 由 App Server/read model 承接,不从旧 YAML manifest 读取。 |
## 3. 插件标准
内容工厂是 [Lime Plugin Package v1](../../tech/plugin/lime-plugin-package-v1.md) 的第一个样板包。标准目标是让 Lime 的插件可以被安装、解释、编排、运行和恢复
内容工厂是 [Plugin v3 标准](../plugin/v3/README.md) 的第一个样板闭环。包结构、字段、目录契约和 validator 规则以 [目标合同](../plugin/v3/01-target-contract.md) 为事实源
Writing 路线图只描述写文章闭环;插件包结构、字段、目录契约和 validator 规则以 `internal/tech/plugin/` 为事实源
Writing 路线图只描述写文章闭环;运行时 workflow、evidence、ArtifactFrame 和 Article Workspace 由 App Server 与 Thread/Turn/Item projection 承接
右侧 dock / tab / pane 的统一标准见 `../rightsurface/README.md`Writing 只保留 articleDraft / Article Editor 相关子面说明。
## 4. 文档索引
@@ -49,9 +49,9 @@ Writing 路线图只描述写文章闭环;插件包结构、字段、目录契
| [`implementation-plan.md`](./implementation-plan.md) | 实施切片、当前进展、验证入口和剩余缺口。 |
| [`prototypes/article-artifacts-editor.html`](./prototypes/article-artifacts-editor.html) | 通用 `ArtifactFrame`、文章 renderer 和右侧 Article Editor 的静态交互原型。 |
## 5. 与 Plugin v4 的关系
## 5. 与 Plugin v3 的关系
Writing 是 Plugin v4 内容工厂主线的第一个可用闭环。v4 的总边界仍然成立
Writing 是 Plugin v3 内容工厂主线的第一个可用闭环。v3 的总边界如下
- 插件是分发和授权根对象。
- Plugin 是插件内 UI 能力,不是宿主内置页面。
@@ -62,14 +62,14 @@ Writing 是 Plugin v4 内容工厂主线的第一个可用闭环。v4 的总边
## 6. MVP 完成判定
- [x] 内容工厂迁到 Lime Plugin Package v1`plugin.json` 成为唯一插件包入口。
- [x] 旧说明文档退出机器事实源,只保留人类说明
- [x] 内容工厂插件包声明 `@写文章` / `@写作` / `@内容工厂` 入口。
- [x] 内容工厂插件包声明 `content_article_workflow`、subagents、skillRefs、CLI、connectorshooks 和 resources
- [x] 宿主插件 contract 读取并投影 activation entries、subagents、workflows、skills、CLI`ArtifactFrame` 和 articleArtifacts renderer contract。
- [x] 内容工厂使用 Agent Plugins v1.0.0 portable 包,`plugin.json``mcp.json``skills/` 是唯一包入口。
- [x] workflow、evidence、Article Workspace 与 renderer 投影退出包 manifest,统一由 App Server/read model 承接
- [x] App Server/runtime projection 暴露 `@写文章` / `@写作` / `@内容工厂` 激活入口。
- [x] App Server/runtime 为内容工厂生成 `content_article_workflow`、subagents、skillRefs、CLI、connectorshook policy 的 activation metadata
- [x] 宿主只读取 typed projection并投影 activation entries、Skills、MCP`ArtifactFrame` 和 articleArtifacts renderer contract。
- [x] `@写作` 激活时向 request metadata 写入 workflow、subagents、skill refs、CLI refs 和 hook policy。
- [x] Electron fixture 真实点击验证:插件中心可见内容工厂,输入框可 `@写文章`,发送后先出现任务卡 / 对话流过程态,再出现独立 `ArtifactFrame`,框内流式输出最终文章,点击展开右侧 Article Editor。
- [x] App Server 在 `content.article.generate` 接受后立即发出 `content_factory.workspace_patch` streaming snapshot;最终 worker patch 覆盖同一 articleDraft,不被初始草稿污染历史恢复。
- [x] App Server 在 `content.article.generate` 接受后立即发出 `content_factory.workspace_patch` streaming snapshot;最终 runtime patch 覆盖同一 articleDraft,不被初始草稿污染历史恢复。
- [x] 宿主 connector / tool timeline 执行 `searchRequests` 并把真实 evidence 回填到 articleDraft metadata,不退化成普通聊天长文。
- [x] 历史会话恢复后默认看到 articleDraft Article Editor,并恢复已编辑正文。
@@ -79,6 +79,6 @@ Writing 是 Plugin v4 内容工厂主线的第一个可用闭环。v4 的总边
- 不恢复旧内容工厂独立 App shell。
- 不把整篇文章直接散落在普通 assistant message;完整文章必须在独立 `ArtifactFrame` 中输出。
- 不为未安装插件伪造 `@写文章` 候选。
- 不让内容工厂 worker 直接拥有右侧栏布局。
- 不让内容工厂 runtime 直接拥有右侧栏布局。
- 不恢复旧 Profile 调试面板或相关兼容入口。
- 不把其他产品的插件格式作为 Lime 发布标准。
+33 -54
View File
@@ -8,11 +8,11 @@
```text
Content Factory Plugin
-> plugin.json
-> app.runtime.yaml / app.workbench.yaml
-> activationEntries / defaultPrompt
-> mcp.json + skills/<skill>/SKILL.md
-> App Server plugin activation snapshot
-> task card / process state
-> content_article_workflow
-> subagents + skillRefs + CLI + connectors + hooks
-> content_article_workflow runtime projection
-> Skills + MCP + tool/runtime capabilities
-> App Server Agent Runtime
-> articleDraft artifact / workspace patch
-> Claw ArtifactFrame(articleArtifacts renderer) final artifact
@@ -25,11 +25,11 @@ Content Factory Plugin
flowchart LR
User[用户] --> Composer[Claw 输入框]
Composer --> Installed[Installed Plugin Registry]
Installed --> Contract[Plugin Contract]
Installed --> Contract[Typed Plugin Contract]
Contract --> RuntimeMeta[plugin activation metadata]
RuntimeMeta --> AppServer[App Server Agent Runtime]
AppServer --> Worker[Content Factory Worker]
Worker --> ArticleArtifacts[articleArtifacts]
AppServer --> Runtime[Workflow/runtime projection]
Runtime --> ArticleArtifacts[articleArtifacts]
ArticleArtifacts --> Frame[聊天独立 ArtifactFrame]
Frame --> RightSurface[右侧 Article Editor]
Contract --> Marketplace[插件中心详情页]
@@ -39,11 +39,11 @@ flowchart LR
| 层 | 责任 | 不允许 |
| ------------------ | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| 内容工厂插件 | 按 Lime Plugin Package v1 声明入口、workflow、subagents、skills、CLI、connectors、hooks、article renderer 契约。 | 直接控制 Lime 右侧栏布局 |
| Lime 插件 contract | 读取并归一化插件包能力。 | 为内容工厂 hard code 入口或默认能力。 |
| 内容工厂插件 | 提供标准 `plugin.json`、根 `mcp.json``skills/<skill>/SKILL.md`;通过这些能力参与写作。 | 直接控制 Lime 右侧栏布局或扩展私有 manifest。 |
| Lime 插件 contract | 读取并归一化标准包,生成 typed catalog/activation projection。 | 为内容工厂 hard code 入口或默认能力。 |
| Claw 输入框 | 从 installed registry 生成 `@` 候选并发送 metadata,任务卡和过程态留在对话流里,再承接最终产物。 | 未安装时伪造 `@写文章`。 |
| App Server Runtime | 执行 turn、注入 plugin activation context、保存 read model。 | 让前端 mock 代替 worker 结果。 |
| 内容工厂 worker | 执行写作 workflow,产出 workspace patch 和 evidence。 | 输出无法物化的长文本聊天正文。 |
| App Server Runtime | 执行 turn、注入 plugin activation context、保存 read model。 | 让前端 mock 代替 runtime 结果。 |
| Workflow projection | 执行写作 workflow,产出 workspace patch 和 evidence。 | 让前端 mock 代替真实 runtime 结果。 |
| 聊天消息区 | 展示运行状态、任务卡、过程态;独立 `ArtifactFrame` 只承载最终文章,文章 renderer 可在框内完整流式输出最终文章。 | 把完整正文散落到普通 assistant message。 |
| Right Surface | 承载 Article Editor、编辑动作、历史恢复;dock / tab 规则见 `../rightsurface/README.md`。 | 直接调用 provider 或插件私有文件系统。 |
| Article Workspace | 插件工作区事实、调度桥、历史恢复输入;右侧布局规则归 `../rightsurface/README.md` 统一。 | 恢复旧 Profile 命名或兼容入口。 |
@@ -52,48 +52,27 @@ Writing 不再单独定义右侧 dock / tab / pane 机制,相关布局与 surf
## 4. 插件包事实源
插件包标准见 [Lime Plugin Package v1](../../tech/plugin/lime-plugin-package-v1.md)。内容工厂插件必须以 `plugin.json` 作为唯一入口,并通过分层能力文件声明写作能力:
插件包标准见 [Plugin v3 总览](../plugin/v3/README.md) 与 [目标合同](../plugin/v3/01-target-contract.md)。
内容工厂插件只提交标准目录:
```yaml
plugin.json:
contributions:
runtime: ./app.runtime.yaml
workbench: ./app.workbench.yaml
skills: ./skills
subagents: ./subagents
clis: ./clis/clis.json
connectors: ./connectors/connectors.json
hooks: ./hooks
app.runtime.yaml:
activationEntries:
- key: content_article_generate
aliases: ["@写文章", "@写作"]
workflows:
- key: content_article_workflow
steps:
- id: research
subagent: content-researcher
skillRefs: [article-research]
- id: strategy
subagent: content-strategist
skillRefs: [article-strategy]
- id: draft
subagent: article-writer
skillRefs: [article-writing]
app.workbench.yaml:
productionObjects:
- kind: articleDraft
artifactFrames:
- key: article-artifact-frame
renderer: articleArtifacts
openTarget: article-editor
articleArtifacts:
- kind: articleDraft
renderer: article-editor
frame: article-artifact-frame
```text
plugin-root/
├── plugin.json
├── mcp.json
└── skills/<skill>/SKILL.md
```
宿主只消费这些标准事实源,不内置内容工厂写作入口。
`plugin.json` 只声明标准身份和显式 Codex extension namespace;不得声明 workflow、独立执行器、
工作区、renderer 或任意可执行路径。`mcp.json` 与 Skills 是可选能力入口,错误按组件
隔离并 fail closed。
`content_article_workflow`、activation entries、subagents、CLI/connectors/hooks、
`articleDraft``articleArtifacts` 是 Lime App Server/runtime 的产品投影:App Server 从
安装态与当前 turn 生成 activation metadata、workflow evidence 和 workspace patchThread/
Turn/Item read model 再供 Claw 与 Right Surface 消费。它们不是插件 manifest 的第二套事实源。
宿主只消费 typed projection,不读取包内旧声明、独立执行器或 renderer registry,也不在 renderer
层维护 installed/activation 状态。
## 5. 数据模型
@@ -197,15 +176,15 @@ flowchart TD
| 仓库 | 责任 |
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/Users/coso/Documents/dev/ai/limecloud/content-factory-app` | 内容工厂插件包、`plugin.json`runtime yaml、workbench yaml、skills、subagents、CLI、connectors、hooks、worker、workflow 文档和插件验证。 |
| `/Users/coso/Documents/dev/ai/aiclientproxy/lime` | 插件安装态读取、manifest normalize、plugin contract、输入栏建议、activation metadata、ArtifactFrame、articleArtifacts、Article Editor、GUI / Playwright 验证。 |
| `/Users/coso/Documents/dev/ai/limecloud/content-factory-app` | 内容工厂标准包、`plugin.json``mcp.json`、Skills 与外部产品验证;workflow 设计不扩展 portable manifest。 |
| `/Users/coso/Documents/dev/ai/aiclientproxy/lime` | 插件安装态读取、manifest normalize、typed plugin contract、输入栏建议、activation metadata、ArtifactFrame、articleArtifacts、Article Editor、GUI / Playwright 验证。 |
## 8. 架构风险
| 风险 | 约束 |
| --------------------------- | ------------------------------------------------------------------------------------------------- |
| 宿主继续 hard code 内容工厂 | 所有 `@写文章`、workflow、subagent 断言绑定 manifest fixture / installed registry。 |
| worker 只返回长正文 | schema 和测试要求返回 workspace patch、artifact、workerEvidence。 |
| 宿主继续 hard code 内容工厂 | 所有 `@写文章`、workflow、subagent 断言绑定 typed activation projection / installed registry。 |
| runtime 只返回长正文 | schema 和测试要求返回 workspace patch、artifact、evidence。 |
| 插件中心只显示营销卡片 | 详情页必须投影 subagents、CLI tools、connectors、hooks、authorization、skills。 |
| 未登录阻断本地插件 | marketplace auth error 和 installed registry 分离。 |
| 右侧栏被插件重建 | 右侧 dock 由 Host 管理,插件只声明 article renderer / surface contract。 |
@@ -24,7 +24,7 @@
| --- | --- | --- |
| 对话流过程态误入产物框 | `src/components/agent/chat/components/ArticleArtifactFrame.tsx:32-79``processSteps`)、`:164-183`(渲染)、`:82-103``facts`)、`:217-232`facts chips 渲染) | 已删除,过程态不再作为独立卡片的一部分。 |
| "本轮执行已完成"兜底文案 | `src/components/agent/chat/hooks/agentStreamCompletionController.ts:16-21` + `agent.json:666` | 保持待查,若仍出现则单独修。 |
| 一输入即完成态 | `lime-rs/.../plugin_worker_streaming.rs:19-81`(初始快照 `status:"streaming"`)+ 前端框头完成态汇总 | 已转成文章框流式状态,保留给最终产物展示。 |
| 一输入即完成态 | App Server runtime streaming projection(初始快照 `status:"streaming"`)+ 前端框头完成态汇总 | 已转成文章框流式状态,保留给最终产物展示。 |
点击展开右侧编辑器接线(`onArtifactClick`)已贯穿 `MessageList`**无需改动**。
@@ -40,7 +40,7 @@
**Tests**`MessageArtifactCards.test.tsx` 已补充流式文章回归。
### Stage 2:消除"一输入即完成"的空回复兜底观感
**Goal**:写文章 worker turn 流式期间仍显示文章框的 streaming 态,不回落成普通聊天长文。
**Goal**:写文章 runtime turn 流式期间仍显示文章框的 streaming 态,不回落成普通聊天长文。
**后续**:若还出现"本轮执行已完成"兜底,再单独定位 completion controller。
### Stage 3:文档与回归
+35 -36
View File
@@ -5,7 +5,7 @@
## 1. 当前主目标
把写文章从宿主硬编码入口收敛为 Lime Plugin Package v1 下的内容工厂插件 workflow,并完成最小可用闭环:
把写文章从宿主硬编码入口收敛为 Agent Plugins v1.0.0 portable 包下的内容工厂插件闭环,并完成最小可用闭环:
```text
已安装内容工厂插件包 -> @写文章 -> 任务卡 / 过程态留在对话流 -> content_article_workflow -> ArtifactFrame(articleArtifacts renderer) -> 右侧 Article Editordock / tab 标准见 ../rightsurface/README.md
@@ -13,12 +13,12 @@
## 2. 当前状态
- 已有内容工厂外部包、runtime yaml、workbench yaml、worker、skills 和基础 workflow,是迁移输入
- 已有宿主 plugin contract、输入栏候选、activation metadata、ArtifactDocument / Workbench 基础路径,是迁移输入。
- 内容工厂样板包骨架已迁到 Lime Plugin Package v1`plugin.json` 成为入口,`subagents/``clis/``connectors/``hooks/``resources/` 已落盘并通过包内验证
- 插件包标准事实源已落到 `internal/tech/plugin/`
- 宿主本地安装链正在切到只读取 `plugin.json`,旧入口归类为 dead。
- LimeCore 服务端控制面本轮暂不修改;本轮只把宿主本地安装、插件投影和内容工厂写作主链收敛到 `plugin.json`。等宿主 package v1 contract、manifest hash 和安装投影稳定后,再统一迁移云端 release / upload 校验。
- 已有内容工厂标准包、Skills、MCP 和基础 workflow,是当前实现输入;workflow/evidence 不属于 portable manifest
- 已有宿主 typed plugin contract、输入栏候选、activation metadata、ArtifactDocument / Article Workspace 基础路径,是当前实现输入。
- 内容工厂样板包已收敛为 `plugin.json``mcp.json``skills/<skill>/SKILL.md`App Server/runtime 负责生成 workflow、subagent、CLI、connector、hook 和 Article Workspace projection
- 插件包标准事实源已落到 `internal/roadmap/plugin/v3/README.md``01-target-contract.md`
- 宿主本地安装链已收敛为只读取标准 `plugin.json`,旧入口归类为 dead。
- LimeCore 服务端控制面本轮暂不修改;本轮只把宿主本地安装、插件投影和内容工厂写作主链收敛到标准 `plugin.json` / `mcp.json` / Skills。等 v3 package identity、manifest hash 和安装投影稳定后,再统一迁移云端 release / upload 校验。
## 3. 实施切片
@@ -26,18 +26,17 @@
状态:完成骨架
- [x] 在 `internal/tech/plugin/` 建立 Lime Plugin Package v1 标准文档。
- [x] 内容工厂外部包新增 `plugin.json` 作为唯一插件包入口。
- [x] 内容工厂外部包补齐 `subagents/``clis/``connectors/``hooks/``resources/` 标准目录
- [x] 在 `internal/roadmap/plugin/v3/` 建立 Agent Plugins v1.0.0 标准文档。
- [x] 内容工厂外部包 `plugin.json``mcp.json``skills/<skill>/SKILL.md` 作为唯一 portable 入口。
- [x] workflow、subagents、CLI、connectors、hooks 和 resources 从 package manifest 移出,统一由 App Server/runtime projection 承接
- [x] 旧说明文档退出机器事实源。
- [x] validator 按 v1 标准校验 `plugin.json`runtime、workbench、skills、subagents、CLI、connectors、hooks、resources
- [x] validator 按 v3 标准校验 `plugin.json``mcp.json`、direct-child Skills、路径安全和组件隔离
### P1:内容工厂样板包
状态:骨架完成,runtime readiness 投影和 prompt/task hook 生命周期执行已接入,connector 授权仍待深化
- [x] `app.runtime.yaml` 使用 v1 骨架声明 `content_article_workflow`
- [x] `app.workbench.yaml` 使用 v1 骨架声明 `articleDraft` 业务对象和 articleArtifacts contract。
- [x] App Server/runtime projection 声明 `content_article_workflow`,并物化 `articleDraft` / `articleArtifacts` contract
- [x] workflow 明确绑定 research、strategy、draft、review、image-plan 五个步骤。
- [x] 每个 subagent 有 `prompt.md` 和输出格式。
- [x] skills 使用稳定 id,被 workflow 引用。
@@ -51,15 +50,15 @@
状态:安装链、activation 投影、详情能力展示、`clis` / `hooks` 一等 contract、runtime readiness 投影和 hook lifecycle evidence 完成;旧 `contentFactoryWorkspacePatch` 临时字段与内容工厂 raw artifact path / kind 兼容读取均已收口到统一 helper / 插件模块白名单
- [x] plugin contract 类型支持 `schemaVersion=lime.plugin.package.v1``contributions``plugin.json` 入口形状
- [x] plugin contract 可从 `contributions` 派生 runtime / workbench / skills / subagents / CLI / connectors / hooks 路径
- [x] plugin contract 类型支持 Agent Plugins v1.0.0 根 `plugin.json`、根 `mcp.json` 与 direct-child Skills
- [x] workflow / Article Workspace / renderer projection 由 App Server/read model 派生,不从 manifest 私有路径读取
- [x] 本地安装从 `plugin.json` 读取插件包入口。
- [x] 本地安装不再支持旧入口;只有负向测试可写旧文件名证明拒绝。
- [x] 本地 / 云包 inspect 从 `plugin.json` 读取 runtime / workbench,并投影 activation entries、workflow、worker、workbench 和 articleDraft 恢复 contract。
- [x] 本地 / 云包 inspect 从标准包读取 identity、Skills、MCP,并由 App Server 投影 activation entries、workflow、Article Workspace 和 articleDraft 恢复 contract。
- [x] App Server 包解析 / 投影从 `local_data_source/plugins` 抽到 `plugin_packages``local_data_source` 只保留 installed state / uninstall / 本地持久化委托。
- [x] activation entry contract 保留 `taskKind``workflowKey``outputArtifactKind``rightSurface``expectedObjects`,不再在前端 contract 归一化时丢失插件包声明
- [x] 插件中心详情页展示 subagents、workflows、skills、CLI / worker、connectors、hooks、授权和可用性。
- [x] marketplace summary 合并 installed plugin manifest 的 workflows / connectors / hooks / clis,不再只展示路径或少量摘要
- [x] activation entry contract 保留 `taskKind``workflowKey``outputArtifactKind``rightSurface``expectedObjects`,不再在前端 contract 归一化时丢失 App Server projection
- [x] 插件中心详情页展示 typed projection 的 subagents、workflows、skills、CLI、connectors、hooks、授权和可用性。
- [x] marketplace summary 合并 installed plugin typed projection 的 workflows / connectors / hooks / clis,不再把这些运行时能力误写成 manifest 字段
- [x] `pluginContract.ts``1000` 行以上拆回阈值内;plugin package component normalizer、Plugin 投影和通用工具已拆分,并补齐 `clis` / `hooks` 的一等 contract 类型。
- [x] workflow contract 保留 `cliRefs``connectorRefs``hookPolicy`,发送 metadata 同步写入 `runtime_readiness` / `plugin_runtime_readiness`App Server `<plugin_activation_context>` 渲染 runtime readiness,历史恢复可反投影同一状态。
- [x] 右侧 Article Workspace 预览 artifact 不再生产 `contentFactoryWorkspacePatch` 旧临时字段,只保留通用 `workspacePatch` / `articleWorkspace` metadata;读取侧暂保留旧历史兼容。
@@ -88,7 +87,7 @@
- [x] 清理前一版把完整文章塞进非文章编辑器面板的偏航实现。
- [x] 新增通用 `ArtifactFrame` shell:从 artifact contract 选择 renderer,支持文章、图片集、表格、演示稿、网页、报告等后续产物框。
- [x] 新增通用 `artifact frame registry`:文章先作为首个 renderer,后续 artifact 只需注册自己的 renderer 与 matcher,不必改主列表分发。
- [x] 新增 `articleArtifacts` renderer:从 articleDraft / worker artifact 在框内流式输出完整文章,不落到普通 assistant message。
- [x] 新增 `articleArtifacts` renderer:从 articleDraft / runtime artifact 在框内流式输出完整文章,不落到普通 assistant message。
- [x] 新增 Article Editor renderer:右侧显示可编辑正文、工具条、结构、引用、配图规划和动作。
- [x] Article Editor 正文画布独立为 Tiptap 组件,避免继续膨胀右侧工作台主文件。
- [x] Article Editor 后续 action 携带当前本地编辑 Markdown,避免改写 / 导出丢失画布内编辑上下文。
@@ -103,12 +102,12 @@
### P5:真实 workflow 执行质量
状态:基础 worker dogfood 已跑通;worker 已输出 host 可执行检索请求、pending 检索证据、审稿清单和配图规划,宿主已回填真实检索 evidence,文章失败态已 fail closed
状态:基础 runtime dogfood 已跑通;runtime 已输出 host 可执行检索请求、pending 检索证据、审稿清单和配图规划,宿主已回填真实检索 evidence,文章失败态已 fail closed
- [x] 内容工厂 worker 拆出 `article-planning.mjs`,入口 worker 降到 800 行以下。
- [x] fixture worker 输出 research -> strategy -> draft -> review -> image plan 的结构化写作对象。
- [x] 内容工厂 runtime 拆出 `article-planning.mjs`,入口模块降到 800 行以下。
- [x] runtime fixture 输出 research -> strategy -> draft -> review -> image plan 的结构化写作对象。
- [x] 多轮检索 evidence 已进入 articleDraft metadata,并在聊天产物框与右侧 Article Editor 可见。
- [x] `articleDraft` / `workerEvidence` 输出 `searchRequests``searchEvidence``reviewChecklist``imagePlan`
- [x] `articleDraft` / App Server evidence projection 输出 `searchRequests``searchEvidence``reviewChecklist``imagePlan`
- [x] 宿主 connector / tool timeline 执行 `searchRequests` 并把真实 evidence 回填到 articleDraft metadata。
- [x] 写作失败时不产出假 articleDraft。
- [x] 审稿和配图规划进入 articleDraft metadata。
@@ -131,31 +130,31 @@
原因:
- 宿主 `plugin.json` 安装链、runtime / workbench 投影、内容工厂 `@写文章` E2E 还在收敛中;服务端此时跟进会提前固化半成品合同。
- 服务端当前边界是 catalog、release metadata、tenant enablement、license / registration、package URL / hash 下发,不执行插件 worker,不渲染 Article Editor,不托管 UI runtime。
- `manifestHash` 已规划为投影后的 Plugin manifest hash`packageHash` 已规划为包内容 hash;这两个口径必须先在宿主本地 fetch / install / review 链路稳定。
- 宿主标准包安装链、activation projection、内容工厂 `@写文章` E2E 还在收敛中;服务端此时跟进会提前固化半成品合同。
- 服务端当前边界是 catalog、release metadata、tenant enablement、license / registration、package URL / hash 下发,不执行插件 runtime,不渲染 Article Editor,不托管 UI runtime。
- `manifestHash` 已规划为标准 manifest hash`packageHash` 已规划为包内容 hash;这两个口径必须先在 `plugin/list` / `plugin/read` / `plugin/install` 链路稳定。
- 内容工厂当前主风险在客户端主链:已安装插件可见、`@写文章` 激活、独立 ArtifactFrame、右侧 Article Editor、多轮搜索后写作。先改服务端不能直接证明这些主风险收口。
本阶段服务端分类:
- `current`:继续保持云端控制面,只负责可见性、授权、release metadata 和包引用下发。
- `deferred`v1 package upload 校验、release summary、OpenAPI / SDK / 类型同步。
- `dead`:在服务端新增插件 worker 执行、UI runtime 托管、Article Editor 渲染或 `/plugins/*/run` 路由。
- `deferred`标准 package upload 校验、release summary、OpenAPI / SDK / 类型同步。
- `dead`:在服务端新增插件 runtime 执行、UI runtime 托管、Article Editor 渲染或 `/plugins/*/run` 路由。
后续进入条件:
- 宿主 `agentAppLocalPackage/inspect``agentAppPackage/fetchCloud` 和前端 install review 均稳定只认 `plugin.json`
- Lime Plugin Package v1`manifestHash` 口径固定为投影后的 Plugin manifest hash`packageHash` 口径固定为包内容 hash。
- 内容工厂外部包完成 v1 validator、sample runtime、local install 和 `@写文章` E2E。
- 宿主 `plugin/list``plugin/read``plugin/install` 和前端 install review 均稳定只认标准包入口
- Agent Plugins v1.0.0`manifestHash` 口径固定为标准 manifest hash`packageHash` 口径固定为包内容 hash。
- 内容工厂外部包完成 v3 validator、sample runtime、local install 和 `@写文章` E2E。
服务端待办:
- [ ] 平台 package upload 校验 zip / lapp 中必须存在唯一 `plugin.json`
- [ ] release metadata / manifestSummary 从旧 Plugin 摘要迁到 Lime Plugin Package v1 摘要。
- [ ] 平台 package upload 校验发布包中必须存在唯一 `plugin.json`、根 `mcp.json`(如声明 MCP)和 `skills/`
- [ ] release metadata / manifestSummary 从旧摘要迁到 Agent Plugins v1.0.0 摘要。
- [ ] `content-factory-app` seeded catalog 指向 v1 package 版本和新 hash。
- [ ] 未激活注册码时继续不下发 package URL / hash,避免本地绕过企业定制授权。
- [ ] API client、OpenAPI、docs 和 contract tests 同步 v1 字段。
- [ ] 保持 LimeCore 不执行插件 worker、不托管 UI runtime、不新增 `/plugins/*/run`
- [ ] API client、OpenAPI、docs 和 contract tests 同步 v3 字段。
- [ ] 保持 LimeCore 不执行插件 runtime、不托管 UI runtime、不新增 `/plugins/*/run`
## 4. 验证入口
@@ -7,7 +7,7 @@
当前用户目标不是“打开一个内容工厂页面”,而是在 Lime 中完成一件具体任务:写一篇文章。01Agent 的交互可以参考,但 Lime 的布局边界不同:Lime 的中间区域是 Claw 对话和运行过程,画布 / 侧边栏在右侧,不应复制 01Agent 的左侧或全屏画布。
内容工厂已经作为插件存在,因此写作入口不应再通过宿主硬编码。正确路径是让内容工厂按 Lime Plugin Package v1 声明自己能写文章,声明需要哪些子智能体、skills、CLI、connectors、hooks 和 workflow;宿主只负责安装态发现、显式激活、运行 metadata 透传、独立 `ArtifactFrame`、article renderer 和右侧 Article Editor,右侧布局标准统一见 `../rightsurface/README.md`
内容工厂已经作为插件存在,因此写作入口不应再通过宿主硬编码。正确路径是让内容工厂按 Agent Plugins v1.0.0 portable 包提供 `plugin.json``mcp.json` 和 Skillsworkflow、子智能体、CLI、connectors、hooks、运行 metadata 和 Article Workspace 属于 App Server/runtime projection,不再写入私有 manifest。宿主只负责安装态发现、显式激活、独立 `ArtifactFrame`、article renderer 和右侧 Article Editor,右侧布局标准统一见 `../rightsurface/README.md`
前一版把 Profile 当成右侧文章主界面是错误方向。当前不再保留这条兼容路径;Article Workspace 承接插件工作区事实,用户看到的产物界面必须是 Article Editor 画布,并遵循 `../rightsurface/README.md` 的 dock / tab 规则。
@@ -25,7 +25,7 @@
| ----------- | ---------------------------------------------------------------------------------------------------- |
| 普通用户 | 用一句“写一篇文章”进入完整写作流程,不需要理解插件包或 workflow 概念。 |
| 内容创作者 | 能在右侧 Article Editor 中看到文章结构、引用、配图建议和审稿状态,后续可继续改写。 |
| 插件开发者 | 能通过 Lime 插件包自描述入口、子 Agent、skills、CLI、hooks 和 article renderer,不需要宿主写死能力。 |
| 插件开发者 | 能通过标准插件包提供 Skills/MCP,并由 typed activation projection 暴露写作能力,不需要宿主写死能力。 |
| Lime 宿主 | 保持 Claw / Right Surface / 历史恢复的一致架构,不为单个插件新增分叉页面。 |
| 运营 / 分发 | 插件中心能解释“内容工厂用了哪些 Agent、工具、授权和 skills”,降低黑盒感。 |
@@ -38,7 +38,7 @@
| WS-03 | 作为用户,我希望文章产物在一个独立框里完整输出,而不是混进普通聊天正文。 | 过程说明留在对话区,`ArtifactFrame` 内只展示最终文章并可流式输出。 |
| WS-04 | 作为用户,我想点击文章产物框后在右侧继续编辑或生成配图。 | `ArtifactFrame` 打开入口点击后打开右侧 `articleDraft` Article Editor。 |
| WS-05 | 作为用户,我即使没有登录云端账号,也能使用本地已安装内容工厂。 | cloud marketplace 401/403 只影响云端列表,不阻断 installed registry。 |
| WS-06 | 作为插件开发者,我想在内容工厂插件包里声明写作 workflow。 | 宿主读取 `activationEntries``workflows``subagents``skillRefs`、CLI、connectors 和 hooks,不靠 hard code。 |
| WS-06 | 作为插件开发者,我想让标准包参与写作 workflow。 | App Server 从安装态与 Skills/MCP 生成 `activationEntries``workflows``subagents``skillRefs`、CLI、connectors 和 hooks,不靠 hard code。 |
## 5. 用户用例
+15 -15
View File
@@ -20,7 +20,7 @@ sequenceDiagram
Page->>Installed: 读取本地已安装插件包
Installed-->>Page: content-factory-app
Page->>Contract: projectPluginRegistryFromInstalledPackages
Contract-->>Page: activationEntries / subagents / skills / CLI / connectors / hooks / workflows
Contract-->>Page: typed Skills / MCP / activation projection / readiness
Page-->>User: 展示内容工厂和能力详情
```
@@ -37,7 +37,7 @@ sequenceDiagram
User->>Composer: 输入 @写文章 写一篇文章
Composer->>Registry: buildPluginActivationMentionCatalog
Registry-->>Composer: 内容工厂插件包 activation entry
Registry-->>Composer: 内容工厂 typed activation entry
Composer->>Intent: resolveWorkspacePluginIntent
Intent-->>Composer: content_article_generate + plugin contract
Composer->>Runtime: agentSession/turn/start + plugin_activation metadata
@@ -50,7 +50,7 @@ sequenceDiagram
sequenceDiagram
autonumber
participant Runtime as App Server Runtime
participant Worker as Content Factory Worker
participant Projection as Workflow Projection
participant Research as content-researcher
participant Strategy as content-strategist
participant Writer as article-writer
@@ -58,18 +58,18 @@ sequenceDiagram
participant Image as image-planner
participant Store as Artifact / Read Model
Runtime->>Worker: content.article.generate
Worker->>Research: 搜索主题和事实
Research-->>Worker: research notes
Worker->>Strategy: 生成角度和大纲
Strategy-->>Worker: brief + outline
Worker->>Writer: 写正文
Writer-->>Worker: markdown draft
Worker->>Editor: 审稿校对
Editor-->>Worker: revised draft + issues
Worker->>Image: 规划配图
Image-->>Worker: image slots + prompts
Worker->>Store: workspace patch + worker evidence
Runtime->>Projection: content.article.generate
Projection->>Research: 搜索主题和事实
Research-->>Projection: research notes
Projection->>Strategy: 生成角度和大纲
Strategy-->>Projection: brief + outline
Projection->>Writer: 写正文
Writer-->>Projection: markdown draft
Projection->>Editor: 审稿校对
Editor-->>Projection: revised draft + issues
Projection->>Image: 规划配图
Image-->>Projection: image slots + prompts
Projection->>Store: workspace patch + runtime evidence
Store-->>Runtime: articleDraft artifact refs
```
+10 -10
View File
@@ -5,7 +5,7 @@
## 1. Workflow 定义
`content_article_workflow`内容工厂插件包声明的文章生产工作流。它不是宿主内置 parser,也不是普通聊天 prompt。
`content_article_workflow` App Server/runtime 从标准插件激活态生成的文章生产 workflow projection。它不是 portable manifest 字段,也不是普通聊天 prompt。
右侧 dock / tab / pane 的统一规则见 `../rightsurface/README.md`;本文件只描述 articleDraft 产物、写作 workflow 和 Article Editor 子面内容。
@@ -36,7 +36,7 @@ content_article_generate
| skill | 责任 | 备注 |
| -------------------- | ---------------------------- | ---------------------------------- |
| `article-research` | 资料检索、事实整理和引用归档。 | 内容工厂插件声明,不由宿主硬编码。 |
| `article-research` | 资料检索、事实整理和引用归档。 | 标准包 Skill,由插件提供,不由宿主硬编码。 |
| `article-strategy` | 选题、角度、受众和结构策划。 | 输出标题候选、大纲和写作计划。 |
| `article-writing` | 中文文章写作和正文成稿。 | 负责 `articleDraft.source.markdown`。 |
| `article-editing` | 审稿、校对、事实检查和表达调整。 | 输出审稿清单和修改建议。 |
@@ -46,11 +46,11 @@ content_article_generate
| 能力 | 责任 |
| ----------------------------- | -------------------------------------------------------------------------- |
| `search_query` / WebSearch | 由 worker 声明 `searchRequests`,由宿主 connector / tool timeline 执行真实检索、事实补充和引用确认,并把 evidence 回填到 articleDraft metadata。 |
| `content-factory-worker` | 执行内容工厂 runtime task,产出 workspace patch |
| `content-factory` CLI | 本地 inspect / run / validate,证明插件包、workflow 和 worker 自洽。 |
| connectors | 声明搜索、知识库、云端账号、媒体生成等外部依赖和授权状态。 |
| toolRefs | 声明 worker / CLI / local tool 依赖与能力标签;它不是 connector 列表。 |
| `search_query` / WebSearch | 由 App Server/runtime projection 生成 `searchRequests`,由宿主 connector / tool timeline 执行真实检索、事实补充和引用确认,并把 evidence 回填到 articleDraft metadata。 |
| runtime projection | 执行内容工厂 workflow,产出 workspace patch 和结构化 evidence。 |
| typed plugin projection | 投影 Skills、MCP、工具、授权和可用性;不把这些运行时能力写回 manifest。 |
| connectors | 由 App Server/runtime 记录搜索、知识库、云端账号、媒体生成等外部依赖和授权状态。 |
| tool refs | 记录当前 turn 的工具依赖与能力标签;它不是 connector 列表。 |
| hooks | 在 prompt / tool / task 生命周期中注入运行约束、路由策略和 evidence 归档。 |
| `artifact writer` | 保存 Markdown / workspace patch / evidence。 |
| `right surface action router` | 处理继续改写、生成配图、导出等受控动作。 |
@@ -76,7 +76,7 @@ flowchart TD
`ArtifactFrame` 是聊天区里的通用独立产物框,承担“承载产物、展示状态、流式更新、点击进入右侧画布”的入口。文章只是其中一种 renderer,后续还应支持图片集、表格、演示稿、网页、报告、代码和媒体产物。注册链以 `ArtifactFrame` 为事实源,不再使用 message 专用命名。写作流程里,任务卡和过程态先回显在对话区,最终文章成熟后才进入 `ArtifactFrame(articleArtifacts)`,右侧展开行为遵循 `../rightsurface/README.md`
当前 worker 的安全契约是 `directProviderAccess=false``directFilesystemAccess=false`worker 可以输出 `searchRequests`、pending `searchEvidence``reviewChecklist``imagePlan`,但不能直接联网或读写宿主文件。真实检索必须由宿主 connector / tool timeline 执行并回填;在这一步完成前,不能把“多轮检索结构已生成”写成“真实搜索已完成”。
当前 runtime projection 的安全契约是 `directProviderAccess=false``directFilesystemAccess=false`runtime 可以输出 `searchRequests`、pending `searchEvidence``reviewChecklist``imagePlan`,但不能直接联网或读写宿主文件。真实检索必须由宿主 connector / tool timeline 执行并回填;在这一步完成前,不能把“多轮检索结构已生成”写成“真实搜索已完成”。
通用框架必须包含:
@@ -132,8 +132,8 @@ flowchart TD
- `@写文章` 输入建议来自 installed plugin contract。
- activation metadata 包含 workflow、subagents、skills、CLI refs、connector refs 和 hook policy。
- worker evidence 包含 `workflowKey``orchestration`
- worker evidence 包含 `searchRequests`、pending `searchEvidence``reviewChecklist``imagePlan`
- runtime evidence 包含 `workflowKey``orchestration`
- runtime evidence 包含 `searchRequests`、pending `searchEvidence``reviewChecklist``imagePlan`
- 宿主 connector 执行 `searchRequests` 后,真实检索结果回填到 articleDraft metadata 和工具时间线。
- 聊天出现独立 `ArtifactFrame`,文章正文在框内流式输出。
- 产物框点击能打开右侧 `articleDraft` Article Editor。
@@ -1,16 +1,15 @@
# 插件中心内置发布工作台 PRD
更新时间:2026-07-06
状态:MVP 工程闭环已实现并完成定向验证;Desktop 开发者云端 preflight、平台审核工作台与提交状态面板已接入;LimeCore console 运营后台 UI 仍待后续阶段
状态:Historical / superseded by Plugin v3;发布能力边界保留为云端控制面证据
适用范围:Lime Desktop / 插件中心 / 插件开发者发布流 / LimeCore Plugin Marketplace
事实源:
- `internal/roadmap/plugin/prd.md`
- `internal/roadmap/plugin/architecture.md`
- `internal/roadmap/plugin/implementation-plan.md`
- `internal/roadmap/plugin/v3/README.md`
- `internal/roadmap/plugin/v3/01-target-contract.md`
- `internal/roadmap/plugin/v3/03-execution-plan.md`
- 服务端专项规划:`internal/roadmap/plugin/deverlop/plugin-publish-limecore-server-plan.md`
- `internal/tech/plugin/lime-plugin-package-v1.md`
- 旧参考:`/Users/coso/Documents/dev/ai/limecloud/lime-agent-app-studio`
- Desktop current 主链:`src/lib/api/plugins.ts -> App Server JSON-RPC`
- Desktop 发布 / 审核 current 主链:
@@ -33,7 +32,7 @@
- `packages/types/index.ts`
- `packages/api-client/index.ts`
- `contracts/openapi/control-plane-svc/*`
- `internal/roadmap/plugin/implementation-plan.md`
- `internal/roadmap/plugin/v3/03-execution-plan.md`
- `internal/roadmap/plugin/operations-runbook.md`
## 1. 一句话目标
@@ -42,7 +41,7 @@
```text
旧时代:安装一个发布应用,再用它发布 Agent App
新时代:插件中心内置开发者发布流,直接发布 Lime Plugin Package v1
新时代:插件中心内置开发者发布流,直接发布 Agent Plugins v1.0.0 portable package
```
## 2. 背景
@@ -68,7 +67,7 @@
| ---------- | ------------------------------ | ----------------------------------------------------- |
| 产品入口 | 独立 Agent App Studio | 插件中心内置发布工作台 |
| 机器事实源 | `APP.md` frontmatter | `plugin.json` |
| 发布包语义 | `.lapp` Agent App 包 | Lime Plugin Package v1 |
| 发布包语义 | `.lapp` Agent App 包 | Agent Plugins v1.0.0 portable package |
| 用户心智 | 先安装发布应用,再发布应用 | 在插件中心管理、开发和发布插件 |
| 运行边界 | Agent App runtime package | Plugin manifest / runtime / workbench contract |
| 市场事实源 | Agent App marketplace 历史形态 | LimeCore Plugin catalog / release / tenant enablement |
@@ -87,7 +86,7 @@
## 3. 目的
1. 统一开发者发布入口,让插件中心同时承接“使用插件”和“发布插件”。
2. 把发布事实源从 `APP.md` / `.lapp` 迁到 Lime Plugin Package v1
2. 把发布事实源从 `APP.md` / `.lapp` 迁到 Agent Plugins v1.0.0 portable package。
3. 复用旧 Studio 中已经验证过的诊断、打包、dry-run、签名和 LimeCore 发布经验。
4. 消除独立 App Studio 带来的安装成本、入口分裂和旧 Agent App 心智。
5. 为后续插件审核、灰度、注册码、租户启用和发布回滚提供统一工作台。
@@ -107,7 +106,7 @@
| Surface | 分类 | 规则 |
| ---------------------------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------- |
| 插件中心内置发布工作台 | `current` | 后续发布 UX、开发者认证、dry-run、发布结果和发布历史都向这里收敛。 |
| Lime Plugin Package v1 | `current` | 插件包、运行、工作区、skills、resources 和验证的机器事实源。 |
| Agent Plugins v1.0.0 portable package | `current` | `plugin.json``mcp.json`、Skills 和包安全校验的机器事实源。 |
| `plugin.json` | `current` | 插件包唯一入口;插件中心、本地校验和云端 manifest summary 均从这里投影。 |
| LimeCore Plugin catalog / release / enablement | `current` | 云端发布、版本、租户可见性和 marketplace 列表事实源。 |
| LimeCore `POST /api/v1/platform/plugins/bulk-publish` | `current` | 已打通 catalog、release、targets 的原子发布入口;新工作台必须复用。 |
@@ -115,7 +114,7 @@
| 旧 `lime-agent-app-studio` 诊断 / 打包 / dry-run 经验 | `compat` | 只作为能力参考或迁移输入,不作为用户主入口。 |
| 旧 npm CLI | `deprecated` | 仅可作为 CI/headless 自动化候选,不是 v1 产品入口;若保留,必须委托插件中心同一发布服务契约。 |
| `APP.md` frontmatter 作为机器事实源 | `dead for new work` | 新插件发布不得依赖;文档说明可保留给历史迁移。 |
| `.lapp` 作为新插件主发布格式 | `dead for new work` | 新发布流使用 Lime Plugin Package v1 的受控插件包。 |
| `.lapp` 作为新插件主发布格式 | `dead for new work` | 新发布流使用 Agent Plugins v1.0.0 的受控插件包。 |
| 独立 Agent App Studio 可视化应用 | `dead for new work` | 不再作为发布插件的产品入口。 |
## 6. 用户与角色
@@ -213,9 +212,9 @@
| 编号 | 需求 | 验收 |
| ----- | ---------------------------------------------------- | ------------------------------------------------------------- |
| FR-05 | 校验 `plugin.json` 是否存在且 schemaVersion 合法。 | 缺失或版本不支持时 fail closed。 |
| FR-06 | 校验 contributions 路径。 | 只允许插件包内相对路径;越界路径阻断发布。 |
| FR-07 | 校验 runtime / workbench / skills / resources 索引。 | 缺少必需文件时展示错误;可选能力缺失只给 warning。 |
| FR-05 | 校验 `plugin.json` 是否存在且符合 Agent Plugins v1.0.0 schema。 | 缺失或 schema 不支持时 fail closed。 |
| FR-06 | 校验`mcp.json``skills/` 目录路径。 | 只允许插件包内固定位置;越界路径阻断发布。 |
| FR-07 | 校验 MCP server 与 direct-child Skills。 | 缺少可选组件不阻断;非法组件按类型隔离并记录 warning。 |
| FR-08 | 校验版本号和 release channel。 | 版本不能低于或等于已发布 latest version,除非是明确重发策略。 |
| FR-09 | 展示 warnings 与 blockers。 | blockers 阻断打包和发布;warnings 不阻断但必须可见。 |
@@ -411,9 +410,8 @@ flowchart TD
subgraph Local[本地插件包]
PluginJson[plugin.json]
RuntimeYaml[app.runtime.yaml]
WorkbenchYaml[app.workbench.yaml]
Skills[skills / subagents / resources]
McpJson[mcp.json]
Skills[skills/<skill>/SKILL.md]
end
subgraph Desktop[Lime Desktop]
@@ -440,8 +438,7 @@ flowchart TD
PublishWorkbench --> DirectoryPicker
DirectoryPicker --> PluginJson
PluginJson --> Validator
RuntimeYaml --> Validator
WorkbenchYaml --> Validator
McpJson --> Validator
Skills --> Validator
Validator --> Packager
Packager --> Signature
@@ -466,7 +463,7 @@ flowchart TD
| 层 | 职责 | 不做什么 |
| ------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------- |
| 插件中心 UI | 入口、状态展示、发布向导、错误呈现。 | 不拼 LimeCore payload 细节。 |
| 发布 View Model | 目录状态、诊断结果、dry-run 计划、按钮可用性。 | 不直接读取 provider key 或行插件 worker。 |
| 发布 View Model | 目录状态、诊断结果、dry-run 计划、按钮可用性。 | 不直接读取 provider key 或行插件 runtime。 |
| 本地发布服务 | 读取插件包、校验、打包、hash、签名证明。 | 不持久化明文 token。 |
| LimeCore client | developer profile、package upload、release submission、platform review、marketplace refresh。 | 不通过 Lime App Server 中转 marketplace 发布。 |
| LimeCore control-plane | catalog / release / enablement / registration policy。 | 不执行插件 runtime。 |
@@ -559,7 +556,7 @@ sequenceDiagram
Studio->>Studio: inspectProject(APP.md / dist/ui)
Center->>Center: inspectPluginPackage(plugin.json / contributions)
Studio->>Studio: packageProject(.lapp) + sha256
Center->>Center: packagePlugin(Lime Plugin Package v1) + sha256
Center->>Center: packagePlugin(Agent Plugins v1.0.0) + sha256
Studio->>Studio: read app.signature.yaml
Center->>Center: read plugin signature proof
Studio->>Core: POST /v1/platform/plugins/bulk-publish
@@ -653,9 +650,9 @@ stateDiagram-v2
| ------------------------------ | ------------------------------------- | --------------------------------------- |
| 插件目录 | 用户选择 | 仅作为本次发布上下文,不写入 manifest。 |
| `plugin.json` | 插件包 | 唯一机器入口。 |
| `app.runtime.yaml` | `plugin.json#contributions.runtime` | 运行能力声明。 |
| `app.workbench.yaml` | `plugin.json#contributions.workbench` | 产物、surface、action、历史恢复声明。 |
| skills / subagents / resources | `plugin.json#contributions` | 必须在插件包目录内。 |
| `mcp.json` | 根包文件 | MCP server 声明;只允许标准 schema。 |
| `skills/<skill>/SKILL.md` | 根包目录 | Skills 能力声明;只扫描直接子目录。 |
| workflow / workspace evidence | App Server/read model | 运行与产物投影,不是 manifest 字段。 |
| 签名证明 | 插件包或用户选择 | 只读取签名结果,不生成私钥。 |
| cloud session | Lime 宿主 | 仅用于认证和发布请求,不写入插件包。 |
@@ -934,7 +931,7 @@ stateDiagram-v2
| 旧能力 | 新落点 |
| ------------------------------------------ | ----------------------------------------------------- |
| `project inspect` | 插件中心本地诊断服务。 |
| `.lapp` 打包和 hash | Lime Plugin Package v1 打包和 hash。 |
| `.lapp` 打包和 hash | Agent Plugins v1.0.0 package 打包和 hash。 |
| `publish --dry-run` | 插件中心 dry-run 发布计划。 |
| developer profile 检查 | 插件中心发布前认证 gate。 |
| signature proof 读取 | 插件发布签名校验步骤。 |
@@ -972,7 +969,7 @@ stateDiagram-v2
- [x] 插件中心存在内置发布工作台入口。
- [x] 插件中心存在平台发布审核工作台入口。
- [x] 用户可选择本地 Lime Plugin Package v1 目录。
- [x] 用户可选择本地 Agent Plugins v1.0.0 标准包目录。
- [x] `plugin.json` 缺失、schema 不支持、路径越界时 fail closed。
- [x] 发布前展示 blockers、warnings、package hash、manifest hash、签名状态。
- [x] dry-run 能展示 catalog / release / target impact 摘要;完整 tenant enablement 字段级 diff 仍是后续项。
+2 -2
View File
@@ -1,8 +1,8 @@
# Lime 插件产品需求文档
更新时间:2026-06-25
状态:Draft
事实源:`internal/roadmap/rightsurface/README.md``internal/roadmap/workbench/v3/*``internal/tech/plugin/README.md`、上游插件模型参考;旧 Plugin 标准仅作为迁移输入参考
状态:Historical / superseded by Plugin v3
事实源:`internal/roadmap/plugin/v3/README.md``internal/roadmap/plugin/v3/01-target-contract.md``internal/roadmap/rightsurface/README.md`;本文件仅保留产品决策证据,不是实现入口
## 1. 一句话目标
@@ -1,6 +1,6 @@
# Plugin v3 当前基线
状态:`implemented-baseline / 2026-08-08`
状态:`implemented-baseline / 2026-08-09`
## 结论
@@ -17,7 +17,7 @@ macOS 标准包真实 Agent turn/Right Surface Gate B 已通过。剩余工作
| `current` | `lime-rs/crates/app-server/src/local_data_source/impls/plugins.rs`、App Server v2 `plugin/*` | JSON-RPC 与 typed projection 唯一产品边界 |
| `current` | `lime-rs/crates/mcp/src/agent_plugin_config.rs``lime-rs/crates/skills``agent-runtime``tool-runtime` | 标准 MCP/Skills lowering 与 turn/tool 生命周期 owner |
| `current` | Renderer `pluginCatalog`、Claw mention、Right Surface | 只消费 App Server projection,不解析包 |
| `compat` | Codex `.codex-plugin/plugin.json` extension adapter | 适配 `com.openai` UI metadata;不成为 portable owner,不解释 Lime 私有字段 |
| `compat` | Codex `extensions.com.openai` / `.codex-plugin/plugin.json` adapter | 适配 UI metadata 与 `apps` 配置路径;不成为 portable owner,不解释旧内联 Apps object 或 Lime 私有字段 |
| `dead` | 旧 package API/发布链、renderer SDK/runtime、Electron worker/UI runtime | 已删除并由 contract/governance guard 阻止回流 |
| `dead` | `lime-core::plugin`、processor Plugin hook、`installed_plugins` DAO/schema、孤立 Plugin errors | 已删除,不保留构建或存储双轨 |
| `dead` | MCP smoke 私有 runtime inventory fixture 与 `agentChat.harness.pluginMcpTargets.*` 文案 | 已删除;current inventory 明确忽略私有 metadata 且不投影私有 targets |
@@ -30,6 +30,9 @@ macOS 标准包真实 Agent turn/Right Surface Gate B 已通过。剩余工作
Skills、Codex extension precedence、symlink、根 `mcp.json` 和 enabled snapshot。
- `agent_plugin_config.rs` 覆盖 `stdio` / `streamable-http`、placeholder、保留环境变量、
cwd containment、URL 安全与 sibling failure isolation。
- Codex Apps adapter 只接受 extension 中的包内相对配置路径,配置文件使用
`apps.{name}.{id,category?}`;旧顶层/内联 Apps object fail closed,非法 Apps 配置只禁用
Apps 组件。`apps_jsonrpc.rs``apps-catalog-gate-b.mjs` 均使用标准根 manifest。
- `agentCommandCatalog.json` 只登记 `plugin/list|search|read|install|uninstall|installed|enabled/set`
- `runtime_backend_tool_inventory_does_not_project_plugin_private_targets` 固化私有 metadata
不得进入 current inventoryMCP smoke 只验证标准 MCP JSON-RPC surface。
@@ -23,6 +23,15 @@ mcp.json -> 根 JSON 文档
manifest 不得声明 `skills``mcpServers``apps` 或任意路径来覆盖固定位置。缺失组件是
合法的“没有该能力”;组件错误只禁用该组件类型,不影响其它组件。
## Codex Apps extension
Portable manifest 仍不得出现顶层 `apps`。Codex client extension 可通过
`extensions.com.openai.apps`,或在 inline extension 缺失时通过
`.codex-plugin/plugin.json``apps`,声明一个包内相对 JSON 路径。该文件按 Codex
`apps.{name}.{id,category?}` 形状解析:connector `id` 是 Apps catalog identityname 是
展示名。旧内联 Apps object 必须拒绝,非法/缺失 Apps 配置只禁用 Apps 组件;不得覆盖
portable `name``version`、Skills 或 MCP 固定位置。
## MCP
标准 parser 与内部 `McpServerConfig` 分离:先严格解析官方 `mcp.json`,再 lowering 到
@@ -35,13 +44,15 @@ manifest 不得声明 `skills`、`mcpServers`、`apps` 或任意路径来覆盖
- 禁止插件覆盖两个保留环境变量。
- `streamable-http`:绝对 HTTP/HTTPS URL;非 loopback 必须 HTTPS;拒绝 userinfo 和
fragment`headers` 只能是 package 中的字面量,不能携带 secret。
- legacy `sse` transport 必须 fail closed,不得进入 runtime。
- 单个 server 失败只禁用该 server;顶层 mcp 文件错误只禁用 MCP 组件,不影响 Skills。
## Codex parity
Codex parity 的范围是行为和测试:manifest format selection、direct-child Skills、MCP
normalization、path containment、reserved env、failure isolation、installed/activated
state 和 reload/cold restore。Codex 私有内部类型、存储和 UI 不复制到 Lime。
normalization、Apps extension path/config、path containment、reserved env、failure isolation、
installed/activated state 和 reload/cold restore。Codex 私有内部类型、存储和 UI 不复制到
Lime。
## Lime integration
@@ -1,6 +1,6 @@
# Plugin v3 清理账本
状态:`active / major-deletions-complete`
状态:`active / major-deletions-complete / final-platform-gate`
## 清理原则
@@ -16,7 +16,7 @@
| App Server plugin domain | 继续作为唯一 catalog/install/activation owner |
| `lime-mcp`、Skills、RuntimeCore、tool-runtime | 继续作为领域 owner;增加标准 lowering,不承载 package discovery |
| typed Renderer gateway、Claw mention、Right Surface | 继续消费 projection,删除本地 registry 合并 |
| Codex extension adapter | 仅保留明确外部生态需要的 adapter;禁止新增 Lime 私有 manifest 字段 |
| Codex extension adapter | 仅保留 UI metadata 与 Apps 配置路径 adapter;禁止新增 Lime 私有 manifest 字段或恢复内联 Apps object |
## 已删除
@@ -32,13 +32,17 @@
| MCP 私有 runtime fixture | `--allow-plugin-runtime-fixture``plugin_runtime_capabilities``plugin_mcp_targets` 正向 smoke、transport summary 与五语孤立文案 | Rust inventory 负向测试与 smoke source guard 禁止私有投影回流 |
| 孤立 connector smoke | 无 npm/CI/文档入口且仍调用 `plugin_runtime_get_task``connector-outbox-smoke.mjs` | `scripts/plugin/` 只保留 connector production delivery current 检查 |
| Plugin v2 active 执行计划 | `plugin-v2-current-plan.md` 与 exec-plan current 导航 | v3 执行计划是唯一 active Plugin 计划;v2 roadmap 仅保留历史快照 |
| Plugin Lab i18n/sidebar | 五语言 `plugin.lab.*` 155 个 source key 与 `navigation.sidebar.items.pluginLab` 1 个 source key(共 780 条资源) | `plugin-lab-retired-i18n-keys` dead guard;禁止旧 Lab/sidebar 文案回流 |
| 旧 Plugin 技术标准文档 | `internal/tech/plugin/README.md``lime-plugin-package-v1.md` 及现役入站导航 | 已物理删除;`docs:boundary` 的 Plugin v3 文档守卫禁止重新引用 |
## 剩余 residual
| 分类 | Surface | 退出条件 |
|---|---|---|
| `verification-gap` | Windows junction/reparse point、环境变量大小写与数据根行为 | Windows 真实环境通过验证矩阵 |
| `verification-gap` | Codex parity 独立矩阵与最终分层门禁 | parity 逐项可审计,contracts、治理、Rust related、Agent fixture、GUI smoke、`verify:local` 全通过 |
| `verification-gap` | Windows packaged Electron Gate B 与 Codex parity | Windows runner 真实 artifact evidence;本机 macOS 不能替代 Windows 文件系统与 Squirrel 语义 |
| `verification-complete` | `verify:local` 全量重验(macOS | 2026-08-09 从头通过版本/i18n/lint、前端 120 批、contracts、Bridge、Rust workspace 全量与 GUI smokeWindows platform-gap 仍独立保留 |
| `verification-complete` | Plugin v3 现役文档回流守卫 | `npm run docs:boundary` 通过;Writing 与发布文档不再引用旧技术标准或旧 manifest 合同 |
## 已完成门槛:标准包 Gate B
@@ -46,7 +50,9 @@ macOS arm64 独立 Electron Gate B 已证明根 `plugin.json`、根 `mcp.json`
canonical Plugin mention、真实 Agent turn、canonical MCP Tool Item、elicitation、Right
Surface、reload/cold restore 与卸载后历史读取;worker、legacy command、生产 mock fallback
和 console error 命中均为零。证据位于
`.lime/qc/gui-evidence/plugin-package-electron-gate-b/plugin-package-electron-gate-b-summary.json`
`.lime/qc/gui-evidence/plugin-package-electron-gate-b/plugin-package-electron-gate-b-summary.json`;最新运行
`mcpAppResourceReadCount=4``mcpAppHtmlLoadCount=4``mcpAppToolCallCount=1`
`productionMockFallbackHitCount=0``consoleErrors=[]`
## 已完成门槛:旧 server manager
@@ -1,6 +1,6 @@
# Plugin v3 实施计划
状态:`in-progress`
状态:`in-progress / final-platform-gate`
## 写集纪律
@@ -12,13 +12,13 @@ domain、MCP/Skills、Renderer gateway、清理守卫不能在同一阶段由不
| 阶段 | 目标 | 主要写集 | 退出条件 |
|---|---|---|---|
| V3-0 | `complete` | v3 文档、governance scanner、执行计划 | 标准合同、删除分类架构确认已落盘 |
| V3-0 | `complete` | v3 文档、governance scanner、现役文档回流守卫、执行计划 | 标准合同、删除分类架构确认和旧技术文档删除已落盘 |
| V3-1 | `complete` | `plugin_catalog.rs`、MCP adapter、fixtures | 根 `plugin.json` + direct-child `skills/` + 根 `mcp.json` 已由 current loader 读取 |
| V3-2 | `in-progress` | MCP lowering、PLUGIN_ROOT/DATA、path/security tests、activation snapshot | 实现已落地;仍需独立 Codex parity matrix 与 Windows evidence |
| V3-2 | `complete on macOS/Unix` | MCP lowering、PLUGIN_ROOT/DATA、path/security tests、activation snapshot | current owner 与 macOS/Unix parity tests 已通过;Windows 语义仍待真实 runner |
| V3-3 | `complete` | protocol、typed client、plugin gateway、Claw、Right Surface | typed `plugin/*` 与标准包真实 Electron install/turn/tool/restore Gate B 已完成 |
| V3-4 | `complete` | package API、发布脚本、SDK/renderer/worker | 旧 protocol/client/bridge/scripts/fixtures 正向引用已清零并删除 |
| V3-5 | `complete` | processor/core plugin manager 与孤立 storage/error | 旧 manager/build hook/DAO/schema/error 已物理删除 |
| V3-6 | `in-progress` | parity evidence、文档、guards、全量验证 | parity、macOS/Windows、`verify:local` 全部通过 |
| V3-6 | `in-progress` | parity evidence、文档、guards、全量验证 | Windows runner evidence 与 baseline lint 收口后才能 complete |
## 不可跳过的删除顺序
@@ -42,9 +42,30 @@ extension boundary、MCP 安全边界和旧实现删除状态;责任开发者
## 下一执行刀
1. 固化并逐项执行 [Codex parity matrix](./05-codex-parity-matrix.md)manifest、Skills、MCP、
installed/enabled、reload/cold restore实现存在但未达 Codex 测试粒度的行不得标绿
2. 补 Windows junction/reparse point、环境变量大小写与 root/data 行为证据
3. 执行 contracts、治理、Rust related、Agent fixture、GUI smoke 与 `verify:local` 最终门禁
installed/enabled、reload/cold restoremacOS/Unix parser edge-case 已补独立测试并标绿
Windows 语义仍不得用 macOS 证据替代
2. 补 Windows junction/reparse point、环境变量大小写与 root/data 行为证据;现役文档回流守卫已纳入 `npm run docs:boundary`
3. contracts、治理、Rust related、Agent fixture 和 GUI smoke 已完成并通过;`lime-mcp`
全量为 160/160Rust related 通过。旧 `apps_jsonrpc` fixture 已迁到标准根 manifest +
Codex Apps 配置路径 adapterApps JSON-RPC、adapter unit、runner guard 与迁移后的真实
macOS Apps Gate B 均通过。2026-08-09 已从头完成 `verify:local`:版本/i18n/lint、前端
120 批、contracts、Rust workspace 全量、Bridge 与 GUI smoke 均通过。
Windows 交叉检查另受缺少 `assert.h`、MSVC/Windows SDK、linker 和 runtime 阻塞,不能
作为 Windows parity 证据。
macOS 标准包 Gate B 已于 2026-08-08 通过,证据位于
macOS 标准包 Gate B 已于 2026-08-09 通过,证据位于
`.lime/qc/gui-evidence/plugin-package-electron-gate-b/plugin-package-electron-gate-b-summary.json`
2026-08-09 重跑后仍通过;Gate B 的 MCP App 等待器已修复累计计数竞态,定向守卫为
2 files / 18 tests。真实证据包含首次恢复、renderer reload、cold restart、卸载后历史读取,
resource/HTML 累计为 4/4,且未命中 legacy facade、production mock fallback 或 console error。
Codex Apps extension fixture 已迁到标准根 manifest + `apps: "./apps.json"` adapter,并于
2026-08-09 通过 Apps 专用真实 Electron Gate B。证据路径为
`.lime/qc/project-gates/standalone-apps-catalog-20260809T054741397Z-147740/apps-catalog-gate-b/apps-catalog-gate-b-summary.json`
七个 required method 全部命中,pending -> disabled fresh read 完成,错误与 mock/legacy 命中均为 0。
Content Factory Article Workspace 聚合 Agent fixture 已于 2026-08-09 重跑通过,证据位于
`.lime/qc/gui-evidence/claw-chat-current-fixture/claw-chat-current-fixture-content-factory-article-workspace-regression-summary.json`
场景创建的 canonical session identity 已贯穿 Article Editor、read model、reload/cold restore
与 Gate B`artifact-article-1`、workspace patch evidence 和 `source: workspace_patch` 均已投影。
+30 -15
View File
@@ -1,6 +1,6 @@
# Plugin v3 验证合同
状态:`in-progress`
状态:`in-progress / Windows-platform-gap`
独立逐项对照见 [Codex parity 与平台矩阵](./05-codex-parity-matrix.md)。该矩阵区分
行为已实现、测试证据缺口和 Windows 平台缺口;未补齐前不得标记 v3 complete。
@@ -14,6 +14,8 @@
- MCP stdio`./` command、`args/env/cwd` placeholder、PLUGIN_DATA 持久目录。
- MCP Streamable HTTP`headers`、URL userinfo/fragment、HTTP/HTTPS 和 loopback 规则。
- Codex extension:显式 adapter 可读;portable loader 不读取 `.codex-plugin`
- Codex Appsextension 只声明包内相对配置路径;独立 Apps JSON 投影 connector id;旧
inline object fail closed,非法 Apps 配置隔离。
- 非法 manifest、非法 mcp.json、单个非法 server、symlink/越界路径、超预算 package。
## 最低命令
@@ -34,18 +36,25 @@ Rust 定向测试至少覆盖 `app-server`、`mcp`、`skills`、`runtime-core`
| 验证 | 状态 | 证据/缺口 |
|---|---|---|
| App Server package/store tests | `passed previously` | 标准安装、digest、optional version、Skills、Codex extension、MCP、enabled/uninstall |
| MCP parser tests | `passed previously` | placeholder、reserved env、cwd、HTTP、failure isolation |
| App Server package/store tests | `passed` | 标准安装、digest、optional version、Skills、Codex extension、MCP、enabled/uninstall |
| Codex Apps adapter / exact JSON-RPC | `passed` | 2026-08-09adapter unit 1/1、`apps_jsonrpc` 1/1、Gate B runner guard 1/1;标准根 manifest + extension Apps path + 独立 Apps JSON |
| Codex Apps Electron Gate B | `passed on macOS` | 2026-08-09:真实 Electron/preload/IPC、required methods 7/7、install notification、pending -> disabled fresh readerrors/mock/legacy 全为 0 |
| MCP parser tests | `passed` | 2026-08-09`lime-mcp` 160 tests 全通过;Agent Plugins parser macOS 8/8,覆盖 placeholder、opaque args/env、reserved env、cwd/path、HTTP headers/URL、explicit null、failure isolation、symlink 越界 |
| DevBridge/catalog 定向 tests | `passed` | 2026-08-084 files270 tests |
| legacy report | `passed` | 2026-08-08:边界违规 0、分类漂移候选 0 |
| legacy report | `passed` | 2026-08-09:零引用候选 0、分类漂移候选 0、边界违规 0 |
| scripts governance | `passed` | 2026-08-09:冻结基线通过,retired/untracked root 与一级目录均为 0 |
| Plugin catalog/mention 定向 tests | `passed` | 2026-08-086 files36 testscanonical mention 为 `plugin://<name>@<marketplace>` |
| Plugin Gate B runner 定向 tests | `passed` | 2026-08-082 files6 testsPlugin 场景不依赖无关 dynamic tool |
| `test:contracts` | `pending rerun` | 本轮 catalog/policy/guard 变更后必须重跑 |
| Rust related tests | `pending rerun` | 本轮 core/processor dead surface 删除后必须重跑 |
| Agent fixture / GUI smoke | `pending rerun` | 证明未影响 current Agent/GUI 主链 |
| 标准包 Plugin Gate B | `passed on macOS` | 2026-08-08:根 `plugin.json`/`mcp.json`、合法 Skill、canonical mention、真实 install/turn/MCP Item/Right Surface/cold restore/卸载历史闭环;mock 0、console error 0 |
| Windows matrix | `missing` | junction/reparse point、env 大小写、root/data 行为未验证 |
| Codex parity matrix | `in-progress` | `05-codex-parity-matrix.md` 已建立;parser edge-case 仍需补独立测试 |
| Plugin Gate B runner 定向 tests | `passed` | 2026-08-092 files18 tests包含 MCP App 累计 resource/HTML 等待器回归;Plugin 场景不依赖无关 dynamic tool |
| Plugin Lab i18n cleanup | `passed` | 2026-08-08:五语言删除 780 条旧 Lab/sidebar 资源;JSON 结构、i18n coverage 100%、治理目录与负向测试通过 |
| `test:contracts` | `passed` | 2026-08-09protocol 915 类型无漂移(923 definitions,跳过 8 个 envelope/meta);App Server client 301 checkscommand/harness/modality/release/docs 全通过 |
| Rust related tests | `passed` | 2026-08-09`lime-mcp` 全量 160/160app-server、mcp、skills related gate 全通过,GoalContinuation 回归已修复 |
| Agent fixture | `passed` | 2026-08-09current fixture 全场景通过,包含 Content Factory Article Editor 聚合闭环;canonical session identity、`artifact-article-1`、workspace patch evidence、reload/cold restore 和 Gate B 一致性均通过;证据 `.lime/qc/gui-evidence/claw-chat-current-fixture/claw-chat-current-fixture-content-factory-article-workspace-regression-summary.json` |
| `verify:gui-smoke` | `passed` | 2026-08-09Electron renderer/host build、真实 App Server 初始化、reload、memory settings smoke 通过;最新 evidence `standalone-shell-01-20260809090458-56606` |
| 标准包 Plugin Gate B | `passed on macOS` | 2026-08-09:根 `plugin.json`/`mcp.json`、合法 Skill、canonical mention、真实 install/turn/MCP Item/Right Surface/cold restore/卸载历史闭环;resource/HTML=4/4、mock 0、console error 0 |
| Windows matrix | `platform-gap / evidence-missing` | `build-windows-test` 已独立运行 `lime-mcp agent_plugin_config` 并上传 `lime-windows-agent-plugin-path-contract-tests`,同时运行 packaged Plugin Gate Bjunction/reparse point、env 大小写、root/data、packaged Gate B 尚无真实 Windows runner artifact |
| Codex parity matrix | `in-progress / Windows gap` | macOS/Unix parser edge-case 独立测试已通过;Windows env/path/junction/root-data/install 证据仍缺失 |
| `verify:local` | `passed on macOS` | 2026-08-09 从头通过版本/i18n/lint、前端 120 批、contracts、Bridge、Rust workspace 全量与 GUI smokeWindows platform-gap 仍未消除 |
| Plugin v3 现役文档回流守卫 | `passed` | `npm run docs:boundary` 检查 Writing、插件发布文档和 aiprompts 导航,不允许旧技术标准或旧 manifest 合同回流 |
## Gate B
@@ -59,13 +68,14 @@ Rust 定向测试至少覆盖 `app-server`、`mcp`、`skills`、`runtime-core`
6. 卸载后历史可读但不会重跑旧 worker。
7. worker、legacy command、renderer mock fallback 命中数为零。
2026-08-08 的 macOS arm64 证据位于
2026-08-09 的 macOS arm64 证据位于
`.lime/qc/gui-evidence/plugin-package-electron-gate-b/plugin-package-electron-gate-b-summary.json`
其中 `standardManifestSeen``standardMcpConfigSeen``pluginSkillProjected`
`pluginSkillContextSeen``rendererConfirmedSubmitted``mcpLedgerAccepted`
`coldRestoreCompleted``historyReadableAfterUninstall` 均为 `true`
`pluginMentionPath``plugin://mcp-elicitation-plugin@local`
`productionMockFallbackHitCount``0`
`productionMockFallbackHitCount``0``mcpAppResourceReadCount`
`mcpAppHtmlLoadCount` 均为 `4``mcpAppToolCallCount``1`
## 跨平台
@@ -77,12 +87,17 @@ macOS 与 Windows 必须分别验证:
- symlink/junction/reparse point 行为;
- 安装中断、恢复、卸载和目录清理。
本机 macOS 不能提供 Windows 证据:`x86_64-pc-windows-msvc` target 的 `ring` C 依赖在
交叉构建时缺少 `assert.h`,且没有 MSVC/Windows SDK、linker 或 runtime。Windows parser、
文件系统语义与 Electron Gate B 必须在 Windows runner/真机完成。
## 完成判定
只有同时满足以下条件才能标记 v3 complete;当前不得标记完成:
只有同时满足以下条件才能标记 v3 complete;当前不得标记完成:
- 标准包 contract 与 Codex parity matrix 全通过。
- 旧 package、旧 worker、旧 manager、旧 protocol 和旧脚本无生产正向引用。
- `governance:legacy-report` 通过,历史文本只存在于显式 evidence/negative guard。
- `npm run verify:local`、协议合同、Rust 定向测试和 Gate B 均通过
- `npm run verify:local`、协议合同、Rust 定向测试和 Gate B 均通过macOS);Windows
junction/reparse/env/root-data/packaged Gate B 证据仍是交付前 blocker。
- 未验证项、平台缺口和剩余风险写回执行计划,不用“兼容”掩盖。
@@ -2,7 +2,7 @@
状态:`in-progress / independently auditable`
更新时间:2026-08-08
更新时间:2026-08-09
## 判定口径
@@ -25,16 +25,18 @@ Plugins v1.0.0 portable contract 优先;Codex 的 `.codex-plugin/plugin.json`
| 未知 manifest 字段报告并忽略,非法类型 fail closed | Codex manifest/provider 解析与 schema tests | `plugin_catalog.rs:1014-1062``plugin_catalog/tests.rs:161-218` | `verified` |
| `skills/` 只发现直接子目录,嵌套目录不进入 catalog | `core/tests/suite/plugins.rs:168-198,446-504` | `plugin_catalog.rs` direct-child discovery`plugin_catalog/tests.rs:141-158`Agent runtime fixture | `verified` |
| Codex extension metadata precedence | Codex `.codex-plugin` fixture 与 extension merge tests | `plugin_catalog/tests.rs:161-202``plugin_catalog.rs:1111-1160` | `intentional-adapter` |
| Codex Apps extension path 与独立配置 | `core-plugins/agent_plugin_manifest.rs:184-216``connectors/plugin_config.rs:8-42` | `plugin_catalog.rs` Apps adapter/parser`plugin_catalog/tests.rs` Apps isolation`apps_jsonrpc.rs`macOS Apps Gate B | `intentional-adapter / verified` |
| 根 `mcp.json`、标准 MCP schema、manifest 不内联 MCP | `core/tests/suite/plugins.rs:662-752`Codex `agent_plugin_config.rs:38-108` | `plugin_catalog.rs:488-506,856-870``plugin_catalog/tests.rs:300-378` | `verified` |
| stdio bare/`./` command、`PLUGIN_ROOT`/`PLUGIN_DATA` 注入与 placeholder lowering | Codex `agent_plugin_config.rs:150-245``core/tests/suite/plugins.rs:662-752` | `lime-rs/crates/mcp/src/agent_plugin_config.rs:152-250`;测试 `505-538`Plugin Gate B MCP tool | `verified` |
| cwd/command containment、`..`、portable separators | Codex `agent_plugin_config.rs:349-428``plugin_config_tests.rs:129-206,358-504` | `agent_plugin_config.rs:394-414``plugin_catalog/tests.rs:380-412` | `implemented-test-gap` |
| Streamable HTTP URL、loopback HTTP、userinfo/fragment、headers | Codex `agent_plugin_config.rs:265-332``plugin_config_tests.rs:129-206,432-458` | `agent_plugin_config.rs:253-346`parser sibling isolation test `541-553` | `implemented-test-gap` |
| explicit `null`、unknown server shape、SSE fail closed | Codex `plugin_config_tests.rs:208-326,432-458` | `agent_plugin_config.rs:123-149,287-291` | `implemented-test-gap` |
| stdio bare/`./` command、`PLUGIN_ROOT`/`PLUGIN_DATA` 注入与 placeholder lowering | Codex `agent_plugin_config.rs:150-245``core/tests/suite/plugins.rs:662-752` | `lime-rs/crates/mcp/src/agent_plugin_config.rs:152-250`;测试 `agent_plugin_config.rs:527-560`Plugin Gate B MCP tool | `verified` |
| args/env placeholder 单次展开并保持 opaque | Codex `plugin_config_tests.rs:1-43,504-552` | `agent_plugin_config.rs:377-399``agent_plugin_config_tests.rs:12-52` | `verified` |
| cwd/command containment、`..`、portable separators | Codex `agent_plugin_config.rs:349-428``plugin_config_tests.rs:129-206,358-504` | `agent_plugin_config.rs:412-431``agent_plugin_config_tests.rs:174-210``plugin_catalog/tests.rs:380-412` | `verified`macOS |
| Streamable HTTP URL、loopback HTTP、userinfo/fragment、headers | Codex `agent_plugin_config.rs:265-332``plugin_config_tests.rs:129-206,432-458` | `agent_plugin_config.rs:253-346``agent_plugin_config_tests.rs:54-141`parser sibling isolation test `541-553` | `verified`macOS |
| explicit `null`、unknown server shape、SSE fail closed | Codex `plugin_config_tests.rs:208-326,432-458` | `agent_plugin_config.rs:123-149,287-291``agent_plugin_config_tests.rs:143-172` | `verified` |
| 单个非法 server 不影响健康 sibling | Codex `plugin_config_tests.rs:208-232` | `agent_plugin_config.rs:109-120``plugin_catalog/tests.rs:380-412` | `verified` |
| symlink/越界路径 fail closed | Codex `agent_plugin_config.rs:409-482``plugin_config_tests.rs:358-432` | `agent_plugin_config.rs:383-454``plugin_catalog/tests.rs:224-238` | `implemented-test-gap` |
| symlink/越界路径 fail closed | Codex `agent_plugin_config.rs:409-482``plugin_config_tests.rs:358-432` | `agent_plugin_config.rs:434-470``agent_plugin_config_tests.rs:212-242``plugin_catalog/tests.rs:224-238` | `verified`Unix |
| install digest、同版本幂等/冲突、optional version | Codex plugin provider/load outcome and package fixtures | `plugin_catalog/tests.rs:34-125` | `verified` |
| enabled state、activation snapshot、MCP/Skill turn context | Codex `load_outcome.rs:38-205``core/tests/suite/plugins.rs:446-752` | `plugin_catalog.rs:392-486``plugin_catalog/tests.rs:34-86`Agent fixture | `verified` |
| reload/cold restore、卸载后历史可读且不重跑旧 worker | Codex turn/plugin integration semantics | `.lime/qc/gui-evidence/plugin-package-electron-gate-b/plugin-package-electron-gate-b-summary.json` | `verified`macOS arm64 |
| reload/cold restore、卸载后历史可读且不重跑旧 worker | Codex turn/plugin integration semantics | `.lime/qc/gui-evidence/plugin-package-electron-gate-b/plugin-package-electron-gate-b-summary.json`MCP App resource/HTML=4/4、tool=1 | `verified`macOS arm64 |
## Windows 矩阵
@@ -42,17 +44,19 @@ Plugins v1.0.0 portable contract 优先;Codex 的 `.codex-plugin/plugin.json`
| 项目 | Codex 规则/实现 | Lime 当前实现 | 缺失证据 |
|---|---|---|---|
| 环境变量大小写与重复键 | `agent_plugin_config.rs:177-199,257-263` | `agent_plugin_config.rs:177-197,294-300` | Windows 真实进程与 duplicate case-insensitive fixture |
| 环境变量大小写与重复键 | `agent_plugin_config.rs:177-199,257-263` | `agent_plugin_config.rs:177-197,294-300``build-windows-test` 独立运行 `lime-mcp agent_plugin_config` 并上传日志 | Windows runner 真实进程与 duplicate case-insensitive artifact |
| drive-relative / UNC / extended path | `agent_plugin_config.rs:158-175,484-494` | `agent_plugin_config.rs:160-175,456-466` | Windows `C:relative`、UNC、`\\?\` 矩阵 |
| junction/reparse point containment | Codex path resolver `agent_plugin_config.rs:431-482` | Lime path resolver `416-454` | Windows junction/reparse 创建、越界与清理 |
| root/data 持久目录 | Codex `PLUGIN_DATA` runtime fixture `plugins.rs:707-735` | Lime MCP lowering `103-107,224-230` | Windows AppData/AgentRoot 真实路径与冷恢复 |
| install 中断、恢复、卸载清理 | Codex plugin integration fixtures | Lime store tests + macOS Gate B | Windows packaged Electron Gate B |
| junction/reparse point containment | Codex path resolver `agent_plugin_config.rs:431-482` | Lime path resolver `416-454`junction 越界 fixture 已加入;Windows workflow 独立执行并保留 `--nocapture` 日志 | Windows runner junction/reparse 创建、越界与清理 artifact |
| root/data 持久目录 | Codex `PLUGIN_DATA` runtime fixture `plugins.rs:707-735` | Lime MCP lowering `103-107,224-230`host path/data 测试已加入;Windows workflow 记录独立 parser contract 日志 | Windows AppData/AgentRoot 真实路径与冷恢复 artifact |
| install 中断、恢复、卸载清理 | Codex plugin integration fixtures | Lime store tests + macOS Gate BWindows Squirrel Gate B workflow 入口已加入 | Windows runner packaged Electron Gate B evidence |
## 结论与退出条件
- 当前不能把 Plugin v3 标为 `complete`仍有 `implemented-test-gap``platform-gap`
- 当前不能把 Plugin v3 标为 `complete`parser 行已具备 macOS/Unix 独立证据,但仍有
Windows `platform-gap`Codex 私有字段继续保持 `intentional-adapter`
- 不新增 compat wrapper,不恢复旧 package/worker/SDK;测试缺口只能在 current owner
补齐,Windows 缺口只能通过 Windows 真实矩阵消除。
- V3-2 的下一刀是把 `implemented-test-gap` 行补成可独立运行的 parser testsV3-6
的下一刀是运行 Windows junction/reparse/env/root-data/install matrix,再重跑最终
contracts、Agent fixture、GUI smoke 与 `verify:local`
- V3-2 的 parser edge-case 独立测试已在 macOS/Unix current owner 补齐;Windows current-owner
测试、独立 CI step 和日志 artifact 入口已落盘,但尚未由 Windows runner 产生真实 artifact。V3-6 的下一刀是运行
Windows junction/reparse/env/root-data/install matrix,再重跑最终 contracts、Agent fixture、
GUI smoke 与 `verify:local`
+4 -4
View File
@@ -2,7 +2,7 @@
状态:`in-progress / current-owner-established`
更新时间:2026-08-08
更新时间:2026-08-09
## 主目标
@@ -38,13 +38,13 @@ Electron Desktop Host
|---|---|---|
| V3-0 | `complete` | 标准合同、唯一 owner、删除口径和架构确认已落盘 |
| V3-1 | `complete` | 根 `plugin.json`、直接子目录 Skills、根 `mcp.json` loader 已进入 App Server current owner |
| V3-2 | `in-progress` | MCP lowering、安全校验、失败隔离和 activation snapshot 已实现;Codex parity matrix 仍需补齐独立证据 |
| V3-2 | `complete on macOS/Unix / Windows gap` | MCP lowering、安全校验、失败隔离和 activation snapshot 已实现;Unix parity 已有独立测试,Windows 文件系统语义仍待真实 runner |
| V3-3 | `complete` | `plugin/*` protocol/client/Renderer catalog 与标准包真实 Agent turn + Right Surface Gate B 已完成 |
| V3-4 | `complete` | 旧 package API、发布链、SDK、renderer runtime 和 worker 已物理删除 |
| V3-5 | `complete` | 旧 `PluginManager`、processor hook、孤立 DAO/schema/error surface 已物理删除 |
| V3-6 | `in-progress` | macOS 标准包 Gate B 已通过;等待 parity、Windows 与最终全量门禁 |
当前下一刀是完成 V3-2 parity evidence、Windows 路径矩阵与 V3-6 最终分层门禁,
当前下一刀是完成 Windows 路径矩阵与 V3-6 最终分层门禁,
不再继续扩展任何旧 Plugin 命名或兼容入口。
## v3 包合同
@@ -61,7 +61,7 @@ plugin-root/
- Skills 只扫描 `skills/` 直接子目录。
- MCP 只读取根 `mcp.json`,manifest 不得内联或重定向 MCP/Skills 位置。
- `mcp.json` 必须使用官方 `$schema``mcpServers``stdio``streamable-http` 语义;
`sse` 可选
legacy `sse` 输入必须 fail closed,不属于 v3 支持传输
- stdio 必须提供持久化 `PLUGIN_ROOT``PLUGIN_DATA`,实现官方 placeholder 与路径
containment。
- `.codex-plugin/plugin.json` 只作为显式 Codex 私有扩展 adapter,不是 portable owner。
-17
View File
@@ -1,17 +0,0 @@
# Lime 插件技术规范
本目录沉淀 Lime 自己的插件包标准。这里的规范是宿主、插件包、插件中心、Agent Runtime、ArtifactFrame、articleArtifacts、Article Editor、内部 Product Profile 事实源和验证工具共同遵守的事实源。
## 文档索引
| 文档 | 用途 |
| --- | --- |
| [lime-plugin-package-v1.md](./lime-plugin-package-v1.md) | Lime Plugin Package v1 标准:插件入口、能力目录、runtime、workbench、子智能体、Agent Skills、CLI、connectors、hooks 和验证口径。 |
## 核心原则
1. 一个插件包只有一个机器入口:`plugin.json`
2. 插件能力通过标准目录和分层能力文件声明,不在宿主里 hard code;`skills/` 层采用 Agent Skills 的 `skills/<skill-name>/SKILL.md` 目录和 frontmatter 规则。
3. 宿主负责安装、权限、运行、右侧栏、历史恢复、受控模型生成注入和治理守卫;workflow step 事件只进入 JSONL 审计,不直接进入右侧工作区 UI。
4. 插件负责声明能力、编排流程、运行 worker、产出 ArtifactFrame / articleArtifacts / workspace patch / evidence;需要模型正文时只声明 `hostManagedGeneration` 合同,不直接持有 provider key。
5. 说明文档只给人读,不能成为机器事实源。
@@ -1,367 +0,0 @@
# Lime Plugin Package v1
更新时间:2026-07-02
状态:Draft
适用范围:Lime 本地插件、云端分发插件、领域型 Plugin、文章 / 文档类插件
## 1. 目标
Lime Plugin Package v1 的目标是让一个插件包可以被安装、解释、编排、运行、渲染和恢复。它不是外部插件包格式的兼容层,而是 Lime 自己的插件事实源;其中 `skills/` 能力层采用 Agent Skills 目录和 `SKILL.md` 元数据规则,便于跨 Agent 复用。
一个合格插件包必须回答六个问题:
1. 我是谁:插件身份、版本、展示信息、分发策略。
2. 我能做什么:activation、workflow、Agent Skills、subagents、CLI、connectors、hooks。
3. 我怎么运行:runtime bridge、worker、task、宿主托管生成、权限、失败策略、evidence。
4. 我产出什么:ArtifactFrame、articleArtifacts、artifact kind、workspace patch、内部 Product Profile 事实。
5. 用户在哪里继续工作:独立产物框、右侧 Article Editor、动作、历史恢复。
6. 如何验证:schema、路径、示例请求、示例产物、E2E 场景。
## 2. 包结构
```text
<plugin-id>/
plugin.json
app.runtime.yaml
app.workbench.yaml
skills/
<skill-name>/SKILL.md
subagents/
<subagent-id>/prompt.md
<subagent-id>/references/**
<subagent-id>/scripts/**
<subagent-id>/templates/**
clis/clis.json
connectors/connectors.json
hooks/*.mjs
resources/
i18n.json
recommend.json
icons/**
templates/**
workflows/**
artifacts/**
examples/**
README.md
```
### 目录职责
| 路径 | 职责 | 机器事实源 |
| --- | --- | --- |
| `plugin.json` | 插件包唯一入口,声明身份、展示、安装策略和能力索引。 | 是 |
| `app.runtime.yaml` | 声明 activation、task、workflow、worker、hook policy、runtime 权限和 evidence。 | 是 |
| `app.workbench.yaml` | 声明业务对象、ArtifactFrame、articleArtifacts、surface、materializer、动作和历史恢复。 | 是 |
| `skills/<skill-name>/SKILL.md` | 声明可复用 Agent Skill 的触发条件、输入、步骤、输出和失败处理。 | 是 |
| `subagents/**` | 声明子智能体 prompt、references、scripts、templates 和 skill 绑定。 | 是 |
| `clis/clis.json` | 声明 CLI 工具、来源、版本、校验命令、暴露范围。 | 是 |
| `connectors/connectors.json` | 声明账号、OAuth、API、MCP、数据源依赖。 | 是 |
| `hooks/*.mjs` | 声明 prompt / tool / task 生命周期 hook。 | 是 |
| `resources/**` | 声明 i18n、推荐入口、模板、图标和静态资源。 | 是 |
| `workflows/**` | 承载可审阅 workflow 说明、样例 evidence 和流程文档。 | 辅助 |
| `artifacts/**` | 承载 schema、样例 artifact 和 workspace patch。 | 是 |
| `examples/**` | 承载示例请求、示例输出和本地验证数据。 | 辅助 |
| `README.md` | 给人读的说明文档。 | 否 |
## 3. `plugin.json`
`plugin.json` 是插件包唯一机器入口。宿主安装、本地扫描、插件中心展示和能力加载都从它开始。
最小形状:
```json
{
"schemaVersion": "lime.plugin.package.v1",
"id": "content-factory-app",
"name": "content-factory-app",
"version": "2.0.0",
"displayName": "内容工厂",
"description": "生成文章、配图规划和交付检查清单的内容生产插件。",
"kind": "domain-plugin",
"publisher": {
"name": "Lime"
},
"presentation": {
"icon": "./resources/icons/icon.svg",
"category": "content",
"brandColor": "#10B981"
},
"install": {
"local": true,
"cloud": true,
"authentication": "on_use"
},
"contributions": {
"runtime": "./app.runtime.yaml",
"workbench": "./app.workbench.yaml",
"skills": "./skills",
"subagents": "./subagents",
"clis": "./clis/clis.json",
"connectors": "./connectors/connectors.json",
"hooks": "./hooks",
"resources": "./resources",
"workflows": "./workflows",
"artifacts": "./artifacts"
}
}
```
规则:
- `schemaVersion` 必须固定到 Lime 插件包标准版本。
- `id` 是运行时、artifact、workspace、权限和日志中的稳定标识。
- `contributions` 只声明路径索引,不承载业务编排细节。
- 业务编排进入 `app.runtime.yaml`ArtifactFrame、articleArtifacts 和右侧工作台 contract 进入 `app.workbench.yaml`
- 路径必须是插件包内相对路径,不能写用户机器绝对路径。
## 4. Runtime 能力
`app.runtime.yaml` 是运行事实源,至少覆盖:
- `activationEntries`:如 `@写文章``@写作`
- `tasks`:输入、输出、artifact kind、权限和失败策略。
- `workflows`:步骤、subagent、skillRefs、CLI refs、connector refs、hook policy。
- `worker`:入口、sample request、输出 artifact kind。
- `hostManagedGeneration`:当 worker 需要宿主先执行受控模型生成时,声明输入和输出字段映射。
- `session`new / resume / continue / fork 能力。
- `evidence`:必须记录 workflow key、步骤状态、数据来源、artifact refs。
推荐形状:
```yaml
runtime:
bridge:
kind: app-server-json-rpc
required: true
activationEntries:
- key: content_article_generate
title: 写文章
aliases: ["@写文章", "@写作"]
taskKind: content.article.generate
defaultObjectKind: articleDraft
worker:
entrypoint: ./src/runtime/content-factory-worker.mjs
sampleRequest: ./examples/runtime-request.sample.json
outputArtifactKind: content_factory.workspace_patch
hostManagedGeneration:
enabled: true
systemPrompt: |
只生成可直接进入工作区的 Markdown 正文。
requests:
- id: article-draft-document
kind: markdown_document
targetObjectKind: articleDraft
outputField: documentText
workflows:
- key: content_article_workflow
taskKind: content.article.generate
outputArtifactKind: content_factory.workspace_patch
steps:
- id: research
subagent: content-researcher
skillRefs: [article-research]
- id: strategy
subagent: content-strategist
skillRefs: [article-strategy]
- id: draft
subagent: article-writer
skillRefs: [article-writing]
- id: review
subagent: copy-editor
skillRefs: [article-editing]
- id: image-plan
subagent: image-planner
skillRefs: [article-image-plan]
```
### 宿主托管生成
`hostManagedGeneration` 是通用 worker 能力声明,不是内容工厂专属字段。适用场景是:插件 worker 需要真实模型生成,但不能直接接触 provider key、全局网关 key 或宿主内部凭证。
固定规则:
- 插件只在 `app.runtime.yaml#agentRuntime.worker.hostManagedGeneration` 声明生成需求,不在 worker 里直连 provider。
- 宿主在启动 worker 前完成模型路由和生成,把结果写进 worker request 的 `hostManagedGeneration``runtime.hostManagedGenerationResult`
- worker 只消费 `status / provider / model / outputs[]`,并把消费结果回写到业务对象 source 字段。
- 没有可用 provider、模型路由失败或宿主禁用该能力时,宿主必须写 `status=unavailable`worker 按插件自己的 deterministic fallback 或 fail-closed 逻辑处理。
- `outputs[]` 只传受控内容和最小元数据,不传 provider key、宿主 access token、文件系统句柄或 Electron IPC 能力。
- 该机制是通用宿主能力,不允许为了某个插件在宿主里增加垂直 `content_factory_*` 业务逻辑。
### 宿主工具请求
`hostToolRequests` 是 worker 产物里的通用受控工具请求,不是内容工厂私有搜索协议。适用场景是:worker 需要宿主调用已注册的 Agent 工具来补齐证据,但插件不能直接获得宿主凭证、Electron IPC、Provider key 或工具 registry。
推荐 worker 在 workspace patch 对象的 `source` 中声明:
```json
{
"source": {
"workflowKey": "content_article_workflow",
"hostToolRequests": [
{
"id": "research-query-1",
"toolName": "WebSearch",
"params": {
"query": "公众号文章结构 最新写法"
},
"purpose": "验证写作依据"
}
]
}
}
```
固定规则:
- 宿主只执行当前 Agent registry 已注册并允许的工具;不得在 App Server 里新增一套 `WebSearch` / `WebFetch` 私有实现。
- 工具事件统一标记 `source=workspace_patch_host_tool_requests`,并把 `workflowKey` 原样写入事件 metadata,便于审计和历史恢复。
- 工具结果必须回填为 `hostToolEvidence / hostToolStatus`;WebSearch 兼容场景可额外保留 `searchEvidence / hostSearchEvidence / hostSearchStatus` 给历史文章 artifact 读取。
- workflow step、工具事件和 hook progress 只进入 read model、artifact metadata、evidence pack 和 JSONL 审计,不作为右侧工作区固定 UI 面板。
- 旧 `searchRequests` 只允许作为历史 workspace patch 的兼容读取字段,新 worker 必须写 `hostToolRequests`
## 5. Workbench / ArtifactFrame / articleArtifacts 能力
`app.workbench.yaml` 是业务对象、ArtifactFrame 和 articleArtifacts 的事实源,至少覆盖:
- `productionObjects`:如 `articleDraft``imageGenerationSet``deliveryChecklist`
- `artifactFrames`:聊天区独立产物框 shell、renderer、打开目标和流式策略。
- `articleArtifacts`:文章类产物的内容 renderer、右侧 renderer、可编辑能力和恢复策略。
- `objectSurfaces`:对象默认 surface、renderer kind、layout。
- `artifactMaterializers`artifact / workspace patch 如何物化为业务对象。
- `frames`:聊天独立产物框展示规则。
- `actions`:继续改写、生成配图、导出等受控动作。
- `historyRestore`selected object、primary object、fallback 的恢复策略。
规则:
- 插件只能声明 ArtifactFrame / articleArtifacts / renderer contract,不能直接控制宿主右侧 dock。
- 文章类 ArtifactFrame 可以完整、流式展示正文;完整正文不得散落在普通 assistant message。
- 完整文章必须进入宿主 Article Editor 或 artifact viewer。
- workflow step、hook progress 和编排状态默认只写入宿主 JSONL / workflow audit 日志,不作为右侧工作区固定 UI 面板。
- Product Profile 只作为内部事实源 / 调度桥 / 历史恢复输入,不作为文章用户主界面。
- 历史恢复优先恢复 plugin workspace,再回退 artifact,最后才回退聊天。
## 6. 子智能体与 Agent Skills
子智能体和 Agent Skills 是插件包内的生产能力,不是宿主内置能力。Lime 插件包只在 `skills/` 层采用 Agent Skills 标准;runtime、workbench、worker、artifact 和安装合同仍以 Lime Plugin Package v1 为事实源。
子智能体目录推荐:
```text
subagents/article-writer/
prompt.md
references/style.md
scripts/normalize-outline.mjs
templates/article.md
```
子智能体规则:
- `prompt.md` 是该子智能体的角色、边界和输出格式。
- `references/**` 只放该子智能体需要的领域材料。
- `scripts/**` 只放该子智能体可调用的本地辅助脚本。
- 子智能体不能自行切换 workflow 或越权读其他插件资产。
Agent Skill 目录规则:
- 每个 skill 使用 `skills/<skill-name>/SKILL.md``<skill-name>` 只能包含小写字母、数字和连字符,不能以下划线、连续连字符、开头连字符或结尾连字符命名。
- `SKILL.md` 必须包含 YAML frontmatter,且 `name` 必须与父目录 `<skill-name>` 完全一致。
- `description` 必须非空,描述这个 skill 做什么以及何时使用,长度不超过 1024 字符。
- `license``compatibility``metadata``allowed-tools` 可以按 Agent Skills 规范作为可选 frontmatter 字段。
- Markdown 正文必须说明何时使用、输入、步骤、输出和失败回退;正文保持短而清晰,把长材料按渐进展开方式拆到同目录 `references/`,可执行辅助脚本放到同目录 `scripts/`,模板或静态资源放到同目录 `assets/`
- `references/``scripts/``assets/` 只服务当前 skill;相对路径解析以 `SKILL.md` 所在目录为根,不把宿主仓库路径写进 skill 正文。
- workflow 引用 skill 时使用稳定 `skill-name`,也就是 `SKILL.md#name` 和父目录名,不使用文件路径作为业务 id。
- 宿主和 validator 必须严格按目录名读取 skill;禁止新增或继续兼容 `skills/article_writing` 这类下划线 legacy 目录。
## 7. CLI、Connectors、Hooks
### CLI
`clis/clis.json` 声明插件所需命令行工具:
```json
{
"tools": [
{
"id": "content-factory",
"displayName": "content-factory",
"description": "Content Factory local validation and runtime helper.",
"verifyArgs": ["validate"],
"exposure": "declared-workflows",
"source": {
"type": "local-package",
"bin": "./cli/content-factory.mjs"
}
}
]
}
```
### Connectors
`connectors/connectors.json` 声明账号、OAuth、API、MCP 或数据源依赖。宿主根据 connector 决定授权、可用性和错误展示。
### Hooks
`hooks/*.mjs` 只用于生命周期编排:
- prompt submit 前补充运行上下文。
- tool use 前做权限或路由检查。
- tool use 后做 evidence 归档。
- task 完成后做 artifact / workspace patch 校验。
hooks 不允许承担宿主级 UI 渲染,不允许绕过 App Server Runtime 直接调用模型。
## 8. 安装与发现
本地安装流程:
1. 用户选择插件包目录。
2. 宿主读取 `plugin.json`
3. 校验 `schemaVersion``id``version``contributions` 路径。
4. 加载 runtime / workbench / skills / subagents / CLI / connectors / hooks。
5. 写入 installed registry。
6. 插件中心、输入框候选和 runtime activation 从 installed registry 投影。
未登录云端账号时:
- 云端列表失败不能阻断本地 installed registry。
- 本地插件只要 validator 通过,就能出现在插件中心和输入框候选中。
- 需要云端 connector 的能力可以置灰,但不能让整个本地插件消失。
## 9. 验证要求
插件包 validator 必须检查:
- `plugin.json` 存在且 schemaVersion 正确。
- `contributions` 指向的文件或目录存在。
- `app.runtime.yaml` 中 activation / workflow / task 引用合法。
- 如声明 `hostManagedGeneration`,其 `requests[].id / targetObjectKind / outputField` 必须完整,且 worker 仍声明 `directProviderAccess: false`
- workflow step 引用的 subagent、skill、CLI、connector 存在。
- `skills/**/SKILL.md` 符合 Agent Skills 目录和 frontmatter 规则:父目录名等于 `name`,命名只用小写字母、数字和连字符,`description` 非空且不超过 1024 字符。
- 不存在下划线命名的 legacy skill 目录。
- `app.workbench.yaml` 中 object、surface、materializer、action 引用合法。
- worker sample request 可运行,输出符合 artifact schema。
- i18n、icon、recommend、template 等 resources 路径合法。
- 包内不能出现用户机器绝对路径。
宿主回归必须覆盖:
- 本地安装。
- 插件中心展示。
- 输入框 `@` 候选。
- activation metadata。
- runtime task start / stream / complete。
- 独立 ArtifactFrame。
- 右侧 Article Editor。
- 历史恢复。
## 10. 禁止事项
- 不允许为某个插件在宿主里 hard code 入口、workflow、subagent 或 skill。
- 不允许让说明文档成为机器事实源。
- 不允许插件 worker 直接拥有右侧栏布局。
- 不允许在聊天正文输出完整生产物来替代 Article Editor。
- 不允许把 Product Profile 调试面板做成文章用户界面。
- 不允许为未安装插件伪造 `@` 候选。
- 不允许生产路径依赖 mock fallback。
+30 -30
View File
@@ -21,7 +21,7 @@ dependencies = [
[[package]]
name = "agent-protocol"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"schemars",
"serde",
@@ -30,7 +30,7 @@ dependencies = [
[[package]]
name = "agent-runtime"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"anyhow",
@@ -181,7 +181,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "app-server"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"agent-runtime",
@@ -243,7 +243,7 @@ dependencies = [
[[package]]
name = "app-server-client"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"app-server-protocol",
"app-server-transport",
@@ -254,7 +254,7 @@ dependencies = [
[[package]]
name = "app-server-daemon"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"app-server-protocol",
"app-server-transport",
@@ -266,7 +266,7 @@ dependencies = [
[[package]]
name = "app-server-protocol"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"schemars",
@@ -276,7 +276,7 @@ dependencies = [
[[package]]
name = "app-server-test-client"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"anyhow",
"app-server-client",
@@ -287,7 +287,7 @@ dependencies = [
[[package]]
name = "app-server-transport"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"app-server-protocol",
"axum",
@@ -1357,7 +1357,7 @@ dependencies = [
[[package]]
name = "document-preview"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"flate2",
"tempfile",
@@ -2620,7 +2620,7 @@ dependencies = [
[[package]]
name = "lime-agent"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"agent-runtime",
@@ -2653,7 +2653,7 @@ dependencies = [
[[package]]
name = "lime-browser-runtime"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"chrono",
"futures",
@@ -2670,7 +2670,7 @@ dependencies = [
[[package]]
name = "lime-cli"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"clap",
"lime-core",
@@ -2682,7 +2682,7 @@ dependencies = [
[[package]]
name = "lime-config"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"async-trait",
"lime-core",
@@ -2698,7 +2698,7 @@ dependencies = [
[[package]]
name = "lime-core"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"async-trait",
@@ -2754,7 +2754,7 @@ dependencies = [
[[package]]
name = "lime-gateway"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"aes",
"async-trait",
@@ -2782,7 +2782,7 @@ dependencies = [
[[package]]
name = "lime-infra"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"chrono",
"dashmap",
@@ -2804,7 +2804,7 @@ dependencies = [
[[package]]
name = "lime-knowledge"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"chrono",
"hex",
@@ -2817,7 +2817,7 @@ dependencies = [
[[package]]
name = "lime-mcp"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"async-trait",
"axum",
@@ -2843,7 +2843,7 @@ dependencies = [
[[package]]
name = "lime-media-runtime"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"axum",
"base64 0.22.1",
@@ -2862,7 +2862,7 @@ dependencies = [
[[package]]
name = "lime-processor"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"async-trait",
"lime-core",
@@ -2902,7 +2902,7 @@ dependencies = [
[[package]]
name = "lime-server"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"async-stream",
@@ -2945,7 +2945,7 @@ dependencies = [
[[package]]
name = "lime-server-utils"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"axum",
"futures",
@@ -2960,7 +2960,7 @@ dependencies = [
[[package]]
name = "lime-services"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"anyhow",
"async-trait",
@@ -3003,7 +3003,7 @@ dependencies = [
[[package]]
name = "lime-skills"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"async-trait",
"dirs 5.0.1",
@@ -3024,7 +3024,7 @@ dependencies = [
[[package]]
name = "lime-websocket"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"axum",
"chrono",
@@ -3233,7 +3233,7 @@ dependencies = [
[[package]]
name = "model-provider"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"anyhow",
@@ -3903,7 +3903,7 @@ checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec"
[[package]]
name = "patch-apply"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"tempfile",
"thiserror 1.0.69",
@@ -4662,7 +4662,7 @@ dependencies = [
[[package]]
name = "runtime-core"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"app-server-protocol",
@@ -5419,7 +5419,7 @@ dependencies = [
[[package]]
name = "thread-store"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"chrono",
@@ -5706,7 +5706,7 @@ dependencies = [
[[package]]
name = "tool-runtime"
version = "1.124.0"
version = "1.125.0"
dependencies = [
"agent-protocol",
"app-server-protocol",
+1 -1
View File
@@ -6,7 +6,7 @@ exclude = [
resolver = "2"
[workspace.package]
version = "1.124.0"
version = "1.125.0"
edition = "2021"
authors = ["coso"]
repository = "https://github.com/aiclientproxy/lime"
@@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use crate::hook::HookRunSummary;
use crate::response_item::MessagePhase;
use crate::{AgentInput, ItemId, MessageContentPart, SessionId, ThreadId, TurnId};
@@ -140,7 +139,6 @@ pub enum ItemKind {
Media,
SubAgent,
ContextCompaction,
Hook,
Unknown,
Extension,
}
@@ -442,9 +440,6 @@ pub enum ThreadItemPayload {
#[serde(default, skip_serializing_if = "Option::is_none")]
tail_start_turn_id: Option<String>,
},
Hook {
run: HookRunSummary,
},
Unknown {
upstream_type: String,
#[serde(default)]
@@ -473,7 +468,6 @@ impl ThreadItemPayload {
Self::Media { .. } => ItemKind::Media,
Self::SubAgent { .. } => ItemKind::SubAgent,
Self::ContextCompaction { .. } => ItemKind::ContextCompaction,
Self::Hook { .. } => ItemKind::Hook,
Self::Unknown { .. } => ItemKind::Unknown,
Self::Extension { .. } => ItemKind::Extension,
}
@@ -260,6 +260,9 @@ pub enum CurrentProviderTurnEvent {
ModelVerification {
verifications: Vec<ModelVerification>,
},
TurnModerationMetadata {
metadata: serde_json::Value,
},
ProviderStep {
attempt: u32,
completed: bool,
@@ -952,6 +955,9 @@ where
on_event(CurrentProviderTurnEvent::ModelVerification { verifications });
}
}
CanonicalLlmEvent::TurnModerationMetadata { metadata } => {
on_event(CurrentProviderTurnEvent::TurnModerationMetadata { metadata });
}
CanonicalLlmEvent::Finish { reason, usage, .. } => {
if let Some(usage) = usage {
let usage = current_provider_usage(usage);
@@ -768,6 +768,9 @@ async fn provider_metadata_is_deduplicated_across_sampling_steps() {
Ok(CanonicalLlmEvent::ModelVerification {
verifications: vec![ModelVerification::TrustedAccessForCyber],
}),
Ok(CanonicalLlmEvent::TurnModerationMetadata {
metadata: serde_json::json!({ "presentation": "inline" }),
}),
]
};
let mut first = metadata();
@@ -854,6 +857,16 @@ async fn provider_metadata_is_deduplicated_across_sampling_steps() {
.count(),
1
);
assert_eq!(
events
.iter()
.filter(|event| matches!(
event,
CurrentProviderTurnEvent::TurnModerationMetadata { .. }
))
.count(),
2
);
}
#[tokio::test]
@@ -422,6 +422,11 @@ fn handle_provider_event<F>(
AgentEvent::ModelVerification { verifications },
on_event,
),
CurrentProviderTurnEvent::TurnModerationMetadata { metadata } => emit_with_artifacts(
artifact_events,
AgentEvent::TurnModerationMetadata { metadata },
on_event,
),
CurrentProviderTurnEvent::ProviderStep {
attempt,
completed,
@@ -5,6 +5,7 @@ use crate::agent_tools::execution::{
decide_tool_execution, persisted_tool_execution_policy_from_metadata, ToolExecutionDecision,
ToolExecutionDecisionInput, ToolExecutionDecisionKind, ToolExecutionResolverInput,
};
use crate::guardian_review;
use crate::protocol::{AgentEvent, AgentToolProgressPayload};
use crate::request_tool_policy::{is_same_tool, RequestToolPolicy};
use crate::runtime_state::{AgentRuntimeState, EffectivePermissionGrant};
@@ -275,16 +276,27 @@ impl RuntimeToolExecutor for CurrentTurnToolExecutor {
match decision.kind {
ToolExecutionDecisionKind::Allow => {}
ToolExecutionDecisionKind::RequiresApproval => {
wait_for_tool_approval(
&self.state,
&self.event_sender,
request,
&self.thread_id,
self.pending_input.as_ref(),
&decision,
)
.await
.map_err(RuntimeToolExecutionError::before_handler)?;
if decision.reason_code == "strict_auto_review" {
run_guardian_tool_review(
&self.state,
&self.event_sender,
request,
&self.thread_id,
)
.await
.map_err(RuntimeToolExecutionError::before_handler)?;
} else {
wait_for_tool_approval(
&self.state,
&self.event_sender,
request,
&self.thread_id,
self.pending_input.as_ref(),
&decision,
)
.await
.map_err(RuntimeToolExecutionError::before_handler)?;
}
}
ToolExecutionDecisionKind::Deny => {
return Err(RuntimeToolExecutionError::new(
@@ -443,6 +455,144 @@ impl RuntimeToolExecutor for CurrentTurnToolExecutor {
}
}
async fn run_guardian_tool_review(
state: &AgentRuntimeState,
event_sender: &UnboundedSender<AgentEvent>,
request: RuntimeToolExecutionRequest<'_>,
thread_id: &ThreadId,
) -> Result<(), RuntimeToolExecutionError> {
let identity = request.context.tool_identity().ok_or_else(|| {
RuntimeToolExecutionError::new(
"Guardian review requires canonical tool identity",
Some(RuntimeToolPolicyErrorKind::ExecutionFailed(
"guardian_review_identity_missing".to_string(),
)),
)
})?;
let turn_id = identity.turn_id().to_string();
let command = request
.params
.get("cmd")
.or_else(|| request.params.get("command"))
.and_then(Value::as_str)
.unwrap_or_default()
.trim()
.to_string();
let cwd = request
.context
.working_directory()
.to_string_lossy()
.to_string();
if command.is_empty() {
return Err(RuntimeToolExecutionError::new(
"Guardian review requires a non-empty shell command",
Some(RuntimeToolPolicyErrorKind::PermissionDenied(
"guardian_review_command_missing".to_string(),
)),
));
}
let review_request = guardian_review::GuardianReviewRequest {
session_id: request.context.session_id().to_string(),
thread_id: thread_id.clone(),
turn_id: turn_id.clone(),
target_item_id: Some(identity.call_id().to_string()),
tool_name: request.tool_name.to_string(),
command,
cwd,
started_at_ms: chrono::Utc::now().timestamp_millis(),
};
let review_id = guardian_review::review_id();
let action = guardian_review::action_value(&review_request);
let _ = event_sender.send(guardian_review::started_event(
&review_request,
&review_id,
action.clone(),
));
let provider = state
.provider_for_session(request.context.session_id())
.await
.ok_or_else(|| {
RuntimeToolExecutionError::new(
"Guardian review provider is not ready; the action was denied",
Some(RuntimeToolPolicyErrorKind::PermissionDenied(
"guardian_review_provider_unavailable".to_string(),
)),
)
});
let result = match provider {
Ok(provider) => {
guardian_review::run(
provider,
&review_request,
request_cancel_token(request.context.cancel_token()),
)
.await
}
Err(error) => {
let rationale = "Guardian review provider is not ready; the action was denied.";
let _ = event_sender.send(guardian_review::completed_event(
&review_request,
&review_id,
action,
guardian_review::GuardianReviewResult {
status: crate::protocol::GuardianReviewStatus::Denied,
risk_level: Some(crate::protocol::GuardianRiskLevel::High),
user_authorization: Some(crate::protocol::GuardianUserAuthorization::Unknown),
rationale: rationale.to_string(),
},
chrono::Utc::now().timestamp_millis(),
));
let _ = record_guardian_denial(state, event_sender, request.context, &turn_id).await;
return Err(error);
}
};
let status = result.status;
let rationale = result.rationale.clone();
let _ = event_sender.send(guardian_review::completed_event(
&review_request,
&review_id,
action,
result.clone(),
chrono::Utc::now().timestamp_millis(),
));
if matches!(status, crate::protocol::GuardianReviewStatus::Approved) {
state
.record_guardian_non_denial(request.context.session_id(), &turn_id)
.await;
return Ok(());
}
if matches!(status, crate::protocol::GuardianReviewStatus::Denied) {
let _ = record_guardian_denial(state, event_sender, request.context, &turn_id).await;
}
Err(RuntimeToolExecutionError::new(
format!("Guardian denied shell execution: {rationale}"),
Some(RuntimeToolPolicyErrorKind::PermissionDenied(
"guardian_review_denied".to_string(),
)),
))
}
async fn record_guardian_denial(
state: &AgentRuntimeState,
event_sender: &UnboundedSender<AgentEvent>,
context: &tool_runtime::tool_executor::RuntimeToolExecutionContext,
turn_id: &str,
) -> Option<String> {
let (consecutive_denials, recent_denials) = state
.record_guardian_denial(context.session_id(), turn_id)
.await?;
let message = format!(
"Automatic approval review rejected too many approval requests for this turn ({consecutive_denials} consecutive, {recent_denials} in the last 5 reviews); interrupting the turn."
);
let _ = event_sender.send(AgentEvent::GuardianWarning {
message: message.clone(),
});
if let Some(cancel_token) = context.cancel_token() {
cancel_token.cancel();
}
Some(message)
}
fn trusted_permission_turn_context(
source: Option<&tool_runtime::tool_executor::RuntimeToolTurnContext>,
grant: &EffectivePermissionGrant,
+241
View File
@@ -0,0 +1,241 @@
use crate::credential_bridge::ConfiguredReplyProvider;
use crate::protocol::{
AgentEvent, GuardianReviewStatus, GuardianRiskLevel, GuardianUserAuthorization,
};
use agent_protocol::ThreadId;
use futures::StreamExt;
use model_provider::current_client::CanonicalLlmEvent;
use model_provider::current_client::{
CurrentProviderContent, CurrentProviderMessage, CurrentProviderRequest,
CurrentProviderRequestMetadata, GenerationOptions,
};
use serde::Deserialize;
use serde_json::{json, Value};
use std::time::Duration;
use tokio_util::sync::CancellationToken;
use uuid::Uuid;
const REVIEW_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug, Clone)]
pub(crate) struct GuardianReviewRequest {
pub(crate) session_id: String,
pub(crate) thread_id: ThreadId,
pub(crate) turn_id: String,
pub(crate) target_item_id: Option<String>,
pub(crate) tool_name: String,
pub(crate) command: String,
pub(crate) cwd: String,
pub(crate) started_at_ms: i64,
}
#[derive(Debug, Clone)]
pub(crate) struct GuardianReviewResult {
pub(crate) status: GuardianReviewStatus,
pub(crate) risk_level: Option<GuardianRiskLevel>,
pub(crate) user_authorization: Option<GuardianUserAuthorization>,
pub(crate) rationale: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct GuardianAssessment {
decision: String,
risk_level: Option<String>,
user_authorization: Option<String>,
rationale: Option<String>,
}
pub(crate) fn review_id() -> String {
format!("guardian-review-{}", Uuid::new_v4())
}
pub(crate) fn action_value(request: &GuardianReviewRequest) -> Value {
json!({
"type": "command",
"source": "shell",
"toolName": request.tool_name,
"command": request.command,
"cwd": request.cwd,
})
}
pub(crate) fn started_event(
request: &GuardianReviewRequest,
review_id: &str,
action: Value,
) -> AgentEvent {
AgentEvent::GuardianReviewStarted {
review_id: review_id.to_string(),
target_item_id: request.target_item_id.clone(),
turn_id: request.turn_id.clone(),
action,
started_at_ms: request.started_at_ms,
}
}
pub(crate) fn completed_event(
request: &GuardianReviewRequest,
review_id: &str,
action: Value,
result: GuardianReviewResult,
completed_at_ms: i64,
) -> AgentEvent {
AgentEvent::GuardianReviewCompleted {
review_id: review_id.to_string(),
target_item_id: request.target_item_id.clone(),
turn_id: request.turn_id.clone(),
status: result.status,
risk_level: result.risk_level,
user_authorization: result.user_authorization,
rationale: (!result.rationale.trim().is_empty()).then_some(result.rationale),
decision_source: "agent".to_string(),
action,
started_at_ms: request.started_at_ms,
completed_at_ms,
}
}
pub(crate) async fn run(
provider: ConfiguredReplyProvider,
request: &GuardianReviewRequest,
cancel_token: CancellationToken,
) -> GuardianReviewResult {
let action = action_value(request);
let system_prompt = "You are Lime Guardian, a strict security reviewer for a desktop coding agent. Evaluate exactly one shell command before execution. Return only one JSON object with keys decision (approved or denied), riskLevel (low, medium, high, critical), userAuthorization (unknown, low, medium, high), and rationale (short plain text). Deny when uncertain, destructive, credential-exfiltrating, persistence-related, or outside the requested workspace.";
let user_prompt = format!(
"Review this requested action. Do not execute it and do not suggest alternatives.\n{}",
serde_json::to_string(&action).unwrap_or_else(|_| "{}".to_string())
);
let metadata = CurrentProviderRequestMetadata::new(
request.session_id.clone(),
request.thread_id.as_str().to_string(),
request.turn_id.clone(),
None,
);
let provider_request = CurrentProviderRequest::new(vec![CurrentProviderMessage::user(vec![
CurrentProviderContent::Text(user_prompt),
])])
.with_system_prompt(Some(system_prompt.to_string()))
.with_generation(GenerationOptions {
max_tokens: Some(512),
temperature: Some(0.0),
..Default::default()
})
.with_metadata(metadata);
let stream = match tokio::time::timeout(
REVIEW_TIMEOUT,
provider.client().stream(provider_request),
)
.await
{
Ok(Ok(stream)) => stream,
Ok(Err(error)) => return denied(format!("Guardian provider request failed: {error}")),
Err(_) => return timed_out(),
};
let mut stream = Box::pin(stream);
let mut output = String::new();
let review = async {
while let Some(event) = stream.next().await {
match event {
Ok(CanonicalLlmEvent::TextDelta { text, .. }) => output.push_str(&text),
Ok(CanonicalLlmEvent::ProviderError { message, .. }) => {
return Err(format!("Guardian provider stream failed: {message}"));
}
Ok(CanonicalLlmEvent::Finish { .. } | CanonicalLlmEvent::StepFinish { .. }) => {
break;
}
Ok(_) => {}
Err(error) => return Err(format!("Guardian provider stream failed: {error}")),
}
}
parse_assessment(&output)
};
let parsed = tokio::select! {
_ = cancel_token.cancelled() => return GuardianReviewResult {
status: GuardianReviewStatus::Aborted,
risk_level: None,
user_authorization: None,
rationale: "Guardian review was cancelled.".to_string(),
},
result = tokio::time::timeout(REVIEW_TIMEOUT, review) => result,
};
match parsed {
Ok(Ok(assessment)) => assessment,
Ok(Err(error)) => denied(error),
Err(_) => timed_out(),
}
}
fn parse_assessment(output: &str) -> Result<GuardianReviewResult, String> {
let candidate = output
.find('{')
.and_then(|start| output.rfind('}').map(|end| &output[start..=end]))
.ok_or_else(|| "Guardian response did not contain a JSON assessment".to_string())?;
let assessment: GuardianAssessment = serde_json::from_str(candidate)
.map_err(|error| format!("Guardian response was not valid JSON: {error}"))?;
let risk_level = assessment
.risk_level
.as_deref()
.and_then(parse_risk_level)
.ok_or_else(|| "Guardian response omitted a valid riskLevel".to_string())?;
let user_authorization = assessment
.user_authorization
.as_deref()
.and_then(parse_user_authorization)
.ok_or_else(|| "Guardian response omitted a valid userAuthorization".to_string())?;
let rationale = assessment
.rationale
.filter(|value| !value.trim().is_empty())
.ok_or_else(|| "Guardian response omitted rationale".to_string())?;
let status = match assessment.decision.trim().to_ascii_lowercase().as_str() {
"approved" | "allow" => GuardianReviewStatus::Approved,
"denied" | "deny" => GuardianReviewStatus::Denied,
other => return Err(format!("Guardian response used unknown decision '{other}'")),
};
Ok(GuardianReviewResult {
status,
risk_level: Some(risk_level),
user_authorization: Some(user_authorization),
rationale,
})
}
fn parse_risk_level(value: &str) -> Option<GuardianRiskLevel> {
match value.trim().to_ascii_lowercase().as_str() {
"low" => Some(GuardianRiskLevel::Low),
"medium" => Some(GuardianRiskLevel::Medium),
"high" => Some(GuardianRiskLevel::High),
"critical" => Some(GuardianRiskLevel::Critical),
_ => None,
}
}
fn parse_user_authorization(value: &str) -> Option<GuardianUserAuthorization> {
match value.trim().to_ascii_lowercase().as_str() {
"unknown" => Some(GuardianUserAuthorization::Unknown),
"low" => Some(GuardianUserAuthorization::Low),
"medium" => Some(GuardianUserAuthorization::Medium),
"high" => Some(GuardianUserAuthorization::High),
_ => None,
}
}
fn denied(rationale: impl Into<String>) -> GuardianReviewResult {
GuardianReviewResult {
status: GuardianReviewStatus::Denied,
risk_level: Some(GuardianRiskLevel::High),
user_authorization: Some(GuardianUserAuthorization::Unknown),
rationale: rationale.into(),
}
}
fn timed_out() -> GuardianReviewResult {
GuardianReviewResult {
status: GuardianReviewStatus::TimedOut,
risk_level: None,
user_authorization: None,
rationale: "Guardian review timed out; the action was denied.".to_string(),
}
}
+3 -1
View File
@@ -17,6 +17,7 @@ mod current_provider_turn;
mod direct_text_generation;
pub mod durable_memory_fs;
pub mod filesystem_event_protocol;
mod guardian_review;
mod knowledge_builder_skill;
pub mod lime_session_repository;
mod live_execution_process;
@@ -88,7 +89,8 @@ pub use protocol::{
AgentEvent, AgentImageAttachment, AgentMessage, AgentMessageContent, AgentOp,
AgentProviderTraceEvent, AgentProviderTraceStage, AgentRuntimeStatus, AgentTokenUsage,
AgentToolImage, AgentToolProgressPayload, AgentToolResult, AgentUserInputOp,
AgentUserPreferences, TextDeltaBatchBoundary,
AgentUserPreferences, GuardianReviewStatus, GuardianRiskLevel, GuardianUserAuthorization,
TextDeltaBatchBoundary,
};
pub use protocol_projection::{project_item_runtime, project_turn_runtime};
pub use provider_configuration::{
+79
View File
@@ -260,6 +260,34 @@ impl AgentMessagePhase {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum GuardianReviewStatus {
InProgress,
Approved,
Denied,
TimedOut,
Aborted,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum GuardianRiskLevel {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum GuardianUserAuthorization {
Unknown,
Low,
Medium,
High,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AgentEvent {
@@ -454,6 +482,47 @@ pub enum AgentEvent {
verifications: Vec<ModelVerification>,
},
#[serde(rename = "turn_moderation_metadata")]
TurnModerationMetadata { metadata: Value },
#[serde(rename = "guardian_review_started")]
GuardianReviewStarted {
review_id: String,
#[serde(rename = "targetItemId", skip_serializing_if = "Option::is_none")]
target_item_id: Option<String>,
#[serde(rename = "turnId")]
turn_id: String,
action: Value,
#[serde(rename = "startedAtMs")]
started_at_ms: i64,
},
#[serde(rename = "guardian_review_completed")]
GuardianReviewCompleted {
review_id: String,
#[serde(rename = "targetItemId", skip_serializing_if = "Option::is_none")]
target_item_id: Option<String>,
#[serde(rename = "turnId")]
turn_id: String,
status: GuardianReviewStatus,
#[serde(rename = "riskLevel", skip_serializing_if = "Option::is_none")]
risk_level: Option<GuardianRiskLevel>,
#[serde(rename = "userAuthorization", skip_serializing_if = "Option::is_none")]
user_authorization: Option<GuardianUserAuthorization>,
#[serde(skip_serializing_if = "Option::is_none")]
rationale: Option<String>,
#[serde(rename = "decisionSource")]
decision_source: String,
action: Value,
#[serde(rename = "startedAtMs")]
started_at_ms: i64,
#[serde(rename = "completedAtMs")]
completed_at_ms: i64,
},
#[serde(rename = "guardian_warning")]
GuardianWarning { message: String },
#[serde(rename = "provider_trace")]
ProviderTrace {
#[serde(flatten)]
@@ -1249,6 +1318,16 @@ mod tests {
verification["verifications"],
serde_json::json!(["trusted_access_for_cyber"])
);
let moderation = serde_json::to_value(AgentEvent::TurnModerationMetadata {
metadata: serde_json::json!({ "presentation": "inline" }),
})
.expect("serialize turn moderation metadata");
assert_eq!(moderation["type"], "turn_moderation_metadata");
assert_eq!(
moderation["metadata"],
serde_json::json!({ "presentation": "inline" })
);
}
#[test]
+46 -1
View File
@@ -19,7 +19,7 @@ use model_provider::current_client::{
CurrentProviderError, CurrentProviderHealthRegistry, CurrentProviderHealthSnapshot,
};
use model_provider::runtime_provider::RuntimeProviderConfig;
use std::collections::HashMap;
use std::collections::{HashMap, VecDeque};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::{Mutex, RwLock};
@@ -39,6 +39,7 @@ pub struct AgentRuntimeState {
mcp_runtime_lifecycle: Arc<Mutex<()>>,
action_required: Arc<agent_runtime::action_required::ActionRequiredState>,
permission_grants: Arc<RwLock<PermissionGrantState>>,
guardian_denials: Arc<Mutex<HashMap<(String, String), GuardianDenialState>>>,
live_execution_gateway:
Arc<RwLock<Option<Arc<dyn crate::live_execution_process::LiveExecutionProcessGateway>>>>,
}
@@ -57,6 +58,7 @@ impl Clone for AgentRuntimeState {
mcp_runtime_lifecycle: Arc::clone(&self.mcp_runtime_lifecycle),
action_required: Arc::clone(&self.action_required),
permission_grants: Arc::clone(&self.permission_grants),
guardian_denials: Arc::clone(&self.guardian_denials),
live_execution_gateway: Arc::clone(&self.live_execution_gateway),
}
}
@@ -84,6 +86,7 @@ impl AgentRuntimeState {
agent_runtime::action_required::ActionRequiredState::default(),
),
permission_grants: Arc::new(RwLock::new(PermissionGrantState::default())),
guardian_denials: Arc::new(Mutex::new(HashMap::new())),
live_execution_gateway: Arc::new(RwLock::new(None)),
}
}
@@ -133,6 +136,41 @@ impl AgentRuntimeState {
pub async fn close_provider_session(&self, session_id: &str) {
self.providers.write().await.remove(session_id);
self.clear_permission_grants(session_id).await;
self.guardian_denials
.lock()
.await
.retain(|(candidate_session_id, _), _| candidate_session_id != session_id);
}
pub(crate) async fn record_guardian_non_denial(&self, session_id: &str, turn_id: &str) {
self.guardian_denials
.lock()
.await
.remove(&(session_id.to_string(), turn_id.to_string()));
}
pub(crate) async fn record_guardian_denial(
&self,
session_id: &str,
turn_id: &str,
) -> Option<(u32, u32)> {
const RECENT_DENIAL_WINDOW: usize = 5;
const CONSECUTIVE_DENIAL_LIMIT: u32 = 3;
let mut denials = self.guardian_denials.lock().await;
let state = denials
.entry((session_id.to_string(), turn_id.to_string()))
.or_default();
state.consecutive = state.consecutive.saturating_add(1);
state.recent.push_back(());
while state.recent.len() > RECENT_DENIAL_WINDOW {
state.recent.pop_front();
}
if state.consecutive >= CONSECUTIVE_DENIAL_LIMIT && !state.warning_emitted {
state.warning_emitted = true;
return Some((state.consecutive, state.recent.len() as u32));
}
None
}
pub(crate) fn gateway_tools(&self) -> &RuntimeGatewayToolExecutionRegistry {
@@ -561,6 +599,13 @@ struct PermissionGrantState {
turn: HashMap<(String, String), EffectivePermissionGrant>,
}
#[derive(Default)]
struct GuardianDenialState {
consecutive: u32,
recent: VecDeque<()>,
warning_emitted: bool,
}
fn merge_granted_permissions(
target: &mut GrantedPermissionProfile,
incoming: &GrantedPermissionProfile,
File diff suppressed because it is too large Load Diff
@@ -162,6 +162,26 @@
"kind": "request",
"method": "capability/list"
},
{
"kind": "request",
"method": "command/exec"
},
{
"kind": "notification",
"method": "command/exec/outputDelta"
},
{
"kind": "request",
"method": "command/exec/resize"
},
{
"kind": "request",
"method": "command/exec/terminate"
},
{
"kind": "request",
"method": "command/exec/write"
},
{
"kind": "notification",
"method": "configWarning"
@@ -366,6 +386,10 @@
"kind": "request",
"method": "gatewayTunnel/syncWebhookUrl"
},
{
"kind": "notification",
"method": "guardianWarning"
},
{
"kind": "notification",
"method": "hook/completed"
@@ -390,6 +414,14 @@
"kind": "notification",
"method": "item/agentMessage/delta"
},
{
"kind": "notification",
"method": "item/autoApprovalReview/completed"
},
{
"kind": "notification",
"method": "item/autoApprovalReview/started"
},
{
"kind": "notification",
"method": "item/commandExecution/outputDelta"
@@ -398,6 +430,10 @@
"kind": "serverRequest",
"method": "item/commandExecution/requestApproval"
},
{
"kind": "notification",
"method": "item/commandExecution/terminalInteraction"
},
{
"kind": "notification",
"method": "item/completed"
@@ -884,23 +920,7 @@
},
{
"kind": "request",
"method": "projectShell/session/drainEvents"
},
{
"kind": "request",
"method": "projectShell/session/kill"
},
{
"kind": "request",
"method": "projectShell/session/resize"
},
{
"kind": "request",
"method": "projectShell/session/start"
},
{
"kind": "request",
"method": "projectShell/session/write"
"method": "review/start"
},
{
"kind": "notification",
@@ -1242,10 +1262,18 @@
"kind": "notification",
"method": "turn/completed"
},
{
"kind": "notification",
"method": "turn/diff/updated"
},
{
"kind": "request",
"method": "turn/interrupt"
},
{
"kind": "notification",
"method": "turn/moderationMetadata"
},
{
"kind": "notification",
"method": "turn/plan/updated"
@@ -1477,22 +1505,6 @@
"method": "mcpServer/oauth/login",
"scope": "mcpOauth"
},
{
"method": "projectShell/session/kill",
"scope": "projectShellSession"
},
{
"method": "projectShell/session/resize",
"scope": "projectShellSession"
},
{
"method": "projectShell/session/start",
"scope": "projectShellSession"
},
{
"method": "projectShell/session/write",
"scope": "projectShellSession"
},
{
"method": "thread/approveGuardianDeniedAction",
"scope": "thread"
@@ -1956,16 +1968,6 @@
"ProjectMaterialUploadParams",
"ProjectMemoryReadParams",
"ProjectMemoryReadResponse",
"ProjectShellEmptyResponse",
"ProjectShellSessionDrainEventsParams",
"ProjectShellSessionDrainEventsResponse",
"ProjectShellSessionEvent",
"ProjectShellSessionKillParams",
"ProjectShellSessionResizeParams",
"ProjectShellSessionStartParams",
"ProjectShellSessionStartResponse",
"ProjectShellSessionStream",
"ProjectShellSessionWriteParams",
"ProtocolKind",
"ProviderInfo",
"ProviderKeyInfo",
@@ -2169,6 +2171,7 @@
"ArtifactWriteParams",
"ArtifactWriteResponse",
"ArtifactWriteSidecar",
"AutoReviewDecisionSource",
"ClientRequest",
"ClientResponse",
"CodexErrorInfo",
@@ -2177,6 +2180,17 @@
"CollabAgentTool",
"CollabAgentToolCallStatus",
"CommandAction",
"CommandExecOutputDeltaNotification",
"CommandExecOutputStream",
"CommandExecParams",
"CommandExecResizeParams",
"CommandExecResizeResponse",
"CommandExecResponse",
"CommandExecTerminalSize",
"CommandExecTerminateParams",
"CommandExecTerminateResponse",
"CommandExecWriteParams",
"CommandExecWriteResponse",
"CommandExecutionApprovalDecision",
"CommandExecutionOutputDeltaNotification",
"CommandExecutionRequestApprovalParams",
@@ -2229,6 +2243,13 @@
"FsWriteFileResponse",
"GitInfo",
"GrantedPermissionProfile",
"GuardianApprovalReview",
"GuardianApprovalReviewAction",
"GuardianApprovalReviewStatus",
"GuardianCommandReviewAction",
"GuardianRiskLevel",
"GuardianUserAuthorization",
"GuardianWarningNotification",
"HookErrorInfo",
"HookMetadata",
"HookOutputEntry",
@@ -2243,6 +2264,8 @@
"InputModality",
"InstalledApp",
"ItemCompletedNotification",
"ItemGuardianApprovalReviewCompletedNotification",
"ItemGuardianApprovalReviewStartedNotification",
"ItemStartedNotification",
"McpServerElicitationAction",
"McpServerElicitationRequestParams",
@@ -2336,6 +2359,10 @@
"ReasoningSummaryTextDeltaNotification",
"ReasoningTextDeltaNotification",
"RequestPermissionProfile",
"ReviewDelivery",
"ReviewStartParams",
"ReviewStartResponse",
"ReviewTarget",
"ServerNotification",
"ServerRequest",
"ServerRequestResolvedNotification",
@@ -2470,11 +2497,13 @@
"ToolRequestUserInputResponse",
"Turn",
"TurnCompletedNotification",
"TurnDiffUpdatedNotification",
"TurnEnvironmentParams",
"TurnError",
"TurnInterruptParams",
"TurnInterruptResponse",
"TurnItemsView",
"TurnModerationMetadataNotification",
"TurnPlanStep",
"TurnPlanStepStatus",
"TurnPlanUpdatedNotification",
@@ -185,101 +185,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "projectShell/session/start",
"type": "string"
},
"params": {
"default": null
}
},
"required": [
"id",
"method"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "projectShell/session/write",
"type": "string"
},
"params": {
"default": null
}
},
"required": [
"id",
"method"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "projectShell/session/resize",
"type": "string"
},
"params": {
"default": null
}
},
"required": [
"id",
"method"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "projectShell/session/kill",
"type": "string"
},
"params": {
"default": null
}
},
"required": [
"id",
"method"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "projectShell/session/drainEvents",
"type": "string"
},
"params": {
"default": null
}
},
"required": [
"id",
"method"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -156,11 +156,6 @@
"projectMaterial/update",
"projectMaterial/upload",
"projectMemory/read",
"projectShell/session/drainEvents",
"projectShell/session/kill",
"projectShell/session/resize",
"projectShell/session/start",
"projectShell/session/write",
"sessionFile/delete",
"sessionFile/getOrCreate",
"sessionFile/list",
@@ -4,7 +4,6 @@
"browserSession",
"mcpOauth",
"mcpResourceSubscription",
"projectShellSession",
"thread"
],
"title": "AppServerRequestSerializationScope",
@@ -5,7 +5,6 @@
"browserSession",
"mcpOauth",
"mcpResourceSubscription",
"projectShellSession",
"thread"
],
"type": "string"
@@ -1,22 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"limit": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": [
"integer",
"null"
]
},
"sessionId": {
"type": [
"null",
"string"
]
}
},
"title": "ProjectShellSessionDrainEventsParams",
"type": "object"
}
@@ -1,31 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cols": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": [
"integer",
"null"
]
},
"rootPath": {
"type": "string"
},
"rows": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"required": [
"rootPath"
],
"title": "ProjectShellSessionStartParams",
"type": "object"
}
@@ -1,41 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cwd": {
"type": "string"
},
"localEcho": {
"type": "boolean"
},
"pid": {
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"sessionId": {
"type": "string"
},
"shell": {
"type": "string"
},
"title": {
"type": "string"
},
"tty": {
"type": "boolean"
}
},
"required": [
"cwd",
"localEcho",
"sessionId",
"shell",
"title",
"tty"
],
"title": "ProjectShellSessionStartResponse",
"type": "object"
}
@@ -0,0 +1,8 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"enum": [
"agent"
],
"title": "AutoReviewDecisionSource",
"type": "string"
}
@@ -207,6 +207,159 @@
],
"type": "object"
},
"CommandExecParams": {
"description": "Standalone command execution. It never creates a Thread or Turn.",
"properties": {
"command": {
"items": {
"type": "string"
},
"type": "array"
},
"cwd": {
"type": [
"null",
"string"
]
},
"disableOutputCap": {
"type": "boolean"
},
"disableTimeout": {
"type": "boolean"
},
"env": {
"additionalProperties": {
"type": [
"null",
"string"
]
},
"type": [
"null",
"object"
]
},
"outputBytesCap": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"permissionProfile": {
"type": [
"null",
"string"
]
},
"processId": {
"type": [
"null",
"string"
]
},
"sandboxPolicy": true,
"size": {
"anyOf": [
{
"$ref": "#/$defs/CommandExecTerminalSize"
},
{
"type": "null"
}
]
},
"streamStdin": {
"type": "boolean"
},
"streamStdoutStderr": {
"type": "boolean"
},
"timeoutMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"tty": {
"type": "boolean"
}
},
"required": [
"command"
],
"type": "object"
},
"CommandExecResizeParams": {
"properties": {
"processId": {
"type": "string"
},
"size": {
"$ref": "#/$defs/CommandExecTerminalSize"
}
},
"required": [
"processId",
"size"
],
"type": "object"
},
"CommandExecTerminalSize": {
"properties": {
"cols": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"rows": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
}
},
"required": [
"cols",
"rows"
],
"type": "object"
},
"CommandExecTerminateParams": {
"properties": {
"processId": {
"type": "string"
}
},
"required": [
"processId"
],
"type": "object"
},
"CommandExecWriteParams": {
"properties": {
"closeStdin": {
"type": "boolean"
},
"deltaBase64": {
"type": [
"null",
"string"
]
},
"processId": {
"type": "string"
}
},
"required": [
"processId"
],
"type": "object"
},
"DynamicToolFunctionSpec": {
"properties": {
"deferLoading": {
@@ -890,6 +1043,108 @@
}
]
},
"ReviewDelivery": {
"enum": [
"detached",
"inline"
],
"type": "string"
},
"ReviewStartParams": {
"properties": {
"delivery": {
"anyOf": [
{
"$ref": "#/$defs/ReviewDelivery"
},
{
"type": "null"
}
]
},
"target": {
"$ref": "#/$defs/ReviewTarget"
},
"threadId": {
"type": "string"
}
},
"required": [
"target",
"threadId"
],
"type": "object"
},
"ReviewTarget": {
"oneOf": [
{
"properties": {
"type": {
"const": "uncommittedChanges",
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"properties": {
"branch": {
"type": "string"
},
"type": {
"const": "baseBranch",
"type": "string"
}
},
"required": [
"branch",
"type"
],
"type": "object"
},
{
"properties": {
"sha": {
"type": "string"
},
"title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "commit",
"type": "string"
}
},
"required": [
"sha",
"type"
],
"type": "object"
},
{
"properties": {
"instructions": {
"type": "string"
},
"type": {
"const": "custom",
"type": "string"
}
},
"required": [
"instructions",
"type"
],
"type": "object"
}
]
},
"SkillsConfigWriteParams": {
"properties": {
"enabled": {
@@ -3671,6 +3926,26 @@
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "review/start",
"type": "string"
},
"params": {
"$ref": "#/$defs/ReviewStartParams"
}
},
"required": [
"id",
"method",
"params"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -3930,6 +4205,86 @@
"params"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "command/exec",
"type": "string"
},
"params": {
"$ref": "#/$defs/CommandExecParams"
}
},
"required": [
"id",
"method",
"params"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "command/exec/write",
"type": "string"
},
"params": {
"$ref": "#/$defs/CommandExecWriteParams"
}
},
"required": [
"id",
"method",
"params"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "command/exec/resize",
"type": "string"
},
"params": {
"$ref": "#/$defs/CommandExecResizeParams"
}
},
"required": [
"id",
"method",
"params"
],
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/$defs/RequestId"
},
"method": {
"const": "command/exec/terminate",
"type": "string"
},
"params": {
"$ref": "#/$defs/CommandExecTerminateParams"
}
},
"required": [
"id",
"method",
"params"
],
"type": "object"
}
],
"title": "ClientRequest"
@@ -0,0 +1,34 @@
{
"$defs": {
"CommandExecOutputStream": {
"enum": [
"stderr",
"stdout"
],
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"capReached": {
"type": "boolean"
},
"deltaBase64": {
"type": "string"
},
"processId": {
"type": "string"
},
"stream": {
"$ref": "#/$defs/CommandExecOutputStream"
}
},
"required": [
"capReached",
"deltaBase64",
"processId",
"stream"
],
"title": "CommandExecOutputDeltaNotification",
"type": "object"
}
@@ -4,6 +4,6 @@
"stderr",
"stdout"
],
"title": "ProjectShellSessionStream",
"title": "CommandExecOutputStream",
"type": "string"
}
@@ -0,0 +1,111 @@
{
"$defs": {
"CommandExecTerminalSize": {
"properties": {
"cols": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"rows": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
}
},
"required": [
"cols",
"rows"
],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Standalone command execution. It never creates a Thread or Turn.",
"properties": {
"command": {
"items": {
"type": "string"
},
"type": "array"
},
"cwd": {
"type": [
"null",
"string"
]
},
"disableOutputCap": {
"type": "boolean"
},
"disableTimeout": {
"type": "boolean"
},
"env": {
"additionalProperties": {
"type": [
"null",
"string"
]
},
"type": [
"null",
"object"
]
},
"outputBytesCap": {
"format": "uint",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"permissionProfile": {
"type": [
"null",
"string"
]
},
"processId": {
"type": [
"null",
"string"
]
},
"sandboxPolicy": true,
"size": {
"anyOf": [
{
"$ref": "#/$defs/CommandExecTerminalSize"
},
{
"type": "null"
}
]
},
"streamStdin": {
"type": "boolean"
},
"streamStdoutStderr": {
"type": "boolean"
},
"timeoutMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"tty": {
"type": "boolean"
}
},
"required": [
"command"
],
"title": "CommandExecParams",
"type": "object"
}
@@ -0,0 +1,40 @@
{
"$defs": {
"CommandExecTerminalSize": {
"properties": {
"cols": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"rows": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
}
},
"required": [
"cols",
"rows"
],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"processId": {
"type": "string"
},
"size": {
"$ref": "#/$defs/CommandExecTerminalSize"
}
},
"required": [
"processId",
"size"
],
"title": "CommandExecResizeParams",
"type": "object"
}
@@ -1,5 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "ProjectShellEmptyResponse",
"title": "CommandExecResizeResponse",
"type": "object"
}
@@ -0,0 +1,22 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"exitCode": {
"format": "int32",
"type": "integer"
},
"stderr": {
"type": "string"
},
"stdout": {
"type": "string"
}
},
"required": [
"exitCode",
"stderr",
"stdout"
],
"title": "CommandExecResponse",
"type": "object"
}
@@ -12,16 +12,12 @@
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"sessionId": {
"type": "string"
}
},
"required": [
"cols",
"rows",
"sessionId"
"rows"
],
"title": "ProjectShellSessionResizeParams",
"title": "CommandExecTerminalSize",
"type": "object"
}
@@ -1,13 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"sessionId": {
"processId": {
"type": "string"
}
},
"required": [
"sessionId"
"processId"
],
"title": "ProjectShellSessionKillParams",
"title": "CommandExecTerminateParams",
"type": "object"
}
@@ -0,0 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "CommandExecTerminateResponse",
"type": "object"
}
@@ -0,0 +1,22 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"closeStdin": {
"type": "boolean"
},
"deltaBase64": {
"type": [
"null",
"string"
]
},
"processId": {
"type": "string"
}
},
"required": [
"processId"
],
"title": "CommandExecWriteParams",
"type": "object"
}
@@ -0,0 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "CommandExecWriteResponse",
"type": "object"
}
@@ -0,0 +1,69 @@
{
"$defs": {
"GuardianApprovalReviewStatus": {
"enum": [
"aborted",
"approved",
"denied",
"inProgress",
"timedOut"
],
"type": "string"
},
"GuardianRiskLevel": {
"enum": [
"critical",
"high",
"low",
"medium"
],
"type": "string"
},
"GuardianUserAuthorization": {
"enum": [
"high",
"low",
"medium",
"unknown"
],
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"rationale": {
"type": [
"null",
"string"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/$defs/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/$defs/GuardianApprovalReviewStatus"
},
"userAuthorization": {
"anyOf": [
{
"$ref": "#/$defs/GuardianUserAuthorization"
},
{
"type": "null"
}
]
}
},
"required": [
"status"
],
"title": "GuardianApprovalReview",
"type": "object"
}
@@ -0,0 +1,173 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"properties": {
"command": {
"type": "string"
},
"cwd": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "command",
"type": "string"
}
},
"required": [
"command",
"cwd",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"argv": {
"items": {
"type": "string"
},
"type": "array"
},
"cwd": {
"type": "string"
},
"program": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "execve",
"type": "string"
}
},
"required": [
"argv",
"cwd",
"program",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"cwd": {
"type": "string"
},
"files": {
"items": {
"type": "string"
},
"type": "array"
},
"type": {
"const": "applyPatch",
"type": "string"
}
},
"required": [
"cwd",
"files",
"type"
],
"type": "object"
},
{
"properties": {
"host": {
"type": "string"
},
"port": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
},
"target": {
"type": "string"
},
"type": {
"const": "networkAccess",
"type": "string"
}
},
"required": [
"host",
"port",
"protocol",
"target",
"type"
],
"type": "object"
},
{
"properties": {
"connector_id": {
"type": [
"null",
"string"
]
},
"connector_name": {
"type": [
"null",
"string"
]
},
"server": {
"type": "string"
},
"tool_name": {
"type": "string"
},
"tool_title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "mcpToolCall",
"type": "string"
}
},
"required": [
"server",
"tool_name",
"type"
],
"type": "object"
},
{
"properties": {
"permissions": true,
"reason": {
"type": [
"null",
"string"
]
},
"type": {
"const": "requestPermissions",
"type": "string"
}
},
"required": [
"permissions",
"type"
],
"type": "object"
}
],
"title": "GuardianApprovalReviewAction"
}
@@ -0,0 +1,12 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"enum": [
"aborted",
"approved",
"denied",
"inProgress",
"timedOut"
],
"title": "GuardianApprovalReviewStatus",
"type": "string"
}
@@ -1,17 +1,21 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"data": {
"command": {
"type": "string"
},
"sessionId": {
"cwd": {
"type": "string"
},
"source": {
"type": "string"
}
},
"required": [
"data",
"sessionId"
"command",
"cwd",
"source"
],
"title": "ProjectShellSessionWriteParams",
"title": "GuardianCommandReviewAction",
"type": "object"
}
@@ -0,0 +1,11 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"enum": [
"critical",
"high",
"low",
"medium"
],
"title": "GuardianRiskLevel",
"type": "string"
}
@@ -0,0 +1,11 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"enum": [
"high",
"low",
"medium",
"unknown"
],
"title": "GuardianUserAuthorization",
"type": "string"
}
@@ -0,0 +1,19 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"description": "Reports a high-priority Guardian circuit-breaker warning for a thread.",
"properties": {
"message": {
"type": "string"
},
"threadId": {
"type": "string"
}
},
"required": [
"message",
"threadId"
],
"title": "GuardianWarningNotification",
"type": "object"
}
@@ -274,62 +274,6 @@
],
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -345,115 +289,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -791,36 +626,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -0,0 +1,293 @@
{
"$defs": {
"AutoReviewDecisionSource": {
"enum": [
"agent"
],
"type": "string"
},
"GuardianApprovalReview": {
"properties": {
"rationale": {
"type": [
"null",
"string"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/$defs/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/$defs/GuardianApprovalReviewStatus"
},
"userAuthorization": {
"anyOf": [
{
"$ref": "#/$defs/GuardianUserAuthorization"
},
{
"type": "null"
}
]
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewAction": {
"oneOf": [
{
"properties": {
"command": {
"type": "string"
},
"cwd": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "command",
"type": "string"
}
},
"required": [
"command",
"cwd",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"argv": {
"items": {
"type": "string"
},
"type": "array"
},
"cwd": {
"type": "string"
},
"program": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "execve",
"type": "string"
}
},
"required": [
"argv",
"cwd",
"program",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"cwd": {
"type": "string"
},
"files": {
"items": {
"type": "string"
},
"type": "array"
},
"type": {
"const": "applyPatch",
"type": "string"
}
},
"required": [
"cwd",
"files",
"type"
],
"type": "object"
},
{
"properties": {
"host": {
"type": "string"
},
"port": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
},
"target": {
"type": "string"
},
"type": {
"const": "networkAccess",
"type": "string"
}
},
"required": [
"host",
"port",
"protocol",
"target",
"type"
],
"type": "object"
},
{
"properties": {
"connector_id": {
"type": [
"null",
"string"
]
},
"connector_name": {
"type": [
"null",
"string"
]
},
"server": {
"type": "string"
},
"tool_name": {
"type": "string"
},
"tool_title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "mcpToolCall",
"type": "string"
}
},
"required": [
"server",
"tool_name",
"type"
],
"type": "object"
},
{
"properties": {
"permissions": true,
"reason": {
"type": [
"null",
"string"
]
},
"type": {
"const": "requestPermissions",
"type": "string"
}
},
"required": [
"permissions",
"type"
],
"type": "object"
}
]
},
"GuardianApprovalReviewStatus": {
"enum": [
"aborted",
"approved",
"denied",
"inProgress",
"timedOut"
],
"type": "string"
},
"GuardianRiskLevel": {
"enum": [
"critical",
"high",
"low",
"medium"
],
"type": "string"
},
"GuardianUserAuthorization": {
"enum": [
"high",
"low",
"medium",
"unknown"
],
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"action": {
"$ref": "#/$defs/GuardianApprovalReviewAction"
},
"completedAtMs": {
"format": "int64",
"type": "integer"
},
"decisionSource": {
"$ref": "#/$defs/AutoReviewDecisionSource"
},
"review": {
"$ref": "#/$defs/GuardianApprovalReview"
},
"reviewId": {
"type": "string"
},
"startedAtMs": {
"format": "int64",
"type": "integer"
},
"targetItemId": {
"type": [
"null",
"string"
]
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"action",
"completedAtMs",
"decisionSource",
"review",
"reviewId",
"startedAtMs",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewCompletedNotification",
"type": "object"
}
@@ -0,0 +1,278 @@
{
"$defs": {
"GuardianApprovalReview": {
"properties": {
"rationale": {
"type": [
"null",
"string"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/$defs/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/$defs/GuardianApprovalReviewStatus"
},
"userAuthorization": {
"anyOf": [
{
"$ref": "#/$defs/GuardianUserAuthorization"
},
{
"type": "null"
}
]
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewAction": {
"oneOf": [
{
"properties": {
"command": {
"type": "string"
},
"cwd": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "command",
"type": "string"
}
},
"required": [
"command",
"cwd",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"argv": {
"items": {
"type": "string"
},
"type": "array"
},
"cwd": {
"type": "string"
},
"program": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "execve",
"type": "string"
}
},
"required": [
"argv",
"cwd",
"program",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"cwd": {
"type": "string"
},
"files": {
"items": {
"type": "string"
},
"type": "array"
},
"type": {
"const": "applyPatch",
"type": "string"
}
},
"required": [
"cwd",
"files",
"type"
],
"type": "object"
},
{
"properties": {
"host": {
"type": "string"
},
"port": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
},
"target": {
"type": "string"
},
"type": {
"const": "networkAccess",
"type": "string"
}
},
"required": [
"host",
"port",
"protocol",
"target",
"type"
],
"type": "object"
},
{
"properties": {
"connector_id": {
"type": [
"null",
"string"
]
},
"connector_name": {
"type": [
"null",
"string"
]
},
"server": {
"type": "string"
},
"tool_name": {
"type": "string"
},
"tool_title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "mcpToolCall",
"type": "string"
}
},
"required": [
"server",
"tool_name",
"type"
],
"type": "object"
},
{
"properties": {
"permissions": true,
"reason": {
"type": [
"null",
"string"
]
},
"type": {
"const": "requestPermissions",
"type": "string"
}
},
"required": [
"permissions",
"type"
],
"type": "object"
}
]
},
"GuardianApprovalReviewStatus": {
"enum": [
"aborted",
"approved",
"denied",
"inProgress",
"timedOut"
],
"type": "string"
},
"GuardianRiskLevel": {
"enum": [
"critical",
"high",
"low",
"medium"
],
"type": "string"
},
"GuardianUserAuthorization": {
"enum": [
"high",
"low",
"medium",
"unknown"
],
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"action": {
"$ref": "#/$defs/GuardianApprovalReviewAction"
},
"review": {
"$ref": "#/$defs/GuardianApprovalReview"
},
"reviewId": {
"type": "string"
},
"startedAtMs": {
"format": "int64",
"type": "integer"
},
"targetItemId": {
"type": [
"null",
"string"
]
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"action",
"review",
"reviewId",
"startedAtMs",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewStartedNotification",
"type": "object"
}
@@ -274,62 +274,6 @@
],
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -345,115 +289,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -791,36 +626,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -5,6 +5,10 @@
"app/list",
"app/read",
"artifact/write",
"command/exec",
"command/exec/resize",
"command/exec/terminate",
"command/exec/write",
"fs/copy",
"fs/createDirectory",
"fs/getMetadata",
@@ -31,6 +35,7 @@
"process/resizePty",
"process/spawn",
"process/writeStdin",
"review/start",
"skills/config/write",
"skills/extraRoots/set",
"skills/list",
@@ -0,0 +1,9 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"enum": [
"detached",
"inline"
],
"title": "ReviewDelivery",
"type": "string"
}
@@ -1,100 +1,106 @@
{
"$defs": {
"ProjectShellSessionEvent": {
"ReviewDelivery": {
"enum": [
"detached",
"inline"
],
"type": "string"
},
"ReviewTarget": {
"oneOf": [
{
"properties": {
"data": {
"type": "string"
},
"session_id": {
"type": "string"
},
"stream": {
"$ref": "#/$defs/ProjectShellSessionStream"
},
"type": {
"const": "data",
"const": "uncommittedChanges",
"type": "string"
}
},
"required": [
"data",
"session_id",
"stream",
"type"
],
"type": "object"
},
{
"properties": {
"exit_code": {
"format": "int32",
"type": [
"integer",
"null"
]
},
"session_id": {
"branch": {
"type": "string"
},
"signal": {
"type": {
"const": "baseBranch",
"type": "string"
}
},
"required": [
"branch",
"type"
],
"type": "object"
},
{
"properties": {
"sha": {
"type": "string"
},
"title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "exit",
"const": "commit",
"type": "string"
}
},
"required": [
"session_id",
"sha",
"type"
],
"type": "object"
},
{
"properties": {
"message": {
"type": "string"
},
"session_id": {
"instructions": {
"type": "string"
},
"type": {
"const": "error",
"const": "custom",
"type": "string"
}
},
"required": [
"message",
"session_id",
"instructions",
"type"
],
"type": "object"
}
]
},
"ProjectShellSessionStream": {
"enum": [
"stderr",
"stdout"
],
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"events": {
"default": [],
"items": {
"$ref": "#/$defs/ProjectShellSessionEvent"
},
"type": "array"
"delivery": {
"anyOf": [
{
"$ref": "#/$defs/ReviewDelivery"
},
{
"type": "null"
}
]
},
"target": {
"$ref": "#/$defs/ReviewTarget"
},
"threadId": {
"type": "string"
}
},
"title": "ProjectShellSessionDrainEventsResponse",
"required": [
"target",
"threadId"
],
"title": "ReviewStartParams",
"type": "object"
}
File diff suppressed because it is too large Load Diff
@@ -1,88 +1,72 @@
{
"$defs": {
"ProjectShellSessionStream": {
"enum": [
"stderr",
"stdout"
],
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"properties": {
"data": {
"type": "string"
},
"session_id": {
"type": "string"
},
"stream": {
"$ref": "#/$defs/ProjectShellSessionStream"
},
"type": {
"const": "data",
"const": "uncommittedChanges",
"type": "string"
}
},
"required": [
"data",
"session_id",
"stream",
"type"
],
"type": "object"
},
{
"properties": {
"exit_code": {
"format": "int32",
"type": [
"integer",
"null"
]
},
"session_id": {
"branch": {
"type": "string"
},
"signal": {
"type": {
"const": "baseBranch",
"type": "string"
}
},
"required": [
"branch",
"type"
],
"type": "object"
},
{
"properties": {
"sha": {
"type": "string"
},
"title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "exit",
"const": "commit",
"type": "string"
}
},
"required": [
"session_id",
"sha",
"type"
],
"type": "object"
},
{
"properties": {
"message": {
"type": "string"
},
"session_id": {
"instructions": {
"type": "string"
},
"type": {
"const": "error",
"const": "custom",
"type": "string"
}
},
"required": [
"message",
"session_id",
"instructions",
"type"
],
"type": "object"
}
],
"title": "ProjectShellSessionEvent"
"title": "ReviewTarget"
}
@@ -303,6 +303,12 @@
],
"type": "object"
},
"AutoReviewDecisionSource": {
"enum": [
"agent"
],
"type": "string"
},
"ByteRange": {
"properties": {
"end": {
@@ -638,6 +644,36 @@
}
]
},
"CommandExecOutputDeltaNotification": {
"properties": {
"capReached": {
"type": "boolean"
},
"deltaBase64": {
"type": "string"
},
"processId": {
"type": "string"
},
"stream": {
"$ref": "#/$defs/CommandExecOutputStream"
}
},
"required": [
"capReached",
"deltaBase64",
"processId",
"stream"
],
"type": "object"
},
"CommandExecOutputStream": {
"enum": [
"stderr",
"stdout"
],
"type": "string"
},
"CommandExecutionOutputDeltaNotification": {
"properties": {
"delta": {
@@ -930,6 +966,259 @@
},
"type": "object"
},
"GuardianApprovalReview": {
"properties": {
"rationale": {
"type": [
"null",
"string"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/$defs/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"status": {
"$ref": "#/$defs/GuardianApprovalReviewStatus"
},
"userAuthorization": {
"anyOf": [
{
"$ref": "#/$defs/GuardianUserAuthorization"
},
{
"type": "null"
}
]
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewAction": {
"oneOf": [
{
"properties": {
"command": {
"type": "string"
},
"cwd": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "command",
"type": "string"
}
},
"required": [
"command",
"cwd",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"argv": {
"items": {
"type": "string"
},
"type": "array"
},
"cwd": {
"type": "string"
},
"program": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"const": "execve",
"type": "string"
}
},
"required": [
"argv",
"cwd",
"program",
"source",
"type"
],
"type": "object"
},
{
"properties": {
"cwd": {
"type": "string"
},
"files": {
"items": {
"type": "string"
},
"type": "array"
},
"type": {
"const": "applyPatch",
"type": "string"
}
},
"required": [
"cwd",
"files",
"type"
],
"type": "object"
},
{
"properties": {
"host": {
"type": "string"
},
"port": {
"format": "uint16",
"maximum": 65535,
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
},
"target": {
"type": "string"
},
"type": {
"const": "networkAccess",
"type": "string"
}
},
"required": [
"host",
"port",
"protocol",
"target",
"type"
],
"type": "object"
},
{
"properties": {
"connector_id": {
"type": [
"null",
"string"
]
},
"connector_name": {
"type": [
"null",
"string"
]
},
"server": {
"type": "string"
},
"tool_name": {
"type": "string"
},
"tool_title": {
"type": [
"null",
"string"
]
},
"type": {
"const": "mcpToolCall",
"type": "string"
}
},
"required": [
"server",
"tool_name",
"type"
],
"type": "object"
},
{
"properties": {
"permissions": true,
"reason": {
"type": [
"null",
"string"
]
},
"type": {
"const": "requestPermissions",
"type": "string"
}
},
"required": [
"permissions",
"type"
],
"type": "object"
}
]
},
"GuardianApprovalReviewStatus": {
"enum": [
"aborted",
"approved",
"denied",
"inProgress",
"timedOut"
],
"type": "string"
},
"GuardianRiskLevel": {
"enum": [
"critical",
"high",
"low",
"medium"
],
"type": "string"
},
"GuardianUserAuthorization": {
"enum": [
"high",
"low",
"medium",
"unknown"
],
"type": "string"
},
"GuardianWarningNotification": {
"additionalProperties": false,
"description": "Reports a high-priority Guardian circuit-breaker warning for a thread.",
"properties": {
"message": {
"type": "string"
},
"threadId": {
"type": "string"
}
},
"required": [
"message",
"threadId"
],
"type": "object"
},
"HookCompletedNotification": {
"properties": {
"run": {
@@ -1226,6 +1515,91 @@
],
"type": "object"
},
"ItemGuardianApprovalReviewCompletedNotification": {
"properties": {
"action": {
"$ref": "#/$defs/GuardianApprovalReviewAction"
},
"completedAtMs": {
"format": "int64",
"type": "integer"
},
"decisionSource": {
"$ref": "#/$defs/AutoReviewDecisionSource"
},
"review": {
"$ref": "#/$defs/GuardianApprovalReview"
},
"reviewId": {
"type": "string"
},
"startedAtMs": {
"format": "int64",
"type": "integer"
},
"targetItemId": {
"type": [
"null",
"string"
]
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"action",
"completedAtMs",
"decisionSource",
"review",
"reviewId",
"startedAtMs",
"threadId",
"turnId"
],
"type": "object"
},
"ItemGuardianApprovalReviewStartedNotification": {
"properties": {
"action": {
"$ref": "#/$defs/GuardianApprovalReviewAction"
},
"review": {
"$ref": "#/$defs/GuardianApprovalReview"
},
"reviewId": {
"type": "string"
},
"startedAtMs": {
"format": "int64",
"type": "integer"
},
"targetItemId": {
"type": [
"null",
"string"
]
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"action",
"review",
"reviewId",
"startedAtMs",
"threadId",
"turnId"
],
"type": "object"
},
"ItemStartedNotification": {
"properties": {
"item": {
@@ -2307,36 +2681,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -3523,6 +3867,27 @@
],
"type": "object"
},
"TurnDiffUpdatedNotification": {
"additionalProperties": false,
"description": "Reports the latest aggregated unified diff for the current turn.",
"properties": {
"diff": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"diff",
"threadId",
"turnId"
],
"type": "object"
},
"TurnError": {
"additionalProperties": false,
"properties": {
@@ -3559,6 +3924,24 @@
],
"type": "string"
},
"TurnModerationMetadataNotification": {
"additionalProperties": false,
"properties": {
"metadata": true,
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"metadata",
"threadId",
"turnId"
],
"type": "object"
},
"TurnPlanStep": {
"additionalProperties": false,
"properties": {
@@ -3849,6 +4232,22 @@
],
"type": "object"
},
{
"properties": {
"method": {
"const": "guardianWarning",
"type": "string"
},
"params": {
"$ref": "#/$defs/GuardianWarningNotification"
}
},
"required": [
"method",
"params"
],
"type": "object"
},
{
"properties": {
"method": {
@@ -4105,6 +4504,22 @@
],
"type": "object"
},
{
"properties": {
"method": {
"const": "turn/diff/updated",
"type": "string"
},
"params": {
"$ref": "#/$defs/TurnDiffUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"type": "object"
},
{
"properties": {
"method": {
@@ -4153,6 +4568,38 @@
],
"type": "object"
},
{
"properties": {
"method": {
"const": "item/autoApprovalReview/started",
"type": "string"
},
"params": {
"$ref": "#/$defs/ItemGuardianApprovalReviewStartedNotification"
}
},
"required": [
"method",
"params"
],
"type": "object"
},
{
"properties": {
"method": {
"const": "item/autoApprovalReview/completed",
"type": "string"
},
"params": {
"$ref": "#/$defs/ItemGuardianApprovalReviewCompletedNotification"
}
},
"required": [
"method",
"params"
],
"type": "object"
},
{
"properties": {
"method": {
@@ -4345,6 +4792,22 @@
],
"type": "object"
},
{
"properties": {
"method": {
"const": "turn/moderationMetadata",
"type": "string"
},
"params": {
"$ref": "#/$defs/TurnModerationMetadataNotification"
}
},
"required": [
"method",
"params"
],
"type": "object"
},
{
"properties": {
"method": {
@@ -4409,6 +4872,22 @@
],
"type": "object"
},
{
"properties": {
"method": {
"const": "command/exec/outputDelta",
"type": "string"
},
"params": {
"$ref": "#/$defs/CommandExecOutputDeltaNotification"
}
},
"required": [
"method",
"params"
],
"type": "object"
},
{
"properties": {
"method": {
@@ -430,62 +430,6 @@
},
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -501,115 +445,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -968,36 +803,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -430,62 +430,6 @@
},
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -501,115 +445,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -1146,36 +981,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -274,62 +274,6 @@
],
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -345,115 +289,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -1078,36 +913,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -274,62 +274,6 @@
],
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -345,115 +289,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -791,36 +626,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -274,62 +274,6 @@
],
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -345,115 +289,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -791,36 +626,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {
@@ -430,62 +430,6 @@
},
"type": "object"
},
"HookEventName": {
"enum": [
"permissionRequest",
"postCompact",
"postToolUse",
"preCompact",
"preToolUse",
"sessionEnd",
"sessionStart",
"stop",
"subagentStart",
"subagentStop",
"userPromptSubmit"
],
"type": "string"
},
"HookExecutionMode": {
"enum": [
"async",
"sync"
],
"type": "string"
},
"HookHandlerType": {
"enum": [
"agent",
"command",
"prompt"
],
"type": "string"
},
"HookOutputEntry": {
"properties": {
"kind": {
"$ref": "#/$defs/HookOutputEntryKind"
},
"text": {
"type": "string"
}
},
"required": [
"kind",
"text"
],
"type": "object"
},
"HookOutputEntryKind": {
"enum": [
"context",
"error",
"feedback",
"stop",
"warning"
],
"type": "string"
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -501,115 +445,6 @@
],
"type": "object"
},
"HookRunStatus": {
"enum": [
"blocked",
"completed",
"failed",
"running",
"stopped"
],
"type": "string"
},
"HookRunSummary": {
"properties": {
"completedAt": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"displayOrder": {
"format": "int64",
"type": "integer"
},
"durationMs": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"entries": {
"items": {
"$ref": "#/$defs/HookOutputEntry"
},
"type": "array"
},
"eventName": {
"$ref": "#/$defs/HookEventName"
},
"executionMode": {
"$ref": "#/$defs/HookExecutionMode"
},
"handlerType": {
"$ref": "#/$defs/HookHandlerType"
},
"id": {
"type": "string"
},
"scope": {
"$ref": "#/$defs/HookScope"
},
"source": {
"$ref": "#/$defs/HookSource"
},
"sourcePath": {
"type": "string"
},
"startedAt": {
"format": "int64",
"type": "integer"
},
"status": {
"$ref": "#/$defs/HookRunStatus"
},
"statusMessage": {
"type": [
"null",
"string"
]
}
},
"required": [
"displayOrder",
"entries",
"eventName",
"executionMode",
"handlerType",
"id",
"scope",
"source",
"sourcePath",
"startedAt",
"status"
],
"type": "object"
},
"HookScope": {
"enum": [
"thread",
"turn"
],
"type": "string"
},
"HookSource": {
"enum": [
"cloudManagedConfig",
"cloudRequirements",
"legacyManagedConfigFile",
"legacyManagedConfigMdm",
"mdm",
"plugin",
"project",
"sessionFlags",
"system",
"unknown",
"user"
],
"type": "string"
},
"ImageDetail": {
"enum": [
"auto",
@@ -1122,36 +957,6 @@
],
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"$ref": "#/$defs/ThreadItemMetadata"
},
{
"type": "null"
}
]
},
"run": {
"$ref": "#/$defs/HookRunSummary"
},
"type": {
"const": "hook",
"type": "string"
}
},
"required": [
"id",
"run",
"type"
],
"type": "object"
},
{
"properties": {
"id": {

Some files were not shown because too many files have changed in this diff Show More