@xcanwin/manyoyo 8.6.7 → 8.6.9
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/bin/manyoyo.js +1 -0
- package/lib/agent-instructions.js +50 -0
- package/lib/plugin/playwright.js +4 -2
- package/lib/setup-config.js +6 -1
- package/lib/web/AGENTS.md +5 -0
- package/lib/web/git-changes.js +130 -0
- package/lib/web/index.html +86 -80
- package/lib/web/server.js +383 -28
- package/lib/web/session-meta.js +117 -0
- package/manyoyo.example.json +2 -0
- package/package.json +2 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// 会话的展示信息(标题、首条消息、斜杠命令列表):来自容器里 Agent 自己写的文件或输出,
|
|
4
|
+
// 都按不可信文本处理——只保留可打印字符、限制长度,前端一律当纯文本显示。
|
|
5
|
+
|
|
6
|
+
const TITLE_MAX_CHARS = 60;
|
|
7
|
+
const FIRST_PROMPT_MAX_CHARS = 80;
|
|
8
|
+
// 只读会话文件尾部:标题记录在 Claude 每轮结束时追加,读尾部就够了,文件再大也不慢
|
|
9
|
+
const TITLE_TAIL_BYTES = 256 * 1024;
|
|
10
|
+
const SLASH_COMMAND_PATTERN = /^[A-Za-z0-9:_.-]{1,64}$/;
|
|
11
|
+
const SLASH_COMMANDS_MAX = 200;
|
|
12
|
+
const CLAUDE_SESSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
13
|
+
|
|
14
|
+
function toDisplayText(value, maxChars) {
|
|
15
|
+
if (typeof value !== 'string') {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
const text = value
|
|
19
|
+
.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069]/g, ' ')
|
|
20
|
+
.replace(/\s+/g, ' ')
|
|
21
|
+
.trim();
|
|
22
|
+
return Array.from(text).slice(0, maxChars).join('');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeTitle(value) {
|
|
26
|
+
return toDisplayText(value, TITLE_MAX_CHARS);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function normalizeFirstPrompt(value) {
|
|
30
|
+
return toDisplayText(value, FIRST_PROMPT_MAX_CHARS);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizeSlashCommands(value) {
|
|
34
|
+
if (!Array.isArray(value)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const seen = new Set();
|
|
38
|
+
const result = [];
|
|
39
|
+
for (const item of value) {
|
|
40
|
+
const name = typeof item === 'string' ? item.replace(/^\//, '') : '';
|
|
41
|
+
if (!SLASH_COMMAND_PATTERN.test(name) || seen.has(name)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
seen.add(name);
|
|
45
|
+
result.push(name);
|
|
46
|
+
if (result.length >= SLASH_COMMANDS_MAX) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isClaudeSessionId(value) {
|
|
54
|
+
return typeof value === 'string' && CLAUDE_SESSION_ID_PATTERN.test(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 在容器里执行的只读命令:找到这个会话的 jsonl,只读尾部,只留标题类记录。
|
|
58
|
+
// ai-title 是 claude 交互模式自动生成的(-p 下实测不生成);custom-title 是 /rename 写的,优先
|
|
59
|
+
// session id 已按 UUID 格式校验,拼进命令前不需要再转义
|
|
60
|
+
function buildClaudeTitleReadCommand(sessionId) {
|
|
61
|
+
if (!isClaudeSessionId(sessionId)) {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
return [
|
|
65
|
+
`for f in "\${CLAUDE_CONFIG_DIR:-$HOME/.claude}"/projects/*/${sessionId}.jsonl; do`,
|
|
66
|
+
`[ -f "$f" ] && tail -c ${TITLE_TAIL_BYTES} "$f" | grep -E '"type":"(ai-title|custom-title)"' | tail -n 20;`,
|
|
67
|
+
'break; done'
|
|
68
|
+
].join(' ');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function parseClaudeTitleOutput(output) {
|
|
72
|
+
const lines = String(output || '').split('\n').map(line => line.trim()).filter(Boolean);
|
|
73
|
+
let custom = '';
|
|
74
|
+
let generated = '';
|
|
75
|
+
for (const line of lines) {
|
|
76
|
+
try {
|
|
77
|
+
const record = JSON.parse(line);
|
|
78
|
+
if (record && record.type === 'custom-title') {
|
|
79
|
+
custom = normalizeTitle(record.customTitle) || custom;
|
|
80
|
+
} else if (record && record.type === 'ai-title') {
|
|
81
|
+
generated = normalizeTitle(record.aiTitle) || generated;
|
|
82
|
+
}
|
|
83
|
+
} catch (e) {
|
|
84
|
+
// 尾部第一行可能被截断,跳过
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return custom || generated;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 在 claude -p(Web 端的执行方式)下实测有用的内置命令(2026-10-19,claude 2.1.290):
|
|
91
|
+
// context / usage / recap / mcp / list-agents / rename 都返回了正常结果。不列的:compact(-p 下没有压缩,
|
|
92
|
+
// 输出和 usage 一样)、agents(已移除)、insights(报告写在容器里的 file:// 地址,网页打不开)、
|
|
93
|
+
// model / effort / goal(只影响这一次进程,网页里换模型用模型菜单)、clear / init 等改状态的没测,宁缺毋滥。
|
|
94
|
+
// skill 类命令会展开成提示词,实测可用
|
|
95
|
+
const HEADLESS_BUILTIN_COMMANDS = new Set(['context', 'usage', 'recap', 'mcp', 'list-agents', 'rename']);
|
|
96
|
+
|
|
97
|
+
function listUsableSlashCommands(stored) {
|
|
98
|
+
if (!stored || !Array.isArray(stored.all)) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
const skills = new Set(stored.skills || []);
|
|
102
|
+
const terminal = new Set(stored.terminal || []);
|
|
103
|
+
return stored.all.filter(name => !terminal.has(name) && (skills.has(name) || HEADLESS_BUILTIN_COMMANDS.has(name)));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
HEADLESS_BUILTIN_COMMANDS,
|
|
108
|
+
listUsableSlashCommands,
|
|
109
|
+
TITLE_MAX_CHARS,
|
|
110
|
+
FIRST_PROMPT_MAX_CHARS,
|
|
111
|
+
normalizeTitle,
|
|
112
|
+
normalizeFirstPrompt,
|
|
113
|
+
normalizeSlashCommands,
|
|
114
|
+
isClaudeSessionId,
|
|
115
|
+
buildClaudeTitleReadCommand,
|
|
116
|
+
parseClaudeTitleOutput
|
|
117
|
+
};
|
package/manyoyo.example.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcanwin/manyoyo",
|
|
3
|
-
"version": "8.6.
|
|
3
|
+
"version": "8.6.9",
|
|
4
4
|
"imageVersion": "2.2.0-common",
|
|
5
5
|
"playwrightCliVersion": "0.1.19",
|
|
6
6
|
"patchrightCoreVersion": "1.63.0",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"test": "jest --coverage && npm run test:web",
|
|
46
46
|
"test:unit": "jest test/ --testPathIgnorePatterns '<rootDir>/temp/' '<rootDir>/.claude/' '<rootDir>/test/integration/' && npm run test:web",
|
|
47
47
|
"test:integration": "jest test/integration/ --runInBand",
|
|
48
|
+
"test:experience": "jest test/integration/web-chat-experience.test.js --runInBand",
|
|
48
49
|
"test:installer": "jest test/installer.test.js",
|
|
49
50
|
"lint:sh": "command -v shellcheck >/dev/null 2>&1 || { echo '未安装 shellcheck:macOS 用 brew install shellcheck,Debian/Ubuntu 用 sudo apt install shellcheck,或用 docker run --rm -v \"$PWD:/mnt\" -w /mnt koalaman/shellcheck:stable scripts/install.sh scripts/offline/*.sh' >&2; exit 1; } && shellcheck -s sh -x -e SC1091 scripts/install.sh scripts/offline/*.sh",
|
|
50
51
|
"docs:dev": "vitepress dev docs --host 127.0.0.1 --port 5173",
|