{"_id":"@agentskillmania/wrangler-daemon","_rev":"3-d2d58c6b78e44ae3beeed64c1dc1a154","name":"@agentskillmania/wrangler-daemon","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.0":{"name":"@agentskillmania/wrangler-daemon","version":"0.2.0","author":{"name":"yusangeng","email":"yusangeng@outlook.com"},"license":"MIT","_id":"@agentskillmania/wrangler-daemon@0.2.0","maintainers":[{"name":"yusangeng","email":"yusangeng@outlook.com"}],"homepage":"https://github.com/agentskillmania/wrangler#readme","bugs":{"url":"https://github.com/agentskillmania/wrangler/issues"},"bin":{"wrangler-daemon":"dist/cli/index.js"},"dist":{"shasum":"4cd62a89160c27484324aaf6df1afa510c88760a","tarball":"https://registry.npmjs.org/@agentskillmania/wrangler-daemon/-/wrangler-daemon-0.2.0.tgz","fileCount":128,"integrity":"sha512-kAq1a9eVVOyFK3VzT2h+Sam4tG3KhI7cdHh8SVm7flMB3YYEdR8t9qFYA6kTFHL3MU2QuHTwDJuHK0rJimlSlg==","signatures":[{"sig":"MEYCIQD7Urhg1cVCjtp5arlUF+iVD1z12F9Q+VEBXQ9JRlhfgAIhAK7zFDd1JJiewb/uCsevKQKvPhf/6IpZfUZUBOf1iZVy","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":376303},"main":"dist/index.js","type":"module","_from":"file:agentskillmania-wrangler-daemon-0.2.0.tgz","types":"dist/index.d.ts","scripts":{"dev":"tsx watch src/daemon.ts","test":"vitest run","build":"tsc","test:intg":"vitest run test/integration","test:unit":"vitest run test/unit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"yusangeng","email":"yusangeng@outlook.com"},"_resolved":"/private/var/folders/dc/61lk2kgn1697rt0gd1s5jwf80000gn/T/32f084b4b88463dbdaba454c0d46d090/agentskillmania-wrangler-daemon-0.2.0.tgz","_integrity":"sha512-kAq1a9eVVOyFK3VzT2h+Sam4tG3KhI7cdHh8SVm7flMB3YYEdR8t9qFYA6kTFHL3MU2QuHTwDJuHK0rJimlSlg==","repository":{"url":"git+https://github.com/agentskillmania/wrangler.git","type":"git","directory":"packages/wrangler-daemon"},"_npmVersion":"11.6.1","description":"[English Documentation](./README.md)","directories":{},"_nodeVersion":"22.15.0","dependencies":{"dotenv":"^16.4.0","fastify":"^5.3.0","js-yaml":"^4.1.1","@agentskillmania/colts":"^0.4.0","@agentskillmania/wrangler":"0.2.0","@agentskillmania/llm-client":"^0.4.0","@agentskillmania/settings-yaml":"^0.4.0","@agentskillmania/wrangler-devtool":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","vitest":"^3.1.0","typescript":"^5.0.0","@types/node":"^20.0.0","@types/js-yaml":"^4.0.9","typescript-eslint":"^8.58.0","@vitest/coverage-v8":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/wrangler-daemon_0.2.0_1786612495098_0.5540770931829173","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@agentskillmania/wrangler-daemon","version":"0.2.1","author":{"name":"yusangeng","email":"yusangeng@outlook.com"},"license":"MIT","_id":"@agentskillmania/wrangler-daemon@0.2.1","maintainers":[{"name":"yusangeng","email":"yusangeng@outlook.com"}],"homepage":"https://github.com/agentskillmania/wrangler#readme","bugs":{"url":"https://github.com/agentskillmania/wrangler/issues"},"bin":{"wrangler-daemon":"dist/cli/index.js"},"dist":{"shasum":"148f698c57202af7da0721f042b565533059d691","tarball":"https://registry.npmjs.org/@agentskillmania/wrangler-daemon/-/wrangler-daemon-0.2.1.tgz","fileCount":128,"integrity":"sha512-59iSngxoyPtWXpiA4tt39xsDBqMaLipBlD/0d5vXDWMsoo5tffp2cmoJOZfu1+iZ6yqTSgAQgqjaocOOQJUaZQ==","signatures":[{"sig":"MEUCIQC0ZuozjNTNSVA/flJqlO2MzzIYvf8FV+GQvDD3gEwY3AIgM6Qx9KZe3S9HR69qk1Vx+fBrKGagJRuyqbmWiV6XhYo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":376553},"main":"dist/index.js","type":"module","_from":"file:agentskillmania-wrangler-daemon-0.2.1.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./core":{"types":"./dist/core/index.d.ts","import":"./dist/core/index.js"},"./package.json":"./package.json"},"scripts":{"dev":"tsx watch src/daemon.ts","test":"vitest run","build":"tsc","test:intg":"vitest run test/integration","test:unit":"vitest run test/unit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"yusangeng","email":"yusangeng@outlook.com"},"_resolved":"/private/var/folders/dc/61lk2kgn1697rt0gd1s5jwf80000gn/T/efaa17379d7038f8baf9774d0a68ef49/agentskillmania-wrangler-daemon-0.2.1.tgz","_integrity":"sha512-59iSngxoyPtWXpiA4tt39xsDBqMaLipBlD/0d5vXDWMsoo5tffp2cmoJOZfu1+iZ6yqTSgAQgqjaocOOQJUaZQ==","repository":{"url":"git+https://github.com/agentskillmania/wrangler.git","type":"git","directory":"packages/wrangler-daemon"},"_npmVersion":"11.6.1","description":"[English Documentation](./README.md)","directories":{},"_nodeVersion":"22.15.0","dependencies":{"dotenv":"^16.4.0","fastify":"^5.3.0","js-yaml":"^4.1.1","@agentskillmania/colts":"^0.4.0","@agentskillmania/wrangler":"0.2.0","@agentskillmania/llm-client":"^0.4.0","@agentskillmania/settings-yaml":"^0.4.0","@agentskillmania/wrangler-devtool":"0.2.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","vitest":"^3.1.0","typescript":"^5.0.0","@types/node":"^20.0.0","@types/js-yaml":"^4.0.9","typescript-eslint":"^8.58.0","@vitest/coverage-v8":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/wrangler-daemon_0.2.1_1786614523527_0.25542560630154165","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"_id":"@agentskillmania/wrangler-daemon@0.3.0","bin":{"wrangler-daemon":"dist/cli/index.js"},"dist":{"shasum":"15df20830ea582b03a0318b0e9c5b48dbfd2f8ff","tarball":"https://registry.npmjs.org/@agentskillmania/wrangler-daemon/-/wrangler-daemon-0.3.0.tgz","fileCount":120,"integrity":"sha512-72onUJ/+1miwt+OYfe8Bal7YmUT3+RtLvAaEd/PiET1+GxejubEG+ZLK+71bxwBR+exLlqKfHRcPh5oXdPXMiA==","signatures":[{"sig":"MEUCIGYG54h7FW0erADiq5VAvQ7eMjguUBrNYi9uNN9/GoZzAiEAz/ZkZaNequr0wm+lXzIbkzgCzMwrq0um+vWiV6LLiJM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCmMn4ZMVxwPOnqGKNMp+IYSDEtJ373UiPS38KHHxas6QIhAI5nzled0kXPd9cdnqseydvsDh4NFfUQFKjUM5VShWOM"}],"unpackedSize":564798},"main":"dist/index.js","name":"@agentskillmania/wrangler-daemon","type":"module","_from":"file:agentskillmania-wrangler-daemon-0.3.0.tgz","types":"dist/index.d.ts","author":{"name":"yusangeng","email":"yusangeng@outlook.com"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./core":{"types":"./dist/core/index.d.ts","import":"./dist/core/index.js"},"./package.json":"./package.json"},"license":"MIT","scripts":{"dev":"tsx watch src/daemon.ts","test":"vitest run","build":"rm -rf dist *.tsbuildinfo && tsc","test:intg":"vitest run test/integration","test:unit":"vitest run test/unit","test:watch":"vitest run --watch","test:coverage":"vitest run --coverage"},"version":"0.3.0","_npmUser":{"name":"yusangeng","email":"yusangeng@outlook.com"},"_resolved":"/private/var/folders/dc/61lk2kgn1697rt0gd1s5jwf80000gn/T/f9bea77eff3296e7bbd8a2541880c55f/agentskillmania-wrangler-daemon-0.3.0.tgz","_integrity":"sha512-72onUJ/+1miwt+OYfe8Bal7YmUT3+RtLvAaEd/PiET1+GxejubEG+ZLK+71bxwBR+exLlqKfHRcPh5oXdPXMiA==","repository":{"url":"https://gitee.com/agentskillmania/wrangler.git","type":"git","directory":"packages/wrangler-daemon"},"_npmVersion":"10.9.8","description":"[English Documentation](./README.md)","directories":{},"maintainers":[{"name":"yusangeng","email":"yusangeng@outlook.com"}],"_nodeVersion":"22.23.2","dependencies":{"dotenv":"^16.4.0","fastify":"^5.3.0","js-yaml":"^4.1.1","@agentskillmania/sandbox":"^1.3.1","@agentskillmania/wrangler":"0.3.0","@agentskillmania/settings-yaml":"^0.5.0","@agentskillmania/wrangler-devtool":"0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","vitest":"^3.1.0","typescript":"^5.0.0","@types/node":"^20.0.0","@types/js-yaml":"^4.0.9","typescript-eslint":"^8.58.0","@vitest/coverage-v8":"^3.0.0","@agentskillmania/colts":"^0.5.0","@agentskillmania/llm-client":"^0.5.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wrangler-daemon_0.3.0_1790060566758_0.8002378793330207"}}},"time":{"created":"2026-08-13T09:14:54.957Z","modified":"2026-09-22T07:02:47.095Z","0.2.0":"2026-08-13T09:14:55.257Z","0.2.1":"2026-08-13T09:48:43.664Z","0.3.0":"2026-09-22T07:02:46.882Z"},"author":{"name":"yusangeng","email":"yusangeng@outlook.com"},"license":"MIT","repository":{"url":"https://gitee.com/agentskillmania/wrangler.git","type":"git","directory":"packages/wrangler-daemon"},"description":"[English Documentation](./README.md)","maintainers":[{"name":"yusangeng","email":"yusangeng@outlook.com"}],"readme":"# @agentskillmania/wrangler-daemon\n\n[English Documentation](./README.md)\n\nagentskillmania 技术栈的 HTTP 服务 + Playground 界面。用会话化的 HTTP API、SSE 流式传输和内置 Web UI 包装 [`@agentskillmania/wrangler`](../wrangler) 的 `AgentHarness`，支持与 Agent 和团队对话。\n\n## 它能做什么\n\n- **Agent 对话** —— `POST /api/agents/:name/chat` 根据 `AGENT.md` 定义启动新会话。本轮在常驻 events 流（`GET /api/chat/:id/events`）上观察——token、思考、工具调用、技能、子代理委托、投递——直到 `done`。\n- **团队对话** —— `POST /api/crews/:id/chat` 根据团队目录（`CREW.md` + `agents/*.md`）启动会话。主 Agent 成为 Runner，其余 Agent 成为可通过 `delegate` 工具调用的子代理。团队会话打上 `crewId` 标记以便正确恢复。\n- **会话恢复** —— `POST /api/chat/:sessionId` 继续已有会话。Daemon 通过 `meta.runnerConfig.crewId` 检测团队会话并自动重载团队配置以重建子代理。\n- **资源 CRUD** —— Agent、技能、团队存储在磁盘 `~/.agentskillmania/skill-studio/{agents,skills,crews}/` 下，通过 REST 端点管理。\n- **Playground** —— Preact 单页应用，三列聊天布局、配置面板、座舱事件日志、Agent 状态检查器、文件浏览器。团队对话有独立的 `#crew-chat` 路由，实时渲染子代理事件（token/思考/工具）。\n- **Devtool 端点** —— 项目脚手架（`init --type agent|crew|skill`）、结构化文件变更、评估套件运行器。\n\n## 快速开始\n\n```bash\n# 构建所有包（在 wrangler 仓库根目录运行）\npnpm install\npnpm run build\n\n# 前台启动 daemon\nnode packages/wrangler-daemon/dist/daemon.js\n\n# 或通过 CLI\nnpx wrangler-daemon start    # 后台运行，PID 写入 ~/.agentskillmania/skill-studio/daemon.pid\nwrangler-daemon status\nwrangler-daemon stop\n```\n\nDaemon 默认监听 `localhost:3100`。浏览器打开 `http://localhost:3100/` 进入 Playground。\n\n## 配置\n\nDaemon 启动时读取 `~/.agentskillmania/skill-studio/config.yaml`：\n\n```yaml\nllm:\n  providers:\n    - name: openai\n      apiKey: your-key\n      baseUrl: https://open.bigmodel.cn/api/coding/paas/v4\n      models:\n        - modelId: glm-5.1\nserver:\n  port: 3100\n  host: localhost\n```\n\n资源与配置同目录：\n\n```\n~/.agentskillmania/skill-studio/\n├── config.yaml     # LLM + 服务配置\n├── agents/         # <id>/AGENT.md\n├── skills/         # <id>/SKILL.md\n├── crews/          # <id>/CREW.md + <id>/agents/*.md\n└── sessions/       # <workspaceHash>/<sessionId>/{meta.yaml, state.json, entries.jsonl}\n```\n\n## HTTP API\n\n### 对话\n\n会话通过**常驻 events 流**观察；发消息返回 **ack**，帧从流上到达（0.3.0 协议，迁移说明见下）。\n\n| 方法   | 路径                                    | 用途                                                                              |\n| ------ | --------------------------------------- | --------------------------------------------------------------------------------- |\n| `POST` | `/api/agents/:name/chat`                | 启动新的 Agent 对话                                                               |\n| `POST` | `/api/crews/:id/chat`                   | 启动新的团队对话                                                                  |\n| `POST` | `/api/chat/:sessionId`                  | 向既有会话发消息 → **JSON ack**                                                   |\n| `GET`  | `/api/chat/:sessionId/events?lastSeq=N` | **常驻 SSE 流**（帧携带 `seq`）                                                   |\n| `POST` | `/api/chat/:sessionId/stop`             | 中止当前运行                                                                      |\n| `POST` | `/api/chat/:sessionId/respond`          | 响应 `ask_human` 提示                                                             |\n| `POST` | `/api/chat/:sessionId/truncate`         | 按轮截断（`{ \"keepTurns\": N }`）——编辑重发/重新生成/回退/Fork 共用                |\n| `GET`  | `/api/chat/:sessionId/messages`         | 已持久化的消息历史（notebook 目录会话用 `?sessionDir=`）                          |\n| `GET`  | `/api/chat/commands`                    | 预定义的斜杠命令（供 UI 使用）                                                    |\n| `GET`  | `/api/env`                              | 宿主自省（版本、app 目录、agents/skills/crews/sessions 目录、pid 路径——不含凭据） |\n\n新会话请求体（`/api/agents/:name/chat` 和 `/api/crews/:id/chat`）：\n\n```jsonc\n{\n  \"message\": \"工作区里有哪些文件？\",\n  \"workspacePath\": \"/abs/path/to/project\",\n  \"sessionId\": \"可选，客户端指定 ID\",\n  \"thinkingEnabled\": false,\n  \"model\": \"glm-4\", // 可选，按请求覆盖\n  \"subAgents\": [\n    // 可选：内联子 agent（无需建 crew 目录）\n    { \"name\": \"researcher\", \"instructions\": \"做调研\" },\n  ],\n  \"config\": {\n    // 可选的 Runner 配置（结构化配置组）\n    \"skills\": { \"dirs\": [\"./skills\"] },\n    \"tools\": {\n      \"mcpConfigPaths\": [\"./mcp.json\"],\n      \"builtinFilter\": { \"shell\": true, \"file_read\": true },\n    },\n    \"sandbox\": true, // 或 { \"enabled\": true, \"timeout\": 600000, ... }\n    \"thinking\": { \"enabled\": false },\n    \"session\": { \"enabled\": true },\n    \"todolist\": { \"enabled\": true },\n    \"specPlan\": { \"enabled\": true },\n    \"commands\": { \"enabled\": true },\n    \"a2ui\": { \"enabled\": false },\n    \"limits\": { \"maxSteps\": 500, \"requestTimeout\": 1800000 },\n    \"search\": { \"provider\": \"sogou\" },\n    \"compression\": { \"enabled\": true, \"strategy\": \"summarize\", \"threshold\": 120 },\n  },\n}\n```\n\n#### 发送与事件流配合\n\n```js\n// 1) 先挂常驻流（重连时带上你见过的最大 seq）。\nconst events = await fetch(`/api/chat/${sid}/events?lastSeq=${lastSeq}`);\n// 帧的 data 携带 { seq, ...事件字段 }\n\n// 2) 发消息——返回你要等待的那一轮。\nconst ack = await fetch(`/api/chat/${sid}`, {\n  method: 'POST',\n  body: JSON.stringify({ message }),\n}).then((r) => r.json()); // { ok, sessionId, turnSeq }\n\n// 3) 回答在 events 流上；data.turnSeq === ack.turnSeq 的那条 done 帧即本轮完结。\n```\n\n- 每帧的 `data.seq` 会话内单调：`seq <= lastSeq` 丢弃（去重）、`> lastSeq` 应用（补洞）——断线重连不丢帧不重帧。\n- 重放段结束后流上发一条 `history-end` 分界帧 `{ firstSeq, lastSeq }`：`lastSeq` 倒退=会话被驱逐重建（seq 空间重启）；`firstSeq` 跳变=最旧的帧被裁掉。\n- 挂着流时会话被驱逐 → 收到 `session-evicted` 后流关闭，需连新会话。\n- **ack 之后的错误**（LLM/工具失败）以 `error` 帧到达流上，不在 POST 响应里。\n- `POST /api/chat/:id` 加 `?stream=1` 保持旧「发消息即流」形状（响应头 `Deprecation: true`），后续 minor 移除。\n\n常驻流上的事件：`session-start`、`token`、`thinking`、`tool-start`、`tool-end`、`skill-start`、`skill-end`、`subagent-start`、`subagent-token`、`subagent-thinking`、`subagent-tool-start`、`subagent-tool-end`、`subagent-end`、`step-start`、`step-end`、`phase-change`、`llm-request`、`llm-response`、`compressing`、`compressed`、`waiting-human`、`human-input`、`human-input-resolved`、`delivery`、`session-title`、`session-cleared`、`history-end`、`session-evicted`、`error`、`done`。\n\n#### 委派是异步的\n\n会话配了子 agent（crew，或内联 `subAgents`）时，`delegate` 工具**受理即返回**回执（`{ status: \"accepted\", subtaskId, agent, task, message }`）而非结果。子 agent 在后台跑；完成后 daemon 把投递写进会话邮箱并发 `delivery` 帧，随后由消费轮把结果喂回主 agent。等 `delivery` 帧（或下一条 `done`），不要等工具结果。\n\n### 会话\n\n| 方法     | 路径                     | 用途                                    |\n| -------- | ------------------------ | --------------------------------------- |\n| `GET`    | `/api/sessions`          | 列出会话（可选 `?workspacePath=` 过滤） |\n| `GET`    | `/api/sessions/:id`      | 会话元数据                              |\n| `DELETE` | `/api/sessions/:id`      | 删除会话（停止活动运行 + 移除磁盘文件） |\n| `POST`   | `/api/sessions/:id/fork` | 复制会话                                |\n\n### Agent\n\n| 方法                        | 路径                   | 用途                                   |\n| --------------------------- | ---------------------- | -------------------------------------- |\n| `GET`                       | `/api/agents`          | 列出 Agent                             |\n| `GET`                       | `/api/agents/:id`      | Agent 详情（解析后的 AGENT.md）        |\n| `POST`                      | `/api/agents`          | 创建 Agent                             |\n| `DELETE`                    | `/api/agents/:id`      | 删除 Agent                             |\n| `GET`/`PUT`/`POST`/`DELETE` | `/api/agents/:id/file` | 在 Agent 目录内读取/写入/创建/删除文件 |\n\n### 团队\n\n| 方法                        | 路径                  | 用途                                      |\n| --------------------------- | --------------------- | ----------------------------------------- |\n| `GET`                       | `/api/crews`          | 列出团队                                  |\n| `GET`                       | `/api/crews/:id`      | 团队详情（解析后的 CREW.md + Agent 列表） |\n| `POST`                      | `/api/crews`          | 创建团队                                  |\n| `DELETE`                    | `/api/crews/:id`      | 删除团队                                  |\n| `GET`/`PUT`/`POST`/`DELETE` | `/api/crews/:id/file` | 团队目录内的文件操作                      |\n\n### 技能\n\n结构与 Agent 相同：`/api/skills`、`/api/skills/:id`、`/api/skills/:id/file`。\n\n### 工作区文件（按会话）\n\n| 方法  | 路径                                  | 用途               |\n| ----- | ------------------------------------- | ------------------ |\n| `GET` | `/api/files/:sessionId/tree`          | 会话工作区的文件树 |\n| `GET` | `/api/files/:sessionId/content?path=` | 读取文件           |\n| `PUT` | `/api/files/:sessionId/content`       | 写入文件           |\n\n### Agent 状态（座舱 SSE）\n\n| 方法  | 路径                          | 用途                           |\n| ----- | ----------------------------- | ------------------------------ |\n| `GET` | `/api/agent/:sessionId/state` | Agent 诊断 + 事件日志的 SSE 流 |\n\n### Spec 和 Plan\n\n| 方法         | 路径                                            | 用途           |\n| ------------ | ----------------------------------------------- | -------------- |\n| `GET`/`POST` | `/api/specs`                                    | 列出/创建 Spec |\n| `GET`/`PUT`  | `/api/specs/:name/:version`                     | 读取/更新 Spec |\n| `POST`       | `/api/specs/:name/:version/status`              | 更新 Spec 状态 |\n| `GET`/`POST` | `/api/plans`                                    | 列出/创建 Plan |\n| `GET`/`PUT`  | `/api/plans/:name/:specVersion/:version`        | 读取/更新 Plan |\n| `POST`       | `/api/plans/:name/:specVersion/:version/status` | 更新 Plan 状态 |\n\n### 模型\n\n| 方法  | 路径                            | 用途                                           |\n| ----- | ------------------------------- | ---------------------------------------------- |\n| `GET` | `/api/models/:modelId/metadata` | 模型元数据（上下文窗口、最大 token、推理能力） |\n\n### Devtool\n\n| 方法   | 路径                         | 用途                                 |\n| ------ | ---------------------------- | ------------------------------------ |\n| `POST` | `/api/devtool/project/init`  | 创建项目脚手架（`type: agent         | crew | skill`） |\n| `POST` | `/api/devtool/template`      | 渲染模板（agent/skill/crew/session） |\n| `POST` | `/api/devtool/changes/apply` | 应用结构化文件变更                   |\n| `POST` | `/api/devtool/eval/run`      | 运行评估套件                         |\n\n### 配置与健康检查\n\n| 方法        | 路径              | 用途                      |\n| ----------- | ----------------- | ------------------------- |\n| `GET`/`PUT` | `/api/config`     | 读取/更新 Daemon 配置     |\n| `GET`/`PUT` | `/api/config/raw` | 读取/写入原始 config.yaml |\n| `GET`       | `/api/health`     | 健康检查                  |\n| `GET`       | `/api/launcher`   | 工作区启动器数据          |\n\n## Playground 界面\n\nDaemon 从 `/` 提供 Preact 单页应用。页面：\n\n- **Chat**（`#chat`）—— Agent 对话，含 Runner 配置、模型选择器、AskHuman 桥接。\n- **Crew Chat**（`#crew-chat`）—— 团队对话，镜像 Agent 布局，子代理事件（token/思考/工具）内联渲染。子代理 token 按代理名命名空间化，避免多个并发工作体互相干扰。\n- **Agents / Skills / Crews** —— CRUD 页面，含内联文件编辑器。\n- **Sessions** —— 列出、复制、删除。\n- **State** —— 实时 Agent 状态检查器（座舱 SSE）。\n- **Files** —— 工作区文件浏览器 + 编辑器。\n- **Specs / Plans** —— Spec/Plan 管理。\n- **Config** —— Daemon 配置编辑器。\n\n## 架构\n\n```\nHTTP 请求\n  → Fastify 路由（routes/*.ts）\n    → ResourceManager（从磁盘加载 AGENT.md / CREW.md）\n    → AgentSession.create / .resume（包装 AgentHarness）\n      → AgentHarness.create({ llm, skills, delegation, crewId, ... })\n        → colts AgentRunner（ReAct 循环，EventEmitter）\n    → SSE 流（AgentSession.handleMessage → reply.raw）\n```\n\nDaemon 跨重启无状态：会话持久化在磁盘上（`meta.yaml` + `state.json` + `entries.jsonl`），内存中的 `activeSessions` 映射在重启后首次恢复时按需重建。\n\n## 依赖\n\n- [`@agentskillmania/wrangler`](../wrangler) —— AgentHarness、CrewLoader、AgentLoader、SessionStore\n- [`@agentskillmania/wrangler-devtool`](../wrangler-devtool) —— 脚手架、文件变更、评估框架、内置技能\n- [`@agentskillmania/colts`](https://github.com/agentskillmania/colts) —— ReAct Agent 框架\n- [`fastify`](https://fastify.dev) —— HTTP 服务\n\n## License\n\nMIT\n","readmeFilename":"README.zh_CN.md"}