@zat-design/sisyphus-scene 4.6.4 → 4.6.5-beta.2
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 +5 -1
- package/bin/sisyphus-scene.mjs +15 -5
- package/mcp/sisyphus-react.json +1 -1
- package/package.json +1 -1
- package/scripts/install-mcp.mjs +135 -7
- package/skills/sisyphus-scene/assets/ai-contract.json +1 -1
- package/skills/sisyphus-scene/evals/fixtures/valid-decisions.json +4 -4
- package/skills/sisyphus-scene/references/approved-examples.yaml +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,11 @@ npx -y @zat-design/sisyphus-scene install --check
|
|
|
13
13
|
npx -y @zat-design/sisyphus-scene install
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
常用参数:`--global`、`--platform claude,cursor,codex`、`--skip-mcp`、`--skill sisyphus-scene-legacy`。`--skip-mcp` 只安装 Skill,不提供组件 API/demo 查询能力;不需要 Codex 时可显式使用 `--platform claude,cursor`。
|
|
16
|
+
常用参数:`--global`、`--platform claude,cursor,codex`、`--project <项目根>`、`--mcp-cwd <前端目录>`、`--skip-mcp`、`--skill sisyphus-scene-legacy`。`--skip-mcp` 只安装 Skill,不提供组件 API/demo 查询能力;不需要 Codex 时可显式使用 `--platform claude,cursor`。
|
|
17
|
+
|
|
18
|
+
Codex 项目配置写入 `<项目根>/.codex/config.toml`。当 Codex 保存项目根是 monorepo 或工作区父目录,而 Sisyphus 前端位于子目录时,使用 `--mcp-cwd` 单独指定组件解析目录;相对路径以 `--project` 为基准。该参数不能与 `--skip-mcp`、legacy 技能或不含 Codex 的平台组合。用户级安装默认不会绑定业务项目;对尚不加载项目级 MCP 的旧版 Codex Desktop,可显式组合 `--global --mcp-cwd <前端目录>` 创建兼容入口。
|
|
19
|
+
|
|
20
|
+
安装器修正已有 Codex `cwd` 前会创建带时间戳的配置备份,通过同目录临时文件原子替换,并在 Codex CLI 读回校验失败时恢复原文件。更新仅定位有效的 `[mcp_servers.sisyphus-react]` 表,不匹配注释中的示例,也不改动后续 MCP 表。
|
|
17
21
|
|
|
18
22
|
Codex MCP 安装失败时,先在同一终端运行 `codex --version` 和 `codex mcp list --json`。若 Codex 命令非零退出且 stdout/stderr 为空,请检查当前终端实际命中的 Codex CLI 来源和兼容性;可临时使用 `--skip-mcp` 绕过 MCP,但这不代表 MCP 已安装。
|
|
19
23
|
|
package/bin/sisyphus-scene.mjs
CHANGED
|
@@ -17,6 +17,7 @@ const options = {
|
|
|
17
17
|
skill: 'sisyphus-scene',
|
|
18
18
|
platform: 'all',
|
|
19
19
|
project: process.cwd(),
|
|
20
|
+
mcpCwd: undefined,
|
|
20
21
|
check: false,
|
|
21
22
|
skipMcp: false,
|
|
22
23
|
};
|
|
@@ -26,10 +27,11 @@ for (let index = 0; index < argv.length; index += 1) {
|
|
|
26
27
|
if (token === '--global') options.scope = 'user';
|
|
27
28
|
else if (token === '--check') options.check = true;
|
|
28
29
|
else if (token === '--skip-mcp') options.skipMcp = true;
|
|
29
|
-
else if (['--skill', '--platform', '--project'].includes(token)) {
|
|
30
|
+
else if (['--skill', '--platform', '--project', '--mcp-cwd'].includes(token)) {
|
|
30
31
|
const value = argv[index + 1];
|
|
31
32
|
if (!value || value.startsWith('--')) throw new Error(`${token} 缺少参数。`);
|
|
32
|
-
|
|
33
|
+
if (token === '--mcp-cwd') options.mcpCwd = value;
|
|
34
|
+
else options[token.slice(2)] = value;
|
|
33
35
|
index += 1;
|
|
34
36
|
} else throw new Error(`不支持的参数:${token}`);
|
|
35
37
|
}
|
|
@@ -43,6 +45,13 @@ const selectedPlatforms = platform.split(',');
|
|
|
43
45
|
for (const item of selectedPlatforms) {
|
|
44
46
|
if (!['claude', 'cursor', 'codex'].includes(item)) throw new Error(`不支持的平台:${item}`);
|
|
45
47
|
}
|
|
48
|
+
const configureMcp = options.skill === 'sisyphus-scene' && !options.skipMcp;
|
|
49
|
+
if (options.mcpCwd) {
|
|
50
|
+
if (!configureMcp) throw new Error('--mcp-cwd 仅在安装 sisyphus-scene MCP 时可用。');
|
|
51
|
+
if (!selectedPlatforms.includes('codex')) {
|
|
52
|
+
throw new Error('--mcp-cwd 仅适用于包含 codex 的平台安装。');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
46
55
|
|
|
47
56
|
const run = (script, args) =>
|
|
48
57
|
execFileSync(process.execPath, [path.join(scripts, script), ...args], {
|
|
@@ -50,6 +59,7 @@ const run = (script, args) =>
|
|
|
50
59
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
51
60
|
});
|
|
52
61
|
|
|
62
|
+
const projectRoot = path.resolve(options.project);
|
|
53
63
|
const skillArgs = [
|
|
54
64
|
'--platform',
|
|
55
65
|
platform,
|
|
@@ -58,17 +68,17 @@ const skillArgs = [
|
|
|
58
68
|
'--skill',
|
|
59
69
|
options.skill,
|
|
60
70
|
'--project',
|
|
61
|
-
|
|
71
|
+
projectRoot,
|
|
62
72
|
];
|
|
63
|
-
const configureMcp = options.skill === 'sisyphus-scene' && !options.skipMcp;
|
|
64
73
|
const mcpArgs = [
|
|
65
74
|
'--platform',
|
|
66
75
|
platform,
|
|
67
76
|
'--scope',
|
|
68
77
|
options.scope,
|
|
69
78
|
'--project',
|
|
70
|
-
|
|
79
|
+
projectRoot,
|
|
71
80
|
];
|
|
81
|
+
if (options.mcpCwd) mcpArgs.push('--mcp-cwd', path.resolve(projectRoot, options.mcpCwd));
|
|
72
82
|
|
|
73
83
|
const preview = {
|
|
74
84
|
skill: JSON.parse(run('sync-platforms.mjs', [...skillArgs, '--check'])),
|
package/mcp/sisyphus-react.json
CHANGED
package/package.json
CHANGED
package/scripts/install-mcp.mjs
CHANGED
|
@@ -32,6 +32,10 @@ const platformInput = String(args.platform || 'all');
|
|
|
32
32
|
const platforms =
|
|
33
33
|
platformInput === 'all' ? ['claude', 'cursor', 'codex'] : platformInput.split(',');
|
|
34
34
|
const projectRoot = path.resolve(String(args.project || process.cwd()));
|
|
35
|
+
const mcpCwdInput = String(args['mcp-cwd'] || projectRoot);
|
|
36
|
+
const requestedMcpCwd = path.isAbsolute(mcpCwdInput)
|
|
37
|
+
? path.normalize(mcpCwdInput)
|
|
38
|
+
: path.resolve(projectRoot, mcpCwdInput);
|
|
35
39
|
const scope = String(args.scope || 'project');
|
|
36
40
|
const write = Boolean(args.write);
|
|
37
41
|
const check = Boolean(args.check);
|
|
@@ -42,6 +46,12 @@ if (write === check || (!write && !check)) {
|
|
|
42
46
|
|
|
43
47
|
const allowedPlatforms = new Set(['claude', 'cursor', 'codex']);
|
|
44
48
|
if (!['user', 'project'].includes(scope)) throw new Error(`不支持的 scope:${scope}`);
|
|
49
|
+
if (
|
|
50
|
+
(scope === 'project' || args['mcp-cwd']) &&
|
|
51
|
+
!fs.statSync(requestedMcpCwd, { throwIfNoEntry: false })?.isDirectory()
|
|
52
|
+
) {
|
|
53
|
+
throw new Error(`MCP 工作目录不存在或不是目录:${requestedMcpCwd}`);
|
|
54
|
+
}
|
|
45
55
|
for (const platform of platforms) {
|
|
46
56
|
if (!allowedPlatforms.has(platform)) throw new Error(`不支持的平台:${platform}`);
|
|
47
57
|
}
|
|
@@ -65,6 +75,19 @@ const codexHome =
|
|
|
65
75
|
scope === 'user'
|
|
66
76
|
? path.resolve(process.env.CODEX_HOME || path.join(os.homedir(), '.codex'))
|
|
67
77
|
: path.join(projectRoot, '.codex');
|
|
78
|
+
const codexTarget = path.join(codexHome, 'config.toml');
|
|
79
|
+
|
|
80
|
+
const normalizePath = (value) => {
|
|
81
|
+
if (!value) return null;
|
|
82
|
+
try {
|
|
83
|
+
return fs.realpathSync(value);
|
|
84
|
+
} catch {
|
|
85
|
+
return path.resolve(value);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const expectedCodexCwd =
|
|
90
|
+
scope === 'project' || args['mcp-cwd'] ? normalizePath(requestedMcpCwd) : null;
|
|
68
91
|
|
|
69
92
|
const codexEnv = { ...process.env, CODEX_HOME: codexHome };
|
|
70
93
|
|
|
@@ -126,7 +149,7 @@ const inspectCodex = () => {
|
|
|
126
149
|
if (!value) return { status: 'missing' };
|
|
127
150
|
if (value.enabled === false) {
|
|
128
151
|
throw new Error(
|
|
129
|
-
`${
|
|
152
|
+
`${codexTarget} 中的 sisyphus-react MCP 已禁用;请人工启用后重试。`,
|
|
130
153
|
);
|
|
131
154
|
}
|
|
132
155
|
|
|
@@ -134,12 +157,100 @@ const inspectCodex = () => {
|
|
|
134
157
|
const expectedArgs = server.args || [];
|
|
135
158
|
if (transport.command !== server.command || !sameJson(transport.args || [], expectedArgs)) {
|
|
136
159
|
throw new Error(
|
|
137
|
-
`${
|
|
160
|
+
`${codexTarget} 已存在不同的 sisyphus-react 配置;请人工确认。`,
|
|
138
161
|
);
|
|
139
162
|
}
|
|
163
|
+
const actualCwd = normalizePath(transport.cwd);
|
|
164
|
+
if (actualCwd !== expectedCodexCwd) {
|
|
165
|
+
return {
|
|
166
|
+
status: 'needs-update',
|
|
167
|
+
reason: 'cwd',
|
|
168
|
+
expectedCwd: expectedCodexCwd,
|
|
169
|
+
actualCwd,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
140
172
|
return { status: 'unchanged' };
|
|
141
173
|
};
|
|
142
174
|
|
|
175
|
+
const findTomlTableRange = (content, tableName) => {
|
|
176
|
+
const escapedName = tableName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
177
|
+
const targetPattern = new RegExp(
|
|
178
|
+
`^\\s*\\[${escapedName}\\]\\s*(?:#.*)?(?:\\r?\\n)?$`,
|
|
179
|
+
);
|
|
180
|
+
const tablePattern = /^\s*\[\[?[^\]\r\n]+\]\]?\s*(?:#.*)?(?:\r?\n)?$/;
|
|
181
|
+
const lines = content.match(/[^\n]*(?:\n|$)/g)?.filter(Boolean) || [];
|
|
182
|
+
let offset = 0;
|
|
183
|
+
let start = -1;
|
|
184
|
+
let end = content.length;
|
|
185
|
+
|
|
186
|
+
for (const line of lines) {
|
|
187
|
+
if (start < 0 && targetPattern.test(line)) start = offset;
|
|
188
|
+
else if (start >= 0 && tablePattern.test(line)) {
|
|
189
|
+
end = offset;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
offset += line.length;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (start < 0) throw new Error(`${codexTarget} 缺少 [${tableName}],无法校准 cwd。`);
|
|
196
|
+
return { start, end };
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const createCodexBackup = () => {
|
|
200
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
201
|
+
let candidate = `${codexTarget}.backup-${timestamp}`;
|
|
202
|
+
let suffix = 0;
|
|
203
|
+
while (fs.existsSync(candidate)) {
|
|
204
|
+
suffix += 1;
|
|
205
|
+
candidate = `${codexTarget}.backup-${timestamp}-${suffix}`;
|
|
206
|
+
}
|
|
207
|
+
fs.copyFileSync(codexTarget, candidate, fs.constants.COPYFILE_EXCL);
|
|
208
|
+
return candidate;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const writeCodexConfigAtomically = (content) => {
|
|
212
|
+
const temporary = path.join(
|
|
213
|
+
path.dirname(codexTarget),
|
|
214
|
+
`.${path.basename(codexTarget)}.${process.pid}.${Date.now()}.tmp`,
|
|
215
|
+
);
|
|
216
|
+
const mode = fs.statSync(codexTarget).mode;
|
|
217
|
+
try {
|
|
218
|
+
fs.writeFileSync(temporary, content, { mode });
|
|
219
|
+
fs.renameSync(temporary, codexTarget);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
if (fs.existsSync(temporary)) fs.unlinkSync(temporary);
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const updateCodexCwd = () => {
|
|
227
|
+
const content = fs.readFileSync(codexTarget, 'utf8');
|
|
228
|
+
const { start, end } = findTomlTableRange(content, 'mcp_servers.sisyphus-react');
|
|
229
|
+
const eol = content.includes('\r\n') ? '\r\n' : '\n';
|
|
230
|
+
const lines = content
|
|
231
|
+
.slice(start, end)
|
|
232
|
+
.split(/\r?\n/)
|
|
233
|
+
.filter((line) => !/^\s*cwd\s*=/.test(line));
|
|
234
|
+
while (lines.at(-1) === '') lines.pop();
|
|
235
|
+
if (expectedCodexCwd) lines.push(`cwd = ${JSON.stringify(expectedCodexCwd)}`);
|
|
236
|
+
const updatedBlock = `${lines.join(eol)}${eol}`;
|
|
237
|
+
const updatedContent = `${content.slice(0, start)}${updatedBlock}${content.slice(end)}`;
|
|
238
|
+
findTomlTableRange(updatedContent, 'mcp_servers.sisyphus-react');
|
|
239
|
+
|
|
240
|
+
const backup = createCodexBackup();
|
|
241
|
+
try {
|
|
242
|
+
writeCodexConfigAtomically(updatedContent);
|
|
243
|
+
const verified = inspectCodex();
|
|
244
|
+
if (verified.status !== 'unchanged') {
|
|
245
|
+
throw new Error(`Codex MCP 配置校验未通过:${JSON.stringify(verified)}`);
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
fs.copyFileSync(backup, codexTarget);
|
|
249
|
+
throw new Error(`更新 Codex MCP 配置失败,已恢复原文件;备份:${backup};${error.message}`);
|
|
250
|
+
}
|
|
251
|
+
return backup;
|
|
252
|
+
};
|
|
253
|
+
|
|
143
254
|
const readConfig = (target) => {
|
|
144
255
|
if (!fs.existsSync(target)) return { mcpServers: {} };
|
|
145
256
|
const value = JSON.parse(fs.readFileSync(target, 'utf8'));
|
|
@@ -193,11 +304,24 @@ for (const platform of platforms) {
|
|
|
193
304
|
throw new Error(`写入 Codex MCP 配置失败:\n${formatCodexFailure(commandArgs, result)}`);
|
|
194
305
|
}
|
|
195
306
|
}
|
|
196
|
-
|
|
307
|
+
const backup = write && inspected.status !== 'unchanged' ? updateCodexCwd() : null;
|
|
308
|
+
const result = {
|
|
197
309
|
platform,
|
|
198
|
-
target:
|
|
199
|
-
status:
|
|
200
|
-
|
|
310
|
+
target: codexTarget,
|
|
311
|
+
status:
|
|
312
|
+
inspected.status === 'unchanged'
|
|
313
|
+
? 'unchanged'
|
|
314
|
+
: inspected.status === 'missing'
|
|
315
|
+
? write
|
|
316
|
+
? 'added'
|
|
317
|
+
: 'would-add'
|
|
318
|
+
: write
|
|
319
|
+
? 'updated'
|
|
320
|
+
: 'would-update',
|
|
321
|
+
};
|
|
322
|
+
if (inspected.reason) result.reason = inspected.reason;
|
|
323
|
+
if (backup) result.backup = backup;
|
|
324
|
+
results.push(result);
|
|
201
325
|
continue;
|
|
202
326
|
}
|
|
203
327
|
|
|
@@ -222,5 +346,9 @@ for (const platform of platforms) {
|
|
|
222
346
|
}
|
|
223
347
|
|
|
224
348
|
process.stdout.write(
|
|
225
|
-
`${JSON.stringify(
|
|
349
|
+
`${JSON.stringify(
|
|
350
|
+
{ projectRoot, mcpCwd: expectedCodexCwd, scope, mode: write ? 'write' : 'check', results },
|
|
351
|
+
null,
|
|
352
|
+
2,
|
|
353
|
+
)}\n`,
|
|
226
354
|
);
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"apiEvidence": {
|
|
9
9
|
"tool": "sisyphus-get-component-api",
|
|
10
10
|
"target": "ProForm",
|
|
11
|
-
"libraryVersion": "4.6.
|
|
11
|
+
"libraryVersion": "4.6.5-beta.2",
|
|
12
12
|
"schemaVersion": 2
|
|
13
13
|
},
|
|
14
14
|
"demoEvidence": {
|
|
15
15
|
"tool": "sisyphus-get-example",
|
|
16
16
|
"target": "ProForm/demos/base.tsx",
|
|
17
|
-
"libraryVersion": "4.6.
|
|
17
|
+
"libraryVersion": "4.6.5-beta.2",
|
|
18
18
|
"schemaVersion": 2,
|
|
19
19
|
"exampleId": "ProForm/demos/base.tsx"
|
|
20
20
|
}
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"apiEvidence": {
|
|
29
29
|
"tool": "sisyphus-get-component-api",
|
|
30
30
|
"target": "ProTable",
|
|
31
|
-
"libraryVersion": "4.6.
|
|
31
|
+
"libraryVersion": "4.6.5-beta.2",
|
|
32
32
|
"schemaVersion": 2
|
|
33
33
|
},
|
|
34
34
|
"demoEvidence": {
|
|
35
35
|
"tool": "sisyphus-get-example",
|
|
36
36
|
"target": "ProTable/demos/base.tsx",
|
|
37
|
-
"libraryVersion": "4.6.
|
|
37
|
+
"libraryVersion": "4.6.5-beta.2",
|
|
38
38
|
"schemaVersion": 2,
|
|
39
39
|
"exampleId": "ProTable/demos/base.tsx"
|
|
40
40
|
}
|
|
@@ -7,7 +7,7 @@ examples: []
|
|
|
7
7
|
# status: approved
|
|
8
8
|
# application: xk-wjs-claim-web
|
|
9
9
|
# capabilities: [search-form, data-table, table-tabs, drawer-form]
|
|
10
|
-
# sisyphus_version: "4.6.
|
|
10
|
+
# sisyphus_version: "4.6.5-beta.2"
|
|
11
11
|
# antd_range: ">=6 <7"
|
|
12
12
|
# paths:
|
|
13
13
|
# - src/pages/litigationManagement/index.tsx
|