mocode-ai 1.2.3 → 1.2.5
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/dist/agent/index.js +3 -2
- package/dist/agent/spawn.js +25 -1
- package/dist/config/index.js +3 -2
- package/dist/context/classifier.js +1 -0
- package/dist/context/pipeline.js +1 -1
- package/dist/i18n/index.js +8 -0
- package/dist/memory/graph.js +409 -0
- package/dist/memory/index.js +2 -1
- package/dist/memory/reflect.js +25 -6
- package/dist/repl/index.js +71 -5
- package/dist/sandbox/policy.js +1 -1
- package/dist/skills/activation.js +26 -0
- package/dist/skills/builtin-skills.js +5 -0
- package/dist/skills/discover.js +167 -21
- package/dist/skills/index.js +32 -7
- package/dist/skills/runner.js +191 -33
- package/dist/skills/toolmap.js +56 -0
- package/dist/skills/trust.js +134 -0
- package/dist/tools/builtins/index.js +8 -1
- package/dist/tools/builtins/memory-graph.js +118 -0
- package/dist/tools/builtins/memory-save.js +42 -5
- package/dist/tools/builtins/memory-search.js +26 -5
- package/dist/tools/builtins/run-skill.js +42 -0
- package/dist/tools/builtins/use-skill.js +43 -5
- package/dist/tools/constants.js +14 -0
- package/dist/ui/layout.js +2 -2
- package/dist/ui/theme.js +11 -11
- package/package.json +1 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { saveEntry } from '../../memory/store.js';
|
|
2
|
+
import { addTriple } from '../../memory/graph.js';
|
|
2
3
|
// ---------- memory_save ----------
|
|
3
4
|
// 存一条长期记忆(跨会话)。启动只把标题/摘要注入索引(几百 token);详情按需 memory_search 取。
|
|
4
5
|
// 撞库(name→id 已存在)拒绝,引导用 memory_update。
|
|
6
|
+
// 可选 links:把本条记忆挂进知识图谱(memory-graph.json)——src 省略时默认以记忆 name 为主实体。
|
|
5
7
|
export const memorySaveTool = {
|
|
6
8
|
name: 'memory_save',
|
|
7
|
-
description: 'Save a cross-session long-term memory entry. Store only non-obvious, useful facts/decisions/pitfalls. Title enters the startup index; retrieve body via memory_search.',
|
|
9
|
+
description: 'Save a cross-session long-term memory entry. Store only non-obvious, useful facts/decisions/pitfalls. Title enters the startup index; retrieve body via memory_search. Optionally attach knowledge-graph links (triples) to relate this memory to entities.',
|
|
8
10
|
risk: 'confirm',
|
|
9
11
|
parameters: {
|
|
10
12
|
type: 'object',
|
|
@@ -23,6 +25,20 @@ export const memorySaveTool = {
|
|
|
23
25
|
enum: ['project', 'global'],
|
|
24
26
|
description: 'Store at project level (<cwd>/.mocode/) or global (~/.mocode/), default project',
|
|
25
27
|
},
|
|
28
|
+
links: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
description: 'Optional knowledge-graph triples relating this memory to entities, e.g. [{"src":"mocode","relation":"depends_on","dst":"JSONL store"}]. src defaults to the memory name when omitted.',
|
|
31
|
+
items: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
src: { type: 'string', description: 'Source entity name (defaults to the memory name)' },
|
|
35
|
+
relation: { type: 'string', description: 'Relation, snake_case, e.g. depends_on / decided_by / conflicts_with' },
|
|
36
|
+
dst: { type: 'string', description: 'Target entity name' },
|
|
37
|
+
fact: { type: 'string', description: 'Optional one-line statement for the edge' },
|
|
38
|
+
},
|
|
39
|
+
required: ['relation', 'dst'],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
26
42
|
},
|
|
27
43
|
required: ['name', 'summary', 'body'],
|
|
28
44
|
},
|
|
@@ -37,16 +53,37 @@ export const memorySaveTool = {
|
|
|
37
53
|
if (!body)
|
|
38
54
|
return '错误:缺少 body。';
|
|
39
55
|
const type = typeof args.type === 'string' ? args.type : undefined;
|
|
56
|
+
const scope = args.scope === 'global' ? 'global' : 'project';
|
|
40
57
|
const r = saveEntry({
|
|
41
58
|
name,
|
|
42
59
|
summary,
|
|
43
60
|
body,
|
|
44
61
|
type,
|
|
45
62
|
pinned: args.pinned === true,
|
|
46
|
-
scope
|
|
63
|
+
scope,
|
|
47
64
|
});
|
|
48
|
-
if (r.ok)
|
|
49
|
-
return
|
|
50
|
-
|
|
65
|
+
if (!r.ok) {
|
|
66
|
+
return `已存在同名记忆 [${r.exists}]。改用 memory_update(id="${r.exists}", …) 更新,或换一个 name。`;
|
|
67
|
+
}
|
|
68
|
+
// 知识图谱挂边:容错——图失败不影响记忆保存结果
|
|
69
|
+
const links = Array.isArray(args.links) ? args.links : [];
|
|
70
|
+
let linked = 0;
|
|
71
|
+
for (const l of links) {
|
|
72
|
+
if (!l || typeof l !== 'object')
|
|
73
|
+
continue;
|
|
74
|
+
const link = l;
|
|
75
|
+
const tr = addTriple({
|
|
76
|
+
src: typeof link.src === 'string' && link.src.trim() ? link.src : name,
|
|
77
|
+
relation: typeof link.relation === 'string' ? link.relation : '',
|
|
78
|
+
dst: typeof link.dst === 'string' ? link.dst : '',
|
|
79
|
+
fact: typeof link.fact === 'string' ? link.fact : undefined,
|
|
80
|
+
sourceEntry: r.id,
|
|
81
|
+
scope,
|
|
82
|
+
});
|
|
83
|
+
if (tr.ok)
|
|
84
|
+
linked++;
|
|
85
|
+
}
|
|
86
|
+
const linkNote = links.length > 0 ? `;知识图谱挂边 ${linked}/${links.length}` : '';
|
|
87
|
+
return `已保存记忆 [${r.id}] "${name}"(下次启动进索引)${linkNote}。`;
|
|
51
88
|
},
|
|
52
89
|
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { searchEntries } from '../../memory/store.js';
|
|
2
|
+
import { searchGraph } from '../../memory/graph.js';
|
|
2
3
|
// ---------- memory_search ----------
|
|
3
|
-
//
|
|
4
|
+
// 唯一记忆搜索入口:关键词搜记忆正文(多词子串匹配,name 权重最高)+ 知识图谱事实段
|
|
5
|
+
// (命中实体的 active 边)。命中条目即 bump recallCount(遗忘衰减依据)。
|
|
4
6
|
// 结果走 capToolResultForHistory 的放宽上限(同 use_skill,保正文完整)。
|
|
7
|
+
const GRAPH_FACTS_LIMIT = 10;
|
|
5
8
|
export const memorySearchTool = {
|
|
6
9
|
name: 'memory_search',
|
|
7
|
-
description: 'Search memory entries by keyword (substring match), returning full body.',
|
|
10
|
+
description: 'Search memory entries by keyword (substring match), returning full body. Also surfaces knowledge-graph facts (active edges) for entities matching the query.',
|
|
8
11
|
parameters: {
|
|
9
12
|
type: 'object',
|
|
10
13
|
properties: {
|
|
@@ -33,10 +36,28 @@ export const memorySearchTool = {
|
|
|
33
36
|
: undefined,
|
|
34
37
|
limit: typeof args.limit === 'number' ? args.limit : undefined,
|
|
35
38
|
});
|
|
36
|
-
|
|
37
|
-
return `(无匹配记忆:query="${query}")`;
|
|
38
|
-
return r
|
|
39
|
+
const entryText = r
|
|
39
40
|
.map((e) => `# [${e.id}] ${e.name} (${e.type}, recalled ${e.recallCount})\nsummary: ${e.summary}\n\n${e.body}`)
|
|
40
41
|
.join('\n\n---\n\n');
|
|
42
|
+
// 知识图谱事实段:命中实体的 active 边(容错:图坏了不连累条目搜索)。
|
|
43
|
+
let graphText = '';
|
|
44
|
+
try {
|
|
45
|
+
const g = searchGraph(query, 8);
|
|
46
|
+
if (g.edges.length > 0) {
|
|
47
|
+
const lines = g.edges
|
|
48
|
+
.slice(0, GRAPH_FACTS_LIMIT)
|
|
49
|
+
.map((e) => `${e.src} --[${e.relation}]--> ${e.dst}${e.fact ? ` (${e.fact})` : ''}`);
|
|
50
|
+
const more = g.edges.length > GRAPH_FACTS_LIMIT ? `\n…(共 ${g.edges.length} 条,其余用 memory_graph action=neighbors 展开)` : '';
|
|
51
|
+
graphText = `\n\n## 知识图谱事实\n${lines.join('\n')}${more}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// 静默:图谱段是增强,失败只降级为纯条目结果
|
|
56
|
+
}
|
|
57
|
+
if (!entryText && !graphText)
|
|
58
|
+
return `(无匹配记忆:query="${query}")`;
|
|
59
|
+
if (!entryText)
|
|
60
|
+
return `(无匹配记忆条目,但图谱有命中)\n${graphText.trimStart()}`;
|
|
61
|
+
return entryText + graphText;
|
|
41
62
|
},
|
|
42
63
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { runSkill } from '../../skills/runner.js';
|
|
2
|
+
// ---------- run_skill ----------
|
|
3
|
+
// 唯一新增的常驻工具(L2-①):把某个 skill 作为隔离工作流(fork 子 agent)执行并返回摘要。
|
|
4
|
+
// 无论装 100 个还是 1000 个 skill,常驻工具表只多这 1 个。上下文 / 工具面 / 副作用 / 中断
|
|
5
|
+
// 全部由 spawnAgent 现成能力承接(设计 §3.4)。
|
|
6
|
+
export const runSkillTool = {
|
|
7
|
+
name: 'run_skill',
|
|
8
|
+
description: 'Execute a skill as an isolated workflow (forked sub-agent) and return its summary. ' +
|
|
9
|
+
'Use for skills marked [fork] in the skill list. Args are rendered into the skill body.',
|
|
10
|
+
parameters: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Name of the skill to execute (see the skill list in the system prompt).',
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
description: 'Arguments rendered into the skill body ($ARGUMENTS, $1..$9). Optional.',
|
|
20
|
+
},
|
|
21
|
+
context: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Optional extra context/facts to inject into the sub-agent (authoritative; not rediscovered).',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ['name'],
|
|
27
|
+
},
|
|
28
|
+
risk: 'confirm',
|
|
29
|
+
capabilities: {
|
|
30
|
+
effect: 'process',
|
|
31
|
+
concurrency: 'serial',
|
|
32
|
+
delegatesResourceLocks: true, // 与 sub-agent 一致:锁由内层工具取,避免父子自锁
|
|
33
|
+
supportsAbort: true,
|
|
34
|
+
},
|
|
35
|
+
async execute(args, ctx) {
|
|
36
|
+
return runSkill({
|
|
37
|
+
name: String(args.name ?? ''),
|
|
38
|
+
args: args.args,
|
|
39
|
+
context: typeof args.context === 'string' ? args.context : undefined,
|
|
40
|
+
}, ctx);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findSkill } from '../../skills/index.js';
|
|
2
|
+
import { renderSkillBody, readSkillFile } from '../../skills/runner.js';
|
|
3
|
+
import { activateSkill } from '../../skills/activation.js';
|
|
2
4
|
// ---------- use_skill ----------
|
|
3
5
|
// 模型按需加载某 skill 的 SKILL.md 正文(渐进式披露第②层)。
|
|
4
6
|
// 系统提示里已列出可用 skill 的 name + description(何时用),模型据此决定调用。
|
|
7
|
+
//
|
|
8
|
+
// 设计 §3.3 升级:
|
|
9
|
+
// - args:渲染 $ARGUMENTS / $1..$9 / ${SKILL_DIR}
|
|
10
|
+
// - file:读 skill 目录内附属文件(L2 披露,jail 约束)
|
|
11
|
+
// - context: fork 的 skill 不返回正文,改为引导调 run_skill(隔离白做才是真隔离)
|
|
12
|
+
// - inline skill 成功加载后激活会话级工具面约束(allowed/disallowed-tools)
|
|
13
|
+
const MAX_SKILL_FILE = 200_000;
|
|
5
14
|
export const useSkillTool = {
|
|
6
15
|
name: 'use_skill',
|
|
7
|
-
description: 'Load the full SKILL.md instructions for a given skill. See the skill list in the system prompt for when to use each.'
|
|
16
|
+
description: 'Load the full SKILL.md instructions for a given skill. See the skill list in the system prompt for when to use each. ' +
|
|
17
|
+
'Supports args (renders $ARGUMENTS / $1.. / ${SKILL_DIR}) and file (reads a bundled reference file). ' +
|
|
18
|
+
'For skills marked [fork], this returns a guide to call run_skill instead of loading the body inline.',
|
|
8
19
|
parameters: {
|
|
9
20
|
type: 'object',
|
|
10
21
|
properties: {
|
|
@@ -12,16 +23,43 @@ export const useSkillTool = {
|
|
|
12
23
|
type: 'string',
|
|
13
24
|
description: 'Name of the skill to load (see the skill list in the system prompt, or the /skills command)',
|
|
14
25
|
},
|
|
26
|
+
args: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
description: 'Arguments rendered into the skill body ($ARGUMENTS, $1..$9). Optional.',
|
|
29
|
+
},
|
|
30
|
+
file: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Optional bundled file inside the skill directory to read (e.g. references/api.md). Subject to jail bounds.',
|
|
33
|
+
},
|
|
15
34
|
},
|
|
16
35
|
required: ['name'],
|
|
17
36
|
},
|
|
18
|
-
async execute(args) {
|
|
37
|
+
async execute(args, ctx) {
|
|
19
38
|
const name = String(args.name ?? '').trim();
|
|
20
39
|
if (!name)
|
|
21
40
|
return '错误:缺少 skill 名。用 /skills 查看可用 skill 列表。';
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
41
|
+
const skill = findSkill(name);
|
|
42
|
+
if (!skill)
|
|
24
43
|
return `错误:未找到 skill "${name}"。用 /skills 查看可用 skill 列表。`;
|
|
44
|
+
// fork skill:不把正文读进主上下文,引导走 run_skill。
|
|
45
|
+
if (skill.context === 'fork') {
|
|
46
|
+
return (`# Skill: ${name}\n\n` +
|
|
47
|
+
`该 skill 以隔离工作流(fork)形式执行。请勿在此加载其正文——调用 ` +
|
|
48
|
+
`\`run_skill({ name: "${name}"${Object.keys(args.args ?? {}).length ? ', args: {...}' : ''} })\` ` +
|
|
49
|
+
`即可在隔离子 agent 中执行并返回摘要。`);
|
|
50
|
+
}
|
|
51
|
+
// file 优先:L2 渐进式披露
|
|
52
|
+
if (typeof args.file === 'string' && args.file.trim()) {
|
|
53
|
+
const content = readSkillFile(skill, args.file.trim(), MAX_SKILL_FILE);
|
|
54
|
+
if (content === null)
|
|
55
|
+
return `错误:无法读取 skill "${name}" 的文件 "${args.file}"(不存在 / 越界 / 过大)。`;
|
|
56
|
+
return `# Skill: ${name} · ${args.file}\n\n${content}`;
|
|
57
|
+
}
|
|
58
|
+
const body = await renderSkillBody(skill, args.args, ctx?.signal);
|
|
59
|
+
if (body === null)
|
|
60
|
+
return `错误:未找到 skill "${name}" 的正文。用 /skills 查看可用 skill 列表。`;
|
|
61
|
+
// 激活 inline skill 的工具面约束(allowed/disallowed),本轮内生效。
|
|
62
|
+
activateSkill(skill);
|
|
25
63
|
return `# Skill: ${name}\n\n${body}`;
|
|
26
64
|
},
|
|
27
65
|
};
|
package/dist/tools/constants.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** 工具共享的截断 / 上限 / 忽略规则。 */
|
|
2
2
|
import { isMemoryEnabled, isSubAgentEnabled, isFrontendToolsEnabled } from '../config/index.js';
|
|
3
|
+
import { getActiveSkill } from '../skills/activation.js';
|
|
3
4
|
export const MAX_FILE_LINES = 2000;
|
|
4
5
|
export const MAX_OUTPUT = 20000;
|
|
5
6
|
export const MAX_RESULTS = 100;
|
|
@@ -22,6 +23,11 @@ export const DECAY_DAYS = 30;
|
|
|
22
23
|
export const GC_DAYS = 90;
|
|
23
24
|
/** memory_search 结果(召回的记忆正文)的放宽上限:指令性内容,中截破坏语义,对齐 use_skill。 */
|
|
24
25
|
export const MAX_MEMORY_RESULT = 64000;
|
|
26
|
+
// ── 知识图谱层(memory-graph.json,单 scope 容量)──────────────────────────
|
|
27
|
+
/** 单 scope 实体封顶:超限先清孤儿实体(无 active 边相连),仍超则拒绝新建。 */
|
|
28
|
+
export const MAX_GRAPH_ENTITIES = 500;
|
|
29
|
+
/** 单 scope 边封顶:超限先清已失效边,仍超则拒绝新边。 */
|
|
30
|
+
export const MAX_GRAPH_EDGES = 2000;
|
|
25
31
|
// .codegraph:codegraph 索引目录(codegraph.db 是 SQLite 二进制 + daemon.log),
|
|
26
32
|
// grep/glob 扫它无意义且会产出数 KB 的超长「行」,污染 TUI 展开渲染。
|
|
27
33
|
export const IGNORE = ['**/node_modules/**', '**/.git/**', '**/.codegraph/**'];
|
|
@@ -55,7 +61,9 @@ export const PLAN_DISABLED_TOOLS = new Set([
|
|
|
55
61
|
'memory_save',
|
|
56
62
|
'memory_update',
|
|
57
63
|
'memory_forget',
|
|
64
|
+
'memory_graph', // 混合工具(add 写图),plan 只读模式整体屏蔽
|
|
58
65
|
'sub-agent',
|
|
66
|
+
'run_skill', // fork 子 agent 执行面;plan 模式不应派生子工作流
|
|
59
67
|
]);
|
|
60
68
|
/**
|
|
61
69
|
* 按当前 isMemoryEnabled() 现算 plan 模式应屏蔽的工具。
|
|
@@ -89,5 +97,11 @@ export function getRuntimeDisabledTools() {
|
|
|
89
97
|
for (const name of FRONTEND_TOOLS)
|
|
90
98
|
disabled.add(name);
|
|
91
99
|
}
|
|
100
|
+
// inline skill 激活态的 disallowed-tools:即便模型幻觉调用也执行不了(设计 §3.6)。
|
|
101
|
+
const active = getActiveSkill();
|
|
102
|
+
if (active?.disallowed) {
|
|
103
|
+
for (const name of active.disallowed)
|
|
104
|
+
disabled.add(name);
|
|
105
|
+
}
|
|
92
106
|
return disabled;
|
|
93
107
|
}
|
package/dist/ui/layout.js
CHANGED
|
@@ -1361,8 +1361,8 @@ function composeSpinnerLine(status, cols) {
|
|
|
1361
1361
|
leadW = 1 + 1 + displayWidth(status.status) + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
|
1362
1362
|
}
|
|
1363
1363
|
else if (spinning) {
|
|
1364
|
-
// 运行态心跳帧(流式输出中):帧 +
|
|
1365
|
-
const label = '生成中';
|
|
1364
|
+
// 运行态心跳帧(流式输出中 / 命令态如 /rollback /compact /resume):帧 + 状态文字(优先)或生成中(兜底) + 走时
|
|
1365
|
+
const label = status.status || '生成中';
|
|
1366
1366
|
const ePart = elapsed ? ` ${ui.dim}${elapsed}${ui.reset}` : '';
|
|
1367
1367
|
lead = `${ui.bold}${ui.accent}${RUNNING_FRAMES[runningFrame]}${ui.reset} ${ui.dim}${label}${ui.reset}${ePart}`;
|
|
1368
1368
|
leadW = 1 + 1 + displayWidth(label) + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
package/dist/ui/theme.js
CHANGED
|
@@ -29,7 +29,7 @@ const DEFAULT = {
|
|
|
29
29
|
brightCyan: '\x1B[38;2;86;182;194m',
|
|
30
30
|
brightMagenta: '\x1B[38;2;198;120;221m',
|
|
31
31
|
accent: '\x1B[38;2;86;182;194m', // 与 cyan 同源(One Dark):logo/标题/输入框顶线/选中项统一承载
|
|
32
|
-
userBg: '\x1B[48;2;
|
|
32
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
33
33
|
// diff 行底色:One Dark bg #282c34 上加 ~14% 亮度的对应色,够辨识但不刺眼
|
|
34
34
|
addBg: '\x1B[48;2;44;62;42m', // 偏暗绿(One Dark green(152,195,121)暗化)
|
|
35
35
|
delBg: '\x1B[48;2;62;38;42m', // 偏暗红(One Dark red(224,108,117)暗化)
|
|
@@ -54,7 +54,7 @@ const THEMES = {
|
|
|
54
54
|
brightCyan: '\x1B[38;2;42;161;152m',
|
|
55
55
|
brightMagenta: '\x1B[38;2;108;113;196m',
|
|
56
56
|
accent: '\x1B[38;2;38;139;210m', // Solarized blue:浅底下更醒目的强调
|
|
57
|
-
userBg: '\x1B[48;2;
|
|
57
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
58
58
|
// diff 行底色:Solarized Light base2(238,232,213)上贴同色族浅 tint,
|
|
59
59
|
// 比直接用 base1 更柔,跟深 fg(red/green)对比充足
|
|
60
60
|
addBg: '\x1B[48;2;220;235;205m',
|
|
@@ -72,7 +72,7 @@ const THEMES = {
|
|
|
72
72
|
brightCyan: '\x1B[38;2;147;161;161m',
|
|
73
73
|
brightMagenta: '\x1B[38;2;108;113;196m',
|
|
74
74
|
accent: '\x1B[38;2;42;161;152m', // Solarized cyan(深底版):暗底上跳出
|
|
75
|
-
userBg: '\x1B[48;2;
|
|
75
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
76
76
|
// diff 行底色:Solarized Dark base03(0,43,54)上加对应色族暗 tint
|
|
77
77
|
addBg: '\x1B[48;2;20;50;38m',
|
|
78
78
|
delBg: '\x1B[48;2;55;30;30m',
|
|
@@ -89,7 +89,7 @@ const THEMES = {
|
|
|
89
89
|
brightCyan: '\x1B[38;2;142;192;124m',
|
|
90
90
|
brightMagenta: '\x1B[38;2;211;134;155m',
|
|
91
91
|
accent: '\x1B[38;2;250;189;47m', // Gruvbox yellow(主题色)
|
|
92
|
-
userBg: '\x1B[48;2;
|
|
92
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
93
93
|
// diff 行底色:Gruvbox dark bg(40,40,40)上贴暗 bg0_a 风格
|
|
94
94
|
addBg: '\x1B[48;2;40;55;30m',
|
|
95
95
|
delBg: '\x1B[48;2;70;35;30m',
|
|
@@ -106,7 +106,7 @@ const THEMES = {
|
|
|
106
106
|
brightCyan: '\x1B[38;2;136;192;208m',
|
|
107
107
|
brightMagenta: '\x1B[38;2;180;142;173m',
|
|
108
108
|
accent: '\x1B[38;2;136;192;208m', // Nord 浅冰蓝(主题色)
|
|
109
|
-
userBg: '\x1B[48;2;
|
|
109
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
110
110
|
// diff 行底色:Nord polar night(46,52,64)上贴对应色族暗 tint
|
|
111
111
|
addBg: '\x1B[48;2;46;66;52m',
|
|
112
112
|
delBg: '\x1B[48;2;72;46;52m',
|
|
@@ -126,7 +126,7 @@ const THEMES = {
|
|
|
126
126
|
brightCyan: '\x1B[38;2;160;220;220m',
|
|
127
127
|
brightMagenta: '\x1B[38;2;245;165;215m',
|
|
128
128
|
accent: '\x1B[38;2;255;170;60m', // 南瓜橙(主题主色:logo/标题/输入框顶线/选中项)
|
|
129
|
-
userBg: '\x1B[48;2;
|
|
129
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
130
130
|
// diff 行底色:暖深棕底上贴对应色族暗 tint,跟 fg 配对柔和可辨
|
|
131
131
|
addBg: '\x1B[48;2;55;70;35m',
|
|
132
132
|
delBg: '\x1B[48;2;78;42;32m',
|
|
@@ -145,7 +145,7 @@ const THEMES = {
|
|
|
145
145
|
brightCyan: '\x1B[38;2;170;220;220m',
|
|
146
146
|
brightMagenta: '\x1B[38;2;250;160;200m',
|
|
147
147
|
accent: '\x1B[38;2;230;90;150m', // 玫粉(主题主色)
|
|
148
|
-
userBg: '\x1B[48;2;
|
|
148
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
149
149
|
// diff 行底色:深紫底贴对应色族暗 tint,绿暗化偏橄榄、红暗化偏紫红
|
|
150
150
|
addBg: '\x1B[48;2;50;60;42m',
|
|
151
151
|
delBg: '\x1B[48;2;75;40;52m',
|
|
@@ -164,7 +164,7 @@ const THEMES = {
|
|
|
164
164
|
brightCyan: '\x1B[38;2;140;230;210m',
|
|
165
165
|
brightMagenta: '\x1B[38;2;210;170;230m',
|
|
166
166
|
accent: '\x1B[38;2;80;210;140m', // 翡翠绿(主题主色)
|
|
167
|
-
userBg: '\x1B[48;2;
|
|
167
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
168
168
|
// diff 行底色:深绿底贴对应色族暗 tint,绿暗化偏深绿、红暗化偏暗红
|
|
169
169
|
addBg: '\x1B[48;2;30;55;40m',
|
|
170
170
|
delBg: '\x1B[48;2;60;40;40m',
|
|
@@ -183,7 +183,7 @@ const THEMES = {
|
|
|
183
183
|
brightCyan: '\x1B[38;2;170;210;200m',
|
|
184
184
|
brightMagenta: '\x1B[38;2;240;180;210m',
|
|
185
185
|
accent: '\x1B[38;2;255;200;80m', // 琥珀金黄(主题主色)
|
|
186
|
-
userBg: '\x1B[48;2;
|
|
186
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
187
187
|
// diff 行底色:深棕底贴对应色族暗 tint,绿暗化偏橄榄、红暗化偏暗棕红
|
|
188
188
|
addBg: '\x1B[48;2;50;55;25m',
|
|
189
189
|
delBg: '\x1B[48;2;70;40;28m',
|
|
@@ -202,7 +202,7 @@ const THEMES = {
|
|
|
202
202
|
brightCyan: '\x1B[38;2;180;230;230m',
|
|
203
203
|
brightMagenta: '\x1B[38;2;210;180;250m',
|
|
204
204
|
accent: '\x1B[38;2;180;150;230m', // 薰衣草紫(主题主色)
|
|
205
|
-
userBg: '\x1B[48;2;
|
|
205
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
206
206
|
// diff 行底色:深紫底贴对应色族暗 tint,绿暗化偏冷绿、红暗化偏冷紫红
|
|
207
207
|
addBg: '\x1B[48;2;38;46;42m',
|
|
208
208
|
delBg: '\x1B[48;2;60;40;55m',
|
|
@@ -221,7 +221,7 @@ const THEMES = {
|
|
|
221
221
|
brightCyan: '\x1B[38;2;170;225;215m',
|
|
222
222
|
brightMagenta: '\x1B[38;2;250;170;210m',
|
|
223
223
|
accent: '\x1B[38;2;255;120;100m', // 珊瑚红(主题主色)
|
|
224
|
-
userBg: '\x1B[48;2;
|
|
224
|
+
userBg: '\x1B[48;2;72;78;90m', // 统一灰白用户消息底(黑底终端可见)
|
|
225
225
|
// diff 行底色:深棕红底贴对应色族暗 tint,绿暗化偏橄榄、红暗化偏暗棕红
|
|
226
226
|
addBg: '\x1B[48;2;50;55;30m',
|
|
227
227
|
delBg: '\x1B[48;2;75;32;30m',
|