@birdie_moblie/plugin-marketplace-cli 1.0.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.
@@ -0,0 +1,116 @@
1
+ /**
2
+ * init-repo 命令 — 创建新的 plugin marketplace 仓库
3
+ */
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
5
+ import { basename, join } from 'node:path';
6
+ import chalk from 'chalk';
7
+ import { resolveInvocationPath, toTitleCase } from '../utils/helpers.js';
8
+ const CLI_PACKAGE = '@birdie_moblie/plugin-marketplace-cli';
9
+ const DEFAULT_SCRIPTS = {
10
+ mp: 'plugin-marketplace',
11
+ 'validate:plugins': 'plugin-marketplace validate --all',
12
+ 'build:plugins': 'plugin-marketplace build --all',
13
+ 'build:index': 'plugin-marketplace index',
14
+ 'build:all': 'npm run build:plugins && npm run build:index',
15
+ 'ci:local': 'npm run validate:plugins && npm run build:all',
16
+ 'release:local': 'npm run ci:local && plugin-marketplace release-local',
17
+ };
18
+ function marketplaceYaml(name, organization) {
19
+ return `# Marketplace metadata
20
+
21
+ name: ${name}
22
+ description: "${toTitleCase(name)} plugin marketplace"
23
+ organization: "${organization}"
24
+
25
+ categories:
26
+ - id: tooling
27
+ label: "Tooling"
28
+ description: "Development tools and scaffolding"
29
+ - id: integration
30
+ label: "Integration"
31
+ description: "Third-party service connectors"
32
+ - id: quality
33
+ label: "Quality"
34
+ description: "Quality checks and review workflows"
35
+ - id: workflow
36
+ label: "Workflow"
37
+ description: "Automation workflows"
38
+ - id: general
39
+ label: "General"
40
+ description: "Other plugins"
41
+
42
+ platforms:
43
+ - name: "Claude Code"
44
+ manifest: ".claude-plugin/plugin.json"
45
+ - name: "Codex"
46
+ manifest: ".codex-plugin/plugin.json"
47
+ `;
48
+ }
49
+ function readPackageJson(path) {
50
+ const raw = readFileSync(path, 'utf-8');
51
+ const parsed = JSON.parse(raw);
52
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
53
+ throw new Error(`package.json must contain an object: ${path}`);
54
+ }
55
+ return parsed;
56
+ }
57
+ function ensurePackageJson(rootDir, name) {
58
+ const packagePath = join(rootDir, 'package.json');
59
+ const packageJson = existsSync(packagePath)
60
+ ? readPackageJson(packagePath)
61
+ : {
62
+ name,
63
+ version: '1.0.0',
64
+ private: true,
65
+ };
66
+ packageJson.scripts = {
67
+ ...DEFAULT_SCRIPTS,
68
+ ...(packageJson.scripts || {}),
69
+ };
70
+ packageJson.devDependencies = {
71
+ ...(packageJson.devDependencies || {}),
72
+ };
73
+ if (!packageJson.devDependencies[CLI_PACKAGE]) {
74
+ packageJson.devDependencies[CLI_PACKAGE] = '^1.0.0';
75
+ }
76
+ writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
77
+ }
78
+ function ensureReadme(rootDir, name) {
79
+ const readmePath = join(rootDir, 'README.md');
80
+ if (existsSync(readmePath))
81
+ return;
82
+ const readme = `# ${toTitleCase(name)}
83
+
84
+ Plugin marketplace repository powered by \`${CLI_PACKAGE}\`.
85
+
86
+ ## Workflow
87
+
88
+ \`\`\`bash
89
+ npm install
90
+ npm run mp -- init my-plugin
91
+ npm run ci:local
92
+ npm run release:local
93
+ \`\`\`
94
+ `;
95
+ writeFileSync(readmePath, readme);
96
+ }
97
+ export function runInitRepo(name, options) {
98
+ const rootDir = options.root ? resolveInvocationPath(options.root) : resolveInvocationPath('.');
99
+ const marketplaceName = name || basename(rootDir);
100
+ const organization = options.organization || toTitleCase(marketplaceName);
101
+ const marketplacePath = join(rootDir, 'marketplace.yaml');
102
+ if (existsSync(marketplacePath)) {
103
+ console.error(chalk.red(`✗ marketplace.yaml 已存在: ${marketplacePath}`));
104
+ process.exit(1);
105
+ }
106
+ console.log(chalk.blue(`⟳ 初始化 plugin marketplace 仓库: ${marketplaceName}`));
107
+ mkdirSync(rootDir, { recursive: true });
108
+ mkdirSync(join(rootDir, 'plugins'), { recursive: true });
109
+ writeFileSync(marketplacePath, marketplaceYaml(marketplaceName, organization));
110
+ ensurePackageJson(rootDir, marketplaceName);
111
+ ensureReadme(rootDir, marketplaceName);
112
+ console.log(chalk.green(`✓ 仓库初始化完成: ${rootDir}`));
113
+ console.log(chalk.gray(' → npm install'));
114
+ console.log(chalk.gray(' → npm run mp -- init my-plugin'));
115
+ }
116
+ //# sourceMappingURL=init-repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-repo.js","sourceRoot":"","sources":["../../src/commands/init-repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * init 命令 — 创建新插件骨架
3
+ *
4
+ * 用法:mp init <name> [--type skill|mcp|hook]
5
+ */
6
+ export declare function runInit(name: string, options: {
7
+ type: string;
8
+ root?: string;
9
+ }): void;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * init 命令 — 创建新插件骨架
3
+ *
4
+ * 用法:mp init <name> [--type skill|mcp|hook]
5
+ */
6
+ import { chmodSync, mkdirSync, writeFileSync, existsSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import chalk from 'chalk';
9
+ import { resolveRepoContext } from '../utils/helpers.js';
10
+ const SKILL_TEMPLATE = `---
11
+ name: {{SKILL_NAME}}
12
+ description: "TODO: 填写 skill 描述"
13
+ ---
14
+
15
+ # {{SKILL_NAME}}
16
+
17
+ ## 触发条件
18
+ 当用户需要 TODO 时,激活此 skill。
19
+
20
+ ## 指令
21
+
22
+ 1. 第一步
23
+ 2. 第二步
24
+ 3. 第三步
25
+ `;
26
+ const PLUGIN_YAML_TEMPLATE = (name, type) => {
27
+ const base = `name: ${name}
28
+ version: "0.1.0"
29
+ description: "TODO: 填写插件描述"
30
+ author:
31
+ name: "Mobile Team"
32
+
33
+ category: general
34
+ tags: []
35
+
36
+ components:`;
37
+ switch (type) {
38
+ case 'mcp':
39
+ return `${base}
40
+ skills:
41
+ - name: ${name}
42
+ path: skills/${name}
43
+ description: "TODO: 填写 skill 描述"
44
+ mcp:
45
+ - name: ${name}-server
46
+ command: npx
47
+ args: ["-y", "${name}-server"]
48
+ description: "TODO: 填写 MCP server 描述"
49
+ `;
50
+ case 'hook':
51
+ return `${base}
52
+ hooks:
53
+ - event: PreToolUse
54
+ pattern: "Write|Edit"
55
+ command: "./hooks/check.sh"
56
+ `;
57
+ default: // skill
58
+ return `${base}
59
+ skills:
60
+ - name: ${name}
61
+ path: skills/${name}
62
+ description: "TODO: 填写 skill 描述"
63
+ `;
64
+ }
65
+ };
66
+ export function runInit(name, options) {
67
+ const context = resolveRepoContext(options.root);
68
+ const pluginDir = join(context.pluginsDir, name);
69
+ if (existsSync(pluginDir)) {
70
+ console.error(chalk.red(`✗ 插件目录已存在: plugins/${name}`));
71
+ process.exit(1);
72
+ }
73
+ const type = options.type || 'skill';
74
+ console.log(chalk.blue(`⟳ 创建插件: ${name} (类型: ${type})`));
75
+ // 创建目录结构
76
+ mkdirSync(pluginDir, { recursive: true });
77
+ // plugin.yaml
78
+ writeFileSync(join(pluginDir, 'plugin.yaml'), PLUGIN_YAML_TEMPLATE(name, type));
79
+ // 根据类型创建组件
80
+ if (type === 'skill' || type === 'mcp') {
81
+ const skillDir = join(pluginDir, 'skills', name);
82
+ mkdirSync(skillDir, { recursive: true });
83
+ writeFileSync(join(skillDir, 'SKILL.md'), SKILL_TEMPLATE.replaceAll('{{SKILL_NAME}}', name));
84
+ }
85
+ if (type === 'hook') {
86
+ const hooksDir = join(pluginDir, 'hooks');
87
+ const hookPath = join(hooksDir, 'check.sh');
88
+ mkdirSync(hooksDir, { recursive: true });
89
+ writeFileSync(hookPath, '#!/bin/bash\n# TODO: 实现 hook 逻辑\nexit 0\n');
90
+ chmodSync(hookPath, 0o755);
91
+ }
92
+ console.log(chalk.green(`✓ 插件创建成功: plugins/${name}/`));
93
+ console.log(chalk.gray(` → 编辑 plugin.yaml 完善配置`));
94
+ if (type === 'skill' || type === 'mcp') {
95
+ console.log(chalk.gray(` → 编辑 skills/${name}/SKILL.md 编写指令`));
96
+ }
97
+ if (type === 'hook') {
98
+ console.log(chalk.gray(` → 编辑 hooks/check.sh 实现逻辑`));
99
+ }
100
+ }
101
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * release-local 命令 — 组装本地发布产物
3
+ *
4
+ * 该命令假定调用前已执行完整构建流程。
5
+ */
6
+ export declare function runReleaseLocal(options?: {
7
+ root?: string;
8
+ }): void;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * release-local 命令 — 组装本地发布产物
3
+ *
4
+ * 该命令假定调用前已执行完整构建流程。
5
+ */
6
+ import { spawnSync } from 'node:child_process';
7
+ import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import chalk from 'chalk';
10
+ import { loadAllPlugins, loadMarketplaceMetadata, resolveRepoContext, } from '../utils/helpers.js';
11
+ function assertExists(path, label) {
12
+ if (!existsSync(path)) {
13
+ throw new Error(`${label} 不存在,请先运行 npm run ci:local`);
14
+ }
15
+ }
16
+ function copyDirectory(from, to) {
17
+ cpSync(from, to, {
18
+ recursive: true,
19
+ filter: (src) => !src.endsWith('.DS_Store'),
20
+ });
21
+ }
22
+ function writeReleaseReadme(releaseDir, marketplaceName, pluginCount) {
23
+ const readme = `# ${marketplaceName} 本地发布包
24
+
25
+ 本目录由 \`plugin-marketplace release-local\` 生成。
26
+
27
+ ## 内容
28
+
29
+ - \`plugins/\`: 插件源文件以及生成后的 Claude Code / Codex manifest
30
+ - \`.claude-plugin/marketplace.json\`: Claude Code marketplace manifest
31
+ - \`.agents/plugins/marketplace.json\`: Codex repo marketplace manifest
32
+ - \`marketplace.json\`: 根目录兼容镜像
33
+ - \`marketplace.yaml\`: marketplace 元数据
34
+ - \`release-manifest.json\`: 本次发布包的元信息
35
+
36
+ ## 插件数量
37
+
38
+ ${pluginCount}
39
+ `;
40
+ writeFileSync(join(releaseDir, 'README.md'), readme);
41
+ }
42
+ function createArchive(distDir, marketplaceName) {
43
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
44
+ const safeName = marketplaceName.replace(/[^a-zA-Z0-9._-]+/g, '-');
45
+ const archiveName = `${safeName}-release-${stamp}.tar.gz`;
46
+ const archivePath = join(distDir, archiveName);
47
+ const result = spawnSync('tar', ['-czf', archivePath, '-C', distDir, 'release'], {
48
+ stdio: 'inherit',
49
+ });
50
+ if (result.status !== 0) {
51
+ throw new Error(`发布包压缩失败: ${archiveName}`);
52
+ }
53
+ return archivePath;
54
+ }
55
+ export function runReleaseLocal(options = {}) {
56
+ console.log(chalk.blue('⟳ 组装本地发布包...\n'));
57
+ const context = resolveRepoContext(options.root);
58
+ const marketplace = loadMarketplaceMetadata(context);
59
+ const plugins = loadAllPlugins(context);
60
+ const releaseDir = join(context.distDir, 'release');
61
+ assertExists(join(context.rootDir, '.claude-plugin/marketplace.json'), 'Claude marketplace manifest');
62
+ assertExists(join(context.rootDir, '.agents/plugins/marketplace.json'), 'Codex marketplace manifest');
63
+ assertExists(join(context.rootDir, 'marketplace.json'), 'marketplace.json');
64
+ assertExists(context.marketplaceYamlPath, 'marketplace.yaml');
65
+ assertExists(join(context.pluginsDir, 'CATALOG.md'), 'plugins/CATALOG.md');
66
+ for (const { name, dir, config } of plugins) {
67
+ assertExists(join(dir, '.claude-plugin/plugin.json'), `${name} Claude manifest`);
68
+ assertExists(join(dir, '.codex-plugin/plugin.json'), `${name} Codex manifest`);
69
+ if (config.components.mcp?.length) {
70
+ assertExists(join(dir, '.mcp.json'), `${name} MCP 配置`);
71
+ }
72
+ if (config.components.hooks?.length) {
73
+ assertExists(join(dir, 'hooks/hooks.json'), `${name} hooks 配置`);
74
+ }
75
+ }
76
+ rmSync(releaseDir, { recursive: true, force: true });
77
+ mkdirSync(releaseDir, { recursive: true });
78
+ copyDirectory(context.pluginsDir, join(releaseDir, 'plugins'));
79
+ copyDirectory(join(context.rootDir, '.claude-plugin'), join(releaseDir, '.claude-plugin'));
80
+ copyDirectory(join(context.rootDir, '.agents'), join(releaseDir, '.agents'));
81
+ cpSync(join(context.rootDir, 'marketplace.json'), join(releaseDir, 'marketplace.json'));
82
+ cpSync(context.marketplaceYamlPath, join(releaseDir, 'marketplace.yaml'));
83
+ const manifest = {
84
+ generatedAt: new Date().toISOString(),
85
+ pluginCount: plugins.length,
86
+ plugins: plugins.map(({ name, config }) => ({
87
+ name,
88
+ version: config.version,
89
+ category: config.category || 'general',
90
+ })),
91
+ artifacts: {
92
+ plugins: 'plugins/',
93
+ claudeMarketplace: '.claude-plugin/marketplace.json',
94
+ codexMarketplace: '.agents/plugins/marketplace.json',
95
+ marketplaceMirror: 'marketplace.json',
96
+ marketplaceMetadata: 'marketplace.yaml',
97
+ },
98
+ };
99
+ writeFileSync(join(releaseDir, 'release-manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
100
+ writeReleaseReadme(releaseDir, marketplace.name, plugins.length);
101
+ const archivePath = createArchive(context.distDir, marketplace.name);
102
+ console.log(chalk.green(` ✓ dist/release (${plugins.length} 个插件)`));
103
+ console.log(chalk.green(` ✓ ${archivePath}`));
104
+ console.log(chalk.green('\n✓ 本地发布包生成完成'));
105
+ }
106
+ //# sourceMappingURL=release-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-local.js","sourceRoot":"","sources":["../../src/commands/release-local.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * validate 命令 — 验证插件格式
3
+ *
4
+ * 用法:mp validate [name] 或 mp validate --all
5
+ */
6
+ export declare function runValidate(name: string | undefined, options: {
7
+ all: boolean;
8
+ root?: string;
9
+ }): void;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * validate 命令 — 验证插件格式
3
+ *
4
+ * 用法:mp validate [name] 或 mp validate --all
5
+ */
6
+ import { accessSync, constants, existsSync, statSync } from 'node:fs';
7
+ import { isAbsolute, join, relative, resolve } from 'node:path';
8
+ import chalk from 'chalk';
9
+ import { loadPluginYaml, listPluginNames, resolveRepoContext, } from '../utils/helpers.js';
10
+ function isInsidePlugin(pluginDir, targetPath) {
11
+ const rel = relative(pluginDir, targetPath);
12
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
13
+ }
14
+ function resolvePluginPath(pluginDir, configuredPath, label, errors) {
15
+ if (isAbsolute(configuredPath)) {
16
+ errors.push(`${label} 不应使用绝对路径: ${configuredPath}`);
17
+ return undefined;
18
+ }
19
+ const resolvedPath = resolve(pluginDir, configuredPath);
20
+ if (!isInsidePlugin(pluginDir, resolvedPath)) {
21
+ errors.push(`${label} 越过插件目录: ${configuredPath}`);
22
+ return undefined;
23
+ }
24
+ return resolvedPath;
25
+ }
26
+ function looksLikePluginLocalPath(value) {
27
+ return (value.startsWith('./') ||
28
+ value.startsWith('../') ||
29
+ value.startsWith('/') ||
30
+ value.startsWith('hooks/') ||
31
+ value.startsWith('mcp/') ||
32
+ value.startsWith('skills/'));
33
+ }
34
+ function validateExecutable(filePath, displayPath, errors) {
35
+ try {
36
+ const stat = statSync(filePath);
37
+ if (!stat.isFile()) {
38
+ errors.push(`Hook 脚本不是文件: ${displayPath}`);
39
+ return;
40
+ }
41
+ accessSync(filePath, constants.X_OK);
42
+ }
43
+ catch {
44
+ errors.push(`Hook 脚本不可执行: ${displayPath}`);
45
+ }
46
+ }
47
+ function validateOne(context, name) {
48
+ const pluginDir = join(context.pluginsDir, name);
49
+ const errors = [];
50
+ // 1. 目录存在
51
+ if (!existsSync(pluginDir)) {
52
+ return { name, valid: false, errors: [`插件目录不存在: plugins/${name}`] };
53
+ }
54
+ // 2. plugin.yaml 存在且格式正确
55
+ try {
56
+ const config = loadPluginYaml(pluginDir);
57
+ // 3. 验证引用的 skill 目录存在
58
+ if (config.components.skills) {
59
+ for (const skill of config.components.skills) {
60
+ const skillDir = resolvePluginPath(pluginDir, skill.path, 'Skill 路径', errors);
61
+ if (!skillDir)
62
+ continue;
63
+ if (!existsSync(skillDir)) {
64
+ errors.push(`Skill 目录不存在: ${skill.path}`);
65
+ continue;
66
+ }
67
+ if (!statSync(skillDir).isDirectory()) {
68
+ errors.push(`Skill 路径不是目录: ${skill.path}`);
69
+ continue;
70
+ }
71
+ const skillMd = join(skillDir, 'SKILL.md');
72
+ if (!existsSync(skillMd)) {
73
+ errors.push(`SKILL.md 不存在: ${skill.path}/SKILL.md`);
74
+ }
75
+ }
76
+ }
77
+ // 4. 验证 hook 脚本存在
78
+ if (config.components.hooks) {
79
+ for (const hook of config.components.hooks) {
80
+ const scriptPath = resolvePluginPath(pluginDir, hook.command, 'Hook 脚本路径', errors);
81
+ if (!scriptPath)
82
+ continue;
83
+ if (!existsSync(scriptPath)) {
84
+ errors.push(`Hook 脚本不存在: ${hook.command}`);
85
+ continue;
86
+ }
87
+ validateExecutable(scriptPath, hook.command, errors);
88
+ }
89
+ }
90
+ // 5. 验证 MCP 本地文件引用存在且不越过插件目录
91
+ if (config.components.mcp) {
92
+ for (const mcp of config.components.mcp) {
93
+ if (looksLikePluginLocalPath(mcp.command)) {
94
+ const commandPath = resolvePluginPath(pluginDir, mcp.command, 'MCP command 路径', errors);
95
+ if (commandPath && !existsSync(commandPath)) {
96
+ errors.push(`MCP command 文件不存在: ${mcp.command}`);
97
+ }
98
+ }
99
+ for (const arg of mcp.args || []) {
100
+ if (!looksLikePluginLocalPath(arg))
101
+ continue;
102
+ const argPath = resolvePluginPath(pluginDir, arg, 'MCP args 路径', errors);
103
+ if (argPath && !existsSync(argPath)) {
104
+ errors.push(`MCP args 引用的文件不存在: ${arg}`);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ // 6. 名称一致性检查
110
+ if (config.name !== name) {
111
+ errors.push(`plugin.yaml 中的 name (${config.name}) 与目录名 (${name}) 不一致`);
112
+ }
113
+ }
114
+ catch (err) {
115
+ errors.push(err.message);
116
+ }
117
+ return { name, valid: errors.length === 0, errors };
118
+ }
119
+ export function runValidate(name, options) {
120
+ const context = resolveRepoContext(options.root);
121
+ const names = options.all ? listPluginNames(context) : name ? [name] : [];
122
+ if (names.length === 0) {
123
+ console.error(chalk.red('✗ 请指定插件名或使用 --all'));
124
+ process.exit(1);
125
+ }
126
+ console.log(chalk.blue(`⟳ 验证 ${names.length} 个插件...\n`));
127
+ let allValid = true;
128
+ for (const n of names) {
129
+ const result = validateOne(context, n);
130
+ if (result.valid) {
131
+ console.log(chalk.green(` ✓ ${n}`));
132
+ }
133
+ else {
134
+ allValid = false;
135
+ console.log(chalk.red(` ✗ ${n}`));
136
+ for (const err of result.errors) {
137
+ console.log(chalk.red(` └─ ${err}`));
138
+ }
139
+ }
140
+ }
141
+ console.log();
142
+ if (allValid) {
143
+ console.log(chalk.green(`✓ 所有插件验证通过`));
144
+ }
145
+ else {
146
+ console.error(chalk.red(`✗ 存在验证错误`));
147
+ process.exit(1);
148
+ }
149
+ }
150
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAQ7B,SAAS,cAAc,CAAC,SAAiB,EAAE,UAAkB;IAC3D,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC5C,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,iBAAiB,CACxB,SAAiB,EACjB,cAAsB,EACtB,KAAa,EACb,MAAgB;IAEhB,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,cAAc,cAAc,EAAE,CAAC,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxD,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,YAAY,cAAc,EAAE,CAAC,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAa;IAC7C,OAAO,CACL,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QACtB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QACrB,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC1B,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QACxB,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAC5B,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB,EAAE,WAAmB,EAAE,MAAgB;IACjF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,OAA0B,EAAE,IAAY;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,UAAU;IACV,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QAEzC,sBAAsB;QACtB,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;gBAC7C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;gBAC9E,IAAI,CAAC,QAAQ;oBAAE,SAAS;gBACxB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC1B,MAAM,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC1C,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;oBACtC,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC3C,SAAS;gBACX,CAAC;gBACD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBAC3C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,IAAI,WAAW,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;QAED,kBAAkB;QAClB,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YAC5B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBAC3C,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;gBACnF,IAAI,CAAC,UAAU;oBAAE,SAAS;gBAC1B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC5B,MAAM,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC3C,SAAS;gBACX,CAAC;gBACD,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;YAC1B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;gBACxC,IAAI,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1C,MAAM,WAAW,GAAG,iBAAiB,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;oBACxF,IAAI,WAAW,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;wBAC5C,MAAM,CAAC,IAAI,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBACnD,CAAC;gBACH,CAAC;gBAED,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;oBACjC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC;wBAAE,SAAS;oBAE7C,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;oBACzE,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;wBACpC,MAAM,CAAC,IAAI,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,aAAa;QACb,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,wBAAwB,MAAM,CAAC,IAAI,WAAW,IAAI,OAAO,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,IAAwB,EACxB,OAAwC;IAExC,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC;IAEzD,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAEvC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,KAAK,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YACnC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * plugin.yaml JSON Schema 定义
3
+ *
4
+ * 这是 marketplace 的核心数据模型。所有 plugin.yaml 都必须符合此 schema。
5
+ * 生成双平台 manifest 时,也基于此 schema 做字段映射。
6
+ */
7
+ import type { JSONSchemaType } from 'ajv';
8
+ export interface PluginSkill {
9
+ name: string;
10
+ path: string;
11
+ description?: string;
12
+ 'argument-hint'?: string;
13
+ }
14
+ export interface PluginMcp {
15
+ name: string;
16
+ command: string;
17
+ args?: string[];
18
+ env?: Record<string, string>;
19
+ description?: string;
20
+ }
21
+ export interface PluginHook {
22
+ event: string;
23
+ pattern?: string;
24
+ command: string;
25
+ timeout?: number;
26
+ }
27
+ export interface PluginAuthor {
28
+ name: string;
29
+ email?: string;
30
+ url?: string;
31
+ }
32
+ export interface CodexInterface {
33
+ displayName?: string;
34
+ shortDescription?: string;
35
+ longDescription?: string;
36
+ category?: string;
37
+ developerName?: string;
38
+ }
39
+ export interface PlatformOverrides {
40
+ codex?: {
41
+ interface?: CodexInterface;
42
+ };
43
+ }
44
+ export interface PluginComponents {
45
+ skills?: PluginSkill[];
46
+ mcp?: PluginMcp[];
47
+ hooks?: PluginHook[];
48
+ }
49
+ export interface PluginYaml {
50
+ name: string;
51
+ version: string;
52
+ description: string;
53
+ author: PluginAuthor;
54
+ category?: string;
55
+ tags?: string[];
56
+ components: PluginComponents;
57
+ platform?: PlatformOverrides;
58
+ }
59
+ export declare const pluginYamlSchema: JSONSchemaType<PluginYaml>;