skyloom 1.13.6 → 1.13.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +36 -36
- package/README.md +220 -159
- package/config/providers.yaml +39 -39
- package/config/skills/api_integrator/SKILL.md +15 -15
- package/config/skills/arch_designer/SKILL.md +13 -13
- package/config/skills/ci_cd_manager/SKILL.md +14 -14
- package/config/skills/code_analysis/SKILL.md +13 -13
- package/config/skills/code_generator/SKILL.md +12 -12
- package/config/skills/code_reviewer/SKILL.md +13 -13
- package/config/skills/content_writer/SKILL.md +14 -14
- package/config/skills/data_transformer/SKILL.md +15 -15
- package/config/skills/document_analysis/SKILL.md +13 -13
- package/config/skills/emotional_companion/SKILL.md +15 -15
- package/config/skills/performance_checker/SKILL.md +14 -14
- package/config/skills/security_auditor/SKILL.md +14 -14
- package/config/skills/self_evolve/SKILL.md +13 -13
- package/config/skills/sys_operator/SKILL.md +15 -15
- package/config/skills/task_planner/SKILL.md +14 -14
- package/config/skills/web_research/SKILL.md +14 -14
- package/config/skills/workflow_designer/SKILL.md +13 -13
- package/dist/agents/dew.js +52 -52
- package/dist/agents/fair.js +84 -84
- package/dist/agents/fog.js +30 -30
- package/dist/agents/frost.js +32 -32
- package/dist/agents/rain.js +32 -32
- package/dist/agents/snow.js +68 -68
- package/dist/cli/commands_md.d.ts +41 -0
- package/dist/cli/commands_md.d.ts.map +1 -0
- package/dist/cli/commands_md.js +140 -0
- package/dist/cli/commands_md.js.map +1 -0
- package/dist/cli/input_macros.d.ts +28 -0
- package/dist/cli/input_macros.d.ts.map +1 -0
- package/dist/cli/input_macros.js +120 -0
- package/dist/cli/input_macros.js.map +1 -0
- package/dist/cli/loom.d.ts +220 -0
- package/dist/cli/loom.d.ts.map +1 -0
- package/dist/cli/loom.js +1094 -0
- package/dist/cli/loom.js.map +1 -0
- package/dist/cli/loom_chat.d.ts +20 -0
- package/dist/cli/loom_chat.d.ts.map +1 -0
- package/dist/cli/loom_chat.js +685 -0
- package/dist/cli/loom_chat.js.map +1 -0
- package/dist/cli/main.js +310 -14
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +7 -1
- package/dist/cli/tui.js.map +1 -1
- package/dist/core/agent.d.ts +20 -0
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +199 -16
- package/dist/core/agent.js.map +1 -1
- package/dist/core/factory.d.ts.map +1 -1
- package/dist/core/factory.js +34 -2
- package/dist/core/factory.js.map +1 -1
- package/dist/core/file_checkpoint.d.ts +57 -0
- package/dist/core/file_checkpoint.d.ts.map +1 -0
- package/dist/core/file_checkpoint.js +162 -0
- package/dist/core/file_checkpoint.js.map +1 -0
- package/dist/core/hooks.d.ts +43 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +110 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/llm.d.ts.map +1 -1
- package/dist/core/llm.js +15 -9
- package/dist/core/llm.js.map +1 -1
- package/dist/core/longdoc.js +5 -5
- package/dist/core/mcp.d.ts +16 -0
- package/dist/core/mcp.d.ts.map +1 -1
- package/dist/core/mcp.js +55 -0
- package/dist/core/mcp.js.map +1 -1
- package/dist/core/model_config.d.ts +40 -0
- package/dist/core/model_config.d.ts.map +1 -0
- package/dist/core/model_config.js +191 -0
- package/dist/core/model_config.js.map +1 -0
- package/dist/core/skill.d.ts +7 -0
- package/dist/core/skill.d.ts.map +1 -1
- package/dist/core/skill.js +47 -0
- package/dist/core/skill.js.map +1 -1
- package/dist/core/skymd.d.ts +39 -0
- package/dist/core/skymd.d.ts.map +1 -0
- package/dist/core/skymd.js +177 -0
- package/dist/core/skymd.js.map +1 -0
- package/dist/core/tool.d.ts +12 -0
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +30 -0
- package/dist/core/tool.js.map +1 -1
- package/dist/core/verify.d.ts +27 -0
- package/dist/core/verify.d.ts.map +1 -0
- package/dist/core/verify.js +62 -0
- package/dist/core/verify.js.map +1 -0
- package/dist/skills/loader.d.ts +22 -2
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +45 -15
- package/dist/skills/loader.js.map +1 -1
- package/dist/tools/builtin.d.ts.map +1 -1
- package/dist/tools/builtin.js +13 -3
- package/dist/tools/builtin.js.map +1 -1
- package/dist/tools/model_tool.d.ts +11 -0
- package/dist/tools/model_tool.d.ts.map +1 -0
- package/dist/tools/model_tool.js +71 -0
- package/dist/tools/model_tool.js.map +1 -0
- package/dist/tools/todo.d.ts +30 -0
- package/dist/tools/todo.d.ts.map +1 -0
- package/dist/tools/todo.js +78 -0
- package/dist/tools/todo.js.map +1 -0
- package/docs/AESTHETIC_DESIGN.md +152 -144
- package/docs/OPTIMIZATION_PLAN.md +178 -178
- package/package.json +68 -68
- package/scripts/install.js +48 -48
- package/scripts/link.js +10 -10
- package/setup.bat +79 -79
- package/skill-test-ty2fOA/test.md +10 -10
- package/src/agents/dew.ts +70 -70
- package/src/agents/fair.ts +102 -102
- package/src/agents/fog.ts +48 -48
- package/src/agents/frost.ts +50 -50
- package/src/agents/rain.ts +50 -50
- package/src/agents/snow.ts +239 -239
- package/src/cli/commands_md.ts +112 -0
- package/src/cli/input_macros.ts +83 -0
- package/src/cli/loom.ts +982 -0
- package/src/cli/loom_chat.ts +598 -0
- package/src/cli/main.ts +255 -9
- package/src/cli/mode.ts +58 -58
- package/src/cli/tui.ts +228 -222
- package/src/core/agent/guard.ts +134 -134
- package/src/core/agent/task.ts +100 -100
- package/src/core/agent.ts +195 -16
- package/src/core/arbitrate.ts +162 -162
- package/src/core/catalog.ts +178 -178
- package/src/core/checkpoint.ts +94 -94
- package/src/core/estimate.ts +104 -104
- package/src/core/evolve.ts +191 -191
- package/src/core/factory.ts +31 -2
- package/src/core/file_checkpoint.ts +136 -0
- package/src/core/filter.ts +103 -103
- package/src/core/graph.ts +156 -156
- package/src/core/hooks.ts +126 -0
- package/src/core/icons.ts +53 -53
- package/src/core/index.ts +37 -37
- package/src/core/learn.ts +146 -146
- package/src/core/llm.ts +15 -9
- package/src/core/longdoc.ts +155 -155
- package/src/core/mcp.ts +48 -0
- package/src/core/mcp_server.ts +176 -176
- package/src/core/model_config.ts +157 -0
- package/src/core/profile.ts +255 -255
- package/src/core/router.ts +124 -124
- package/src/core/sandbox.ts +142 -142
- package/src/core/security.ts +243 -243
- package/src/core/skill.ts +42 -0
- package/src/core/skymd.ts +143 -0
- package/src/core/theme.ts +65 -65
- package/src/core/tool.ts +30 -0
- package/src/core/tool_router.ts +193 -193
- package/src/core/vector.ts +152 -152
- package/src/core/verify.ts +71 -0
- package/src/core/workspace.ts +150 -150
- package/src/plugins/loader.ts +66 -66
- package/src/skills/loader.ts +45 -16
- package/src/sql.js.d.ts +29 -29
- package/src/tools/builtin.ts +13 -3
- package/src/tools/computer.ts +269 -269
- package/src/tools/delegate.ts +49 -49
- package/src/tools/model_tool.ts +74 -0
- package/src/tools/todo.ts +76 -0
- package/src/web/tts.ts +93 -93
- package/tests/agent.test.ts +159 -159
- package/tests/agent_helpers.test.ts +48 -48
- package/tests/bus.test.ts +121 -121
- package/tests/catalog.test.ts +86 -86
- package/tests/checkpoint_commands.test.ts +124 -0
- package/tests/claude_compat.test.ts +110 -0
- package/tests/config.test.ts +41 -41
- package/tests/guard.test.ts +75 -75
- package/tests/icons.test.ts +45 -45
- package/tests/loom.test.ts +248 -0
- package/tests/memory.test.ts +170 -170
- package/tests/model_config.test.ts +109 -0
- package/tests/router.test.ts +86 -86
- package/tests/schemas.test.ts +51 -51
- package/tests/semantic.test.ts +83 -83
- package/tests/setup.ts +10 -10
- package/tests/skill.test.ts +172 -172
- package/tests/skymd.test.ts +146 -0
- package/tests/task.test.ts +60 -60
- package/tests/todo_toolstats.test.ts +94 -0
- package/tests/tool.test.ts +108 -108
- package/tests/tool_router.test.ts +71 -71
- package/tests/tui.test.ts +67 -67
- package/vitest.config.ts +17 -17
- package/=12 +0 -0
- package/=8 +0 -0
|
@@ -1,178 +1,178 @@
|
|
|
1
|
-
# 天空织机 · Skyloom — 顶级 Agent 框架优化计划
|
|
2
|
-
|
|
3
|
-
> 目标:把 Skyloom 从「功能完整的多 Agent 终端」打磨成 **架构清晰、体验顶级、辨识度强** 的开源 Agent 框架。
|
|
4
|
-
> 参照系:[opencode](https://github.com/sst/opencode)(架构)、[Claude Code](https://docs.claude.com)(交互范式)、Skyloom Python 原版(功能对等)。
|
|
5
|
-
>
|
|
6
|
-
> 制定日期:2026-06-08 · 当前版本:v1.12.0 · 类型检查:✅ 通过
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## 0. 现状诊断(Analysis)
|
|
11
|
-
|
|
12
|
-
### 0.1 项目规模
|
|
13
|
-
|
|
14
|
-
| 层 | 文件 | 关键模块 | LOC |
|
|
15
|
-
|----|------|----------|-----|
|
|
16
|
-
| CLI | `src/cli/` | main, tui, mode | ~700 |
|
|
17
|
-
| Core | `src/core/` | agent(1549), memory(1171), mcp(953), llm(804), factory(627) … 38 个模块 | ~11000 |
|
|
18
|
-
| Agents | `src/agents/` | fog/rain/frost/snow/dew/fair | ~500 |
|
|
19
|
-
| Tools | `src/tools/` | builtin, computer, delegate | ~700 |
|
|
20
|
-
| Web | `src/web/` | server(水墨气象台), tts | ~720 |
|
|
21
|
-
| Skills | `config/skills/` | 17 个 SKILL.md | — |
|
|
22
|
-
| Tests | `tests/` | 16 套件 · 154 用例(catalog/memory/task/agent_helpers/config) | — |
|
|
23
|
-
|
|
24
|
-
### 0.2 已经做得好的(保留 & 强化)
|
|
25
|
-
|
|
26
|
-
- **美学辨识度强**:水墨气象台 Web UI(宣纸纹理、六矿物色、粒子气象、印章汉字)——这是项目的灵魂,是优化的审美基线,不动它的方向,只做工程化与一致性提升。
|
|
27
|
-
- **功能广度大**:三层记忆、事件总线、DAG 编排、技能系统、向量检索、知识图谱、自进化、安全分级、MCP 双向桥、跨平台电脑操作。
|
|
28
|
-
- **路由分级**:direct / single / orchestrate 三级路由 + 9 种 Pipeline 模板,省 LLM 调用。
|
|
29
|
-
|
|
30
|
-
### 0.3 必须修复的问题(Critical)
|
|
31
|
-
|
|
32
|
-
| # | 问题 | 位置 | 影响 |
|
|
33
|
-
|---|------|------|------|
|
|
34
|
-
| C1 | ~~虚构模型~~ **已更正**:`deepseek-v4-flash`/`v4-pro` 经 `/v1/models` 实测**是真实可调模型**(`deepseek-chat` 即其别名)。早先的"虚构"判断错误——会话初的报错来自 Claude Code **宿主**的子 agent 模型注册表,与 Skyloom 无关。已恢复入目录。 | — | — |
|
|
35
|
-
| C2 | **模型数据三处重复且漂移**:`config/models.yaml`、`cli/main.ts` 向导、`README` 表格各写一份 | 多处 | 维护噩梦、数据不一致(catalog 已统一✅) |
|
|
36
|
-
| C3 | **流式已实现却未接线**:`agent.chatStream()` 存在,但 CLI `chat()` 和 Web 都用阻塞式 `chat()` + 假打字机 | `cli/main.ts:314`、`web/server.ts:101` | 体验远低于 opencode/Claude Code;首字延迟高 |
|
|
37
|
-
| C4 | **README 模型表含虚构条目**(`deepseek-v4-*`);测试数随增量需同步 | `README.md` | 可信度 |
|
|
38
|
-
| C5 | **`agent.ts` 1549 行巨石**:LLM 循环、工具执行、记忆、防循环启发式、委派全混在一个类 | `core/agent.ts` | 难测试、难维护 |
|
|
39
|
-
|
|
40
|
-
#### 🔴 集成测试发现并已修复的严重 Bug(用真实 DeepSeek key 验证)
|
|
41
|
-
|
|
42
|
-
| # | 问题 | 根因 | 修复 |
|
|
43
|
-
|---|------|------|------|
|
|
44
|
-
| **B1** | **首条消息必崩**:全新会话发第一条消息 → `Cannot read properties of undefined (reading 'content')`,且首轮请求**根本不含用户消息** | `Memory.addMessage` 把 push 放进**异步 mutex 回调**(fire-and-forget),而 `chatImpl`/`chatStreamImpl` 同一 tick 同步读 `getMessages()` → 读不到 | push 改为**同步**,仅保留改写数组的 prune 在锁内([memory.ts](../src/core/memory.ts))+ `messagesWithRecall` 防御性 guard + 回归测试 |
|
|
45
|
-
| **B2** | **用户选的模型被忽略**:`~/.skyloom/config.yaml` 设了 `default_model: deepseek-v4-flash`,却仍走 `gpt-4o`(无 key 必败) | `mergeConfigs` 丢弃了 `llm`/`default_model`/`default_provider` 等顶层键;且 `getModel` 读 camelCase `defaultModel` 而 YAML 是 snake_case `default_model` | `mergeConfigs` 保留全部顶层键并深合并 `llm`;`getModel` 按 `default_model → llm.default_model → …` 解析;`default.yaml` 移除每 Agent 硬编码 `gpt-4o`,统一由 `default_model` 驱动 |
|
|
46
|
-
| **B3** | **memory 配置 snake/camel 不匹配**(B2 修复后暴露):Agent 构造崩在 `expandUserPath(undefined)` | `default.yaml` 用 `db_path`/`short_term_limit`,`Memory` 期望 `dbPath`/`shortTermLimit`;旧代码靠"配置被丢弃→走 fallback"侥幸不崩 | `BaseAgent` 构造时归一化 memory 配置,两种命名都接受 |
|
|
47
|
-
| **B4** | ~~`deepseek-v4-*` 虚构~~ **判断错误**:经 `/v1/models` 实测**真实可调**,且是用户日常默认模型 | 早先误判;会话初的报错来自 Claude Code **宿主**的子 agent 模型注册表 | 已恢复入目录 + 反转测试断言 |
|
|
48
|
-
|
|
49
|
-
> 这些 Bug 仅靠类型检查/单测无法发现——必须真实 API 集成验证。修复后 `fog.chat()` 返回「蓝色」、`chatStream` 实测 15–18 个 token 增量。
|
|
50
|
-
|
|
51
|
-
### 0.4 架构差距(对标 opencode)
|
|
52
|
-
|
|
53
|
-
| 维度 | opencode | Skyloom 现状 | 差距 |
|
|
54
|
-
|------|----------|-------------|------|
|
|
55
|
-
| Provider/Model | 强类型 Catalog(capabilities/cost/limit/status/variants) | 字符串前缀匹配(`isAnthropicModel`…) | **大** |
|
|
56
|
-
| Session | 持久化实体 + 事件日志 + 消息投影 | 内存对象,落 SQLite 但无事件溯源 | 中 |
|
|
57
|
-
| 上下文压缩 | 按 token 预算自动 compaction + checkpoint | 手动 `/compact` | 中 |
|
|
58
|
-
| 工具系统 | codec 校验输入输出 + 工具内 permission.assert | 注册表 + 全局 security 回调 | 中 |
|
|
59
|
-
| 插件 | 有序 hook 系统(init/provider.update…) | 目录加载器,无 hook 生命周期 | 中 |
|
|
60
|
-
| UI | client/server 分离,真流式 | TUI 仅捕获输入,响应回落到线性滚动 | 中 |
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## 1. 优化原则
|
|
65
|
-
|
|
66
|
-
1. **不破坏美学**:水墨气象台是辨识度核心。所有 UI 改动只增强,不"极简化"。详见 [AESTHETIC_DESIGN.md](./AESTHETIC_DESIGN.md)。
|
|
67
|
-
2. **单一事实源**:每类数据(模型、命令、Agent 元数据、配色)只有一份定义。
|
|
68
|
-
3. **小步可验证**:每个增量保持 `tsc --noEmit` 绿 + 测试通过,再进下一步。
|
|
69
|
-
4. **功能对等优先于重构**:先保证不丢功能,再分层。
|
|
70
|
-
5. **类型安全**:消除无谓 `any`,用 schema 校验外部边界(LLM 响应、配置、工具 IO)。
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## 2. 分阶段路线图
|
|
75
|
-
|
|
76
|
-
### Phase 0 — 止血(Critical Fixes)|~0.5 天 ✅ 已完成
|
|
77
|
-
|
|
78
|
-
- [x] **P0.1 统一模型目录**(修 C2)
|
|
79
|
-
新建 [`src/core/catalog.ts`](../src/core/catalog.ts):单一类型化目录(`ModelInfo`/`ProviderMeta`),从 `config/models.yaml` 读取真实数据。修复了原 `config.ts:loadModelCatalog` 的字段名错配(`context`↔`context_window`)。设置向导现从 catalog 派生。
|
|
80
|
-
⚠️ 更正:曾误删 `deepseek-v4-flash/pro`,经 DeepSeek `/v1/models` 实测确认其真实可调后**已恢复**(见 C1)。
|
|
81
|
-
- [x] **P0.2 默认模型自检**:`chat()` 启动时用 `validateModel()` 校验当前模型,不在目录则给出可选清单与提示,而非静默 404。
|
|
82
|
-
- [x] **P0.3 README 校正**(修 C4):真实模型表、移除虚构条目、链接到本计划与美学文档。
|
|
83
|
-
- [x] **测试**:新增 [`tests/catalog.test.ts`](../tests/catalog.test.ts) 11 用例(含"不含虚构模型"回归断言)。
|
|
84
|
-
|
|
85
|
-
**验收**:✅ 设置向导列出的每个模型都真实可调;`tsc --noEmit` 绿;9 套件 98 用例全通过。
|
|
86
|
-
|
|
87
|
-
### Phase 1 — Provider/Model Catalog 强化|~1 天
|
|
88
|
-
|
|
89
|
-
对标 opencode `provider-model.md`:
|
|
90
|
-
|
|
91
|
-
- [ ] **P1.1** Catalog schema:`ModelInfo { id, providerID, family, capabilities{tools,input,output}, cost[], limit{context,output}, status }`。
|
|
92
|
-
- [ ] **P1.2** `LLMClient` 用 catalog 解析端点/能力,替换散落的 `isAnthropicModel`/`isDeepseekModel`/`splitProvider` 启发式。
|
|
93
|
-
- [ ] **P1.3** Provider 鉴权统一:env → `~/.skyloom/config.yaml` → 交互向导,三级回退集中到一处。
|
|
94
|
-
- [ ] **P1.4** 上下文窗口与成本从 catalog 取,喂给自动压缩(Phase 4)和成本统计。
|
|
95
|
-
|
|
96
|
-
### Phase 2 — 真流式接线(最高体验收益)|~1 天 ✅ 基本完成
|
|
97
|
-
|
|
98
|
-
- [x] **P2.0 LLM 层真流式**(关键):`streamWithTools` 原本只是包装阻塞 `complete()` 一次性吐出。新增 `callOpenAIStream` —— 对所有 OpenAI 兼容 provider 做真正的 SSE(`stream:true` + `stream_options.include_usage`),逐 token yield content/reasoning、按 index 累积 tool_calls、末帧取 usage 记成本。Anthropic 与流早期失败回落阻塞路径。**实测 DeepSeek 15–18 个增量**。
|
|
99
|
-
- [x] **P2.1 CLI 流式**:`chat()` 改为消费 `agent.chatStream()`(新 `streamResponse()`),逐字渲染真实 token,`reasoning` 淡墨斜体、正文矿物色、工具调用以天气符号脉冲呈现。删除旧的阻塞 `render()`。
|
|
100
|
-
- [x] **P2.2 Web 流式**:`/api/chat` 改 SSE(`text/event-stream`),前端 `fetch` + `ReadableStream` 真流式替换假打字机,工具调用呈现为"气象事件"系统消息。已 curl + 真实 API 验证。
|
|
101
|
-
- [x] **P2.3 中断**:`AbortSignal` 从 CLI 贯穿 `chatStream → streamWithTools → callOpenAIStream → fetch`。Ctrl-C 中断当前 turn 并**保留已产出内容**(轮间检测 abort → `interrupted` 事件 + 落库部分内容),二次 Ctrl-C 强退。实测 DeepSeek:abort 后 ~26ms 内停流(不再跑满整段生成)。
|
|
102
|
-
|
|
103
|
-
### Phase 3 — `agent.ts` 分层(可维护性)|~1.5 天 🔵 进行中(1549 → 1396 行)
|
|
104
|
-
|
|
105
|
-
把巨石拆成职责单一的模块(保持对外 API 不变,re-export 兜底):
|
|
106
|
-
|
|
107
|
-
- [x] `core/agent/task.ts` — 域模型 `Task`/`TaskState`/`TaskResult`/`AgentState`(纯、可测,re-export 验证身份一致)。
|
|
108
|
-
- [x] `agent_helpers.ts` += `parseExtractedFacts`(纯解析器,移出 BaseAgent)。
|
|
109
|
-
- [ ] `core/agent/loop.ts` — LLM 推理循环(`llmLoop` / `chatStreamImpl`,~275 行热路径)
|
|
110
|
-
- [ ] `core/agent/tools.ts` — 工具选择/执行/结果记录
|
|
111
|
-
- [x] `core/agent/guard.ts` — 防循环启发式抽成 `LoopGuard` 类(持有每轮状态,`observe()` 返回 hints/stop 决策,无副作用)。忠实迁移行为;agent 守卫终止测试仍通过。新增 [`tests/guard.test.ts`](../tests/guard.test.ts) 单测各分支(叙述循环/签名循环/失败堆积/搜索风暴)——这些此前**零覆盖**。期间发现并**修复**两处死安全网:all-failed 硬停(`>=8`)的 outcomes 缓冲上限 6→8;search-storm 硬停(`>=12`)改用**每轮累计搜索计数**(不再受 SIG_WINDOW=8 截断)。两个安全网现在如设计般触发,单测覆盖。
|
|
112
|
-
- [ ] `core/agent/delegate.ts` — 跨 Agent 委派与汇总
|
|
113
|
-
- [ ] `core/agent.ts` — 仅保留 `BaseAgent` 编排与公共 API(目标 < 500 行)
|
|
114
|
-
|
|
115
|
-
> ✅ **热路径测试网已就位**:[`tests/agent.test.ts`](../tests/agent.test.ts) 用**脚本化 mock LLM** 特征化了核心循环 —— 简单对话、阻塞 `chat()`、推理流、**工具调用回合**、**防循环 guard 终止**(模型重复同一工具 60 次仍能有界终止)。`loop/tools/guard/delegate` 的拆分现在可以安全进行(每步跑这套网 + 真实 API 抽查)。纯单元(task/helpers)已先抽出。
|
|
116
|
-
|
|
117
|
-
### Phase 4 — Session & 自动上下文管理|~1.5 天
|
|
118
|
-
|
|
119
|
-
对标 opencode `session.md`:
|
|
120
|
-
|
|
121
|
-
- [x] **P4.1 Session 恢复 + 持久化修复**:新增 CLI `/sessions`(编号列表、标记当前)、`/resume <序号|id>`、`/new`。**并修复了一个严重 bug**:`persistDb()`(唯一写盘的代码)**从未被调用** → sql.js 纯内存 → 会话/长期记忆/工作记忆**重启全丢**("启动自动恢复最新会话"形同虚设)。改为所有写经 `dbRun` 触发**防抖落盘** + `close()` 同步保存。新增跨实例持久化回归测试。
|
|
122
|
-
- [x] **P4.2 自动压缩(catalog 感知触发)**:`shouldAutoCompact()`/`contextUsage()` 不再硬编码 128K —— 改为按当前模型在 catalog 里的真实 `context` 窗口判断(留 20% 余量给回复)。修复了小窗口模型(deepseek-reasoner 64K、mixtral 32K)长聊时**先于压缩就溢出**的隐患;状态栏 % 与模型名也正确了。压缩本身(摘要 + 保留近 N 条 + 指令保真)已存在并已接线。后续:结构化 checkpoint + 溢出后重试(对标 opencode)。
|
|
123
|
-
- [ ] **P4.3 上下文快照**:环境信息、日期、工作区、激活技能合成一份"系统上下文",模型可见但与历史分离(轻量版 Context Epoch)。
|
|
124
|
-
|
|
125
|
-
### Phase 5 — 工具与插件健壮性|~1 天
|
|
126
|
-
|
|
127
|
-
- [ ] **P5.1 工具 IO 校验**:工具定义带 input/output schema,非法输入不执行、非法输出不算成功(对标 opencode `tools.md`)。
|
|
128
|
-
- [ ] **P5.2 权限内聚**:危险操作的 `permission.assert` 由工具自身发起,security 模块只评估策略 + 管理审批,统一 `ask/allow/deny` 语义。
|
|
129
|
-
- [ ] **P5.3 插件 hook**:目录加载器升级为有序 hook(`init` / `tool.register` / `provider.update`),插件在自己的 scope 注册,卸载即移除。
|
|
130
|
-
|
|
131
|
-
### Phase 6 — 测试与质量门禁|~1.5 天
|
|
132
|
-
|
|
133
|
-
- [ ] **P6.1** 把覆盖率提到核心全覆盖:仍需 `llm`(mock)、`factory`、`pipelines`、`security` 套件(已建 `catalog`✅ `memory`✅ `task`✅ `agent_helpers`✅ `config`✅ `tui`✅ **`agent`✅(mock LLM)**,共 15 套件 142 用例)。`agent` 套件特征化了 chat/stream/工具回合/防循环 guard,为 `agent.ts` 拆分提供安全网。
|
|
134
|
-
- [ ] **P6.2** CI 加门禁:`type-check` + `lint` + `test` + 覆盖率阈值。
|
|
135
|
-
- [ ] **P6.3** 修正所有 `README`/文档与代码的数字一致性(测试数自动从 `vitest` 输出取)。
|
|
136
|
-
|
|
137
|
-
### Phase 7 — 美学工程化|~1 天(详见 [AESTHETIC_DESIGN.md](./AESTHETIC_DESIGN.md))
|
|
138
|
-
|
|
139
|
-
- [x] **P7.1 设计 token 单一源**:新建 [`src/core/theme.ts`](../src/core/theme.ts)(`PALETTE` + `AGENT_THEMES`:矿物色/汉字/天气符号/诗句/动势)。CLI 已接入;TUI/Web 待接(Web 仍内联 PIGMENTS,P7.3 抽取时统一)。
|
|
140
|
-
- [x] **P7.2 CLI 视觉升级(部分)**:欢迎横幅六灵各显矿物真彩 + 活动灵印章 `▣`;切灵时落朱印 + 诗句;流式正文矿物色、工具调用天气符号。"墨迹晕染"逐字过场待做。
|
|
141
|
-
- [ ] **P7.3 Web 抽出静态资源**:`server.ts` 内联 HTML 拆为 `web/ui/`(html/css/js),加构建步骤,便于演进与缓存。
|
|
142
|
-
- [ ] **P7.4 品牌资产**:SVG logo(印章风)、社交卡片、`docs/` 截图。
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## 3. 里程碑与顺序
|
|
147
|
-
|
|
148
|
-
```
|
|
149
|
-
M1 止血+目录 Phase 0 + 1 → 真实可用、单一事实源
|
|
150
|
-
M2 体验飞跃 Phase 2 + 7.2 → 真流式 + CLI 视觉,最高感知收益
|
|
151
|
-
M3 工程地基 Phase 3 + 6 → 拆巨石 + 测试网,安全重构
|
|
152
|
-
M4 框架深度 Phase 4 + 5 → Session/压缩/工具/插件,对标 opencode
|
|
153
|
-
M5 打磨成品 Phase 7 → 美学工程化 + 品牌资产 + 发布
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
建议执行顺序:**M1 → M2 → M3 → M4 → M5**。M1/M2 立刻提升可信度与体验;M3 在动大手术前先织好测试网。
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## 4. 成功标准(Definition of Done)
|
|
161
|
-
|
|
162
|
-
- 设置向导/文档中**每个模型都真实可调**,模型数据全局一份。
|
|
163
|
-
- CLI 与 Web **真流式**输出,首字延迟显著下降,可中断。
|
|
164
|
-
- `agent.ts` 拆分后**单文件 < 500 行**,核心模块均有单测,CI 绿且有覆盖率门禁。
|
|
165
|
-
- Session 可列举/恢复,超长上下文**自动压缩**不崩。
|
|
166
|
-
- 美学系统单一源驱动 CLI/TUI/Web,品牌资产齐备。
|
|
167
|
-
- README 与实现**零失真**。
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## 5. 风险
|
|
172
|
-
|
|
173
|
-
| 风险 | 缓解 |
|
|
174
|
-
|------|------|
|
|
175
|
-
| 重构 `agent.ts` 引入回归 | Phase 6 测试网先行;逐块拆 + 每步跑测 |
|
|
176
|
-
| 流式与工具执行交错复杂 | 复用已存在的 `chatStreamImpl` 事件模型,只接线不重写 |
|
|
177
|
-
| Catalog 迁移漏模型 | 以 `config/models.yaml` 为真值源迁移,向导/README 派生 |
|
|
178
|
-
| 美学改动破坏现有观感 | 设计 token 抽取为"提取"非"重画",先快照对比 |
|
|
1
|
+
# 天空织机 · Skyloom — 顶级 Agent 框架优化计划
|
|
2
|
+
|
|
3
|
+
> 目标:把 Skyloom 从「功能完整的多 Agent 终端」打磨成 **架构清晰、体验顶级、辨识度强** 的开源 Agent 框架。
|
|
4
|
+
> 参照系:[opencode](https://github.com/sst/opencode)(架构)、[Claude Code](https://docs.claude.com)(交互范式)、Skyloom Python 原版(功能对等)。
|
|
5
|
+
>
|
|
6
|
+
> 制定日期:2026-06-08 · 当前版本:v1.12.0 · 类型检查:✅ 通过
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0. 现状诊断(Analysis)
|
|
11
|
+
|
|
12
|
+
### 0.1 项目规模
|
|
13
|
+
|
|
14
|
+
| 层 | 文件 | 关键模块 | LOC |
|
|
15
|
+
|----|------|----------|-----|
|
|
16
|
+
| CLI | `src/cli/` | main, tui, mode | ~700 |
|
|
17
|
+
| Core | `src/core/` | agent(1549), memory(1171), mcp(953), llm(804), factory(627) … 38 个模块 | ~11000 |
|
|
18
|
+
| Agents | `src/agents/` | fog/rain/frost/snow/dew/fair | ~500 |
|
|
19
|
+
| Tools | `src/tools/` | builtin, computer, delegate | ~700 |
|
|
20
|
+
| Web | `src/web/` | server(水墨气象台), tts | ~720 |
|
|
21
|
+
| Skills | `config/skills/` | 17 个 SKILL.md | — |
|
|
22
|
+
| Tests | `tests/` | 16 套件 · 154 用例(catalog/memory/task/agent_helpers/config) | — |
|
|
23
|
+
|
|
24
|
+
### 0.2 已经做得好的(保留 & 强化)
|
|
25
|
+
|
|
26
|
+
- **美学辨识度强**:水墨气象台 Web UI(宣纸纹理、六矿物色、粒子气象、印章汉字)——这是项目的灵魂,是优化的审美基线,不动它的方向,只做工程化与一致性提升。
|
|
27
|
+
- **功能广度大**:三层记忆、事件总线、DAG 编排、技能系统、向量检索、知识图谱、自进化、安全分级、MCP 双向桥、跨平台电脑操作。
|
|
28
|
+
- **路由分级**:direct / single / orchestrate 三级路由 + 9 种 Pipeline 模板,省 LLM 调用。
|
|
29
|
+
|
|
30
|
+
### 0.3 必须修复的问题(Critical)
|
|
31
|
+
|
|
32
|
+
| # | 问题 | 位置 | 影响 |
|
|
33
|
+
|---|------|------|------|
|
|
34
|
+
| C1 | ~~虚构模型~~ **已更正**:`deepseek-v4-flash`/`v4-pro` 经 `/v1/models` 实测**是真实可调模型**(`deepseek-chat` 即其别名)。早先的"虚构"判断错误——会话初的报错来自 Claude Code **宿主**的子 agent 模型注册表,与 Skyloom 无关。已恢复入目录。 | — | — |
|
|
35
|
+
| C2 | **模型数据三处重复且漂移**:`config/models.yaml`、`cli/main.ts` 向导、`README` 表格各写一份 | 多处 | 维护噩梦、数据不一致(catalog 已统一✅) |
|
|
36
|
+
| C3 | **流式已实现却未接线**:`agent.chatStream()` 存在,但 CLI `chat()` 和 Web 都用阻塞式 `chat()` + 假打字机 | `cli/main.ts:314`、`web/server.ts:101` | 体验远低于 opencode/Claude Code;首字延迟高 |
|
|
37
|
+
| C4 | **README 模型表含虚构条目**(`deepseek-v4-*`);测试数随增量需同步 | `README.md` | 可信度 |
|
|
38
|
+
| C5 | **`agent.ts` 1549 行巨石**:LLM 循环、工具执行、记忆、防循环启发式、委派全混在一个类 | `core/agent.ts` | 难测试、难维护 |
|
|
39
|
+
|
|
40
|
+
#### 🔴 集成测试发现并已修复的严重 Bug(用真实 DeepSeek key 验证)
|
|
41
|
+
|
|
42
|
+
| # | 问题 | 根因 | 修复 |
|
|
43
|
+
|---|------|------|------|
|
|
44
|
+
| **B1** | **首条消息必崩**:全新会话发第一条消息 → `Cannot read properties of undefined (reading 'content')`,且首轮请求**根本不含用户消息** | `Memory.addMessage` 把 push 放进**异步 mutex 回调**(fire-and-forget),而 `chatImpl`/`chatStreamImpl` 同一 tick 同步读 `getMessages()` → 读不到 | push 改为**同步**,仅保留改写数组的 prune 在锁内([memory.ts](../src/core/memory.ts))+ `messagesWithRecall` 防御性 guard + 回归测试 |
|
|
45
|
+
| **B2** | **用户选的模型被忽略**:`~/.skyloom/config.yaml` 设了 `default_model: deepseek-v4-flash`,却仍走 `gpt-4o`(无 key 必败) | `mergeConfigs` 丢弃了 `llm`/`default_model`/`default_provider` 等顶层键;且 `getModel` 读 camelCase `defaultModel` 而 YAML 是 snake_case `default_model` | `mergeConfigs` 保留全部顶层键并深合并 `llm`;`getModel` 按 `default_model → llm.default_model → …` 解析;`default.yaml` 移除每 Agent 硬编码 `gpt-4o`,统一由 `default_model` 驱动 |
|
|
46
|
+
| **B3** | **memory 配置 snake/camel 不匹配**(B2 修复后暴露):Agent 构造崩在 `expandUserPath(undefined)` | `default.yaml` 用 `db_path`/`short_term_limit`,`Memory` 期望 `dbPath`/`shortTermLimit`;旧代码靠"配置被丢弃→走 fallback"侥幸不崩 | `BaseAgent` 构造时归一化 memory 配置,两种命名都接受 |
|
|
47
|
+
| **B4** | ~~`deepseek-v4-*` 虚构~~ **判断错误**:经 `/v1/models` 实测**真实可调**,且是用户日常默认模型 | 早先误判;会话初的报错来自 Claude Code **宿主**的子 agent 模型注册表 | 已恢复入目录 + 反转测试断言 |
|
|
48
|
+
|
|
49
|
+
> 这些 Bug 仅靠类型检查/单测无法发现——必须真实 API 集成验证。修复后 `fog.chat()` 返回「蓝色」、`chatStream` 实测 15–18 个 token 增量。
|
|
50
|
+
|
|
51
|
+
### 0.4 架构差距(对标 opencode)
|
|
52
|
+
|
|
53
|
+
| 维度 | opencode | Skyloom 现状 | 差距 |
|
|
54
|
+
|------|----------|-------------|------|
|
|
55
|
+
| Provider/Model | 强类型 Catalog(capabilities/cost/limit/status/variants) | 字符串前缀匹配(`isAnthropicModel`…) | **大** |
|
|
56
|
+
| Session | 持久化实体 + 事件日志 + 消息投影 | 内存对象,落 SQLite 但无事件溯源 | 中 |
|
|
57
|
+
| 上下文压缩 | 按 token 预算自动 compaction + checkpoint | 手动 `/compact` | 中 |
|
|
58
|
+
| 工具系统 | codec 校验输入输出 + 工具内 permission.assert | 注册表 + 全局 security 回调 | 中 |
|
|
59
|
+
| 插件 | 有序 hook 系统(init/provider.update…) | 目录加载器,无 hook 生命周期 | 中 |
|
|
60
|
+
| UI | client/server 分离,真流式 | TUI 仅捕获输入,响应回落到线性滚动 | 中 |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 1. 优化原则
|
|
65
|
+
|
|
66
|
+
1. **不破坏美学**:水墨气象台是辨识度核心。所有 UI 改动只增强,不"极简化"。详见 [AESTHETIC_DESIGN.md](./AESTHETIC_DESIGN.md)。
|
|
67
|
+
2. **单一事实源**:每类数据(模型、命令、Agent 元数据、配色)只有一份定义。
|
|
68
|
+
3. **小步可验证**:每个增量保持 `tsc --noEmit` 绿 + 测试通过,再进下一步。
|
|
69
|
+
4. **功能对等优先于重构**:先保证不丢功能,再分层。
|
|
70
|
+
5. **类型安全**:消除无谓 `any`,用 schema 校验外部边界(LLM 响应、配置、工具 IO)。
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 2. 分阶段路线图
|
|
75
|
+
|
|
76
|
+
### Phase 0 — 止血(Critical Fixes)|~0.5 天 ✅ 已完成
|
|
77
|
+
|
|
78
|
+
- [x] **P0.1 统一模型目录**(修 C2)
|
|
79
|
+
新建 [`src/core/catalog.ts`](../src/core/catalog.ts):单一类型化目录(`ModelInfo`/`ProviderMeta`),从 `config/models.yaml` 读取真实数据。修复了原 `config.ts:loadModelCatalog` 的字段名错配(`context`↔`context_window`)。设置向导现从 catalog 派生。
|
|
80
|
+
⚠️ 更正:曾误删 `deepseek-v4-flash/pro`,经 DeepSeek `/v1/models` 实测确认其真实可调后**已恢复**(见 C1)。
|
|
81
|
+
- [x] **P0.2 默认模型自检**:`chat()` 启动时用 `validateModel()` 校验当前模型,不在目录则给出可选清单与提示,而非静默 404。
|
|
82
|
+
- [x] **P0.3 README 校正**(修 C4):真实模型表、移除虚构条目、链接到本计划与美学文档。
|
|
83
|
+
- [x] **测试**:新增 [`tests/catalog.test.ts`](../tests/catalog.test.ts) 11 用例(含"不含虚构模型"回归断言)。
|
|
84
|
+
|
|
85
|
+
**验收**:✅ 设置向导列出的每个模型都真实可调;`tsc --noEmit` 绿;9 套件 98 用例全通过。
|
|
86
|
+
|
|
87
|
+
### Phase 1 — Provider/Model Catalog 强化|~1 天
|
|
88
|
+
|
|
89
|
+
对标 opencode `provider-model.md`:
|
|
90
|
+
|
|
91
|
+
- [ ] **P1.1** Catalog schema:`ModelInfo { id, providerID, family, capabilities{tools,input,output}, cost[], limit{context,output}, status }`。
|
|
92
|
+
- [ ] **P1.2** `LLMClient` 用 catalog 解析端点/能力,替换散落的 `isAnthropicModel`/`isDeepseekModel`/`splitProvider` 启发式。
|
|
93
|
+
- [ ] **P1.3** Provider 鉴权统一:env → `~/.skyloom/config.yaml` → 交互向导,三级回退集中到一处。
|
|
94
|
+
- [ ] **P1.4** 上下文窗口与成本从 catalog 取,喂给自动压缩(Phase 4)和成本统计。
|
|
95
|
+
|
|
96
|
+
### Phase 2 — 真流式接线(最高体验收益)|~1 天 ✅ 基本完成
|
|
97
|
+
|
|
98
|
+
- [x] **P2.0 LLM 层真流式**(关键):`streamWithTools` 原本只是包装阻塞 `complete()` 一次性吐出。新增 `callOpenAIStream` —— 对所有 OpenAI 兼容 provider 做真正的 SSE(`stream:true` + `stream_options.include_usage`),逐 token yield content/reasoning、按 index 累积 tool_calls、末帧取 usage 记成本。Anthropic 与流早期失败回落阻塞路径。**实测 DeepSeek 15–18 个增量**。
|
|
99
|
+
- [x] **P2.1 CLI 流式**:`chat()` 改为消费 `agent.chatStream()`(新 `streamResponse()`),逐字渲染真实 token,`reasoning` 淡墨斜体、正文矿物色、工具调用以天气符号脉冲呈现。删除旧的阻塞 `render()`。
|
|
100
|
+
- [x] **P2.2 Web 流式**:`/api/chat` 改 SSE(`text/event-stream`),前端 `fetch` + `ReadableStream` 真流式替换假打字机,工具调用呈现为"气象事件"系统消息。已 curl + 真实 API 验证。
|
|
101
|
+
- [x] **P2.3 中断**:`AbortSignal` 从 CLI 贯穿 `chatStream → streamWithTools → callOpenAIStream → fetch`。Ctrl-C 中断当前 turn 并**保留已产出内容**(轮间检测 abort → `interrupted` 事件 + 落库部分内容),二次 Ctrl-C 强退。实测 DeepSeek:abort 后 ~26ms 内停流(不再跑满整段生成)。
|
|
102
|
+
|
|
103
|
+
### Phase 3 — `agent.ts` 分层(可维护性)|~1.5 天 🔵 进行中(1549 → 1396 行)
|
|
104
|
+
|
|
105
|
+
把巨石拆成职责单一的模块(保持对外 API 不变,re-export 兜底):
|
|
106
|
+
|
|
107
|
+
- [x] `core/agent/task.ts` — 域模型 `Task`/`TaskState`/`TaskResult`/`AgentState`(纯、可测,re-export 验证身份一致)。
|
|
108
|
+
- [x] `agent_helpers.ts` += `parseExtractedFacts`(纯解析器,移出 BaseAgent)。
|
|
109
|
+
- [ ] `core/agent/loop.ts` — LLM 推理循环(`llmLoop` / `chatStreamImpl`,~275 行热路径)
|
|
110
|
+
- [ ] `core/agent/tools.ts` — 工具选择/执行/结果记录
|
|
111
|
+
- [x] `core/agent/guard.ts` — 防循环启发式抽成 `LoopGuard` 类(持有每轮状态,`observe()` 返回 hints/stop 决策,无副作用)。忠实迁移行为;agent 守卫终止测试仍通过。新增 [`tests/guard.test.ts`](../tests/guard.test.ts) 单测各分支(叙述循环/签名循环/失败堆积/搜索风暴)——这些此前**零覆盖**。期间发现并**修复**两处死安全网:all-failed 硬停(`>=8`)的 outcomes 缓冲上限 6→8;search-storm 硬停(`>=12`)改用**每轮累计搜索计数**(不再受 SIG_WINDOW=8 截断)。两个安全网现在如设计般触发,单测覆盖。
|
|
112
|
+
- [ ] `core/agent/delegate.ts` — 跨 Agent 委派与汇总
|
|
113
|
+
- [ ] `core/agent.ts` — 仅保留 `BaseAgent` 编排与公共 API(目标 < 500 行)
|
|
114
|
+
|
|
115
|
+
> ✅ **热路径测试网已就位**:[`tests/agent.test.ts`](../tests/agent.test.ts) 用**脚本化 mock LLM** 特征化了核心循环 —— 简单对话、阻塞 `chat()`、推理流、**工具调用回合**、**防循环 guard 终止**(模型重复同一工具 60 次仍能有界终止)。`loop/tools/guard/delegate` 的拆分现在可以安全进行(每步跑这套网 + 真实 API 抽查)。纯单元(task/helpers)已先抽出。
|
|
116
|
+
|
|
117
|
+
### Phase 4 — Session & 自动上下文管理|~1.5 天
|
|
118
|
+
|
|
119
|
+
对标 opencode `session.md`:
|
|
120
|
+
|
|
121
|
+
- [x] **P4.1 Session 恢复 + 持久化修复**:新增 CLI `/sessions`(编号列表、标记当前)、`/resume <序号|id>`、`/new`。**并修复了一个严重 bug**:`persistDb()`(唯一写盘的代码)**从未被调用** → sql.js 纯内存 → 会话/长期记忆/工作记忆**重启全丢**("启动自动恢复最新会话"形同虚设)。改为所有写经 `dbRun` 触发**防抖落盘** + `close()` 同步保存。新增跨实例持久化回归测试。
|
|
122
|
+
- [x] **P4.2 自动压缩(catalog 感知触发)**:`shouldAutoCompact()`/`contextUsage()` 不再硬编码 128K —— 改为按当前模型在 catalog 里的真实 `context` 窗口判断(留 20% 余量给回复)。修复了小窗口模型(deepseek-reasoner 64K、mixtral 32K)长聊时**先于压缩就溢出**的隐患;状态栏 % 与模型名也正确了。压缩本身(摘要 + 保留近 N 条 + 指令保真)已存在并已接线。后续:结构化 checkpoint + 溢出后重试(对标 opencode)。
|
|
123
|
+
- [ ] **P4.3 上下文快照**:环境信息、日期、工作区、激活技能合成一份"系统上下文",模型可见但与历史分离(轻量版 Context Epoch)。
|
|
124
|
+
|
|
125
|
+
### Phase 5 — 工具与插件健壮性|~1 天
|
|
126
|
+
|
|
127
|
+
- [ ] **P5.1 工具 IO 校验**:工具定义带 input/output schema,非法输入不执行、非法输出不算成功(对标 opencode `tools.md`)。
|
|
128
|
+
- [ ] **P5.2 权限内聚**:危险操作的 `permission.assert` 由工具自身发起,security 模块只评估策略 + 管理审批,统一 `ask/allow/deny` 语义。
|
|
129
|
+
- [ ] **P5.3 插件 hook**:目录加载器升级为有序 hook(`init` / `tool.register` / `provider.update`),插件在自己的 scope 注册,卸载即移除。
|
|
130
|
+
|
|
131
|
+
### Phase 6 — 测试与质量门禁|~1.5 天
|
|
132
|
+
|
|
133
|
+
- [ ] **P6.1** 把覆盖率提到核心全覆盖:仍需 `llm`(mock)、`factory`、`pipelines`、`security` 套件(已建 `catalog`✅ `memory`✅ `task`✅ `agent_helpers`✅ `config`✅ `tui`✅ **`agent`✅(mock LLM)**,共 15 套件 142 用例)。`agent` 套件特征化了 chat/stream/工具回合/防循环 guard,为 `agent.ts` 拆分提供安全网。
|
|
134
|
+
- [ ] **P6.2** CI 加门禁:`type-check` + `lint` + `test` + 覆盖率阈值。
|
|
135
|
+
- [ ] **P6.3** 修正所有 `README`/文档与代码的数字一致性(测试数自动从 `vitest` 输出取)。
|
|
136
|
+
|
|
137
|
+
### Phase 7 — 美学工程化|~1 天(详见 [AESTHETIC_DESIGN.md](./AESTHETIC_DESIGN.md))
|
|
138
|
+
|
|
139
|
+
- [x] **P7.1 设计 token 单一源**:新建 [`src/core/theme.ts`](../src/core/theme.ts)(`PALETTE` + `AGENT_THEMES`:矿物色/汉字/天气符号/诗句/动势)。CLI 已接入;TUI/Web 待接(Web 仍内联 PIGMENTS,P7.3 抽取时统一)。
|
|
140
|
+
- [x] **P7.2 CLI 视觉升级(部分)**:欢迎横幅六灵各显矿物真彩 + 活动灵印章 `▣`;切灵时落朱印 + 诗句;流式正文矿物色、工具调用天气符号。"墨迹晕染"逐字过场待做。
|
|
141
|
+
- [ ] **P7.3 Web 抽出静态资源**:`server.ts` 内联 HTML 拆为 `web/ui/`(html/css/js),加构建步骤,便于演进与缓存。
|
|
142
|
+
- [ ] **P7.4 品牌资产**:SVG logo(印章风)、社交卡片、`docs/` 截图。
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 3. 里程碑与顺序
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
M1 止血+目录 Phase 0 + 1 → 真实可用、单一事实源
|
|
150
|
+
M2 体验飞跃 Phase 2 + 7.2 → 真流式 + CLI 视觉,最高感知收益
|
|
151
|
+
M3 工程地基 Phase 3 + 6 → 拆巨石 + 测试网,安全重构
|
|
152
|
+
M4 框架深度 Phase 4 + 5 → Session/压缩/工具/插件,对标 opencode
|
|
153
|
+
M5 打磨成品 Phase 7 → 美学工程化 + 品牌资产 + 发布
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
建议执行顺序:**M1 → M2 → M3 → M4 → M5**。M1/M2 立刻提升可信度与体验;M3 在动大手术前先织好测试网。
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 4. 成功标准(Definition of Done)
|
|
161
|
+
|
|
162
|
+
- 设置向导/文档中**每个模型都真实可调**,模型数据全局一份。
|
|
163
|
+
- CLI 与 Web **真流式**输出,首字延迟显著下降,可中断。
|
|
164
|
+
- `agent.ts` 拆分后**单文件 < 500 行**,核心模块均有单测,CI 绿且有覆盖率门禁。
|
|
165
|
+
- Session 可列举/恢复,超长上下文**自动压缩**不崩。
|
|
166
|
+
- 美学系统单一源驱动 CLI/TUI/Web,品牌资产齐备。
|
|
167
|
+
- README 与实现**零失真**。
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 5. 风险
|
|
172
|
+
|
|
173
|
+
| 风险 | 缓解 |
|
|
174
|
+
|------|------|
|
|
175
|
+
| 重构 `agent.ts` 引入回归 | Phase 6 测试网先行;逐块拆 + 每步跑测 |
|
|
176
|
+
| 流式与工具执行交错复杂 | 复用已存在的 `chatStreamImpl` 事件模型,只接线不重写 |
|
|
177
|
+
| Catalog 迁移漏模型 | 以 `config/models.yaml` 为真值源迁移,向导/README 派生 |
|
|
178
|
+
| 美学改动破坏现有观感 | 设计 token 抽取为"提取"非"重画",先快照对比 |
|
package/package.json
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "skyloom",
|
|
3
|
-
"version": "1.13.
|
|
4
|
-
"description": "天空织机 Skyloom — 6 weather-themed AI agents: Fog, Rain, Frost, Snow, Dew, Fair",
|
|
5
|
-
"preferGlobal": true,
|
|
6
|
-
"type": "commonjs",
|
|
7
|
-
"main": "./dist/index.js",
|
|
8
|
-
"bin": {
|
|
9
|
-
"sky": "dist/cli/main.js"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"build": "tsc",
|
|
13
|
-
"dev": "tsc --watch",
|
|
14
|
-
"start": "node ./dist/cli/main.js",
|
|
15
|
-
"chat": "node ./dist/cli/main.js chat",
|
|
16
|
-
"task": "node ./dist/cli/main.js task",
|
|
17
|
-
"web": "node ./dist/cli/main.js web",
|
|
18
|
-
"test": "vitest",
|
|
19
|
-
"test:coverage": "vitest --coverage",
|
|
20
|
-
"lint": "eslint src --ext .ts",
|
|
21
|
-
"type-check": "tsc --noEmit",
|
|
22
|
-
"format": "prettier --write \"src/**/*.ts\"",
|
|
23
|
-
"pretest": "npm run type-check",
|
|
24
|
-
"setup": "node scripts/install.js",
|
|
25
|
-
"postinstall": "node scripts/link.js"
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"multi-agent",
|
|
29
|
-
"llm",
|
|
30
|
-
"orchestration",
|
|
31
|
-
"ai",
|
|
32
|
-
"tool-use"
|
|
33
|
-
],
|
|
34
|
-
"author": "Skyloom Team",
|
|
35
|
-
"license": "MIT",
|
|
36
|
-
"repository": {
|
|
37
|
-
"type": "git",
|
|
38
|
-
"url": "git+https://github.com/susurrune/skyloom-ts.git"
|
|
39
|
-
},
|
|
40
|
-
"homepage": "https://github.com/susurrune/skyloom-ts#readme",
|
|
41
|
-
"bugs": {
|
|
42
|
-
"url": "https://github.com/susurrune/skyloom-ts/issues"
|
|
43
|
-
},
|
|
44
|
-
"dependencies": {
|
|
45
|
-
"axios": "^1.7.7",
|
|
46
|
-
"chalk": "^5.3.0",
|
|
47
|
-
"commander": "^12.1.0",
|
|
48
|
-
"glob": "^11.0.0",
|
|
49
|
-
"sql.js": "^1.14.1",
|
|
50
|
-
"yaml": "^2.4.1"
|
|
51
|
-
},
|
|
52
|
-
"devDependencies": {
|
|
53
|
-
"@types/glob": "^8.1.0",
|
|
54
|
-
"@types/node": "^22.0.0",
|
|
55
|
-
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
56
|
-
"@typescript-eslint/parser": "^8.0.0",
|
|
57
|
-
"@vitest/coverage-v8": "^2.0.0",
|
|
58
|
-
"@vitest/ui": "^2.0.0",
|
|
59
|
-
"eslint": "^9.0.0",
|
|
60
|
-
"prettier": "^3.2.0",
|
|
61
|
-
"tsx": "^4.7.0",
|
|
62
|
-
"typescript": "^5.4.0",
|
|
63
|
-
"vitest": "^2.0.0"
|
|
64
|
-
},
|
|
65
|
-
"engines": {
|
|
66
|
-
"node": ">=18.0.0"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "skyloom",
|
|
3
|
+
"version": "1.13.8",
|
|
4
|
+
"description": "天空织机 Skyloom — 6 weather-themed AI agents: Fog, Rain, Frost, Snow, Dew, Fair",
|
|
5
|
+
"preferGlobal": true,
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"sky": "dist/cli/main.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"start": "node ./dist/cli/main.js",
|
|
15
|
+
"chat": "node ./dist/cli/main.js chat",
|
|
16
|
+
"task": "node ./dist/cli/main.js task",
|
|
17
|
+
"web": "node ./dist/cli/main.js web",
|
|
18
|
+
"test": "vitest",
|
|
19
|
+
"test:coverage": "vitest --coverage",
|
|
20
|
+
"lint": "eslint src --ext .ts",
|
|
21
|
+
"type-check": "tsc --noEmit",
|
|
22
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
23
|
+
"pretest": "npm run type-check",
|
|
24
|
+
"setup": "node scripts/install.js",
|
|
25
|
+
"postinstall": "node scripts/link.js"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"multi-agent",
|
|
29
|
+
"llm",
|
|
30
|
+
"orchestration",
|
|
31
|
+
"ai",
|
|
32
|
+
"tool-use"
|
|
33
|
+
],
|
|
34
|
+
"author": "Skyloom Team",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/susurrune/skyloom-ts.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/susurrune/skyloom-ts#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/susurrune/skyloom-ts/issues"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"axios": "^1.7.7",
|
|
46
|
+
"chalk": "^5.3.0",
|
|
47
|
+
"commander": "^12.1.0",
|
|
48
|
+
"glob": "^11.0.0",
|
|
49
|
+
"sql.js": "^1.14.1",
|
|
50
|
+
"yaml": "^2.4.1"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/glob": "^8.1.0",
|
|
54
|
+
"@types/node": "^22.0.0",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
56
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
57
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
58
|
+
"@vitest/ui": "^2.0.0",
|
|
59
|
+
"eslint": "^9.0.0",
|
|
60
|
+
"prettier": "^3.2.0",
|
|
61
|
+
"tsx": "^4.7.0",
|
|
62
|
+
"typescript": "^5.4.0",
|
|
63
|
+
"vitest": "^2.0.0"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|
package/scripts/install.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* 天空织机 · Skyloom — 一键安装
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* npm run setup # 自动 install → build → link
|
|
7
|
-
* npm install -g ./ # 全局安装(装完后 sky 命令可用)
|
|
8
|
-
* npx skyloom # 免安装直接运行
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const { execSync } = require("child_process");
|
|
12
|
-
const { existsSync } = require("fs");
|
|
13
|
-
|
|
14
|
-
const CYAN = "\x1b[36m";
|
|
15
|
-
const GREEN = "\x1b[32m";
|
|
16
|
-
const DIM = "\x1b[2m";
|
|
17
|
-
const RESET = "\x1b[0m";
|
|
18
|
-
|
|
19
|
-
function run(cmd, label) {
|
|
20
|
-
process.stdout.write(` ${CYAN}✦${RESET} ${label} ${DIM}...${RESET}`);
|
|
21
|
-
try {
|
|
22
|
-
execSync(cmd, { stdio: "pipe", encoding: "utf-8" });
|
|
23
|
-
process.stdout.write(` ${GREEN}✓${RESET}\n`);
|
|
24
|
-
} catch (e) {
|
|
25
|
-
process.stdout.write(` ${GREEN}✓${RESET}\n`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
console.log(`\n ${CYAN}✦ 天空织机 · Skyloom ✦${RESET}\n`);
|
|
30
|
-
|
|
31
|
-
run("npm install --no-fund --no-audit", "Installing dependencies");
|
|
32
|
-
run("npx tsc", "Building TypeScript");
|
|
33
|
-
|
|
34
|
-
// Try global link so `sky` works anywhere
|
|
35
|
-
try {
|
|
36
|
-
execSync("npm link", { stdio: "pipe", encoding: "utf-8", timeout: 10000 });
|
|
37
|
-
process.stdout.write(` ${CYAN}✦${RESET} Global 'sky' command ${GREEN}✓${RESET}\n`);
|
|
38
|
-
} catch {
|
|
39
|
-
process.stdout.write(` ${CYAN}✦${RESET} Global 'sky' command ${DIM}(use: npm install -g .)${RESET}\n`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
console.log(`\n ${GREEN}✅ 天空织机 已就绪${RESET}\n`);
|
|
43
|
-
console.log(` ${DIM}────────────────────────────────${RESET}`);
|
|
44
|
-
console.log(` ${CYAN}sky chat ${DIM}开始对话${RESET}`);
|
|
45
|
-
console.log(` ${CYAN}sky web ${DIM}启动 Web UI → http://localhost:3000${RESET}`);
|
|
46
|
-
console.log(` ${CYAN}sky task <goal> ${DIM}多 Agent 编排${RESET}`);
|
|
47
|
-
console.log(` ${CYAN}sky help ${DIM}所有命令${RESET}`);
|
|
48
|
-
console.log(` ${DIM}────────────────────────────────${RESET}\n`);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 天空织机 · Skyloom — 一键安装
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npm run setup # 自动 install → build → link
|
|
7
|
+
* npm install -g ./ # 全局安装(装完后 sky 命令可用)
|
|
8
|
+
* npx skyloom # 免安装直接运行
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { execSync } = require("child_process");
|
|
12
|
+
const { existsSync } = require("fs");
|
|
13
|
+
|
|
14
|
+
const CYAN = "\x1b[36m";
|
|
15
|
+
const GREEN = "\x1b[32m";
|
|
16
|
+
const DIM = "\x1b[2m";
|
|
17
|
+
const RESET = "\x1b[0m";
|
|
18
|
+
|
|
19
|
+
function run(cmd, label) {
|
|
20
|
+
process.stdout.write(` ${CYAN}✦${RESET} ${label} ${DIM}...${RESET}`);
|
|
21
|
+
try {
|
|
22
|
+
execSync(cmd, { stdio: "pipe", encoding: "utf-8" });
|
|
23
|
+
process.stdout.write(` ${GREEN}✓${RESET}\n`);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
process.stdout.write(` ${GREEN}✓${RESET}\n`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(`\n ${CYAN}✦ 天空织机 · Skyloom ✦${RESET}\n`);
|
|
30
|
+
|
|
31
|
+
run("npm install --no-fund --no-audit", "Installing dependencies");
|
|
32
|
+
run("npx tsc", "Building TypeScript");
|
|
33
|
+
|
|
34
|
+
// Try global link so `sky` works anywhere
|
|
35
|
+
try {
|
|
36
|
+
execSync("npm link", { stdio: "pipe", encoding: "utf-8", timeout: 10000 });
|
|
37
|
+
process.stdout.write(` ${CYAN}✦${RESET} Global 'sky' command ${GREEN}✓${RESET}\n`);
|
|
38
|
+
} catch {
|
|
39
|
+
process.stdout.write(` ${CYAN}✦${RESET} Global 'sky' command ${DIM}(use: npm install -g .)${RESET}\n`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log(`\n ${GREEN}✅ 天空织机 已就绪${RESET}\n`);
|
|
43
|
+
console.log(` ${DIM}────────────────────────────────${RESET}`);
|
|
44
|
+
console.log(` ${CYAN}sky chat ${DIM}开始对话${RESET}`);
|
|
45
|
+
console.log(` ${CYAN}sky web ${DIM}启动 Web UI → http://localhost:3000${RESET}`);
|
|
46
|
+
console.log(` ${CYAN}sky task <goal> ${DIM}多 Agent 编排${RESET}`);
|
|
47
|
+
console.log(` ${CYAN}sky help ${DIM}所有命令${RESET}`);
|
|
48
|
+
console.log(` ${DIM}────────────────────────────────${RESET}\n`);
|
package/scripts/link.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Post-install hook — runs `npm link` so `sky` is globally available.
|
|
4
|
-
* Silently skipped on CI or when permissions are insufficient.
|
|
5
|
-
*/
|
|
6
|
-
if (process.env.CI || process.env.NODE_ENV === "production") process.exit(0);
|
|
7
|
-
const { execSync } = require("child_process");
|
|
8
|
-
try {
|
|
9
|
-
execSync("npm link", { stdio: "pipe", encoding: "utf-8", timeout: 10000 });
|
|
10
|
-
} catch (_) {}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Post-install hook — runs `npm link` so `sky` is globally available.
|
|
4
|
+
* Silently skipped on CI or when permissions are insufficient.
|
|
5
|
+
*/
|
|
6
|
+
if (process.env.CI || process.env.NODE_ENV === "production") process.exit(0);
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
try {
|
|
9
|
+
execSync("npm link", { stdio: "pipe", encoding: "utf-8", timeout: 10000 });
|
|
10
|
+
} catch (_) {}
|