@vetta-org/plugin-cli 0.1.5 → 0.1.7
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/CHANGELOG.md +33 -0
- package/README.md +16 -4
- package/dist/agents-template.d.ts +3 -1
- package/dist/agents-template.d.ts.map +1 -1
- package/dist/cli.js +292 -54
- package/dist/command.d.ts +9 -1
- package/dist/command.d.ts.map +1 -1
- package/dist/hub-template.d.ts.map +1 -1
- package/dist/index.js +292 -54
- package/dist/init.d.ts +14 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11904,6 +11904,18 @@ var agentExperimentalSettingsUpdateType = Type.Object({
|
|
|
11904
11904
|
promptPrediction: Type.Optional(Type.Boolean()),
|
|
11905
11905
|
agentSkills: Type.Optional(Type.Boolean())
|
|
11906
11906
|
}, { additionalProperties: false, minProperties: 1 });
|
|
11907
|
+
var imageGenerationSettingsType = Type.Object({
|
|
11908
|
+
textToImageProviderId: Type.Optional(Type.String({ minLength: 1, maxLength: 129 })),
|
|
11909
|
+
textToImageModelId: Type.Optional(Type.String({ minLength: 1, maxLength: 256 })),
|
|
11910
|
+
imageToImageProviderId: Type.Optional(Type.String({ minLength: 1, maxLength: 129 })),
|
|
11911
|
+
imageToImageModelId: Type.Optional(Type.String({ minLength: 1, maxLength: 256 }))
|
|
11912
|
+
}, { additionalProperties: false });
|
|
11913
|
+
var imageGenerationSettingsUpdateType = Type.Object({
|
|
11914
|
+
textToImageProviderId: Type.Optional(Type.Union([Type.String({ minLength: 1, maxLength: 129 }), Type.Null()])),
|
|
11915
|
+
textToImageModelId: Type.Optional(Type.Union([Type.String({ minLength: 1, maxLength: 256 }), Type.Null()])),
|
|
11916
|
+
imageToImageProviderId: Type.Optional(Type.Union([Type.String({ minLength: 1, maxLength: 129 }), Type.Null()])),
|
|
11917
|
+
imageToImageModelId: Type.Optional(Type.Union([Type.String({ minLength: 1, maxLength: 256 }), Type.Null()]))
|
|
11918
|
+
}, { additionalProperties: false, minProperties: 1 });
|
|
11907
11919
|
var agentSettingsEmptyInputSchema = defineCapabilityInputSchema(agentSettingsEmptyInputType);
|
|
11908
11920
|
var agentExperimentalSettingsSchema = defineCapabilityOutputSchema(agentExperimentalSettingsType, { clean: true });
|
|
11909
11921
|
var agentExperimentalSettingsUpdateSchema = defineCapabilityInputSchema(agentExperimentalSettingsUpdateType);
|
|
@@ -11923,6 +11935,22 @@ var DOMAIN_AGENT_SETTINGS_CAPABILITIES = {
|
|
|
11923
11935
|
version: 1,
|
|
11924
11936
|
input: agentExperimentalSettingsUpdateSchema,
|
|
11925
11937
|
output: agentExperimentalSettingsSchema
|
|
11938
|
+
}),
|
|
11939
|
+
GET_IMAGE_GENERATION: defineCapability({
|
|
11940
|
+
id: "cap.domain.vetta.agent-settings.image-generation.get",
|
|
11941
|
+
kind: "query",
|
|
11942
|
+
layer: CAPABILITY_LAYERS.DOMAIN,
|
|
11943
|
+
version: 1,
|
|
11944
|
+
input: agentSettingsEmptyInputSchema,
|
|
11945
|
+
output: defineCapabilityOutputSchema(imageGenerationSettingsType, { clean: true })
|
|
11946
|
+
}),
|
|
11947
|
+
SET_IMAGE_GENERATION: defineCapability({
|
|
11948
|
+
id: "cap.domain.vetta.agent-settings.image-generation.set",
|
|
11949
|
+
kind: "command",
|
|
11950
|
+
layer: CAPABILITY_LAYERS.DOMAIN,
|
|
11951
|
+
version: 1,
|
|
11952
|
+
input: defineCapabilityInputSchema(imageGenerationSettingsUpdateType),
|
|
11953
|
+
output: defineCapabilityOutputSchema(imageGenerationSettingsType, { clean: true })
|
|
11926
11954
|
})
|
|
11927
11955
|
};
|
|
11928
11956
|
var DOMAIN_AGENT_SETTINGS_CAPABILITY_CATALOG = createCapabilityCatalog(Object.values(DOMAIN_AGENT_SETTINGS_CAPABILITIES));
|
|
@@ -13028,7 +13056,7 @@ var FOUNDATION_JOB_CAPABILITIES = {
|
|
|
13028
13056
|
var FOUNDATION_JOB_CAPABILITY_CATALOG = createCapabilityCatalog(Object.values(FOUNDATION_JOB_CAPABILITIES));
|
|
13029
13057
|
|
|
13030
13058
|
// ../../capability-sdk/dist/domain/media.js
|
|
13031
|
-
var MEDIA_PROTOCOL_VERSION =
|
|
13059
|
+
var MEDIA_PROTOCOL_VERSION = 5;
|
|
13032
13060
|
var MEDIA_OPERATIONS = {
|
|
13033
13061
|
GENERATE: "generate",
|
|
13034
13062
|
COMPOSE: "compose",
|
|
@@ -13127,6 +13155,16 @@ var mediaGenerationModeCapabilityType = Type.Object({
|
|
|
13127
13155
|
aspectRatioPolicy: Type.Optional(Type.Union([Type.Literal("configurable"), Type.Literal("input-derived")])),
|
|
13128
13156
|
audioGeneration: Type.Optional(Type.Union([Type.Literal("none"), Type.Literal("always"), Type.Literal("optional")]))
|
|
13129
13157
|
}, { additionalProperties: false });
|
|
13158
|
+
var mediaGenerationModelDescriptorType = Type.Object({
|
|
13159
|
+
id: requiredStringType2,
|
|
13160
|
+
displayName: Type.Optional(Type.String({ minLength: 1, maxLength: 128 })),
|
|
13161
|
+
sourceId: Type.Optional(requiredStringType2),
|
|
13162
|
+
sourceDisplayName: Type.Optional(Type.String({ minLength: 1, maxLength: 128 })),
|
|
13163
|
+
modes: Type.Array(mediaGenerationModeType, { minItems: 1 }),
|
|
13164
|
+
aspectRatios: Type.Optional(Type.Array(requiredStringType2)),
|
|
13165
|
+
resolutions: Type.Optional(Type.Array(requiredStringType2)),
|
|
13166
|
+
defaultResolution: Type.Optional(requiredStringType2)
|
|
13167
|
+
}, { additionalProperties: false });
|
|
13130
13168
|
var mediaGenerateCapabilityType = Type.Object({
|
|
13131
13169
|
operation: Type.Literal(MEDIA_OPERATIONS.GENERATE),
|
|
13132
13170
|
kind: mediaGenerationKindType,
|
|
@@ -13134,6 +13172,8 @@ var mediaGenerateCapabilityType = Type.Object({
|
|
|
13134
13172
|
aspectRatios: Type.Optional(Type.Array(requiredStringType2)),
|
|
13135
13173
|
resolutions: Type.Optional(Type.Array(requiredStringType2)),
|
|
13136
13174
|
defaultResolution: Type.Optional(requiredStringType2),
|
|
13175
|
+
models: Type.Optional(Type.Array(mediaGenerationModelDescriptorType, { minItems: 1 })),
|
|
13176
|
+
defaultModelId: Type.Optional(requiredStringType2),
|
|
13137
13177
|
durationsSeconds: Type.Optional(Type.Array(Type.Number({ exclusiveMinimum: 0 }))),
|
|
13138
13178
|
modeCapabilities: Type.Optional(Type.Array(mediaGenerationModeCapabilityType))
|
|
13139
13179
|
}, { additionalProperties: false });
|
|
@@ -13317,6 +13357,8 @@ var modelProviderUpsertModelType = Type.Object({
|
|
|
13317
13357
|
name: Type.Optional(Type.String()),
|
|
13318
13358
|
api: Type.Optional(Type.String()),
|
|
13319
13359
|
reasoning: Type.Optional(Type.Boolean()),
|
|
13360
|
+
reasoningLevels: modelDefinitionDetailType.properties.reasoningLevels,
|
|
13361
|
+
defaultReasoningLevel: modelDefinitionDetailType.properties.defaultReasoningLevel,
|
|
13320
13362
|
contextWindow: Type.Optional(Type.Number()),
|
|
13321
13363
|
maxTokens: Type.Optional(Type.Number())
|
|
13322
13364
|
}, { additionalProperties: false });
|
|
@@ -15418,7 +15460,9 @@ var PluginAgentTeamMemberManifestSchema = Type.Object({
|
|
|
15418
15460
|
agent: Type.Optional(NonWhitespaceStringSchema),
|
|
15419
15461
|
role: Type.Optional(PluginAgentRoleSchema),
|
|
15420
15462
|
responsibility: Type.String({ maxLength: 2000 }),
|
|
15421
|
-
optional: Type.Optional(Type.Boolean())
|
|
15463
|
+
optional: Type.Optional(Type.Boolean()),
|
|
15464
|
+
instructions: Type.Optional(Type.String({ maxLength: 64000 })),
|
|
15465
|
+
instructionsPath: Type.Optional(NonWhitespaceStringSchema)
|
|
15422
15466
|
}, { additionalProperties: false });
|
|
15423
15467
|
var PluginAgentTeamManifestSchema = Type.Object({
|
|
15424
15468
|
id: Type.String({ pattern: "^[a-z0-9][a-z0-9-]{0,63}$" }),
|
|
@@ -18920,13 +18964,33 @@ async function resolveNpmPluginArchive(packageSpec, pack = runNpmPack) {
|
|
|
18920
18964
|
}
|
|
18921
18965
|
|
|
18922
18966
|
// src/agents-template.ts
|
|
18923
|
-
var AGENTS_GUIDE_REVISION =
|
|
18967
|
+
var AGENTS_GUIDE_REVISION = 3;
|
|
18924
18968
|
function readAgentsGuideRevision(content) {
|
|
18925
18969
|
const match2 = /<!--\s*vetta-guide-revision:\s*(\d+)\s*-->/.exec(content);
|
|
18926
18970
|
if (!match2)
|
|
18927
18971
|
return;
|
|
18928
18972
|
return Number(match2[1]);
|
|
18929
18973
|
}
|
|
18974
|
+
function renderCommands(pluginId, scripts) {
|
|
18975
|
+
const known = [
|
|
18976
|
+
["dev", "npm run dev # 开发服务器"],
|
|
18977
|
+
["build", "npm run build # 产出 dist/"],
|
|
18978
|
+
["install:vetta", "npm run install:vetta # 打包并装进正在运行的 Vetta(需要 Vetta 已启动)"]
|
|
18979
|
+
];
|
|
18980
|
+
const lines = known.filter(([name]) => scripts.includes(name)).map(([, line]) => line);
|
|
18981
|
+
if (!scripts.includes("install:vetta")) {
|
|
18982
|
+
lines.push("npx vetta-plugin-cli add . # 打包并装进正在运行的 Vetta");
|
|
18983
|
+
}
|
|
18984
|
+
return [
|
|
18985
|
+
...lines,
|
|
18986
|
+
"",
|
|
18987
|
+
"npx vetta-plugin-cli watch # 热更新:宿主改从本工程目录加载,改完即生效",
|
|
18988
|
+
`npx vetta-plugin-cli reload ${pluginId} # 装完提示有 pending 版本时用它`,
|
|
18989
|
+
"npx vetta-plugin-cli uninstall # 卸载(省略 id 即本工程对应的插件)",
|
|
18990
|
+
"npx vetta-plugin-cli sync # 在 hub 仓库根上跑:把索引与各能力目录对账"
|
|
18991
|
+
].join(`
|
|
18992
|
+
`);
|
|
18993
|
+
}
|
|
18930
18994
|
function renderAgentsGuide(input) {
|
|
18931
18995
|
return `<!-- vetta-guide-revision: ${AGENTS_GUIDE_REVISION} -->
|
|
18932
18996
|
# ${input.displayName}
|
|
@@ -18966,14 +19030,7 @@ npx vetta-plugin-cli docs --check-latest
|
|
|
18966
19030
|
## 常用命令
|
|
18967
19031
|
|
|
18968
19032
|
\`\`\`bash
|
|
18969
|
-
|
|
18970
|
-
npm run build # 产出 dist/
|
|
18971
|
-
npm run install:vetta # 打包并装进正在运行的 Vetta(需要 Vetta 已启动)
|
|
18972
|
-
|
|
18973
|
-
npx vetta-plugin-cli watch # 热更新:宿主改从本工程目录加载,改完即生效
|
|
18974
|
-
npx vetta-plugin-cli reload ${input.pluginId} # 装完提示有 pending 版本时用它
|
|
18975
|
-
npx vetta-plugin-cli uninstall # 卸载(省略 id 即本工程对应的插件)
|
|
18976
|
-
npx vetta-plugin-cli sync # 在 hub 仓库根上跑:把索引与各能力目录对账
|
|
19033
|
+
${renderCommands(input.pluginId, input.scripts ?? ["dev", "build", "install:vetta"])}
|
|
18977
19034
|
\`\`\`
|
|
18978
19035
|
|
|
18979
19036
|
细节都在 \`getting-started.md\`。\`docs\` 打印了 \`Marketplace index:\` 就说明这个目录之上有能力
|
|
@@ -19026,16 +19083,25 @@ npx @vetta-org/plugin-cli init --id <slug> --name "<Display Name>" abilities/plu
|
|
|
19026
19083
|
|
|
19027
19084
|
## 索引由工具对账,不要手改派生字段
|
|
19028
19085
|
|
|
19029
|
-
|
|
19030
|
-
\`config.commands\` 全都是从能力包推导出来的。改完能力后:
|
|
19086
|
+
改完能力后:
|
|
19031
19087
|
|
|
19032
19088
|
\`\`\`bash
|
|
19033
|
-
npx @vetta-org/plugin-cli sync #
|
|
19089
|
+
npx @vetta-org/plugin-cli sync # 对账并回填,看输出
|
|
19034
19090
|
npx @vetta-org/plugin-cli sync --check # 只报不写,非零退出(CI 用)
|
|
19035
19091
|
\`\`\`
|
|
19036
19092
|
|
|
19093
|
+
\`sync\` 到底做什么,分三档看清楚——它不是万能的:
|
|
19094
|
+
|
|
19095
|
+
| 字段 | \`sync\` 的行为 |
|
|
19096
|
+
| --- | --- |
|
|
19097
|
+
| 条目 \`version\` | **回填**成能力包里的版本 |
|
|
19098
|
+
| \`marketplaceVersion\` | 内容有变化时**尝试**推进。只认 semver(\`1.2.3\`)和纯整数;\`YYYY.MM.DD-NN\` 之类的格式推不动,会报出来要你手改 |
|
|
19099
|
+
| \`config.api_version\` / \`config.permissions\` / \`config.commands\` | **不写**。宿主建目录时用 \`plugin.json\` 整个重算 \`config\`,索引里的副本读都不读。已经存在且与真源不符时 \`sync\` 会提醒你删掉或改对 |
|
|
19100
|
+
|
|
19101
|
+
所以 \`sync\` 跑完要看输出:它报出来的问题(尤其是推不动的 \`marketplaceVersion\`)没人会替你处理。
|
|
19102
|
+
|
|
19037
19103
|
要**手写**的只有身份与展示:\`slug\`、\`name\`、\`description\`、\`source.path\`、\`category\`、\`tags\`、
|
|
19038
|
-
\`detail
|
|
19104
|
+
\`detail\`。新能力上架时手动加一条这样的条目。
|
|
19039
19105
|
|
|
19040
19106
|
三条容易踩的约束,\`sync --check\` 会替你守住:
|
|
19041
19107
|
|
|
@@ -19045,7 +19111,7 @@ npx @vetta-org/plugin-cli sync --check # 只报不写,非零退出(CI 用
|
|
|
19045
19111
|
| \`plugin.json\` 的 \`entry\` / \`styles\` 必须在已发布目录里真实存在 | 本地能装,市场上装不了 |
|
|
19046
19112
|
| 改了任何内容必须换 \`marketplaceVersion\` | 客户端不报错、也不更新,用户永远收不到 |
|
|
19047
19113
|
|
|
19048
|
-
|
|
19114
|
+
第三条最阴险——它不报错。\`sync\` 只在版本号是 semver 或整数时才推得动,其余格式要你自己换。
|
|
19049
19115
|
|
|
19050
19116
|
## 为什么插件目录里要提交 \`dist/\`
|
|
19051
19117
|
|
|
@@ -19213,26 +19279,80 @@ node_modules/
|
|
|
19213
19279
|
}
|
|
19214
19280
|
return { root, pluginId: input.pluginId, files: Object.keys(files).sort() };
|
|
19215
19281
|
}
|
|
19216
|
-
function refreshAgentsGuide(targetDir) {
|
|
19282
|
+
function refreshAgentsGuide(targetDir, options = {}) {
|
|
19217
19283
|
const root = resolve2(targetDir);
|
|
19284
|
+
const file = join3(root, "AGENTS.md");
|
|
19218
19285
|
const manifestPath = join3(root, "plugin.json");
|
|
19286
|
+
const hubManifestPath = join3(root, ".vetta", "marketplace.json");
|
|
19287
|
+
let kind;
|
|
19288
|
+
let content;
|
|
19219
19289
|
if (existsSync(manifestPath)) {
|
|
19220
19290
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
19221
19291
|
const pluginId = typeof manifest.id === "string" ? manifest.id : undefined;
|
|
19222
19292
|
if (!pluginId)
|
|
19223
19293
|
throw new Error(`plugin.json at ${root} has no id`);
|
|
19224
|
-
|
|
19225
|
-
|
|
19226
|
-
|
|
19294
|
+
kind = "plugin";
|
|
19295
|
+
content = renderAgentsGuide({
|
|
19296
|
+
pluginId,
|
|
19297
|
+
displayName: resolveManifestText(manifest.name, root, pluginId),
|
|
19298
|
+
scripts: readPackageScripts(root)
|
|
19299
|
+
});
|
|
19300
|
+
} else if (existsSync(hubManifestPath)) {
|
|
19301
|
+
const manifest = JSON.parse(readFileSync(hubManifestPath, "utf8"));
|
|
19302
|
+
kind = "hub";
|
|
19303
|
+
content = renderHubAgentsGuide({
|
|
19304
|
+
name: typeof manifest.name === "string" && manifest.name.length > 0 ? manifest.name : "marketplace"
|
|
19305
|
+
});
|
|
19306
|
+
} else {
|
|
19307
|
+
throw new Error(`Not a plugin project or marketplace repository: ${root}`);
|
|
19308
|
+
}
|
|
19309
|
+
if (!options.dryRun)
|
|
19310
|
+
assertSafeToOverwrite(file, options.force === true);
|
|
19311
|
+
if (options.dryRun)
|
|
19312
|
+
return { root, kind, file, content, written: false };
|
|
19313
|
+
writeFileSync(file, content, "utf8");
|
|
19314
|
+
return { root, kind, file, content, written: true };
|
|
19315
|
+
}
|
|
19316
|
+
function assertSafeToOverwrite(file, force) {
|
|
19317
|
+
if (force || !existsSync(file))
|
|
19318
|
+
return;
|
|
19319
|
+
if (readAgentsGuideRevision(readFileSync(file, "utf8")) !== undefined)
|
|
19320
|
+
return;
|
|
19321
|
+
throw new Error(`${file} has no vetta-guide-revision marker, so it looks hand-written rather than scaffolded. ` + "Refusing to overwrite it. Review the new template with `--dry-run`, merge what you want by hand, " + "or pass `--force` to replace the file.");
|
|
19322
|
+
}
|
|
19323
|
+
function resolveManifestText(raw2, root, fallback) {
|
|
19324
|
+
if (typeof raw2 !== "string" || raw2.length === 0)
|
|
19325
|
+
return fallback;
|
|
19326
|
+
const match2 = /^%([^%]+)%$/.exec(raw2);
|
|
19327
|
+
if (!match2)
|
|
19328
|
+
return raw2;
|
|
19329
|
+
const key = match2[1];
|
|
19330
|
+
const pluginManifest = readJsonFile(join3(root, "plugin.json"));
|
|
19331
|
+
const locale = typeof pluginManifest?.defaultLocale === "string" ? pluginManifest.defaultLocale : "zh";
|
|
19332
|
+
for (const candidate of [locale, "zh", "en"]) {
|
|
19333
|
+
const table = readJsonFile(join3(root, "locales", `${candidate}.json`));
|
|
19334
|
+
const value = table?.[key];
|
|
19335
|
+
if (typeof value === "string" && value.length > 0)
|
|
19336
|
+
return value;
|
|
19227
19337
|
}
|
|
19228
|
-
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
|
|
19338
|
+
return fallback;
|
|
19339
|
+
}
|
|
19340
|
+
function readPackageScripts(root) {
|
|
19341
|
+
const pkg = readJsonFile(join3(root, "package.json"));
|
|
19342
|
+
const scripts = pkg?.scripts;
|
|
19343
|
+
if (typeof scripts !== "object" || scripts === null || Array.isArray(scripts))
|
|
19344
|
+
return [];
|
|
19345
|
+
return Object.keys(scripts);
|
|
19346
|
+
}
|
|
19347
|
+
function readJsonFile(path) {
|
|
19348
|
+
if (!existsSync(path))
|
|
19349
|
+
return;
|
|
19350
|
+
try {
|
|
19351
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
19352
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : undefined;
|
|
19353
|
+
} catch {
|
|
19354
|
+
return;
|
|
19234
19355
|
}
|
|
19235
|
-
throw new Error(`Not a plugin project or marketplace repository: ${root}`);
|
|
19236
19356
|
}
|
|
19237
19357
|
var HUB_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
19238
19358
|
var APP_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
@@ -19292,7 +19412,7 @@ function detectJsonIndent(source) {
|
|
|
19292
19412
|
const match2 = /\n([ \t]+)\S/.exec(source);
|
|
19293
19413
|
return match2?.[1] ?? "\t";
|
|
19294
19414
|
}
|
|
19295
|
-
function
|
|
19415
|
+
function readJsonFile2(path) {
|
|
19296
19416
|
try {
|
|
19297
19417
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
19298
19418
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
@@ -19336,7 +19456,7 @@ function nextMarketplaceVersion(current) {
|
|
|
19336
19456
|
return;
|
|
19337
19457
|
}
|
|
19338
19458
|
function syncMarketplaceIndex(input) {
|
|
19339
|
-
const manifest =
|
|
19459
|
+
const manifest = readJsonFile2(input.manifestPath);
|
|
19340
19460
|
if (!manifest)
|
|
19341
19461
|
throw new Error(`Malformed marketplace manifest: ${input.manifestPath}`);
|
|
19342
19462
|
const abilities = Array.isArray(manifest.abilities) ? manifest.abilities : [];
|
|
@@ -19354,13 +19474,31 @@ function syncMarketplaceIndex(input) {
|
|
|
19354
19474
|
for (const member of Array.isArray(bundleConfig?.members) ? bundleConfig.members : []) {
|
|
19355
19475
|
if (typeof member !== "object" || member === null || Array.isArray(member))
|
|
19356
19476
|
continue;
|
|
19357
|
-
const
|
|
19477
|
+
const memberEntry = member;
|
|
19478
|
+
const memberSource = memberEntry.source;
|
|
19358
19479
|
const memberPath = typeof memberSource === "object" && memberSource !== null && !Array.isArray(memberSource) ? memberSource.path : undefined;
|
|
19359
19480
|
if (typeof memberPath !== "string")
|
|
19360
19481
|
continue;
|
|
19361
19482
|
const dir = resolveAbilityDir(input.hubRoot, memberPath);
|
|
19362
|
-
if (dir)
|
|
19483
|
+
if (dir) {
|
|
19363
19484
|
listedDirs.add(dir);
|
|
19485
|
+
if (manifest.schemaVersion === 3 && memberEntry.type === "plugin") {
|
|
19486
|
+
const descriptor2 = readJsonFile2(join4(dir, "ability.json"));
|
|
19487
|
+
const memberChanges = [];
|
|
19488
|
+
reconcilePlugin({
|
|
19489
|
+
entry: { ...memberEntry, version: descriptor2?.version },
|
|
19490
|
+
slug: typeof memberEntry.slug === "string" ? memberEntry.slug : "(unnamed)",
|
|
19491
|
+
abilityDir: dir,
|
|
19492
|
+
schemaVersion: manifest.schemaVersion,
|
|
19493
|
+
minAppVersion: manifest.minAppVersion,
|
|
19494
|
+
changes: memberChanges,
|
|
19495
|
+
problems
|
|
19496
|
+
});
|
|
19497
|
+
for (const change of memberChanges) {
|
|
19498
|
+
problems.push({ slug: change.slug, message: `ability.json version does not match latest release: ${change.to}` });
|
|
19499
|
+
}
|
|
19500
|
+
}
|
|
19501
|
+
}
|
|
19364
19502
|
}
|
|
19365
19503
|
continue;
|
|
19366
19504
|
}
|
|
@@ -19377,7 +19515,7 @@ function syncMarketplaceIndex(input) {
|
|
|
19377
19515
|
}
|
|
19378
19516
|
listedDirs.add(abilityDir);
|
|
19379
19517
|
if (type === "plugin")
|
|
19380
|
-
reconcilePlugin({ entry, slug, abilityDir, changes, problems });
|
|
19518
|
+
reconcilePlugin({ entry, slug, abilityDir, schemaVersion: manifest.schemaVersion, minAppVersion: manifest.minAppVersion, changes, problems });
|
|
19381
19519
|
else if (type === "mcp")
|
|
19382
19520
|
reconcileIdentityFile({ entry, slug, abilityDir, fileName: "mcp.json", changes, problems });
|
|
19383
19521
|
}
|
|
@@ -19404,8 +19542,78 @@ function syncMarketplaceIndex(input) {
|
|
|
19404
19542
|
return { manifestPath: input.manifestPath, changes, problems, unlisted, written };
|
|
19405
19543
|
}
|
|
19406
19544
|
function reconcilePlugin(context) {
|
|
19407
|
-
const { entry, slug, abilityDir, changes, problems } = context;
|
|
19408
|
-
|
|
19545
|
+
const { entry, slug, abilityDir, schemaVersion, minAppVersion, changes, problems } = context;
|
|
19546
|
+
if (schemaVersion === 3 && !("releases" in entry)) {
|
|
19547
|
+
problems.push({ slug, message: "schemaVersion 3 plugin requires versioned releases" });
|
|
19548
|
+
return;
|
|
19549
|
+
}
|
|
19550
|
+
if ("releases" in entry) {
|
|
19551
|
+
if (schemaVersion !== 3) {
|
|
19552
|
+
problems.push({ slug, message: "versioned plugin releases require marketplace schemaVersion 3" });
|
|
19553
|
+
return;
|
|
19554
|
+
}
|
|
19555
|
+
const releases = entry.releases;
|
|
19556
|
+
if (!Array.isArray(releases) || releases.length === 0) {
|
|
19557
|
+
problems.push({ slug, message: "plugin releases must be a nonempty array" });
|
|
19558
|
+
return;
|
|
19559
|
+
}
|
|
19560
|
+
let latest;
|
|
19561
|
+
const seen = new Set;
|
|
19562
|
+
for (const raw2 of releases) {
|
|
19563
|
+
if (typeof raw2 !== "object" || raw2 === null || Array.isArray(raw2)) {
|
|
19564
|
+
problems.push({ slug, message: "plugin release must be an object" });
|
|
19565
|
+
continue;
|
|
19566
|
+
}
|
|
19567
|
+
const release = raw2;
|
|
19568
|
+
const match2 = typeof release.version === "string" ? /^(\d+)\.(\d+)\.(\d+)$/.exec(release.version) : null;
|
|
19569
|
+
if (!match2 || seen.has(release.version)) {
|
|
19570
|
+
problems.push({ slug, message: `invalid or duplicate plugin release version: ${String(release.version)}` });
|
|
19571
|
+
continue;
|
|
19572
|
+
}
|
|
19573
|
+
seen.add(release.version);
|
|
19574
|
+
const minimum = typeof release.minAppVersion === "string" ? /^(\d+)\.(\d+)\.(\d+)$/.exec(release.minAppVersion) : null;
|
|
19575
|
+
if (!minimum || typeof minAppVersion !== "string" || !/^(\d+)\.(\d+)\.(\d+)$/.test(minAppVersion)) {
|
|
19576
|
+
problems.push({ slug, message: `release ${release.version} has an invalid minAppVersion` });
|
|
19577
|
+
} else {
|
|
19578
|
+
const marketMinimum = /^(\d+)\.(\d+)\.(\d+)$/.exec(minAppVersion);
|
|
19579
|
+
if (marketMinimum && compareVersionParts(minimum.slice(1).map(Number), marketMinimum.slice(1).map(Number)) < 0) {
|
|
19580
|
+
problems.push({ slug, message: `release ${release.version} requires an app older than the marketplace` });
|
|
19581
|
+
}
|
|
19582
|
+
}
|
|
19583
|
+
if (typeof release.pluginApiVersion !== "string" || !/^\^\d+\.\d+\.\d+$/.test(release.pluginApiVersion)) {
|
|
19584
|
+
problems.push({ slug, message: `release ${release.version} has an invalid pluginApiVersion` });
|
|
19585
|
+
}
|
|
19586
|
+
for (const field of ["permissions", "commands"]) {
|
|
19587
|
+
if (release[field] !== undefined && !stringArray(release[field])) {
|
|
19588
|
+
problems.push({ slug, message: `release ${release.version} has invalid ${field}` });
|
|
19589
|
+
}
|
|
19590
|
+
}
|
|
19591
|
+
const parts = [Number(match2[1]), Number(match2[2]), Number(match2[3])];
|
|
19592
|
+
if (!latest || compareVersionParts(parts, latest.parts) > 0) {
|
|
19593
|
+
latest = { version: release.version, parts };
|
|
19594
|
+
}
|
|
19595
|
+
const artifact = release.artifact;
|
|
19596
|
+
if (typeof artifact !== "object" || artifact === null || Array.isArray(artifact)) {
|
|
19597
|
+
problems.push({ slug, message: `release ${release.version} has no artifact` });
|
|
19598
|
+
continue;
|
|
19599
|
+
}
|
|
19600
|
+
const { url, sha256 } = artifact;
|
|
19601
|
+
let validUrl = false;
|
|
19602
|
+
try {
|
|
19603
|
+
const parsed = new URL(String(url));
|
|
19604
|
+
validUrl = parsed.protocol === "https:" && !parsed.username && !parsed.password && !parsed.hash;
|
|
19605
|
+
} catch {}
|
|
19606
|
+
if (!validUrl || typeof sha256 !== "string" || !/^[a-f0-9]{64}$/.test(sha256)) {
|
|
19607
|
+
problems.push({ slug, message: `release ${release.version} has an invalid HTTPS artifact or SHA-256` });
|
|
19608
|
+
}
|
|
19609
|
+
}
|
|
19610
|
+
if (latest && entry.version !== latest.version) {
|
|
19611
|
+
changes.push({ slug, field: "version", from: entry.version, to: latest.version });
|
|
19612
|
+
entry.version = latest.version;
|
|
19613
|
+
}
|
|
19614
|
+
return;
|
|
19615
|
+
}
|
|
19616
|
+
const manifest = readJsonFile2(join4(abilityDir, "plugin.json"));
|
|
19409
19617
|
if (!manifest) {
|
|
19410
19618
|
problems.push({ slug, message: "plugin.json is missing or malformed" });
|
|
19411
19619
|
return;
|
|
@@ -19444,9 +19652,16 @@ function reconcilePlugin(context) {
|
|
|
19444
19652
|
}
|
|
19445
19653
|
}
|
|
19446
19654
|
}
|
|
19655
|
+
function compareVersionParts(left, right) {
|
|
19656
|
+
for (let index = 0;index < 3; index += 1) {
|
|
19657
|
+
if (left[index] !== right[index])
|
|
19658
|
+
return (left[index] ?? 0) - (right[index] ?? 0);
|
|
19659
|
+
}
|
|
19660
|
+
return 0;
|
|
19661
|
+
}
|
|
19447
19662
|
function reconcileIdentityFile(context) {
|
|
19448
19663
|
const { entry, slug, abilityDir, fileName, changes, problems } = context;
|
|
19449
|
-
const identity =
|
|
19664
|
+
const identity = readJsonFile2(join4(abilityDir, fileName));
|
|
19450
19665
|
if (!identity) {
|
|
19451
19666
|
problems.push({ slug, message: `${fileName} is missing or malformed` });
|
|
19452
19667
|
return;
|
|
@@ -19489,7 +19704,7 @@ function findAbilityDirectories(hubRoot) {
|
|
|
19489
19704
|
return found.sort();
|
|
19490
19705
|
}
|
|
19491
19706
|
function describeIndexDrift(input) {
|
|
19492
|
-
const manifest =
|
|
19707
|
+
const manifest = readJsonFile2(input.manifestPath);
|
|
19493
19708
|
if (!manifest || !Array.isArray(manifest.abilities))
|
|
19494
19709
|
return;
|
|
19495
19710
|
const entry = manifest.abilities.find((item) => typeof item === "object" && item !== null && !Array.isArray(item) && item.slug === input.slug);
|
|
@@ -19575,11 +19790,11 @@ function readManualSdkVersion(manualDir) {
|
|
|
19575
19790
|
var HELP_TEXT = `Vetta plugin manager
|
|
19576
19791
|
|
|
19577
19792
|
Usage:
|
|
19578
|
-
vetta-plugin-cli add <npm-package|
|
|
19793
|
+
vetta-plugin-cli add <npm-package|package-path|http-url> [--json]
|
|
19579
19794
|
vetta-plugin-cli reload <plugin-id> [--json]
|
|
19580
19795
|
vetta-plugin-cli docs [--check-latest] [--json]
|
|
19581
19796
|
vetta-plugin-cli init --id <plugin-id> [--name <display>] [dir] [--json]
|
|
19582
|
-
vetta-plugin-cli init --refresh-guide [dir] [--json]
|
|
19797
|
+
vetta-plugin-cli init --refresh-guide [dir] [--dry-run] [--force] [--json]
|
|
19583
19798
|
vetta-plugin-cli init hub --name <slug> --repository <url> --min-app-version <x.y.z> [dir]
|
|
19584
19799
|
vetta-plugin-cli watch [dir] [--stop] [--json]
|
|
19585
19800
|
vetta-plugin-cli uninstall [plugin-id] [--json]
|
|
@@ -19589,7 +19804,7 @@ Examples:
|
|
|
19589
19804
|
npx @vetta-org/plugin-cli add @example/vetta-plugin-demo
|
|
19590
19805
|
npx @vetta-org/plugin-cli add @example/vetta-plugin-demo@1.2.0
|
|
19591
19806
|
npx @vetta-org/plugin-cli add . # 当前插件工程(先 pack)
|
|
19592
|
-
npx @vetta-org/plugin-cli add ./release/demo-1.2.0.
|
|
19807
|
+
npx @vetta-org/plugin-cli add ./release/demo-1.2.0.vettapkg
|
|
19593
19808
|
npx @vetta-org/plugin-cli reload demo
|
|
19594
19809
|
npx @vetta-org/plugin-cli docs
|
|
19595
19810
|
npx @vetta-org/plugin-cli init --id my-plugin --name "My Plugin"
|
|
@@ -19615,7 +19830,7 @@ function parsePluginAddCommand(argv) {
|
|
|
19615
19830
|
}
|
|
19616
19831
|
const [source, unexpected] = parsed.positionals;
|
|
19617
19832
|
if (!source)
|
|
19618
|
-
return { type: "error", message: "Missing <npm-package|
|
|
19833
|
+
return { type: "error", message: "Missing <npm-package|package-path|http-url>" };
|
|
19619
19834
|
if (unexpected)
|
|
19620
19835
|
return { type: "error", message: `Unexpected argument: ${unexpected}` };
|
|
19621
19836
|
return { type: "add", source, json: parsed.values.json === true };
|
|
@@ -19680,7 +19895,9 @@ function parsePluginInitCommand(argv) {
|
|
|
19680
19895
|
id: { type: "string" },
|
|
19681
19896
|
name: { type: "string" },
|
|
19682
19897
|
json: { type: "boolean" },
|
|
19683
|
-
"refresh-guide": { type: "boolean" }
|
|
19898
|
+
"refresh-guide": { type: "boolean" },
|
|
19899
|
+
force: { type: "boolean" },
|
|
19900
|
+
"dry-run": { type: "boolean" }
|
|
19684
19901
|
}
|
|
19685
19902
|
});
|
|
19686
19903
|
} catch (error) {
|
|
@@ -19690,7 +19907,13 @@ function parsePluginInitCommand(argv) {
|
|
|
19690
19907
|
const [dir, extra] = parsed.positionals;
|
|
19691
19908
|
if (extra)
|
|
19692
19909
|
return { type: "error", message: `Unexpected argument: ${extra}` };
|
|
19693
|
-
return {
|
|
19910
|
+
return {
|
|
19911
|
+
type: "refresh-guide",
|
|
19912
|
+
...dir ? { targetDir: dir } : {},
|
|
19913
|
+
json: parsed.values.json === true,
|
|
19914
|
+
force: parsed.values.force === true,
|
|
19915
|
+
dryRun: parsed.values["dry-run"] === true
|
|
19916
|
+
};
|
|
19694
19917
|
}
|
|
19695
19918
|
const pluginId = parsed.values.id;
|
|
19696
19919
|
if (typeof pluginId !== "string" || pluginId.length === 0) {
|
|
@@ -19838,8 +20061,9 @@ function isHttpUrl(source) {
|
|
|
19838
20061
|
return false;
|
|
19839
20062
|
}
|
|
19840
20063
|
}
|
|
19841
|
-
function
|
|
19842
|
-
|
|
20064
|
+
function isLocalPackage(source) {
|
|
20065
|
+
const lower = source.toLowerCase();
|
|
20066
|
+
if (lower.endsWith(".vettapkg") || lower.endsWith(".zip"))
|
|
19843
20067
|
return true;
|
|
19844
20068
|
const path = resolve5(source);
|
|
19845
20069
|
return existsSync4(path) && !statSync2(path).isDirectory();
|
|
@@ -19858,7 +20082,7 @@ function resolveProjectArchive(source) {
|
|
|
19858
20082
|
}
|
|
19859
20083
|
throw new Error(`No plugin.json found in ${from} or any parent directory.`);
|
|
19860
20084
|
}
|
|
19861
|
-
const archivePath = join6(project.root, "release", `${project.pluginId}-${project.version}.
|
|
20085
|
+
const archivePath = join6(project.root, "release", `${project.pluginId}-${project.version}.vettapkg`);
|
|
19862
20086
|
if (!existsSync4(archivePath)) {
|
|
19863
20087
|
throw new Error(`Packaged archive not found: ${archivePath}
|
|
19864
20088
|
Build it first: npm run build && npx vetta-plugin pack`);
|
|
@@ -19879,6 +20103,7 @@ function indexDriftHint(project) {
|
|
|
19879
20103
|
function npmInstallInput(resolved) {
|
|
19880
20104
|
return {
|
|
19881
20105
|
operation: "install-from-path",
|
|
20106
|
+
initiator: "plugin-cli",
|
|
19882
20107
|
path: resolved.archivePath,
|
|
19883
20108
|
enable: true,
|
|
19884
20109
|
source: "npm",
|
|
@@ -19972,19 +20197,22 @@ async function runPluginCommand(command, dependencies = defaultDependencies) {
|
|
|
19972
20197
|
} else if (isHttpUrl(command.source)) {
|
|
19973
20198
|
result = await dependencies.runAction("plugins.manage", {
|
|
19974
20199
|
operation: "install-from-url",
|
|
20200
|
+
initiator: "plugin-cli",
|
|
19975
20201
|
url: command.source
|
|
19976
20202
|
});
|
|
19977
20203
|
} else if (isDirectorySource(command.source)) {
|
|
19978
20204
|
const { archivePath, project } = resolveProjectArchive(command.source);
|
|
19979
20205
|
result = await dependencies.runAction("plugins.manage", {
|
|
19980
20206
|
operation: "install-from-path",
|
|
20207
|
+
initiator: "plugin-cli",
|
|
19981
20208
|
path: archivePath,
|
|
19982
20209
|
enable: true
|
|
19983
20210
|
});
|
|
19984
20211
|
driftHint = indexDriftHint(project);
|
|
19985
|
-
} else if (
|
|
20212
|
+
} else if (isLocalPackage(command.source)) {
|
|
19986
20213
|
result = await dependencies.runAction("plugins.manage", {
|
|
19987
20214
|
operation: "install-from-path",
|
|
20215
|
+
initiator: "plugin-cli",
|
|
19988
20216
|
path: resolve5(command.source),
|
|
19989
20217
|
enable: true
|
|
19990
20218
|
});
|
|
@@ -20068,7 +20296,9 @@ async function runDocsCommand(command, dependencies) {
|
|
|
20068
20296
|
lines.push(`Manual follows the installed SDK. To refresh it: ${SDK_REFRESH_COMMAND}`);
|
|
20069
20297
|
}
|
|
20070
20298
|
if (guide.stale) {
|
|
20071
|
-
lines.push(`This brief is stale (AGENTS.md revision ${guide.revision
|
|
20299
|
+
lines.push(`This brief is stale (AGENTS.md revision ${guide.revision} < ${AGENTS_GUIDE_REVISION}). Refresh it with: ${GUIDE_REFRESH_COMMAND}`);
|
|
20300
|
+
} else if (guide.unstamped) {
|
|
20301
|
+
lines.push(`AGENTS.md has no revision marker, so it looks hand-written. Review the current template with \`${GUIDE_REFRESH_COMMAND} --dry-run\` and merge by hand; do not overwrite it blindly.`);
|
|
20072
20302
|
}
|
|
20073
20303
|
if (hub) {
|
|
20074
20304
|
lines.push(`Marketplace index: ${hub.manifestPath}`);
|
|
@@ -20084,17 +20314,18 @@ var GUIDE_REFRESH_COMMAND = "npx @vetta-org/plugin-cli init --refresh-guide";
|
|
|
20084
20314
|
function inspectAgentsGuide(root) {
|
|
20085
20315
|
const path = join6(root, "AGENTS.md");
|
|
20086
20316
|
if (!existsSync4(path))
|
|
20087
|
-
return { present: false, stale: false };
|
|
20317
|
+
return { present: false, stale: false, unstamped: false };
|
|
20088
20318
|
let revision;
|
|
20089
20319
|
try {
|
|
20090
20320
|
revision = readAgentsGuideRevision(readFileSync4(path, "utf8"));
|
|
20091
20321
|
} catch {
|
|
20092
|
-
return { present: true, stale: false };
|
|
20322
|
+
return { present: true, stale: false, unstamped: false };
|
|
20093
20323
|
}
|
|
20094
20324
|
return {
|
|
20095
20325
|
present: true,
|
|
20096
20326
|
...revision === undefined ? {} : { revision },
|
|
20097
|
-
stale: revision
|
|
20327
|
+
stale: revision !== undefined && revision < AGENTS_GUIDE_REVISION,
|
|
20328
|
+
unstamped: revision === undefined
|
|
20098
20329
|
};
|
|
20099
20330
|
}
|
|
20100
20331
|
function compareSemver(left, right) {
|
|
@@ -20117,11 +20348,18 @@ function compareSemver(left, right) {
|
|
|
20117
20348
|
function runRefreshGuideCommand(command, dependencies) {
|
|
20118
20349
|
const cwd = dependencies.cwd?.() ?? process.cwd();
|
|
20119
20350
|
try {
|
|
20120
|
-
const result = refreshAgentsGuide(resolve5(cwd, command.targetDir ?? ".")
|
|
20121
|
-
|
|
20122
|
-
|
|
20123
|
-
|
|
20351
|
+
const result = refreshAgentsGuide(resolve5(cwd, command.targetDir ?? "."), {
|
|
20352
|
+
force: command.force,
|
|
20353
|
+
dryRun: command.dryRun
|
|
20354
|
+
});
|
|
20355
|
+
if (command.json) {
|
|
20356
|
+
dependencies.writeStdout(`${JSON.stringify({ ok: true, ...result })}
|
|
20124
20357
|
`);
|
|
20358
|
+
return 0;
|
|
20359
|
+
}
|
|
20360
|
+
dependencies.writeStdout(result.written ? `Rewrote ${result.file}
|
|
20361
|
+
Next: npx vetta-plugin-cli docs --check-latest
|
|
20362
|
+
` : `${result.content}`);
|
|
20125
20363
|
return 0;
|
|
20126
20364
|
} catch (error) {
|
|
20127
20365
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/init.d.ts
CHANGED
|
@@ -14,10 +14,19 @@ export interface InitPluginResult {
|
|
|
14
14
|
readonly files: readonly string[];
|
|
15
15
|
}
|
|
16
16
|
export declare function initPluginProject(input: InitPluginInput): InitPluginResult;
|
|
17
|
+
export interface RefreshGuideOptions {
|
|
18
|
+
/** 覆盖一份没有版本戳的 `AGENTS.md`。缺省拒绝——没有戳的多半是手写的。 */
|
|
19
|
+
readonly force?: boolean;
|
|
20
|
+
/** 只算出内容,不落盘。 */
|
|
21
|
+
readonly dryRun?: boolean;
|
|
22
|
+
}
|
|
17
23
|
export interface RefreshGuideResult {
|
|
18
24
|
readonly root: string;
|
|
19
25
|
readonly kind: "plugin" | "hub";
|
|
20
26
|
readonly file: string;
|
|
27
|
+
/** 这次生成的说明书正文。`dryRun` 时用它做人工合并。 */
|
|
28
|
+
readonly content: string;
|
|
29
|
+
readonly written: boolean;
|
|
21
30
|
}
|
|
22
31
|
/**
|
|
23
32
|
* 在已有的工程或能力市场仓库里重写 `AGENTS.md`。
|
|
@@ -25,8 +34,12 @@ export interface RefreshGuideResult {
|
|
|
25
34
|
* `init` 拒绝覆盖已有工程,所以老目录里那份说明书从落地起就再也没变过——它写于某个版本的
|
|
26
35
|
* SDK,之后新增的约定一条都没有。这里只重写这一个文件:它是脚手架里唯一「纯派生、没有用户
|
|
27
36
|
* 内容」的产物,其余文件都可能被改过,不该被一次刷新抹掉。
|
|
37
|
+
*
|
|
38
|
+
* **只有确实由脚手架生成的那份才算纯派生。** 没有版本戳的文件无法与手写内容区分——能力市场
|
|
39
|
+
* 仓库的根 `AGENTS.md` 往往是一整本手写的市场规范——所以一律拒绝覆盖,让调用方拿 `dryRun`
|
|
40
|
+
* 的内容去人工合并,或显式 `force`。宁可少刷新一份,也不能悄悄删掉别人写的东西。
|
|
28
41
|
*/
|
|
29
|
-
export declare function refreshAgentsGuide(targetDir: string): RefreshGuideResult;
|
|
42
|
+
export declare function refreshAgentsGuide(targetDir: string, options?: RefreshGuideOptions): RefreshGuideResult;
|
|
30
43
|
export interface InitHubInput {
|
|
31
44
|
readonly targetDir: string;
|
|
32
45
|
/** 市场名(slug)。 */
|