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