skyloom 1.14.8 → 1.15.0
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 +2 -2
- package/.github/workflows/publish.yml +51 -4
- package/CONVERSION_PLAN.md +191 -191
- package/config/default.yaml +46 -43
- package/config/models.yaml +928 -155
- package/config/providers.yaml +109 -6
- package/dist/agents/snow.d.ts +2 -0
- package/dist/agents/snow.d.ts.map +1 -1
- package/dist/agents/snow.js +36 -5
- package/dist/agents/snow.js.map +1 -1
- package/dist/cli/loom_chat.d.ts.map +1 -1
- package/dist/cli/loom_chat.js +207 -1
- package/dist/cli/loom_chat.js.map +1 -1
- package/dist/cli/main.js +190 -40
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +6 -31
- package/dist/cli/tui.js.map +1 -1
- package/dist/core/agent.d.ts +6 -4
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +61 -20
- package/dist/core/agent.js.map +1 -1
- package/dist/core/catalog.d.ts.map +1 -1
- package/dist/core/catalog.js +30 -9
- package/dist/core/catalog.js.map +1 -1
- package/dist/core/commands.d.ts +110 -0
- package/dist/core/commands.d.ts.map +1 -0
- package/dist/core/commands.js +633 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/concurrency.d.ts +38 -0
- package/dist/core/concurrency.d.ts.map +1 -0
- package/dist/core/concurrency.js +65 -0
- package/dist/core/concurrency.js.map +1 -0
- package/dist/core/factory.js +16 -16
- package/dist/core/file_checkpoint.d.ts +9 -0
- package/dist/core/file_checkpoint.d.ts.map +1 -1
- package/dist/core/file_checkpoint.js +33 -1
- package/dist/core/file_checkpoint.js.map +1 -1
- package/dist/core/llm.d.ts.map +1 -1
- package/dist/core/llm.js +66 -13
- package/dist/core/llm.js.map +1 -1
- package/dist/core/memory.js +51 -51
- package/dist/core/schemas.d.ts +16 -0
- package/dist/core/schemas.d.ts.map +1 -1
- package/dist/core/schemas.js +32 -0
- package/dist/core/schemas.js.map +1 -1
- package/dist/core/security.d.ts.map +1 -1
- package/dist/core/security.js +27 -0
- package/dist/core/security.js.map +1 -1
- package/dist/core/skymd.js +14 -14
- package/dist/core/trace.d.ts +105 -0
- package/dist/core/trace.d.ts.map +1 -0
- package/dist/core/trace.js +213 -0
- package/dist/core/trace.js.map +1 -0
- package/dist/tools/builtin.d.ts +2 -6
- package/dist/tools/builtin.d.ts.map +1 -1
- package/dist/tools/builtin.js +18 -111
- package/dist/tools/builtin.js.map +1 -1
- package/dist/tools/extra.d.ts +13 -0
- package/dist/tools/extra.d.ts.map +1 -0
- package/dist/tools/extra.js +827 -0
- package/dist/tools/extra.js.map +1 -0
- package/dist/tools/guards.d.ts +12 -0
- package/dist/tools/guards.d.ts.map +1 -0
- package/dist/tools/guards.js +143 -0
- package/dist/tools/guards.js.map +1 -0
- package/dist/tools/model_tool.d.ts.map +1 -1
- package/dist/tools/model_tool.js +24 -4
- package/dist/tools/model_tool.js.map +1 -1
- package/dist/web/markdown.d.ts +32 -0
- package/dist/web/markdown.d.ts.map +1 -0
- package/dist/web/markdown.js +202 -0
- package/dist/web/markdown.js.map +1 -0
- package/dist/web/server.d.ts +4 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +14 -582
- package/dist/web/server.js.map +1 -1
- package/dist/web/ui.d.ts +31 -0
- package/dist/web/ui.d.ts.map +1 -0
- package/dist/web/ui.js +1009 -0
- package/dist/web/ui.js.map +1 -0
- package/docs/AESTHETIC_DESIGN.md +152 -152
- package/docs/OPTIMIZATION_PLAN.md +178 -178
- package/package.json +1 -1
- package/src/agents/snow.ts +38 -5
- package/src/cli/commands_md.ts +112 -112
- package/src/cli/input_macros.ts +83 -83
- package/src/cli/loom.ts +1041 -1041
- package/src/cli/loom_chat.ts +772 -603
- package/src/cli/main.ts +853 -723
- package/src/cli/tui.ts +264 -289
- package/src/core/agent/guard.ts +133 -133
- package/src/core/agent/task.ts +100 -100
- package/src/core/agent.ts +1630 -1590
- package/src/core/agent_helpers.ts +500 -500
- package/src/core/bus.ts +221 -221
- package/src/core/cache.ts +153 -153
- package/src/core/catalog.ts +199 -178
- package/src/core/circuit_breaker.ts +119 -119
- package/src/core/commands.ts +704 -0
- package/src/core/concurrency.ts +73 -0
- package/src/core/config.ts +365 -365
- package/src/core/constants.ts +95 -95
- package/src/core/factory.ts +656 -656
- package/src/core/file_checkpoint.ts +163 -136
- package/src/core/hooks.ts +126 -126
- package/src/core/llm.ts +972 -915
- package/src/core/logger.ts +143 -143
- package/src/core/mcp.ts +1001 -1001
- package/src/core/memory.ts +1201 -1201
- package/src/core/middleware.ts +350 -350
- package/src/core/model_config.ts +159 -159
- package/src/core/pipelines.ts +424 -424
- package/src/core/schemas.ts +319 -282
- package/src/core/security.ts +27 -0
- package/src/core/semantic.ts +211 -211
- package/src/core/skill.ts +384 -384
- package/src/core/skymd.ts +143 -143
- package/src/core/theme.ts +65 -65
- package/src/core/tool.ts +457 -457
- package/src/core/trace.ts +236 -0
- package/src/core/verify.ts +71 -71
- package/src/plugins/loader.ts +91 -91
- package/src/skills/loader.ts +75 -75
- package/src/tools/builtin.ts +571 -642
- package/src/tools/computer.ts +279 -279
- package/src/tools/extra.ts +662 -0
- package/src/tools/guards.ts +82 -0
- package/src/tools/model_tool.ts +93 -74
- package/src/tools/todo.ts +76 -76
- package/src/web/markdown.ts +193 -0
- package/src/web/server.ts +117 -693
- package/src/web/ui.ts +949 -0
- package/tests/agent.test.ts +211 -159
- package/tests/agent_helpers.test.ts +48 -48
- package/tests/catalog.test.ts +86 -86
- package/tests/checkpoint_commands.test.ts +124 -124
- package/tests/claude_compat.test.ts +110 -110
- package/tests/commands.test.ts +103 -0
- package/tests/concurrency.test.ts +102 -0
- package/tests/config.test.ts +41 -41
- package/tests/extra_tools.test.ts +212 -0
- package/tests/fence_plugin.test.ts +52 -52
- package/tests/guard.test.ts +75 -75
- package/tests/loom.test.ts +337 -337
- package/tests/memory.test.ts +170 -170
- package/tests/model_config.test.ts +109 -109
- package/tests/skymd.test.ts +146 -146
- package/tests/ssrf.test.ts +38 -38
- package/tests/structured_retry.test.ts +87 -0
- package/tests/task.test.ts +60 -60
- package/tests/todo_toolstats.test.ts +94 -94
- package/tests/trace.test.ts +128 -0
- package/tests/tui.test.ts +67 -67
- package/tests/web.test.ts +169 -0
- package/tsconfig.json +38 -38
package/src/core/skymd.ts
CHANGED
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 项目记忆 (SKY.md) — Skyloom's equivalent of Claude Code's CLAUDE.md.
|
|
3
|
-
*
|
|
4
|
-
* A layered, auto-loaded instruction file that gives every agent durable
|
|
5
|
-
* knowledge of the project: build commands, conventions, constraints.
|
|
6
|
-
*
|
|
7
|
-
* Load order (all layers concatenate, later = more specific):
|
|
8
|
-
* 1. ~/.skyloom/SKY.md — user level, applies to every project
|
|
9
|
-
* 2. ./SKY.md | ./CLAUDE.md | ./AGENTS.md — project level (first match;
|
|
10
|
-
* CLAUDE.md/AGENTS.md compatibility means existing repos work as-is)
|
|
11
|
-
* 3. ./SKY.local.md — project level, personal (gitignored)
|
|
12
|
-
*
|
|
13
|
-
* The merged text is injected into every agent's system prompt at init.
|
|
14
|
-
* `#<note>` in chat appends to the project file via appendQuickMemory().
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import * as fs from 'fs';
|
|
18
|
-
import * as os from 'os';
|
|
19
|
-
import * as path from 'path';
|
|
20
|
-
|
|
21
|
-
/** Total budget for injected memory — it lives in every prompt, keep it lean. */
|
|
22
|
-
const MAX_MEMORY_CHARS = 12000;
|
|
23
|
-
/** Per-file budget so one bloated layer can't crowd out the others. */
|
|
24
|
-
const MAX_FILE_CHARS = 6000;
|
|
25
|
-
|
|
26
|
-
export interface ProjectMemory {
|
|
27
|
-
/** Merged, truncated text ready for prompt injection ('' if no files). */
|
|
28
|
-
text: string;
|
|
29
|
-
/** Absolute paths of the files that contributed. */
|
|
30
|
-
files: string[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const PROJECT_FILE_CANDIDATES = ['SKY.md', 'CLAUDE.md', 'AGENTS.md'];
|
|
34
|
-
|
|
35
|
-
function readClamped(p: string): string | null {
|
|
36
|
-
try {
|
|
37
|
-
if (!fs.existsSync(p)) return null;
|
|
38
|
-
const raw = fs.readFileSync(p, 'utf-8').trim();
|
|
39
|
-
if (!raw) return null;
|
|
40
|
-
return raw.length > MAX_FILE_CHARS
|
|
41
|
-
? raw.slice(0, MAX_FILE_CHARS) + '\n…[truncated]'
|
|
42
|
-
: raw;
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Resolve the project-level memory file (existing first candidate, or null). */
|
|
49
|
-
export function projectMemoryFile(cwd: string = process.cwd()): string | null {
|
|
50
|
-
for (const name of PROJECT_FILE_CANDIDATES) {
|
|
51
|
-
const p = path.join(cwd, name);
|
|
52
|
-
if (fs.existsSync(p)) return p;
|
|
53
|
-
}
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Load and merge all memory layers for prompt injection. */
|
|
58
|
-
export function loadProjectMemory(cwd: string = process.cwd()): ProjectMemory {
|
|
59
|
-
const layers: Array<{ label: string; file: string }> = [];
|
|
60
|
-
|
|
61
|
-
const userFile = path.join(os.homedir(), '.skyloom', 'SKY.md');
|
|
62
|
-
layers.push({ label: '用户级', file: userFile });
|
|
63
|
-
|
|
64
|
-
const projFile = projectMemoryFile(cwd);
|
|
65
|
-
if (projFile) layers.push({ label: '项目级', file: projFile });
|
|
66
|
-
|
|
67
|
-
const localFile = path.join(cwd, 'SKY.local.md');
|
|
68
|
-
layers.push({ label: '本地', file: localFile });
|
|
69
|
-
|
|
70
|
-
const parts: string[] = [];
|
|
71
|
-
const files: string[] = [];
|
|
72
|
-
for (const { label, file } of layers) {
|
|
73
|
-
const content = readClamped(file);
|
|
74
|
-
if (content === null) continue;
|
|
75
|
-
parts.push(`<!-- ${label}: ${path.basename(file)} -->\n${content}`);
|
|
76
|
-
files.push(file);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let text = parts.join('\n\n');
|
|
80
|
-
if (text.length > MAX_MEMORY_CHARS) text = text.slice(0, MAX_MEMORY_CHARS) + '\n…[truncated]';
|
|
81
|
-
return { text, files };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const SKY_MD_HEADER = `# SKY.md — 项目记忆
|
|
85
|
-
|
|
86
|
-
> Skyloom agents 启动时自动加载本文件。写团队约定、构建/测试命令、代码风格。
|
|
87
|
-
> 对话中输入 \`#内容\` 可快速追加一条。
|
|
88
|
-
|
|
89
|
-
`;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Append a one-line note (the \`#\` quick-memory flow).
|
|
93
|
-
* Writes to the existing project memory file, or creates ./SKY.md.
|
|
94
|
-
* Returns the file path written.
|
|
95
|
-
*/
|
|
96
|
-
export function appendQuickMemory(note: string, cwd: string = process.cwd()): string {
|
|
97
|
-
const target = projectMemoryFile(cwd) ?? path.join(cwd, 'SKY.md');
|
|
98
|
-
const line = `- ${note.trim()}\n`;
|
|
99
|
-
if (!fs.existsSync(target)) {
|
|
100
|
-
fs.writeFileSync(target, SKY_MD_HEADER + line, 'utf-8');
|
|
101
|
-
} else {
|
|
102
|
-
const existing = fs.readFileSync(target, 'utf-8');
|
|
103
|
-
fs.appendFileSync(target, (existing.endsWith('\n') ? '' : '\n') + line, 'utf-8');
|
|
104
|
-
}
|
|
105
|
-
return target;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Extract verify commands from a "## Verify" / "## 验证" section of the
|
|
110
|
-
* merged memory text: each non-comment line of its fenced code block.
|
|
111
|
-
*/
|
|
112
|
-
export function parseVerifyCommands(memoryText: string): string[] {
|
|
113
|
-
const cmds: string[] = [];
|
|
114
|
-
let inSection = false;
|
|
115
|
-
let inFence = false;
|
|
116
|
-
for (const line of memoryText.split('\n')) {
|
|
117
|
-
if (/^##\s*(verify|验证)/i.test(line)) { inSection = true; continue; }
|
|
118
|
-
if (!inSection) continue;
|
|
119
|
-
if (/^##\s/.test(line)) break; // next section
|
|
120
|
-
if (line.trim().startsWith('```')) {
|
|
121
|
-
if (inFence) break; // closing fence — done
|
|
122
|
-
inFence = true;
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
if (inFence) {
|
|
126
|
-
const t = line.trim();
|
|
127
|
-
if (t && !t.startsWith('#') && !t.startsWith('//')) cmds.push(t);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return cmds;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** The prompt behind /init — asks the agent to study the repo and write SKY.md. */
|
|
134
|
-
export const INIT_PROMPT = `请为当前项目生成一份 SKY.md 项目记忆文件(如已存在则改进它):
|
|
135
|
-
|
|
136
|
-
1. 用工具调研项目:读 README、package.json/pyproject.toml/Cargo.toml 等清单文件,list_directory 看结构,必要时读关键入口源码
|
|
137
|
-
2. 写出一份**短而精**的 SKY.md(每一行都占用所有 agent 的上下文,宁缺毋滥),包含:
|
|
138
|
-
- 项目一句话定位与技术栈
|
|
139
|
-
- 构建/测试/lint 命令(放在 "## Verify" 小节的代码块里,agents 会用它自动验证)
|
|
140
|
-
- 目录结构要点(只列关键目录)
|
|
141
|
-
- 代码风格与硬性约束(如「禁止 any」「提交信息格式」)
|
|
142
|
-
3. 用 write_file 写到项目根目录 SKY.md
|
|
143
|
-
4. 最后简要汇报你写了什么`;
|
|
1
|
+
/**
|
|
2
|
+
* 项目记忆 (SKY.md) — Skyloom's equivalent of Claude Code's CLAUDE.md.
|
|
3
|
+
*
|
|
4
|
+
* A layered, auto-loaded instruction file that gives every agent durable
|
|
5
|
+
* knowledge of the project: build commands, conventions, constraints.
|
|
6
|
+
*
|
|
7
|
+
* Load order (all layers concatenate, later = more specific):
|
|
8
|
+
* 1. ~/.skyloom/SKY.md — user level, applies to every project
|
|
9
|
+
* 2. ./SKY.md | ./CLAUDE.md | ./AGENTS.md — project level (first match;
|
|
10
|
+
* CLAUDE.md/AGENTS.md compatibility means existing repos work as-is)
|
|
11
|
+
* 3. ./SKY.local.md — project level, personal (gitignored)
|
|
12
|
+
*
|
|
13
|
+
* The merged text is injected into every agent's system prompt at init.
|
|
14
|
+
* `#<note>` in chat appends to the project file via appendQuickMemory().
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as os from 'os';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
|
|
21
|
+
/** Total budget for injected memory — it lives in every prompt, keep it lean. */
|
|
22
|
+
const MAX_MEMORY_CHARS = 12000;
|
|
23
|
+
/** Per-file budget so one bloated layer can't crowd out the others. */
|
|
24
|
+
const MAX_FILE_CHARS = 6000;
|
|
25
|
+
|
|
26
|
+
export interface ProjectMemory {
|
|
27
|
+
/** Merged, truncated text ready for prompt injection ('' if no files). */
|
|
28
|
+
text: string;
|
|
29
|
+
/** Absolute paths of the files that contributed. */
|
|
30
|
+
files: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const PROJECT_FILE_CANDIDATES = ['SKY.md', 'CLAUDE.md', 'AGENTS.md'];
|
|
34
|
+
|
|
35
|
+
function readClamped(p: string): string | null {
|
|
36
|
+
try {
|
|
37
|
+
if (!fs.existsSync(p)) return null;
|
|
38
|
+
const raw = fs.readFileSync(p, 'utf-8').trim();
|
|
39
|
+
if (!raw) return null;
|
|
40
|
+
return raw.length > MAX_FILE_CHARS
|
|
41
|
+
? raw.slice(0, MAX_FILE_CHARS) + '\n…[truncated]'
|
|
42
|
+
: raw;
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Resolve the project-level memory file (existing first candidate, or null). */
|
|
49
|
+
export function projectMemoryFile(cwd: string = process.cwd()): string | null {
|
|
50
|
+
for (const name of PROJECT_FILE_CANDIDATES) {
|
|
51
|
+
const p = path.join(cwd, name);
|
|
52
|
+
if (fs.existsSync(p)) return p;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Load and merge all memory layers for prompt injection. */
|
|
58
|
+
export function loadProjectMemory(cwd: string = process.cwd()): ProjectMemory {
|
|
59
|
+
const layers: Array<{ label: string; file: string }> = [];
|
|
60
|
+
|
|
61
|
+
const userFile = path.join(os.homedir(), '.skyloom', 'SKY.md');
|
|
62
|
+
layers.push({ label: '用户级', file: userFile });
|
|
63
|
+
|
|
64
|
+
const projFile = projectMemoryFile(cwd);
|
|
65
|
+
if (projFile) layers.push({ label: '项目级', file: projFile });
|
|
66
|
+
|
|
67
|
+
const localFile = path.join(cwd, 'SKY.local.md');
|
|
68
|
+
layers.push({ label: '本地', file: localFile });
|
|
69
|
+
|
|
70
|
+
const parts: string[] = [];
|
|
71
|
+
const files: string[] = [];
|
|
72
|
+
for (const { label, file } of layers) {
|
|
73
|
+
const content = readClamped(file);
|
|
74
|
+
if (content === null) continue;
|
|
75
|
+
parts.push(`<!-- ${label}: ${path.basename(file)} -->\n${content}`);
|
|
76
|
+
files.push(file);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let text = parts.join('\n\n');
|
|
80
|
+
if (text.length > MAX_MEMORY_CHARS) text = text.slice(0, MAX_MEMORY_CHARS) + '\n…[truncated]';
|
|
81
|
+
return { text, files };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const SKY_MD_HEADER = `# SKY.md — 项目记忆
|
|
85
|
+
|
|
86
|
+
> Skyloom agents 启动时自动加载本文件。写团队约定、构建/测试命令、代码风格。
|
|
87
|
+
> 对话中输入 \`#内容\` 可快速追加一条。
|
|
88
|
+
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Append a one-line note (the \`#\` quick-memory flow).
|
|
93
|
+
* Writes to the existing project memory file, or creates ./SKY.md.
|
|
94
|
+
* Returns the file path written.
|
|
95
|
+
*/
|
|
96
|
+
export function appendQuickMemory(note: string, cwd: string = process.cwd()): string {
|
|
97
|
+
const target = projectMemoryFile(cwd) ?? path.join(cwd, 'SKY.md');
|
|
98
|
+
const line = `- ${note.trim()}\n`;
|
|
99
|
+
if (!fs.existsSync(target)) {
|
|
100
|
+
fs.writeFileSync(target, SKY_MD_HEADER + line, 'utf-8');
|
|
101
|
+
} else {
|
|
102
|
+
const existing = fs.readFileSync(target, 'utf-8');
|
|
103
|
+
fs.appendFileSync(target, (existing.endsWith('\n') ? '' : '\n') + line, 'utf-8');
|
|
104
|
+
}
|
|
105
|
+
return target;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Extract verify commands from a "## Verify" / "## 验证" section of the
|
|
110
|
+
* merged memory text: each non-comment line of its fenced code block.
|
|
111
|
+
*/
|
|
112
|
+
export function parseVerifyCommands(memoryText: string): string[] {
|
|
113
|
+
const cmds: string[] = [];
|
|
114
|
+
let inSection = false;
|
|
115
|
+
let inFence = false;
|
|
116
|
+
for (const line of memoryText.split('\n')) {
|
|
117
|
+
if (/^##\s*(verify|验证)/i.test(line)) { inSection = true; continue; }
|
|
118
|
+
if (!inSection) continue;
|
|
119
|
+
if (/^##\s/.test(line)) break; // next section
|
|
120
|
+
if (line.trim().startsWith('```')) {
|
|
121
|
+
if (inFence) break; // closing fence — done
|
|
122
|
+
inFence = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (inFence) {
|
|
126
|
+
const t = line.trim();
|
|
127
|
+
if (t && !t.startsWith('#') && !t.startsWith('//')) cmds.push(t);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return cmds;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** The prompt behind /init — asks the agent to study the repo and write SKY.md. */
|
|
134
|
+
export const INIT_PROMPT = `请为当前项目生成一份 SKY.md 项目记忆文件(如已存在则改进它):
|
|
135
|
+
|
|
136
|
+
1. 用工具调研项目:读 README、package.json/pyproject.toml/Cargo.toml 等清单文件,list_directory 看结构,必要时读关键入口源码
|
|
137
|
+
2. 写出一份**短而精**的 SKY.md(每一行都占用所有 agent 的上下文,宁缺毋滥),包含:
|
|
138
|
+
- 项目一句话定位与技术栈
|
|
139
|
+
- 构建/测试/lint 命令(放在 "## Verify" 小节的代码块里,agents 会用它自动验证)
|
|
140
|
+
- 目录结构要点(只列关键目录)
|
|
141
|
+
- 代码风格与硬性约束(如「禁止 any」「提交信息格式」)
|
|
142
|
+
3. 用 write_file 写到项目根目录 SKY.md
|
|
143
|
+
4. 最后简要汇报你写了什么`;
|
package/src/core/theme.ts
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Design tokens — single source of truth for Skyloom's "水墨气象台" identity.
|
|
3
|
-
*
|
|
4
|
-
* One definition drives every surface: CLI (chalk truecolor), the full-screen
|
|
5
|
-
* TUI, and the Web ink-wash UI. Change a pigment here and all three follow.
|
|
6
|
-
*
|
|
7
|
-
* Design rationale: docs/AESTHETIC_DESIGN.md
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/** Base paper-and-ink palette (hex). */
|
|
11
|
-
export const PALETTE = {
|
|
12
|
-
paper: "#f8f4ec",
|
|
13
|
-
paperWarm: "#f3ede2",
|
|
14
|
-
inkDeep: "#1a1614",
|
|
15
|
-
inkMid: "#3d3833",
|
|
16
|
-
inkLight: "#8c8680",
|
|
17
|
-
inkFaint: "#c4bfb8",
|
|
18
|
-
} as const;
|
|
19
|
-
|
|
20
|
-
/** Per-agent identity: weather + mineral pigment + classical poem + motion. */
|
|
21
|
-
export interface AgentTheme {
|
|
22
|
-
/** Agent key (fog/rain/…). */
|
|
23
|
-
name: string;
|
|
24
|
-
/** Weather kanji used as a seal stamp (霧/雨/…). */
|
|
25
|
-
kanji: string;
|
|
26
|
-
/** Single-glyph weather symbol used across CLI/TUI/Web. */
|
|
27
|
-
symbol: string;
|
|
28
|
-
/** Mineral pigment hex. */
|
|
29
|
-
hex: string;
|
|
30
|
-
/** Mineral pigment RGB triple (for ANSI truecolor / CSS rgba). */
|
|
31
|
-
rgb: [number, number, number];
|
|
32
|
-
/** Pigment name in Chinese (松烟墨/石青/…). */
|
|
33
|
-
pigment: string;
|
|
34
|
-
/** Responsibility (探索洞察/创造产出/…). */
|
|
35
|
-
specialty: string;
|
|
36
|
-
/** Classical poem line shown in empty states / sidebars. */
|
|
37
|
-
poem: string;
|
|
38
|
-
/** Motion keyword (drift/fall/glint/float/bead/rise). */
|
|
39
|
-
motion: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function rgbOf(hex: string): [number, number, number] {
|
|
43
|
-
const h = hex.replace("#", "");
|
|
44
|
-
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const AGENT_THEMES: Record<string, AgentTheme> = {
|
|
48
|
-
fog: { name: "fog", kanji: "霧", symbol: "≋", hex: "#4a4a44", rgb: rgbOf("#4a4a44"), pigment: "松烟墨", specialty: "探索洞察", poem: "山色有无中", motion: "drift" },
|
|
49
|
-
rain: { name: "rain", kanji: "雨", symbol: "⸽", hex: "#2a5c8a", rgb: rgbOf("#2a5c8a"), pigment: "石青", specialty: "创造产出", poem: "一蓑烟雨任平生", motion: "fall" },
|
|
50
|
-
frost: { name: "frost", kanji: "霜", symbol: "✱", hex: "#3a7a6e", rgb: rgbOf("#3a7a6e"), pigment: "石绿", specialty: "精炼品质", poem: "月落乌啼霜满天", motion: "glint" },
|
|
51
|
-
snow: { name: "snow", kanji: "雪", symbol: "❉", hex: "#8a8a82", rgb: rgbOf("#8a8a82"), pigment: "铅白", specialty: "架构规划", poem: "千树万树梨花开", motion: "float" },
|
|
52
|
-
dew: { name: "dew", kanji: "露", symbol: "∘", hex: "#8b6914", rgb: rgbOf("#8b6914"), pigment: "赭石", specialty: "可靠守护", poem: "金风玉露一相逢", motion: "bead" },
|
|
53
|
-
fair: { name: "fair", kanji: "晴", symbol: "☼", hex: "#b3342d", rgb: rgbOf("#b3342d"), pigment: "朱砂", specialty: "情感陪伴", poem: "道是无晴却有晴", motion: "rise" },
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/** Ordered agent keys (織機 six shuttles). */
|
|
57
|
-
export const AGENT_ORDER = ["fog", "rain", "frost", "snow", "dew", "fair"] as const;
|
|
58
|
-
|
|
59
|
-
/** Brand seal pigment (朱砂) — used for the active-agent stamp everywhere. */
|
|
60
|
-
export const SEAL_HEX = AGENT_THEMES.fair.hex;
|
|
61
|
-
|
|
62
|
-
/** Look up an agent theme, defaulting to fog. */
|
|
63
|
-
export function agentTheme(name: string): AgentTheme {
|
|
64
|
-
return AGENT_THEMES[name] ?? AGENT_THEMES.fog;
|
|
65
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Design tokens — single source of truth for Skyloom's "水墨气象台" identity.
|
|
3
|
+
*
|
|
4
|
+
* One definition drives every surface: CLI (chalk truecolor), the full-screen
|
|
5
|
+
* TUI, and the Web ink-wash UI. Change a pigment here and all three follow.
|
|
6
|
+
*
|
|
7
|
+
* Design rationale: docs/AESTHETIC_DESIGN.md
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Base paper-and-ink palette (hex). */
|
|
11
|
+
export const PALETTE = {
|
|
12
|
+
paper: "#f8f4ec",
|
|
13
|
+
paperWarm: "#f3ede2",
|
|
14
|
+
inkDeep: "#1a1614",
|
|
15
|
+
inkMid: "#3d3833",
|
|
16
|
+
inkLight: "#8c8680",
|
|
17
|
+
inkFaint: "#c4bfb8",
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
/** Per-agent identity: weather + mineral pigment + classical poem + motion. */
|
|
21
|
+
export interface AgentTheme {
|
|
22
|
+
/** Agent key (fog/rain/…). */
|
|
23
|
+
name: string;
|
|
24
|
+
/** Weather kanji used as a seal stamp (霧/雨/…). */
|
|
25
|
+
kanji: string;
|
|
26
|
+
/** Single-glyph weather symbol used across CLI/TUI/Web. */
|
|
27
|
+
symbol: string;
|
|
28
|
+
/** Mineral pigment hex. */
|
|
29
|
+
hex: string;
|
|
30
|
+
/** Mineral pigment RGB triple (for ANSI truecolor / CSS rgba). */
|
|
31
|
+
rgb: [number, number, number];
|
|
32
|
+
/** Pigment name in Chinese (松烟墨/石青/…). */
|
|
33
|
+
pigment: string;
|
|
34
|
+
/** Responsibility (探索洞察/创造产出/…). */
|
|
35
|
+
specialty: string;
|
|
36
|
+
/** Classical poem line shown in empty states / sidebars. */
|
|
37
|
+
poem: string;
|
|
38
|
+
/** Motion keyword (drift/fall/glint/float/bead/rise). */
|
|
39
|
+
motion: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function rgbOf(hex: string): [number, number, number] {
|
|
43
|
+
const h = hex.replace("#", "");
|
|
44
|
+
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const AGENT_THEMES: Record<string, AgentTheme> = {
|
|
48
|
+
fog: { name: "fog", kanji: "霧", symbol: "≋", hex: "#4a4a44", rgb: rgbOf("#4a4a44"), pigment: "松烟墨", specialty: "探索洞察", poem: "山色有无中", motion: "drift" },
|
|
49
|
+
rain: { name: "rain", kanji: "雨", symbol: "⸽", hex: "#2a5c8a", rgb: rgbOf("#2a5c8a"), pigment: "石青", specialty: "创造产出", poem: "一蓑烟雨任平生", motion: "fall" },
|
|
50
|
+
frost: { name: "frost", kanji: "霜", symbol: "✱", hex: "#3a7a6e", rgb: rgbOf("#3a7a6e"), pigment: "石绿", specialty: "精炼品质", poem: "月落乌啼霜满天", motion: "glint" },
|
|
51
|
+
snow: { name: "snow", kanji: "雪", symbol: "❉", hex: "#8a8a82", rgb: rgbOf("#8a8a82"), pigment: "铅白", specialty: "架构规划", poem: "千树万树梨花开", motion: "float" },
|
|
52
|
+
dew: { name: "dew", kanji: "露", symbol: "∘", hex: "#8b6914", rgb: rgbOf("#8b6914"), pigment: "赭石", specialty: "可靠守护", poem: "金风玉露一相逢", motion: "bead" },
|
|
53
|
+
fair: { name: "fair", kanji: "晴", symbol: "☼", hex: "#b3342d", rgb: rgbOf("#b3342d"), pigment: "朱砂", specialty: "情感陪伴", poem: "道是无晴却有晴", motion: "rise" },
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** Ordered agent keys (織機 six shuttles). */
|
|
57
|
+
export const AGENT_ORDER = ["fog", "rain", "frost", "snow", "dew", "fair"] as const;
|
|
58
|
+
|
|
59
|
+
/** Brand seal pigment (朱砂) — used for the active-agent stamp everywhere. */
|
|
60
|
+
export const SEAL_HEX = AGENT_THEMES.fair.hex;
|
|
61
|
+
|
|
62
|
+
/** Look up an agent theme, defaulting to fog. */
|
|
63
|
+
export function agentTheme(name: string): AgentTheme {
|
|
64
|
+
return AGENT_THEMES[name] ?? AGENT_THEMES.fog;
|
|
65
|
+
}
|