@yan-geroge/omg 0.1.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/.claude/agents/trellis-check.md +109 -0
- package/.claude/agents/trellis-implement.md +109 -0
- package/.claude/agents/trellis-research.md +137 -0
- package/.claude/commands/trellis/continue.md +55 -0
- package/.claude/commands/trellis/finish-work.md +66 -0
- package/.claude/hooks/inject-subagent-context.py +749 -0
- package/.claude/hooks/inject-workflow-state.py +387 -0
- package/.claude/hooks/session-start.py +797 -0
- package/.claude/settings.json +73 -0
- package/.claude/skills/trellis-before-dev/SKILL.md +34 -0
- package/.claude/skills/trellis-brainstorm/SKILL.md +548 -0
- package/.claude/skills/trellis-break-loop/SKILL.md +130 -0
- package/.claude/skills/trellis-check/SKILL.md +92 -0
- package/.claude/skills/trellis-meta/SKILL.md +73 -0
- package/.claude/skills/trellis-meta/references/customize-local/add-project-local-conventions.md +83 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-agents.md +54 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-context-loading.md +81 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-hooks.md +57 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-skills-or-commands.md +78 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-spec-structure.md +83 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-task-lifecycle.md +90 -0
- package/.claude/skills/trellis-meta/references/customize-local/change-workflow.md +64 -0
- package/.claude/skills/trellis-meta/references/customize-local/overview.md +55 -0
- package/.claude/skills/trellis-meta/references/local-architecture/context-injection.md +68 -0
- package/.claude/skills/trellis-meta/references/local-architecture/generated-files.md +80 -0
- package/.claude/skills/trellis-meta/references/local-architecture/overview.md +51 -0
- package/.claude/skills/trellis-meta/references/local-architecture/spec-system.md +102 -0
- package/.claude/skills/trellis-meta/references/local-architecture/task-system.md +101 -0
- package/.claude/skills/trellis-meta/references/local-architecture/workflow.md +75 -0
- package/.claude/skills/trellis-meta/references/local-architecture/workspace-memory.md +71 -0
- package/.claude/skills/trellis-meta/references/platform-files/agents.md +79 -0
- package/.claude/skills/trellis-meta/references/platform-files/hooks-and-settings.md +69 -0
- package/.claude/skills/trellis-meta/references/platform-files/overview.md +59 -0
- package/.claude/skills/trellis-meta/references/platform-files/platform-map.md +74 -0
- package/.claude/skills/trellis-meta/references/platform-files/skills-and-commands.md +83 -0
- package/.claude/skills/trellis-spec-bootstarp/SKILL.md +41 -0
- package/.claude/skills/trellis-spec-bootstarp/references/mcp-setup.md +90 -0
- package/.claude/skills/trellis-spec-bootstarp/references/repository-analysis.md +59 -0
- package/.claude/skills/trellis-spec-bootstarp/references/spec-task-planning.md +61 -0
- package/.claude/skills/trellis-spec-bootstarp/references/spec-writing.md +70 -0
- package/.claude/skills/trellis-update-spec/SKILL.md +356 -0
- package/CLAUDE.md +88 -0
- package/agents/architect.md +80 -0
- package/agents/executor.md +79 -0
- package/agents/planner.md +76 -0
- package/agents/reviewer.md +81 -0
- package/agents/tdd-guide.md +95 -0
- package/agents/verifier.md +81 -0
- package/hooks/keyword-detector.mjs +115 -0
- package/hooks/lib/keyword-detector.js +89 -0
- package/hooks/session-start.mjs +104 -0
- package/marketplace.json +12 -0
- package/package.json +34 -0
- package/plugin.json +14 -0
- package/scripts/diagnose-marketplace.js +84 -0
- package/scripts/e2e-diagnose.mjs +118 -0
- package/scripts/validate-with-csc-schema.mjs +87 -0
- package/skills/costrict-autopilot/SKILL.md +53 -0
- package/skills/costrict-team/SKILL.md +65 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 关键词检测器 — 纯函数模块
|
|
3
|
+
*
|
|
4
|
+
* 从用户 prompt 中检测预设关键词,返回匹配结果。
|
|
5
|
+
* 此模块为纯函数,不依赖任何外部状态或 I/O,便于单元测试。
|
|
6
|
+
*
|
|
7
|
+
* 关键词映射表(按检测顺序排列):
|
|
8
|
+
* ┌───────────────┬───────────────┬──────────┐
|
|
9
|
+
* │ 关键词 │ 技能 │ 优先级 │
|
|
10
|
+
* ├───────────────┼───────────────┼──────────┤
|
|
11
|
+
* │ autopilot │ costrict-autopilot │ 10 │
|
|
12
|
+
* │ auto(非精确匹配)│ costrict-autopilot │ 5 │
|
|
13
|
+
* │ team │ costrict-team │ 10 │
|
|
14
|
+
* │ tdd │ tdd-guide │ 10 │
|
|
15
|
+
* └───────────────┴───────────────┴──────────┘
|
|
16
|
+
*
|
|
17
|
+
* 匹配规则:
|
|
18
|
+
* - 匹配不区分大小写
|
|
19
|
+
* - 优先级相同时取先匹配到的关键词
|
|
20
|
+
* - "auto" 是部分匹配(包含即命中),其余为词边界匹配
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// 关键词规则配置表
|
|
24
|
+
// 每个规则包含:keyword(检测词)、skill(路由目标技能)、priority(优先级,数字越大越优先)、exact(是否精确词边界匹配)
|
|
25
|
+
const KEYWORD_RULES = [
|
|
26
|
+
{ keyword: 'autopilot', skill: 'oh-my-costrict:costrict-autopilot', priority: 10, exact: true },
|
|
27
|
+
{ keyword: 'auto', skill: 'oh-my-costrict:costrict-autopilot', priority: 5, exact: false },
|
|
28
|
+
{ keyword: 'team', skill: 'oh-my-costrict:costrict-team', priority: 10, exact: true },
|
|
29
|
+
{ keyword: 'tdd', skill: 'oh-my-costrict:tdd-guide', priority: 10, exact: true },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 检测 prompt 中的预设关键词
|
|
34
|
+
*
|
|
35
|
+
* @param {string} prompt - 用户输入的文本
|
|
36
|
+
* @returns {{ keyword: string, skill: string, priority: number } | null}
|
|
37
|
+
* 匹配成功返回 { keyword, skill, priority },否则返回 null
|
|
38
|
+
*/
|
|
39
|
+
function detectKeywords(prompt) {
|
|
40
|
+
// 输入验证:非字符串或空字符串直接返回 null
|
|
41
|
+
if (typeof prompt !== 'string' || prompt.trim().length === 0) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 转为小写以支持不区分大小写匹配
|
|
46
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
47
|
+
|
|
48
|
+
// 当前最佳匹配(按优先级比较)
|
|
49
|
+
let bestMatch = null;
|
|
50
|
+
|
|
51
|
+
// 遍历所有规则,寻找最佳匹配
|
|
52
|
+
for (const rule of KEYWORD_RULES) {
|
|
53
|
+
const keywordLower = rule.keyword.toLowerCase();
|
|
54
|
+
let matched = false;
|
|
55
|
+
|
|
56
|
+
if (rule.exact) {
|
|
57
|
+
// 精确匹配:使用词边界正则(\b 为词边界)
|
|
58
|
+
const exactPattern = new RegExp(`\\b${escapeRegExp(keywordLower)}\\b`);
|
|
59
|
+
matched = exactPattern.test(lowerPrompt);
|
|
60
|
+
} else {
|
|
61
|
+
// 部分匹配:直接检查是否包含
|
|
62
|
+
matched = lowerPrompt.includes(keywordLower);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 命中且优先级更高的匹配(或首次命中)
|
|
66
|
+
if (matched && (!bestMatch || rule.priority > bestMatch.priority)) {
|
|
67
|
+
bestMatch = {
|
|
68
|
+
keyword: rule.keyword,
|
|
69
|
+
skill: rule.skill,
|
|
70
|
+
priority: rule.priority,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return bestMatch;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 转义正则表达式特殊字符
|
|
80
|
+
*
|
|
81
|
+
* @param {string} str - 需要转义的字符串
|
|
82
|
+
* @returns {string} 转义后的安全字符串
|
|
83
|
+
*/
|
|
84
|
+
function escapeRegExp(str) {
|
|
85
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 导出公共 API
|
|
89
|
+
module.exports = { detectKeywords, KEYWORD_RULES };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionStart Hook 脚本
|
|
3
|
+
*
|
|
4
|
+
* 在 CSC 会话启动时触发,读取 claude.md 编排大脑文件,
|
|
5
|
+
* 将其内容作为 systemMessage 注入到 AI 的 system prompt 中。
|
|
6
|
+
*
|
|
7
|
+
* 输入 (stdin JSON):
|
|
8
|
+
* { hook_event_name: "SessionStart", session_id: string, cwd: string }
|
|
9
|
+
*
|
|
10
|
+
* 输出 (stdout JSON):
|
|
11
|
+
* { continue: true, systemMessage: "<claude.md 内容>" }
|
|
12
|
+
*
|
|
13
|
+
* 使用方式:由 CSC hook 引擎以 command 类型调用:
|
|
14
|
+
* node "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs"
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readFile } from 'node:fs/promises';
|
|
18
|
+
import { resolve } from 'node:path';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 读取 stdin 的 JSON 输入
|
|
22
|
+
*
|
|
23
|
+
* @returns {Promise<object>} 解析后的输入对象
|
|
24
|
+
*/
|
|
25
|
+
async function readStdin() {
|
|
26
|
+
// 收集 stdin 的所有数据块
|
|
27
|
+
return new Promise((resolveStdin, reject) => {
|
|
28
|
+
let data = '';
|
|
29
|
+
process.stdin.setEncoding('utf-8');
|
|
30
|
+
process.stdin.on('data', (chunk) => {
|
|
31
|
+
data += chunk;
|
|
32
|
+
});
|
|
33
|
+
process.stdin.on('end', () => {
|
|
34
|
+
try {
|
|
35
|
+
// 尝试将 stdin 内容解析为 JSON
|
|
36
|
+
resolveStdin(JSON.parse(data.trim() || '{}'));
|
|
37
|
+
} catch {
|
|
38
|
+
// JSON 解析失败时返回空对象,不阻塞 CSC
|
|
39
|
+
resolveStdin({});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
process.stdin.on('error', (err) => {
|
|
43
|
+
// stdin 读取失败时返回空对象,保持非侵入式
|
|
44
|
+
resolveStdin({});
|
|
45
|
+
});
|
|
46
|
+
process.stdin.resume();
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 读取 claude.md 编排器文件
|
|
52
|
+
*
|
|
53
|
+
* @returns {Promise<string>} 文件内容,读取失败时返回空字符串
|
|
54
|
+
*/
|
|
55
|
+
async function readOrchestrationBrain() {
|
|
56
|
+
try {
|
|
57
|
+
// 使用 CLAUDE_PLUGIN_ROOT 环境变量定位插件根目录
|
|
58
|
+
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
|
|
59
|
+
if (!pluginRoot) {
|
|
60
|
+
// 环境变量未设置,降级为相对路径(当前工作目录)
|
|
61
|
+
const claudeMdPath = resolve(process.cwd(), 'claude.md');
|
|
62
|
+
return await readFile(claudeMdPath, 'utf-8');
|
|
63
|
+
}
|
|
64
|
+
// 拼接 claude.md 的完整路径
|
|
65
|
+
const filePath = resolve(pluginRoot, 'claude.md');
|
|
66
|
+
// 读取文件内容
|
|
67
|
+
return await readFile(filePath, 'utf-8');
|
|
68
|
+
} catch {
|
|
69
|
+
// 文件读取失败不阻塞 CSC,返回空字符串
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 主函数:读取输入 -> 注入编排器 system prompt -> 输出响应
|
|
76
|
+
*/
|
|
77
|
+
async function main() {
|
|
78
|
+
// 读取 stdin 输入(hook 事件信息)
|
|
79
|
+
const input = await readStdin();
|
|
80
|
+
|
|
81
|
+
// 读取 claude.md 编排大脑文件
|
|
82
|
+
const orchestrationContent = await readOrchestrationBrain();
|
|
83
|
+
|
|
84
|
+
// 构造 hook 响应 JSON
|
|
85
|
+
const response = {
|
|
86
|
+
continue: true,
|
|
87
|
+
systemMessage: orchestrationContent,
|
|
88
|
+
stopReason: null,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// 输出到 stdout(CSC hook 引擎读取)
|
|
92
|
+
process.stdout.write(JSON.stringify(response));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 执行主函数
|
|
96
|
+
main().catch(() => {
|
|
97
|
+
// 任何未预期的错误都不阻塞 CSC,返回空 systemMessage
|
|
98
|
+
const fallback = {
|
|
99
|
+
continue: true,
|
|
100
|
+
systemMessage: '',
|
|
101
|
+
stopReason: null,
|
|
102
|
+
};
|
|
103
|
+
process.stdout.write(JSON.stringify(fallback));
|
|
104
|
+
});
|
package/marketplace.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yan-geroge/omg",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CSC 多智能体编排插件 — 为 CSC 提供多智能体编排、技能路由、生命周期 Hook 注入能力",
|
|
5
|
+
"main": "plugin.json",
|
|
6
|
+
"files": [
|
|
7
|
+
"plugin.json",
|
|
8
|
+
"marketplace.json",
|
|
9
|
+
"agents/",
|
|
10
|
+
"skills/",
|
|
11
|
+
"hooks/",
|
|
12
|
+
"scripts/",
|
|
13
|
+
"CLAUDE.md",
|
|
14
|
+
".claude/",
|
|
15
|
+
"!.claude/settings.local.json"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"prepublishOnly": "node -e \"const fs=require('fs');const p=JSON.parse(fs.readFileSync('plugin.json','utf8'));const pk=JSON.parse(fs.readFileSync('package.json','utf8'));if(p.version!==pk.version){console.error('version mismatch: plugin.json='+p.version+' package.json='+pk.version);process.exit(1);}console.log('✓ plugin.json version matches package.json');\"",
|
|
19
|
+
"pack:check": "npm pack --dry-run"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"csc",
|
|
23
|
+
"costrict",
|
|
24
|
+
"plugin",
|
|
25
|
+
"multi-agent",
|
|
26
|
+
"orchestration",
|
|
27
|
+
"oh-my-costrict"
|
|
28
|
+
],
|
|
29
|
+
"author": "yan-geroge",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "oh-my-costrict",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CSC 多智能体编排插件 — 为 CSC 提供多智能体编排、技能路由、生命周期 Hook 注入能力",
|
|
5
|
+
"skills": "./skills/",
|
|
6
|
+
"hooks": {
|
|
7
|
+
"SessionStart": [
|
|
8
|
+
{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\"", "timeout": 10000 }] }
|
|
9
|
+
],
|
|
10
|
+
"UserPromptSubmit": [
|
|
11
|
+
{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/keyword-detector.mjs\"", "timeout": 5000 }] }
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// 手动验证 marketplace.json
|
|
5
|
+
const mpPath = 'C:/Users/SXF-Admin/.claude/plugins/cache/local/oh-my-costrict/0.1.0/.claude-plugin/marketplace.json';
|
|
6
|
+
const mp = JSON.parse(fs.readFileSync(mpPath, 'utf-8'));
|
|
7
|
+
|
|
8
|
+
console.log('=== marketplace.json ===');
|
|
9
|
+
console.log('name:', mp.name);
|
|
10
|
+
console.log('owner:', JSON.stringify(mp.owner));
|
|
11
|
+
console.log('plugins count:', mp.plugins?.length);
|
|
12
|
+
console.log('plugin[0].name:', mp.plugins?.[0]?.name);
|
|
13
|
+
console.log('plugin[0].source:', JSON.stringify(mp.plugins?.[0]?.source));
|
|
14
|
+
console.log('plugin[0].source type:', typeof mp.plugins?.[0]?.source);
|
|
15
|
+
|
|
16
|
+
// 检查所需字段
|
|
17
|
+
const checks = [
|
|
18
|
+
['name is non-empty string', typeof mp.name === 'string' && mp.name.length > 0],
|
|
19
|
+
['name has no spaces', !mp.name.includes(' ')],
|
|
20
|
+
['owner exists', mp.owner !== undefined && mp.owner !== null],
|
|
21
|
+
['owner.name is non-empty', typeof mp.owner?.name === 'string' && mp.owner.name.length > 0],
|
|
22
|
+
['plugins is array', Array.isArray(mp.plugins)],
|
|
23
|
+
['plugins[0].name exists', typeof mp.plugins?.[0]?.name === 'string'],
|
|
24
|
+
['plugins[0].source exists', mp.plugins?.[0]?.source !== undefined],
|
|
25
|
+
['plugins[0].source is string starting with ./', typeof mp.plugins?.[0]?.source === 'string' && mp.plugins[0].source.startsWith('./')],
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
let allPass = true;
|
|
29
|
+
for (const [name, result] of checks) {
|
|
30
|
+
console.log(result ? ' PASS' : ' FAIL', '-', name);
|
|
31
|
+
if (!result) allPass = false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 检查 known_marketplaces.json
|
|
35
|
+
const kmPath = 'C:/Users/SXF-Admin/.claude/plugins/known_marketplaces.json';
|
|
36
|
+
const km = JSON.parse(fs.readFileSync(kmPath, 'utf-8'));
|
|
37
|
+
|
|
38
|
+
console.log('\n=== known_marketplaces.json ===');
|
|
39
|
+
console.log('local entry exists:', !!km.local);
|
|
40
|
+
console.log('local.source:', JSON.stringify(km.local?.source));
|
|
41
|
+
console.log('local.installLocation:', km.local?.installLocation);
|
|
42
|
+
|
|
43
|
+
// 验证 installLocation 指向的 .claude-plugin/marketplace.json
|
|
44
|
+
const nestedPath = path.join(km.local?.installLocation || '', '.claude-plugin', 'marketplace.json');
|
|
45
|
+
console.log('\n=== installLocation check ===');
|
|
46
|
+
console.log('installLocation exists:', fs.existsSync(km.local?.installLocation));
|
|
47
|
+
console.log('.claude-plugin/marketplace.json exists:', fs.existsSync(nestedPath));
|
|
48
|
+
|
|
49
|
+
// 验证 installLocation 目录下的文件
|
|
50
|
+
if (km.local?.installLocation && fs.existsSync(km.local.installLocation)) {
|
|
51
|
+
console.log('\ninstallLocation contents:');
|
|
52
|
+
fs.readdirSync(km.local.installLocation).forEach(f => console.log(' ', f));
|
|
53
|
+
const cpPath = path.join(km.local.installLocation, '.claude-plugin');
|
|
54
|
+
if (fs.existsSync(cpPath)) {
|
|
55
|
+
console.log('\n.claude-plugin contents:');
|
|
56
|
+
fs.readdirSync(cpPath).forEach(f => console.log(' ', f));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 验证 installed_plugins.json
|
|
61
|
+
const ipPath = 'C:/Users/SXF-Admin/.claude/plugins/installed_plugins.json';
|
|
62
|
+
const ip = JSON.parse(fs.readFileSync(ipPath, 'utf-8'));
|
|
63
|
+
console.log('\n=== installed_plugins.json ===');
|
|
64
|
+
const costrictEntry = ip.plugins?.['oh-my-costrict@local'];
|
|
65
|
+
console.log('oh-my-costrict@local entry:', !!costrictEntry);
|
|
66
|
+
if (costrictEntry?.[0]) {
|
|
67
|
+
console.log(' installPath:', costrictEntry[0].installPath);
|
|
68
|
+
console.log(' version:', costrictEntry[0].version);
|
|
69
|
+
console.log(' scope:', costrictEntry[0].scope);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 尝试用 CSC 的 schema 验证
|
|
73
|
+
console.log('\n=== CSC Schema Validation ===');
|
|
74
|
+
try {
|
|
75
|
+
// 动态导入 CSC 的 schemas 模块
|
|
76
|
+
const schemasPath = 'C:/nvm4w/nodejs/node_modules/@costrict/csc/dist/utils/plugins/schemas.js';
|
|
77
|
+
console.log('Trying schemas at:', schemasPath);
|
|
78
|
+
console.log('File exists:', fs.existsSync(schemasPath));
|
|
79
|
+
} catch(e) {
|
|
80
|
+
console.log('Schema import error:', e.message);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log('\n=== All manual checks done ===');
|
|
84
|
+
console.log(allPass ? 'ALL MANUAL CHECKS PASSED' : 'SOME MANUAL CHECKS FAILED');
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// 端到端模拟 CSC 插件加载流程
|
|
2
|
+
// 1. 验证 known_marketplaces.json → KnownMarketplacesFileSchema
|
|
3
|
+
// 2. 验证 marketplace.json → PluginMarketplaceSchema
|
|
4
|
+
// 3. 模拟 loadPluginsFromMarketplaces 流程
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const KNOWN_MP_PATH = 'C:/Users/SXF-Admin/.claude/plugins/known_marketplaces.json';
|
|
11
|
+
const INSTALLED_PLUGINS_PATH = 'C:/Users/SXF-Admin/.claude/plugins/installed_plugins.json';
|
|
12
|
+
const CACHE_DIR = 'C:/Users/SXF-Admin/.claude/plugins/cache/local/oh-my-costrict/0.1.0';
|
|
13
|
+
const MP_PATH = path.join(CACHE_DIR, '.claude-plugin', 'marketplace.json');
|
|
14
|
+
const PLUGIN_PATH = path.join(CACHE_DIR, '.claude-plugin', 'plugin.json');
|
|
15
|
+
|
|
16
|
+
console.log('=== 步骤 1: 读取 known_marketplaces.json ===');
|
|
17
|
+
const km = JSON.parse(fs.readFileSync(KNOWN_MP_PATH, 'utf-8'));
|
|
18
|
+
console.log('local entry exists:', !!km.local);
|
|
19
|
+
console.log('local.source:', JSON.stringify(km.local?.source));
|
|
20
|
+
console.log('local.installLocation:', km.local?.installLocation);
|
|
21
|
+
console.log('local.lastUpdated:', km.local?.lastUpdated);
|
|
22
|
+
|
|
23
|
+
// 检查 MarketplaceSourceSchema 的关键约束
|
|
24
|
+
const localSource = km.local?.source;
|
|
25
|
+
console.log('\n=== 步骤 2: MarketplaceSourceSchema 检查 ===');
|
|
26
|
+
console.log('source.source type:', localSource?.source);
|
|
27
|
+
console.log('source.source === "directory":', localSource?.source === 'directory');
|
|
28
|
+
console.log('source.path is string:', typeof localSource?.path === 'string');
|
|
29
|
+
console.log('source.path exists:', fs.existsSync(localSource?.path));
|
|
30
|
+
|
|
31
|
+
console.log('\n=== 步骤 3: 读取 marketplace.json (PluginMarketplaceSchema) ===');
|
|
32
|
+
const mp = JSON.parse(fs.readFileSync(MP_PATH, 'utf-8'));
|
|
33
|
+
console.log('marketplace name:', mp.name);
|
|
34
|
+
console.log('marketplace owner:', JSON.stringify(mp.owner));
|
|
35
|
+
console.log('plugins count:', mp.plugins?.length);
|
|
36
|
+
console.log('plugin[0].name:', mp.plugins?.[0]?.name);
|
|
37
|
+
console.log('plugin[0].source:', mp.plugins?.[0]?.source);
|
|
38
|
+
console.log('plugin[0].source type:', typeof mp.plugins?.[0]?.source);
|
|
39
|
+
console.log('plugin[0].source starts with ./:', mp.plugins?.[0]?.source?.startsWith('./'));
|
|
40
|
+
|
|
41
|
+
console.log('\n=== 步骤 4: 插件 .claude-plugin 目录检查 ===');
|
|
42
|
+
console.log('.claude-plugin/ exists:', fs.existsSync(path.join(CACHE_DIR, '.claude-plugin')));
|
|
43
|
+
console.log('plugin.json exists:', fs.existsSync(PLUGIN_PATH));
|
|
44
|
+
const pluginJson = JSON.parse(fs.readFileSync(PLUGIN_PATH, 'utf-8'));
|
|
45
|
+
console.log('plugin name:', pluginJson.name);
|
|
46
|
+
console.log('plugin version:', pluginJson.version);
|
|
47
|
+
console.log('plugin skills:', pluginJson.skills);
|
|
48
|
+
console.log('plugin hooks keys:', Object.keys(pluginJson.hooks || {}));
|
|
49
|
+
|
|
50
|
+
console.log('\n=== 步骤 5: Skills 目录检查 ===');
|
|
51
|
+
const skillsDir = path.join(CACHE_DIR, 'skills');
|
|
52
|
+
if (fs.existsSync(skillsDir)) {
|
|
53
|
+
const skills = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
54
|
+
for (const s of skills) {
|
|
55
|
+
if (s.isDirectory()) {
|
|
56
|
+
const skillMd = path.join(skillsDir, s.name, 'SKILL.md');
|
|
57
|
+
const agentMd = path.join(skillsDir, s.name);
|
|
58
|
+
console.log(` ${s.name}/`);
|
|
59
|
+
console.log(` SKILL.md exists: ${fs.existsSync(skillMd)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('\n=== 步骤 6: Agents 目录检查 ===');
|
|
65
|
+
const agentsDir = path.join(CACHE_DIR, 'agents');
|
|
66
|
+
if (fs.existsSync(agentsDir)) {
|
|
67
|
+
const agents = fs.readdirSync(agentsDir);
|
|
68
|
+
console.log(` ${agents.length} agent files:`, agents.join(', '));
|
|
69
|
+
} else {
|
|
70
|
+
console.log(' agents/ 目录不存在!');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('\n=== 步骤 7: Hooks 目录检查 ===');
|
|
74
|
+
const hooksDir = path.join(CACHE_DIR, 'hooks');
|
|
75
|
+
if (fs.existsSync(hooksDir)) {
|
|
76
|
+
const hooks = fs.readdirSync(hooksDir);
|
|
77
|
+
console.log(` hooks:`, hooks.join(', '));
|
|
78
|
+
// 检查 hook 脚本可执行性
|
|
79
|
+
for (const h of hooks) {
|
|
80
|
+
const hookPath = path.join(hooksDir, h);
|
|
81
|
+
const stat = fs.statSync(hookPath);
|
|
82
|
+
console.log(` ${h}: ${stat.size} bytes`);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
console.log(' hooks/ 目录不存在!');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log('\n=== 步骤 8: installed_plugins.json 检查 ===');
|
|
89
|
+
const ip = JSON.parse(fs.readFileSync(INSTALLED_PLUGINS_PATH, 'utf-8'));
|
|
90
|
+
const entry = ip.plugins?.['oh-my-costrict@local'];
|
|
91
|
+
console.log('oh-my-costrict@local entry:', !!entry);
|
|
92
|
+
if (entry) {
|
|
93
|
+
console.log(' installPath:', entry[0]?.installPath);
|
|
94
|
+
console.log(' version:', entry[0]?.version);
|
|
95
|
+
console.log(' scope:', entry[0]?.scope);
|
|
96
|
+
console.log(' installPath exists:', fs.existsSync(entry[0]?.installPath));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('\n=== 步骤 9: 模拟 getPluginByIdCacheOnly 查找 ===');
|
|
100
|
+
// 模拟: 从 marketplace.plugins 搜索插件
|
|
101
|
+
const found = mp.plugins?.find(p => p.name === 'oh-my-costrict');
|
|
102
|
+
console.log('在 marketplace.json 中找到 oh-my-costrict:', !!found);
|
|
103
|
+
if (found) {
|
|
104
|
+
// 模拟: loadPluginFromMarketplaceEntryCacheOnly
|
|
105
|
+
const pluginPath_resolved = path.join(CACHE_DIR, found.source);
|
|
106
|
+
console.log('解析后的 pluginPath:', pluginPath_resolved);
|
|
107
|
+
console.log('pluginPath 的 .claude-plugin/plugin.json 存在:', fs.existsSync(path.join(pluginPath_resolved, '.claude-plugin', 'plugin.json')));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('\n=== 最终结论 ===');
|
|
111
|
+
const allOk =
|
|
112
|
+
fs.existsSync(MP_PATH) &&
|
|
113
|
+
fs.existsSync(PLUGIN_PATH) &&
|
|
114
|
+
mp.plugins?.find(p => p.name === 'oh-my-costrict') &&
|
|
115
|
+
fs.existsSync(path.join(CACHE_DIR, '.claude-plugin')) &&
|
|
116
|
+
km.local?.source?.source === 'directory';
|
|
117
|
+
|
|
118
|
+
console.log(allOk ? '✅ 所有检查通过 - 插件应该可以加载' : '❌ 存在问题 - 检查上述输出');
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// 使用 CSC 运行时 schema 验证 marketplace.json
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const mpPath = 'C:/Users/SXF-Admin/.claude/plugins/cache/local/oh-my-costrict/0.1.0/.claude-plugin/marketplace.json';
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
// 方法 1: 尝试从 @costrict/csc 导入 schemas
|
|
9
|
+
async function tryImportCsc() {
|
|
10
|
+
try {
|
|
11
|
+
console.log('尝试方法 1: 从 @costrict/csc 导入...');
|
|
12
|
+
const csc = await import('@costrict/csc');
|
|
13
|
+
console.log('CSC exports:', Object.keys(csc));
|
|
14
|
+
} catch (e) {
|
|
15
|
+
console.log('方法 1 失败:', e.message);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 方法 2: 尝试 require csc dist services
|
|
20
|
+
function tryRequireServices() {
|
|
21
|
+
try {
|
|
22
|
+
console.log('\n尝试方法 2: require CSC dist...');
|
|
23
|
+
const schemas = require('C:/nvm4w/nodejs/node_modules/@costrict/csc/dist/cli.js');
|
|
24
|
+
console.log('Loaded CSC dist, keys:', Object.keys(schemas).slice(0, 20));
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.log('方法 2 失败:', e.message);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 方法 3: 读取 bundled CLI 源码,搜索 PluginMarketplaceSchema
|
|
31
|
+
function searchBundledSchema() {
|
|
32
|
+
console.log('\n尝试方法 3: 搜索 bundled 文件中的 schema...');
|
|
33
|
+
const cliPath = 'C:/nvm4w/nodejs/node_modules/@costrict/csc/dist/cli.js';
|
|
34
|
+
const content = fs.readFileSync(cliPath, 'utf-8');
|
|
35
|
+
|
|
36
|
+
// 搜索 PluginMarketplaceSchema
|
|
37
|
+
const match = content.match(/PluginMarketplaceSchema\s*=\s*lazySchema[^}]*\}\s*\)\s*\)/);
|
|
38
|
+
if (match) {
|
|
39
|
+
console.log('找到 PluginMarketplaceSchema 定义 (部分):', match[0].substring(0, 200));
|
|
40
|
+
} else {
|
|
41
|
+
console.log('未找到完整定义,搜索片段...');
|
|
42
|
+
const idx = content.indexOf('PluginMarketplaceSchema');
|
|
43
|
+
if (idx >= 0) {
|
|
44
|
+
console.log('上下文:', content.substring(idx, idx + 500));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 搜索 MarketplaceNameSchema
|
|
49
|
+
const mnIdx = content.indexOf('MarketplaceNameSchema');
|
|
50
|
+
if (mnIdx >= 0) {
|
|
51
|
+
console.log('\nMarketplaceNameSchema 上下文:', content.substring(mnIdx, mnIdx + 600));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 搜索 PluginMarketplaceEntrySchema
|
|
55
|
+
const peIdx = content.indexOf('PluginMarketplaceEntrySchema');
|
|
56
|
+
if (peIdx >= 0) {
|
|
57
|
+
console.log('\nPluginMarketplaceEntrySchema 上下文:', content.substring(peIdx, peIdx + 800));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 方法 4: 直接测试 JSON 解析和基本格式
|
|
62
|
+
function manualCheck() {
|
|
63
|
+
console.log('\n=== 手动验证 marketplace.json ===');
|
|
64
|
+
const mp = JSON.parse(fs.readFileSync(mpPath, 'utf-8'));
|
|
65
|
+
|
|
66
|
+
console.log('顶层 keys:', Object.keys(mp));
|
|
67
|
+
console.log('name type:', typeof mp.name, 'value:', mp.name);
|
|
68
|
+
console.log('owner type:', typeof mp.owner, 'keys:', Object.keys(mp.owner));
|
|
69
|
+
console.log('plugins is array:', Array.isArray(mp.plugins));
|
|
70
|
+
console.log('plugins[0]:', JSON.stringify(mp.plugins[0], null, 2));
|
|
71
|
+
|
|
72
|
+
// 检查相对路径
|
|
73
|
+
const source = mp.plugins[0].source;
|
|
74
|
+
console.log('\nsource 检查:');
|
|
75
|
+
console.log(' 类型:', typeof source);
|
|
76
|
+
console.log(' 值:', JSON.stringify(source));
|
|
77
|
+
console.log(' 是否以 ./ 开头:', typeof source === 'string' && source.startsWith('./'));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function main() {
|
|
81
|
+
manualCheck();
|
|
82
|
+
await tryImportCsc();
|
|
83
|
+
tryRequireServices();
|
|
84
|
+
searchBundledSchema();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: costrict-autopilot
|
|
3
|
+
description: 自动审查流水线 — 全自动质量门(PRD → 设计审查 → 工程审查 → DX 审查 → 汇总报告)
|
|
4
|
+
argument-hint: "<任务描述>"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /costrict-autopilot — 自动审查流水线
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
|
|
11
|
+
全自动质量门流水线,依次执行以下五个阶段,每个阶段产出一个审查报告,最终汇总为完整的质量评估。
|
|
12
|
+
|
|
13
|
+
## 执行流程
|
|
14
|
+
|
|
15
|
+
### Phase 1: PRD 生成
|
|
16
|
+
- 委托 **planner** 代理分析任务需求
|
|
17
|
+
- 产出一份结构化的 PRD 文档,包含:目标、范围、验收标准、技术约束
|
|
18
|
+
- 输出格式:markdown 文档
|
|
19
|
+
|
|
20
|
+
### Phase 2: 设计审查
|
|
21
|
+
- 委托 **architect** 代理审查 PRD 中的技术方案
|
|
22
|
+
- 检查点:架构合理性、技术选型、扩展性、安全性
|
|
23
|
+
- 输出:设计审查报告(通过/需修改/拒绝 + 具体建议)
|
|
24
|
+
|
|
25
|
+
### Phase 3: 工程审查
|
|
26
|
+
- 委托 **reviewer** 代理审查代码实现
|
|
27
|
+
- 检查点:代码质量、命名规范、错误处理、性能、安全
|
|
28
|
+
- 输出:工程审查报告(CRITICAL/HIGH/MEDIUM/LOW 分级问题列表)
|
|
29
|
+
|
|
30
|
+
### Phase 4: DX 审查(开发者体验)
|
|
31
|
+
- 委托 **reviewer** 代理审查开发者体验
|
|
32
|
+
- 检查点:API 易用性、文档完整性、错误信息友好度、配置复杂度
|
|
33
|
+
- 输出:DX 审查报告(改进建议列表)
|
|
34
|
+
|
|
35
|
+
### Phase 5: 汇总报告
|
|
36
|
+
- 汇总前四个阶段的审查结果
|
|
37
|
+
- 生成最终质量评估报告,包含:
|
|
38
|
+
- 各阶段通过/失败状态
|
|
39
|
+
- 问题汇总(按严重程度排序)
|
|
40
|
+
- 改进建议优先级列表
|
|
41
|
+
- 整体质量评分(A/B/C/D/F)
|
|
42
|
+
|
|
43
|
+
## 使用方式
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
/costrict-autopilot 实现用户登录功能,包含 JWT 认证和密码加密
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 注意事项
|
|
50
|
+
|
|
51
|
+
- 每个阶段独立执行,前序阶段的输出作为后续阶段的输入
|
|
52
|
+
- 任一步骤失败(审查结果为"拒绝")则终止后续步骤并报告
|
|
53
|
+
- 所有代理使用 CSC 默认模型,无需手动指定
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: costrict-team
|
|
3
|
+
description: 多智能体团队编排 — 将任务拆解分发给多个子代理并行执行,含审查和修复循环
|
|
4
|
+
argument-hint: "<任务描述>"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /costrict-team — 多智能体团队编排
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
|
|
11
|
+
将一个复杂任务拆解为子任务,分发给多个 executor 代理并行执行,经由 reviewer 审查后进入修复循环,最终由 verifier 验证完成。
|
|
12
|
+
|
|
13
|
+
## 执行流程
|
|
14
|
+
|
|
15
|
+
### Step 1: 规划
|
|
16
|
+
- 委托 **planner** 代理分析任务
|
|
17
|
+
- 将任务拆解为 2-5 个可并行执行的独立子任务
|
|
18
|
+
- 为每个子任务生成明确的任务描述和验收标准
|
|
19
|
+
- 识别子任务间的依赖关系(如有)
|
|
20
|
+
|
|
21
|
+
### Step 2: 并行执行
|
|
22
|
+
- 为每个独立子任务启动一个 **executor** 代理
|
|
23
|
+
- 所有 executor 代理**同时并行**工作
|
|
24
|
+
- 每个 executor 独立完成:阅读代码 → 实现修改 → 自我验证
|
|
25
|
+
- 有依赖关系的子任务按拓扑顺序分批执行
|
|
26
|
+
|
|
27
|
+
### Step 3: 审查
|
|
28
|
+
- 委托 **reviewer** 代理审查所有 executor 的产出
|
|
29
|
+
- 检查点:代码质量、一致性、跨子任务兼容性、安全
|
|
30
|
+
- 输出:审查报告(通过 / 需修改列表)
|
|
31
|
+
|
|
32
|
+
### Step 4: 修复循环
|
|
33
|
+
- 如果审查发现需修改的问题:
|
|
34
|
+
- 将问题列表分发给相应的 executor 代理
|
|
35
|
+
- executor 修复后重新提交
|
|
36
|
+
- reviewer 重新审查
|
|
37
|
+
- **最多 3 轮**修复循环
|
|
38
|
+
- 超过 3 轮仍未通过,则报告阻塞并请求人工介入
|
|
39
|
+
|
|
40
|
+
### Step 5: 验证
|
|
41
|
+
- 委托 **verifier** 代理运行测试套件
|
|
42
|
+
- 验证:所有测试通过、覆盖率 >= 80%
|
|
43
|
+
- 输出:验证报告(通过/失败 + 覆盖率数据)
|
|
44
|
+
|
|
45
|
+
## 使用方式
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
/costrict-team 重构用户模块:拆分 service 层,添加单元测试,优化数据库查询
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 子任务示例
|
|
52
|
+
|
|
53
|
+
对于上述命令,planner 会拆解为:
|
|
54
|
+
1. 拆分 service 层(独立)
|
|
55
|
+
2. 添加单元测试(独立,可与1并行)
|
|
56
|
+
3. 优化数据库查询(独立,可与1、2并行)
|
|
57
|
+
|
|
58
|
+
三个 executor 并行执行,完成后统一审查。
|
|
59
|
+
|
|
60
|
+
## 注意事项
|
|
61
|
+
|
|
62
|
+
- 子任务数量控制在 2-5 个,避免过度拆分
|
|
63
|
+
- 有依赖关系的子任务按拓扑顺序串行执行
|
|
64
|
+
- 修复循环最多 3 轮,超过则报告并等待人工决策
|
|
65
|
+
- 所有代理使用 CSC 默认模型
|