@xcanwin/manyoyo 5.4.6 → 5.4.12
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/README.md +3 -3
- package/bin/manyoyo.js +10 -2
- package/docker/manyoyo.Dockerfile +10 -12
- package/docker/res/playwright/playwright-cli-wrapper.sh +82 -0
- package/lib/global-config.js +228 -1
- package/lib/plugin/playwright.js +43 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ AI Agent CLI 往往需要:
|
|
|
53
53
|
```bash
|
|
54
54
|
npm install -g @xcanwin/manyoyo
|
|
55
55
|
podman pull ubuntu:24.04 # 仅 Podman 需要
|
|
56
|
-
manyoyo build --iv 1.8.
|
|
56
|
+
manyoyo build --iv 1.8.12-common
|
|
57
57
|
manyoyo init all
|
|
58
58
|
manyoyo run -r claude
|
|
59
59
|
```
|
|
@@ -137,10 +137,10 @@ manyoyo config command
|
|
|
137
137
|
|
|
138
138
|
```bash
|
|
139
139
|
# common 版本
|
|
140
|
-
manyoyo build --iv 1.8.
|
|
140
|
+
manyoyo build --iv 1.8.12-common
|
|
141
141
|
|
|
142
142
|
# full 版本
|
|
143
|
-
manyoyo build --iv 1.8.
|
|
143
|
+
manyoyo build --iv 1.8.12-full
|
|
144
144
|
|
|
145
145
|
# 自定义工具集
|
|
146
146
|
manyoyo build --iba TOOL=go,codex,java,gemini
|
package/bin/manyoyo.js
CHANGED
|
@@ -1071,6 +1071,14 @@ async function setupCommander() {
|
|
|
1071
1071
|
host: options.host || ''
|
|
1072
1072
|
}, options));
|
|
1073
1073
|
|
|
1074
|
+
command.command('cli-add')
|
|
1075
|
+
.description('输出 playwright-cli skill 安装命令')
|
|
1076
|
+
.action(() => selectPluginAction({
|
|
1077
|
+
action: 'cli-add',
|
|
1078
|
+
pluginName: 'playwright',
|
|
1079
|
+
scene: 'all'
|
|
1080
|
+
}));
|
|
1081
|
+
|
|
1074
1082
|
command.command('ext-download')
|
|
1075
1083
|
.description('下载并解压 Playwright 扩展到 ~/.manyoyo/plugin/playwright/extensions/')
|
|
1076
1084
|
.option('--prodversion <ver>', 'CRX 下载使用的 Chrome 版本号 (默认 132.0.0.0)')
|
|
@@ -1109,8 +1117,8 @@ async function setupCommander() {
|
|
|
1109
1117
|
${MANYOYO_NAME} serve 127.0.0.1:3000 启动本机网页服务
|
|
1110
1118
|
${MANYOYO_NAME} serve 127.0.0.1:3000 -d 后台启动;未设密码时会打印本次随机密码
|
|
1111
1119
|
${MANYOYO_NAME} serve 0.0.0.0:3000 -U admin -P 123 -d 后台启动并监听全部网卡
|
|
1112
|
-
${MANYOYO_NAME} playwright up mcp-host-headless
|
|
1113
|
-
${MANYOYO_NAME}
|
|
1120
|
+
${MANYOYO_NAME} playwright up mcp-host-headless 启动 playwright MCP 宿主场景(默认/推荐)
|
|
1121
|
+
${MANYOYO_NAME} playwright up cli-host-headless 启动 playwright CLI 宿主场景(供容器内 playwright-cli 附着)
|
|
1114
1122
|
${MANYOYO_NAME} run -n test -q tip -q cmd 多次使用静默选项
|
|
1115
1123
|
`);
|
|
1116
1124
|
|
|
@@ -127,6 +127,7 @@ EOX
|
|
|
127
127
|
|
|
128
128
|
# 从 cache-stage 复制 Node.js(缓存或下载)
|
|
129
129
|
COPY --from=cache-stage /opt/node /usr/local
|
|
130
|
+
COPY ./package.json /tmp/manyoyo-package.json
|
|
130
131
|
COPY ./docker/res/playwright/cli-cont-headless.init.js /app/config/cli-cont-headless.init.js
|
|
131
132
|
COPY ./docker/res/playwright/cli-cont-headless.json /app/config/cli-cont-headless.json
|
|
132
133
|
COPY ./docker/res/ /tmp/docker-res/
|
|
@@ -202,22 +203,15 @@ RUN <<EOX
|
|
|
202
203
|
;; esac
|
|
203
204
|
|
|
204
205
|
# 安装 Playwright CLI skills(不在镜像构建阶段下载浏览器)
|
|
205
|
-
|
|
206
|
+
PLAYWRIGHT_CLI_VERSION=$(node -p "const pkg = require('/tmp/manyoyo-package.json'); const value = String(pkg.playwrightCliVersion || '').trim(); if (!value) { throw new Error('package.json.playwrightCliVersion is required'); } value")
|
|
207
|
+
npm install -g "@playwright/cli@${PLAYWRIGHT_CLI_VERSION}"
|
|
206
208
|
PLAYWRIGHT_CLI_INSTALL_DIR=/tmp/playwright-cli-install
|
|
207
209
|
mkdir -p "${PLAYWRIGHT_CLI_INSTALL_DIR}/.playwright"
|
|
208
|
-
|
|
209
|
-
{
|
|
210
|
-
"browser": {
|
|
211
|
-
"browserName": "chromium",
|
|
212
|
-
"launchOptions": {
|
|
213
|
-
"channel": "chrome"
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
EOF
|
|
210
|
+
echo '{"browser":{"browserName":"chromium","launchOptions":{"channel":"chromium"}}}' > "${PLAYWRIGHT_CLI_INSTALL_DIR}/.playwright/cli.config.json"
|
|
218
211
|
cd "${PLAYWRIGHT_CLI_INSTALL_DIR}"
|
|
219
|
-
playwright-cli install --skills
|
|
212
|
+
playwright-cli --config="${PLAYWRIGHT_CLI_INSTALL_DIR}/.playwright/cli.config.json" install --skills
|
|
220
213
|
mkdir -p "$HOME/.codex/skills/playwright-cli" ~/.gemini/skills/playwright-cli
|
|
214
|
+
cp -R "${PLAYWRIGHT_CLI_INSTALL_DIR}/.claude/skills/playwright-cli/." "$HOME/.claude/skills/playwright-cli/"
|
|
221
215
|
cp -R "${PLAYWRIGHT_CLI_INSTALL_DIR}/.claude/skills/playwright-cli/." "$HOME/.codex/skills/playwright-cli/"
|
|
222
216
|
cp -R "${PLAYWRIGHT_CLI_INSTALL_DIR}/.claude/skills/playwright-cli/." "$HOME/.gemini/skills/playwright-cli/"
|
|
223
217
|
cd $OLDPWD
|
|
@@ -225,9 +219,13 @@ EOF
|
|
|
225
219
|
|
|
226
220
|
# 清理
|
|
227
221
|
npm cache clean --force
|
|
222
|
+
rm -f /tmp/manyoyo-package.json
|
|
228
223
|
rm -rf /tmp/* /var/tmp/* /var/log/apt /var/log/*.log /var/lib/apt/lists/* ~/.npm ~/go/pkg/mod/cache
|
|
229
224
|
EOX
|
|
230
225
|
|
|
226
|
+
COPY ./docker/res/playwright/playwright-cli-wrapper.sh /usr/local/bin/playwright-cli
|
|
227
|
+
RUN chmod +x /usr/local/bin/playwright-cli
|
|
228
|
+
|
|
231
229
|
# 从 cache-stage 复制 JDT LSP(缓存或下载)
|
|
232
230
|
COPY --from=cache-stage /opt/jdtls /tmp/jdtls-cache
|
|
233
231
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
PLAYWRIGHT_NODE_BIN="${PLAYWRIGHT_NODE_BIN:-node}"
|
|
5
|
+
PLAYWRIGHT_CLI_ROOT="/usr/local/lib/node_modules/@playwright/cli/node_modules/playwright"
|
|
6
|
+
PLAYWRIGHT_CLI_PROGRAM="${PLAYWRIGHT_CLI_ROOT}/lib/cli/client/program.js"
|
|
7
|
+
PLAYWRIGHT_REAL_CLI="${PLAYWRIGHT_CLI_ROOT}/cli.js"
|
|
8
|
+
|
|
9
|
+
resolve_browser() {
|
|
10
|
+
browser=""
|
|
11
|
+
|
|
12
|
+
while [ "$#" -gt 0 ]; do
|
|
13
|
+
case "$1" in
|
|
14
|
+
--browser=*)
|
|
15
|
+
browser="${1#--browser=}"
|
|
16
|
+
;;
|
|
17
|
+
--browser)
|
|
18
|
+
shift
|
|
19
|
+
if [ "$#" -gt 0 ]; then
|
|
20
|
+
browser="$1"
|
|
21
|
+
shift
|
|
22
|
+
fi
|
|
23
|
+
continue
|
|
24
|
+
;;
|
|
25
|
+
--)
|
|
26
|
+
break
|
|
27
|
+
;;
|
|
28
|
+
-*)
|
|
29
|
+
;;
|
|
30
|
+
*)
|
|
31
|
+
if [ -z "$browser" ]; then
|
|
32
|
+
browser="$1"
|
|
33
|
+
fi
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
shift
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
if [ -n "$browser" ]; then
|
|
40
|
+
printf '%s\n' "$browser"
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
"$PLAYWRIGHT_NODE_BIN" <<'NODE'
|
|
45
|
+
const fs = require('fs');
|
|
46
|
+
const path = require('path');
|
|
47
|
+
|
|
48
|
+
const candidates = [
|
|
49
|
+
process.env.PLAYWRIGHT_MCP_CONFIG,
|
|
50
|
+
path.resolve('.playwright/cli.config.json')
|
|
51
|
+
].filter(Boolean);
|
|
52
|
+
|
|
53
|
+
for (const filePath of candidates) {
|
|
54
|
+
try {
|
|
55
|
+
const config = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
56
|
+
const browser = config && config.browser ? config.browser : {};
|
|
57
|
+
const launchOptions = browser.launchOptions || {};
|
|
58
|
+
const channel = String(launchOptions.channel || browser.browserName || '').trim();
|
|
59
|
+
if (channel) {
|
|
60
|
+
process.stdout.write(channel);
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
} catch (_) {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
process.stdout.write('chromium');
|
|
67
|
+
NODE
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if [ "${1-}" = "install-browser" ]; then
|
|
71
|
+
shift
|
|
72
|
+
for arg in "$@"; do
|
|
73
|
+
if [ "$arg" = "--help" ] || [ "$arg" = "-h" ]; then
|
|
74
|
+
exec "$PLAYWRIGHT_NODE_BIN" "$PLAYWRIGHT_CLI_PROGRAM" install-browser "$@"
|
|
75
|
+
fi
|
|
76
|
+
done
|
|
77
|
+
|
|
78
|
+
BROWSER="$(resolve_browser "$@")"
|
|
79
|
+
exec "$PLAYWRIGHT_NODE_BIN" "$PLAYWRIGHT_REAL_CLI" install "$BROWSER"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
exec "$PLAYWRIGHT_NODE_BIN" "$PLAYWRIGHT_CLI_PROGRAM" "$@"
|
package/lib/global-config.js
CHANGED
|
@@ -36,6 +36,223 @@ function readManyoyoConfig(homeDir = os.homedir()) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function readQuotedString(text, startIndex) {
|
|
40
|
+
const quote = text[startIndex];
|
|
41
|
+
let value = '';
|
|
42
|
+
|
|
43
|
+
for (let i = startIndex + 1; i < text.length; i += 1) {
|
|
44
|
+
const ch = text[i];
|
|
45
|
+
if (ch === '\\') {
|
|
46
|
+
value += ch;
|
|
47
|
+
if (i + 1 < text.length) {
|
|
48
|
+
value += text[i + 1];
|
|
49
|
+
i += 1;
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (ch === quote) {
|
|
54
|
+
return {
|
|
55
|
+
value,
|
|
56
|
+
end: i + 1
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
value += ch;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isIdentifierStart(ch) {
|
|
66
|
+
return /[A-Za-z_$]/.test(ch);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isIdentifierPart(ch) {
|
|
70
|
+
return /[A-Za-z0-9_$]/.test(ch);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function skipWhitespace(text, index) {
|
|
74
|
+
let i = index;
|
|
75
|
+
while (i < text.length && /\s/.test(text[i])) {
|
|
76
|
+
i += 1;
|
|
77
|
+
}
|
|
78
|
+
return i;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function findTopLevelPropertyValueRange(text, propertyName) {
|
|
82
|
+
let depth = 0;
|
|
83
|
+
let inString = '';
|
|
84
|
+
let inLineComment = false;
|
|
85
|
+
let inBlockComment = false;
|
|
86
|
+
|
|
87
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
88
|
+
const ch = text[i];
|
|
89
|
+
const next = text[i + 1];
|
|
90
|
+
|
|
91
|
+
if (inLineComment) {
|
|
92
|
+
if (ch === '\n') inLineComment = false;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (inBlockComment) {
|
|
96
|
+
if (ch === '*' && next === '/') {
|
|
97
|
+
inBlockComment = false;
|
|
98
|
+
i += 1;
|
|
99
|
+
}
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (inString) {
|
|
103
|
+
if (ch === '\\') {
|
|
104
|
+
i += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (ch === inString) inString = '';
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (ch === '/' && next === '/') {
|
|
112
|
+
inLineComment = true;
|
|
113
|
+
i += 1;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (ch === '/' && next === '*') {
|
|
117
|
+
inBlockComment = true;
|
|
118
|
+
i += 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (depth === 1 && !/\s|,/.test(ch)) {
|
|
122
|
+
let property = '';
|
|
123
|
+
let cursor = i;
|
|
124
|
+
if (ch === '"' || ch === '\'') {
|
|
125
|
+
const token = readQuotedString(text, i);
|
|
126
|
+
if (!token) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
property = token.value;
|
|
130
|
+
cursor = token.end;
|
|
131
|
+
} else if (isIdentifierStart(ch)) {
|
|
132
|
+
cursor = i + 1;
|
|
133
|
+
while (cursor < text.length && isIdentifierPart(text[cursor])) {
|
|
134
|
+
cursor += 1;
|
|
135
|
+
}
|
|
136
|
+
property = text.slice(i, cursor);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (property) {
|
|
140
|
+
const colonIndex = skipWhitespace(text, cursor);
|
|
141
|
+
if (text[colonIndex] === ':') {
|
|
142
|
+
if (property !== propertyName) {
|
|
143
|
+
i = colonIndex;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let valueStart = skipWhitespace(text, colonIndex + 1);
|
|
148
|
+
let valueEnd = valueStart;
|
|
149
|
+
let valueString = '';
|
|
150
|
+
let valueLineComment = false;
|
|
151
|
+
let valueBlockComment = false;
|
|
152
|
+
let valueDepth = 0;
|
|
153
|
+
|
|
154
|
+
for (; valueEnd < text.length; valueEnd += 1) {
|
|
155
|
+
const valueCh = text[valueEnd];
|
|
156
|
+
const valueNext = text[valueEnd + 1];
|
|
157
|
+
|
|
158
|
+
if (valueLineComment) {
|
|
159
|
+
if (valueCh === '\n') valueLineComment = false;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (valueBlockComment) {
|
|
163
|
+
if (valueCh === '*' && valueNext === '/') {
|
|
164
|
+
valueBlockComment = false;
|
|
165
|
+
valueEnd += 1;
|
|
166
|
+
}
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (valueString) {
|
|
170
|
+
if (valueCh === '\\') {
|
|
171
|
+
valueEnd += 1;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (valueCh === valueString) valueString = '';
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (valueCh === '/' && valueNext === '/') {
|
|
179
|
+
valueLineComment = true;
|
|
180
|
+
valueEnd += 1;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (valueCh === '/' && valueNext === '*') {
|
|
184
|
+
valueBlockComment = true;
|
|
185
|
+
valueEnd += 1;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (valueCh === '"' || valueCh === '\'') {
|
|
189
|
+
valueString = valueCh;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (valueCh === '{' || valueCh === '[' || valueCh === '(') {
|
|
193
|
+
valueDepth += 1;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (valueCh === '}' || valueCh === ']' || valueCh === ')') {
|
|
197
|
+
if (valueDepth === 0) {
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
valueDepth -= 1;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (valueDepth === 0 && valueCh === ',') {
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
while (valueEnd > valueStart && /\s/.test(text[valueEnd - 1])) {
|
|
209
|
+
valueEnd -= 1;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
start: valueStart,
|
|
214
|
+
end: valueEnd
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (ch === '"' || ch === '\'') {
|
|
221
|
+
inString = ch;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (ch === '{' || ch === '[') {
|
|
225
|
+
depth += 1;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (ch === '}' || ch === ']') {
|
|
229
|
+
depth -= 1;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function insertTopLevelImageVersion(text, imageVersion) {
|
|
238
|
+
const openBraceIndex = text.indexOf('{');
|
|
239
|
+
if (openBraceIndex === -1) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const newlineIndex = text.indexOf('\n', openBraceIndex);
|
|
244
|
+
const insertIndex = newlineIndex === -1 ? openBraceIndex + 1 : newlineIndex + 1;
|
|
245
|
+
return `${text.slice(0, insertIndex)} imageVersion: ${JSON.stringify(imageVersion)},\n${text.slice(insertIndex)}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function updateImageVersionText(text, imageVersion) {
|
|
249
|
+
const range = findTopLevelPropertyValueRange(text, 'imageVersion');
|
|
250
|
+
if (range) {
|
|
251
|
+
return `${text.slice(0, range.start)}${JSON.stringify(imageVersion)}${text.slice(range.end)}`;
|
|
252
|
+
}
|
|
253
|
+
return insertTopLevelImageVersion(text, imageVersion);
|
|
254
|
+
}
|
|
255
|
+
|
|
39
256
|
function syncGlobalImageVersion(imageVersion, options = {}) {
|
|
40
257
|
const homeDir = options.homeDir || os.homedir();
|
|
41
258
|
const result = readManyoyoConfig(homeDir);
|
|
@@ -72,7 +289,17 @@ function syncGlobalImageVersion(imageVersion, options = {}) {
|
|
|
72
289
|
};
|
|
73
290
|
|
|
74
291
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
75
|
-
|
|
292
|
+
if (result.exists) {
|
|
293
|
+
const currentText = fs.readFileSync(configPath, 'utf-8');
|
|
294
|
+
const updatedText = updateImageVersionText(currentText, imageVersion);
|
|
295
|
+
if (updatedText) {
|
|
296
|
+
fs.writeFileSync(configPath, updatedText.endsWith('\n') ? updatedText : `${updatedText}\n`);
|
|
297
|
+
} else {
|
|
298
|
+
fs.writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 4)}\n`);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
fs.writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 4)}\n`);
|
|
302
|
+
}
|
|
76
303
|
|
|
77
304
|
return {
|
|
78
305
|
updated: true,
|
package/lib/plugin/playwright.js
CHANGED
|
@@ -6,6 +6,7 @@ const os = require('os');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const crypto = require('crypto');
|
|
8
8
|
const { spawn, spawnSync } = require('child_process');
|
|
9
|
+
const { playwrightCliVersion: PLAYWRIGHT_CLI_VERSION } = require('../../package.json');
|
|
9
10
|
|
|
10
11
|
const EXTENSIONS = [
|
|
11
12
|
['ublock-origin-lite', 'ddkjiahejlhfcafbddmgiahcphecmpfh'],
|
|
@@ -379,6 +380,24 @@ class PlaywrightPlugin {
|
|
|
379
380
|
this.stderr.write(`${line}\n`);
|
|
380
381
|
}
|
|
381
382
|
|
|
383
|
+
remindCliSessionScene(sceneName) {
|
|
384
|
+
if (!isCliScene(sceneName)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (sceneName !== 'cli-host-headed') {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (this.config.cliSessionScene === sceneName) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
this.writeStdout('[tip] 如果希望容器内 manyoyo run 自动附着到当前 CLI 宿主场景,请在 ~/.manyoyo/manyoyo.json 中设置:');
|
|
394
|
+
this.writeStdout(' "plugins": {');
|
|
395
|
+
this.writeStdout(' "playwright": {');
|
|
396
|
+
this.writeStdout(' "cliSessionScene": "cli-host-headed"');
|
|
397
|
+
this.writeStdout(' }');
|
|
398
|
+
this.writeStdout(' }');
|
|
399
|
+
}
|
|
400
|
+
|
|
382
401
|
randomAlnum(length = 16) {
|
|
383
402
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
384
403
|
let out = '';
|
|
@@ -1259,6 +1278,7 @@ class PlaywrightPlugin {
|
|
|
1259
1278
|
if (managedPids.length > 0) {
|
|
1260
1279
|
fs.writeFileSync(pidFile, `${managedPids[0]}`, 'utf8');
|
|
1261
1280
|
this.writeStdout(`[up] ${sceneName} ready on 127.0.0.1:${port} (pid(s) ${managedPids.join(' ')})`);
|
|
1281
|
+
this.remindCliSessionScene(sceneName);
|
|
1262
1282
|
return 0;
|
|
1263
1283
|
}
|
|
1264
1284
|
}
|
|
@@ -1539,6 +1559,25 @@ class PlaywrightPlugin {
|
|
|
1539
1559
|
return 0;
|
|
1540
1560
|
}
|
|
1541
1561
|
|
|
1562
|
+
printCliAdd() {
|
|
1563
|
+
const lines = [
|
|
1564
|
+
'PLAYWRIGHT_CLI_INSTALL_DIR="${TMPDIR:-/tmp}/manyoyo-playwright-cli-install-$$"',
|
|
1565
|
+
'mkdir -p "$PLAYWRIGHT_CLI_INSTALL_DIR/.playwright"',
|
|
1566
|
+
'echo \'{"browser":{"browserName":"chromium","launchOptions":{"channel":"chromium"}}}\' > "$PLAYWRIGHT_CLI_INSTALL_DIR/.playwright/cli.config.json"',
|
|
1567
|
+
'cd "$PLAYWRIGHT_CLI_INSTALL_DIR"',
|
|
1568
|
+
`npm install -g @playwright/cli@${PLAYWRIGHT_CLI_VERSION}`,
|
|
1569
|
+
'playwright-cli install --skills',
|
|
1570
|
+
'mkdir -p ~/.codex/skills/playwright-cli ~/.gemini/skills/playwright-cli',
|
|
1571
|
+
'cp -R "$PLAYWRIGHT_CLI_INSTALL_DIR/.claude/skills/playwright-cli/." ~/.claude/skills/playwright-cli/',
|
|
1572
|
+
'cp -R "$PLAYWRIGHT_CLI_INSTALL_DIR/.claude/skills/playwright-cli/." ~/.codex/skills/playwright-cli/',
|
|
1573
|
+
'cp -R "$PLAYWRIGHT_CLI_INSTALL_DIR/.claude/skills/playwright-cli/." ~/.gemini/skills/playwright-cli/',
|
|
1574
|
+
'cd $OLDPWD',
|
|
1575
|
+
'rm -rf "$PLAYWRIGHT_CLI_INSTALL_DIR"'
|
|
1576
|
+
];
|
|
1577
|
+
this.writeStdout(lines.join('\n'));
|
|
1578
|
+
return 0;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1542
1581
|
printSummary() {
|
|
1543
1582
|
const scenes = this.resolveTargets('all');
|
|
1544
1583
|
this.writeStdout(`playwright\truntime=${this.config.runtime}\tscenes=${scenes.join(',')}`);
|
|
@@ -1583,6 +1622,10 @@ class PlaywrightPlugin {
|
|
|
1583
1622
|
return this.printMcpAdd(host);
|
|
1584
1623
|
}
|
|
1585
1624
|
|
|
1625
|
+
if (action === 'cli-add') {
|
|
1626
|
+
return this.printCliAdd();
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1586
1629
|
if (action === 'ext-download') {
|
|
1587
1630
|
return await this.downloadExtensions({ prodversion });
|
|
1588
1631
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcanwin/manyoyo",
|
|
3
|
-
"version": "5.4.
|
|
4
|
-
"imageVersion": "1.8.
|
|
3
|
+
"version": "5.4.12",
|
|
4
|
+
"imageVersion": "1.8.12-common",
|
|
5
|
+
"playwrightCliVersion": "0.1.1",
|
|
5
6
|
"description": "AI Agent CLI Security Sandbox for Docker and Podman",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"manyoyo",
|