@sfmc-bds/cli 0.2.0-beta.0 → 0.2.0-beta.5
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/i18n/locales/en.d.ts +10 -10
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +10 -10
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
- package/dist/i18n/locales/zh-CN.js +10 -10
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/log-filter.d.ts +69 -0
- package/dist/log-filter.d.ts.map +1 -0
- package/dist/log-filter.js +150 -0
- package/dist/log-filter.js.map +7 -0
- package/dist/logs.d.ts +13 -6
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +87 -64
- package/dist/logs.js.map +3 -3
- package/dist/pack-update/providers/curseforge.d.ts.map +1 -1
- package/dist/pack-update/providers/curseforge.js +25 -5
- package/dist/pack-update/providers/curseforge.js.map +2 -2
- package/dist/pack-update/service.d.ts.map +1 -1
- package/dist/pack-update/service.js +12 -7
- package/dist/pack-update/service.js.map +2 -2
- package/dist/pack-update/version-policy.d.ts +3 -2
- package/dist/pack-update/version-policy.d.ts.map +1 -1
- package/dist/pack-update/version-policy.js +11 -17
- package/dist/pack-update/version-policy.js.map +2 -2
- package/dist/world-packs.d.ts +15 -0
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +86 -86
- package/dist/world-packs.js.map +2 -2
- package/package.json +15 -15
|
@@ -164,13 +164,33 @@ class CurseForgeBedrockProvider {
|
|
|
164
164
|
if (!best) return null;
|
|
165
165
|
let downloadUrl = best.downloadUrl ?? "";
|
|
166
166
|
if (!downloadUrl) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
try {
|
|
168
|
+
const dl = await this.apiGet(
|
|
169
|
+
`/v1/mods/${projectId}/files/${best.id}/download-url`,
|
|
170
|
+
{}
|
|
171
|
+
);
|
|
172
|
+
downloadUrl = dl.data ?? "";
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!downloadUrl) {
|
|
177
|
+
let allowDist;
|
|
178
|
+
let slug = String(projectId);
|
|
179
|
+
try {
|
|
180
|
+
const mod = await this.apiGet(`/v1/mods/${projectId}`, {});
|
|
181
|
+
allowDist = mod.data?.allowModDistribution;
|
|
182
|
+
if (mod.data?.slug) slug = mod.data.slug;
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
if (allowDist === false) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`CurseForge\u300C${slug}\u300D\u4F5C\u8005\u5173\u95ED\u4E86\u7B2C\u4E09\u65B9\u5206\u53D1\uFF08allowModDistribution=false\uFF09\uFF0CAPI \u65E0\u6CD5\u4E0B\u8F7D\u3002\u8BF7\u624B\u52A8\u4ECE https://www.curseforge.com/minecraft-bedrock/addons/${slug} \u4E0B\u8F7D\u540E\u653E\u5165 packs/inbox\uFF0C\u6216\u8054\u7CFB\u4F5C\u8005\u5F00\u542F\u5206\u53D1\u3002`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
throw new Error(
|
|
191
|
+
`CurseForge \u65E0\u6CD5\u89E3\u6790\u4E0B\u8F7D\u5730\u5740\uFF08project=${projectId} file=${best.id}\uFF09\u3002\u82E5\u5B98\u65B9\u9875\u53EF\u4E0B\u800C\u6B64\u5904\u5931\u8D25\uFF0C\u591A\u534A\u662F\u4F5C\u8005\u9650\u5236\u4E86 API \u5206\u53D1\u3002`
|
|
170
192
|
);
|
|
171
|
-
downloadUrl = dl.data ?? "";
|
|
172
193
|
}
|
|
173
|
-
if (!downloadUrl) return null;
|
|
174
194
|
const out = {
|
|
175
195
|
provider: "curseforge",
|
|
176
196
|
projectId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/pack-update/providers/curseforge.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * CurseForge Bedrock SourceProvider\n *\n * - \u5B98\u65B9 api.curseforge.com\uFF1AgetMod / files / download\uFF08\u9700 Studios x-api-key\uFF09\n * - \u641C\u7D22\uFF1A\u4F18\u5148\u5B98\u65B9\uFF1B\u82E5 403 \u5219\u56DE\u9000 api.curse.tools\uFF08\u90E8\u5206 key \u5BF9 /v1/mods/search \u88AB\u62D2\uFF09\n * - Bedrock gameId = 78022\uFF0CAddons classId = 4984\n * - \u4E0B\u8F7D\u8D70 bds-tools httpDownload\uFF08\u6D41\u5F0F\u843D\u76D8\uFF0C\u4E0E BDS \u66F4\u65B0\u540C\u4E00\u6743\u5A01 \u2014 DRY/DIP\uFF09\n */\nimport { httpDownload } from \"@sfmc-bds/bds-tools/http\";\nimport { bindByteProgressToBar, createTerminalProgress } from \"@sfmc-bds/sdk/logs\";\nimport type {\n CurseForgeProviderConfig,\n PackReleaseType,\n PackSourceProvider,\n SourceFileRef,\n SourceSearchHit,\n} from \"../types.js\";\n\ninterface CfMod {\n id: number;\n name: string;\n slug: string;\n summary?: string;\n downloadCount?: number;\n links?: { websiteUrl?: string };\n classId?: number;\n}\n\ninterface CfFile {\n id: number;\n displayName: string;\n fileName: string;\n downloadUrl?: string | null;\n fileDate?: string;\n releaseType?: number;\n fileStatus?: number;\n}\n\nconst RELEASE_MAP: Record<number, PackReleaseType> = {\n 1: \"release\",\n 2: \"beta\",\n 3: \"alpha\",\n};\n\n/** \u5386\u53F2\u9519\u8BEF\u9ED8\u8BA4\u503C \u2192 \u7EA0\u6B63\u4E3A Bedrock */\nconst LEGACY_BAD_GAME_IDS = new Set([459]);\nconst BEDROCK_GAME_ID = 78022;\nconst BEDROCK_ADDONS_CLASS_ID = 4984;\nconst DEFAULT_SEARCH_BASE = \"https://api.curse.tools/v1/cf\";\n\nfunction releaseRank(t: PackReleaseType | undefined, preferred: PackReleaseType[]): number {\n if (!t) return 999;\n const i = preferred.indexOf(t);\n return i >= 0 ? i : 100 + (t === \"release\" ? 0 : t === \"beta\" ? 1 : 2);\n}\n\nfunction mapHits(mods: CfMod[]): SourceSearchHit[] {\n return (mods ?? []).map((m) => {\n const hit: SourceSearchHit = {\n provider: \"curseforge\",\n projectId: m.id,\n slug: m.slug,\n name: m.name,\n summary: m.summary ?? \"\",\n websiteUrl: m.links?.websiteUrl ?? `https://www.curseforge.com/minecraft-bedrock/addons/${m.slug}`,\n };\n if (typeof m.downloadCount === \"number\") hit.downloadCount = m.downloadCount;\n return hit;\n });\n}\n\nexport class CurseForgeBedrockProvider implements PackSourceProvider {\n readonly id = \"curseforge\" as const;\n private classIdCache: number | null = null;\n\n constructor(private readonly cfg: CurseForgeProviderConfig) {}\n\n isConfigured(): boolean {\n return !!(this.cfg.enabled && this.cfg.apiKey?.trim());\n }\n\n private gameId(): number {\n const id = this.cfg.gameId;\n if (!id || LEGACY_BAD_GAME_IDS.has(id)) return BEDROCK_GAME_ID;\n return id;\n }\n\n private searchBase(): string {\n return (this.cfg.searchBaseUrl || DEFAULT_SEARCH_BASE).replace(/\\/$/, \"\");\n }\n\n private officialBase(): string {\n return this.cfg.baseUrl.replace(/\\/$/, \"\");\n }\n\n private headers(includeKey = true): Record<string, string> {\n const h: Record<string, string> = { Accept: \"application/json\" };\n if (includeKey && this.cfg.apiKey?.trim()) {\n h[\"x-api-key\"] = this.cfg.apiKey.trim();\n }\n return h;\n }\n\n private looksLikeLegacyUploadToken(key: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(key.trim());\n }\n\n private buildUrl(\n base: string,\n pathname: string,\n query: Record<string, string | number | undefined>\n ): URL {\n const url = new URL(`${base}${pathname.startsWith(\"/\") ? pathname : `/${pathname}`}`);\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null || v === \"\") continue;\n url.searchParams.set(k, String(v));\n }\n return url;\n }\n\n private async fetchJson<T>(\n base: string,\n pathname: string,\n query: Record<string, string | number | undefined>,\n opts?: { requireKey?: boolean; label?: string }\n ): Promise<T> {\n const requireKey = opts?.requireKey !== false;\n if (requireKey && !this.isConfigured()) {\n throw new Error(\"CurseForge API key \u672A\u914D\u7F6E\uFF08configs/pack-update.json \u6216 CURSEFORGE_API_KEY\uFF09\");\n }\n const key = this.cfg.apiKey.trim();\n const url = this.buildUrl(base, pathname, query);\n const res = await fetch(url, { headers: this.headers(requireKey || !!key) });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n if (res.status === 403 && requireKey) {\n const hint = this.looksLikeLegacyUploadToken(key)\n ? \"\u5F53\u524D key \u50CF legacy Upload UUID Token\u3002\u8BF7\u5230 https://console.curseforge.com/ \u7533\u8BF7 Studios Key\u3002\"\n : \"\u82E5\u4EC5\u641C\u7D22\u5931\u8D25\uFF1A\u5B98\u65B9 /mods/search \u53EF\u80FD\u5BF9\u4F60\u7684 key \u8FD4\u56DE 403\uFF08\u5C06\u81EA\u52A8\u6539\u7528 curse.tools\uFF09\u3002\u5176\u5B83\u63A5\u53E3\u4ECD\u9700\u6709\u6548 Studios Key\u3002\";\n throw new Error(\n `CurseForge HTTP 403 (${opts?.label ?? pathname}): ${body.slice(0, 80).trim() || \"Forbidden\"} \u2014 ${hint}`\n );\n }\n throw new Error(`CurseForge HTTP ${res.status} (${opts?.label ?? pathname}): ${body.slice(0, 200)}`);\n }\n return (await res.json()) as T;\n }\n\n /** \u5B98\u65B9 Core API GET */\n private apiGet<T>(\n pathname: string,\n query: Record<string, string | number | undefined>\n ): Promise<T> {\n return this.fetchJson<T>(this.officialBase(), pathname, query, {\n requireKey: true,\n label: `official${pathname}`,\n });\n }\n\n async resolveClassId(): Promise<number | null> {\n if (this.cfg.classId != null) return this.cfg.classId;\n if (this.classIdCache != null) return this.classIdCache;\n try {\n const data = await this.apiGet<{ data: Array<{ id: number; name: string; isClass?: boolean }> }>(\n \"/v1/categories\",\n { gameId: this.gameId(), classesOnly: \"true\" }\n );\n const hit =\n data.data?.find((c) => /^addons?$/i.test(c.name)) ??\n data.data?.find((c) => /addon/i.test(c.name));\n this.classIdCache = hit?.id ?? BEDROCK_ADDONS_CLASS_ID;\n return this.classIdCache;\n } catch {\n this.classIdCache = BEDROCK_ADDONS_CLASS_ID;\n return this.classIdCache;\n }\n }\n\n async search(query: string): Promise<SourceSearchHit[]> {\n const classId = (await this.resolveClassId()) ?? BEDROCK_ADDONS_CLASS_ID;\n const q = {\n gameId: this.gameId(),\n classId,\n searchFilter: query,\n pageSize: this.cfg.pageSize,\n sortField: 2,\n sortOrder: \"desc\",\n };\n\n /* 1) \u5B98\u65B9\u641C\u7D22\uFF08\u90E8\u5206 Studios key \u4F1A\u5BF9 /mods/search \u6052 403\uFF09 */\n try {\n const data = await this.apiGet<{ data: CfMod[] }>(\"/v1/mods/search\", q);\n return mapHits(data.data ?? []);\n } catch (e) {\n const msg = (e as Error).message || \"\";\n if (!/HTTP 403/.test(msg)) throw e;\n }\n\n /* 2) curse.tools \u955C\u50CF\uFF08\u4E0E\u5B98\u65B9\u540C\u8DEF\u5F84\u7EA6\u5B9A\uFF09 */\n const data = await this.fetchJson<{ data: CfMod[] }>(this.searchBase(), \"/mods/search\", q, {\n requireKey: false,\n label: \"search-mirror\",\n });\n return mapHits(data.data ?? []);\n }\n\n async resolveProject(ref: string | number): Promise<SourceSearchHit | null> {\n if (typeof ref === \"number\" || /^\\d+$/.test(String(ref))) {\n const id = Number(ref);\n const data = await this.apiGet<{ data: CfMod }>(`/v1/mods/${id}`, {});\n const m = data.data;\n if (!m) return null;\n return mapHits([m])[0] ?? null;\n }\n const s = String(ref).trim();\n const urlMatch = s.match(/curseforge\\.com\\/minecraft-bedrock\\/[^/]+\\/([^/?#]+)/i);\n const slug = urlMatch?.[1] ?? s;\n const hits = await this.search(slug);\n return hits.find((h) => h.slug === slug) ?? hits[0] ?? null;\n }\n\n async getLatestFile(projectId: number): Promise<SourceFileRef | null> {\n const data = await this.apiGet<{ data: CfFile[] }>(`/v1/mods/${projectId}/files`, {\n pageSize: 50,\n });\n const files = [...(data.data ?? [])];\n files.sort((a, b) => {\n const ra = releaseRank(RELEASE_MAP[a.releaseType ?? 1], this.cfg.preferredReleaseTypes);\n const rb = releaseRank(RELEASE_MAP[b.releaseType ?? 1], this.cfg.preferredReleaseTypes);\n if (ra !== rb) return ra - rb;\n const da = a.fileDate ? Date.parse(a.fileDate) : 0;\n const db = b.fileDate ? Date.parse(b.fileDate) : 0;\n return db - da;\n });\n const best = files[0];\n if (!best) return null;\n let downloadUrl = best.downloadUrl ?? \"\";\n if (!downloadUrl) {\n const dl = await this.apiGet<{ data: string }>(\n `/v1/mods/${projectId}/files/${best.id}/download-url`,\n {}\n );\n downloadUrl = dl.data ?? \"\";\n }\n if (!downloadUrl) return null;\n const out: SourceFileRef = {\n provider: \"curseforge\",\n projectId,\n fileId: best.id,\n fileName: best.fileName,\n displayName: best.displayName,\n downloadUrl,\n };\n if (best.fileDate) out.fileDate = best.fileDate;\n const rt = RELEASE_MAP[best.releaseType ?? 1];\n if (rt) out.releaseType = rt;\n return out;\n }\n\n async download(\n file: SourceFileRef,\n destPath: string,\n onProgress?: (dl: number, total: number) => void\n ): Promise<void> {\n const bar = createTerminalProgress({\n stream: process.stderr,\n format: `\u4E0B\u8F7D ${file.fileName} | {bar} | {percentage}% | {value}/{total} MB | {speed}`,\n });\n const onByteProgress = bindByteProgressToBar(bar, {\n speedSampleMs: 250,\n ...(onProgress ? { onProgress } : {}),\n });\n try {\n await httpDownload(file.downloadUrl, destPath, {\n headers: this.headers(true),\n onProgress: onByteProgress,\n });\n } finally {\n if (bar.active) bar.stop();\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "AAQA,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB,8BAA8B;
|
|
4
|
+
"sourcesContent": ["/**\n * CurseForge Bedrock SourceProvider\n *\n * - \u5B98\u65B9 api.curseforge.com\uFF1AgetMod / files / download\uFF08\u9700 Studios x-api-key\uFF09\n * - \u641C\u7D22\uFF1A\u4F18\u5148\u5B98\u65B9\uFF1B\u82E5 403 \u5219\u56DE\u9000 api.curse.tools\uFF08\u90E8\u5206 key \u5BF9 /v1/mods/search \u88AB\u62D2\uFF09\n * - Bedrock gameId = 78022\uFF0CAddons classId = 4984\n * - \u4E0B\u8F7D\u8D70 bds-tools httpDownload\uFF08\u6D41\u5F0F\u843D\u76D8\uFF0C\u4E0E BDS \u66F4\u65B0\u540C\u4E00\u6743\u5A01 \u2014 DRY/DIP\uFF09\n */\nimport { httpDownload } from \"@sfmc-bds/bds-tools/http\";\nimport { bindByteProgressToBar, createTerminalProgress } from \"@sfmc-bds/sdk/logs\";\nimport type {\n CurseForgeProviderConfig,\n PackReleaseType,\n PackSourceProvider,\n SourceFileRef,\n SourceSearchHit,\n} from \"../types.js\";\n\ninterface CfMod {\n id: number;\n name: string;\n slug: string;\n summary?: string;\n downloadCount?: number;\n links?: { websiteUrl?: string };\n classId?: number;\n /** \u4F5C\u8005\u662F\u5426\u5141\u8BB8\u7B2C\u4E09\u65B9/API \u5206\u53D1\uFF1Bfalse \u65F6 files[].downloadUrl \u6052\u4E3A null */\n allowModDistribution?: boolean;\n}\n\ninterface CfFile {\n id: number;\n displayName: string;\n fileName: string;\n downloadUrl?: string | null;\n fileDate?: string;\n releaseType?: number;\n fileStatus?: number;\n}\n\nconst RELEASE_MAP: Record<number, PackReleaseType> = {\n 1: \"release\",\n 2: \"beta\",\n 3: \"alpha\",\n};\n\n/** \u5386\u53F2\u9519\u8BEF\u9ED8\u8BA4\u503C \u2192 \u7EA0\u6B63\u4E3A Bedrock */\nconst LEGACY_BAD_GAME_IDS = new Set([459]);\nconst BEDROCK_GAME_ID = 78022;\nconst BEDROCK_ADDONS_CLASS_ID = 4984;\nconst DEFAULT_SEARCH_BASE = \"https://api.curse.tools/v1/cf\";\n\nfunction releaseRank(t: PackReleaseType | undefined, preferred: PackReleaseType[]): number {\n if (!t) return 999;\n const i = preferred.indexOf(t);\n return i >= 0 ? i : 100 + (t === \"release\" ? 0 : t === \"beta\" ? 1 : 2);\n}\n\nfunction mapHits(mods: CfMod[]): SourceSearchHit[] {\n return (mods ?? []).map((m) => {\n const hit: SourceSearchHit = {\n provider: \"curseforge\",\n projectId: m.id,\n slug: m.slug,\n name: m.name,\n summary: m.summary ?? \"\",\n websiteUrl: m.links?.websiteUrl ?? `https://www.curseforge.com/minecraft-bedrock/addons/${m.slug}`,\n };\n if (typeof m.downloadCount === \"number\") hit.downloadCount = m.downloadCount;\n return hit;\n });\n}\n\nexport class CurseForgeBedrockProvider implements PackSourceProvider {\n readonly id = \"curseforge\" as const;\n private classIdCache: number | null = null;\n\n constructor(private readonly cfg: CurseForgeProviderConfig) {}\n\n isConfigured(): boolean {\n return !!(this.cfg.enabled && this.cfg.apiKey?.trim());\n }\n\n private gameId(): number {\n const id = this.cfg.gameId;\n if (!id || LEGACY_BAD_GAME_IDS.has(id)) return BEDROCK_GAME_ID;\n return id;\n }\n\n private searchBase(): string {\n return (this.cfg.searchBaseUrl || DEFAULT_SEARCH_BASE).replace(/\\/$/, \"\");\n }\n\n private officialBase(): string {\n return this.cfg.baseUrl.replace(/\\/$/, \"\");\n }\n\n private headers(includeKey = true): Record<string, string> {\n const h: Record<string, string> = { Accept: \"application/json\" };\n if (includeKey && this.cfg.apiKey?.trim()) {\n h[\"x-api-key\"] = this.cfg.apiKey.trim();\n }\n return h;\n }\n\n private looksLikeLegacyUploadToken(key: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(key.trim());\n }\n\n private buildUrl(\n base: string,\n pathname: string,\n query: Record<string, string | number | undefined>\n ): URL {\n const url = new URL(`${base}${pathname.startsWith(\"/\") ? pathname : `/${pathname}`}`);\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null || v === \"\") continue;\n url.searchParams.set(k, String(v));\n }\n return url;\n }\n\n private async fetchJson<T>(\n base: string,\n pathname: string,\n query: Record<string, string | number | undefined>,\n opts?: { requireKey?: boolean; label?: string }\n ): Promise<T> {\n const requireKey = opts?.requireKey !== false;\n if (requireKey && !this.isConfigured()) {\n throw new Error(\"CurseForge API key \u672A\u914D\u7F6E\uFF08configs/pack-update.json \u6216 CURSEFORGE_API_KEY\uFF09\");\n }\n const key = this.cfg.apiKey.trim();\n const url = this.buildUrl(base, pathname, query);\n const res = await fetch(url, { headers: this.headers(requireKey || !!key) });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n if (res.status === 403 && requireKey) {\n const hint = this.looksLikeLegacyUploadToken(key)\n ? \"\u5F53\u524D key \u50CF legacy Upload UUID Token\u3002\u8BF7\u5230 https://console.curseforge.com/ \u7533\u8BF7 Studios Key\u3002\"\n : \"\u82E5\u4EC5\u641C\u7D22\u5931\u8D25\uFF1A\u5B98\u65B9 /mods/search \u53EF\u80FD\u5BF9\u4F60\u7684 key \u8FD4\u56DE 403\uFF08\u5C06\u81EA\u52A8\u6539\u7528 curse.tools\uFF09\u3002\u5176\u5B83\u63A5\u53E3\u4ECD\u9700\u6709\u6548 Studios Key\u3002\";\n throw new Error(\n `CurseForge HTTP 403 (${opts?.label ?? pathname}): ${body.slice(0, 80).trim() || \"Forbidden\"} \u2014 ${hint}`\n );\n }\n throw new Error(`CurseForge HTTP ${res.status} (${opts?.label ?? pathname}): ${body.slice(0, 200)}`);\n }\n return (await res.json()) as T;\n }\n\n /** \u5B98\u65B9 Core API GET */\n private apiGet<T>(\n pathname: string,\n query: Record<string, string | number | undefined>\n ): Promise<T> {\n return this.fetchJson<T>(this.officialBase(), pathname, query, {\n requireKey: true,\n label: `official${pathname}`,\n });\n }\n\n async resolveClassId(): Promise<number | null> {\n if (this.cfg.classId != null) return this.cfg.classId;\n if (this.classIdCache != null) return this.classIdCache;\n try {\n const data = await this.apiGet<{ data: Array<{ id: number; name: string; isClass?: boolean }> }>(\n \"/v1/categories\",\n { gameId: this.gameId(), classesOnly: \"true\" }\n );\n const hit =\n data.data?.find((c) => /^addons?$/i.test(c.name)) ??\n data.data?.find((c) => /addon/i.test(c.name));\n this.classIdCache = hit?.id ?? BEDROCK_ADDONS_CLASS_ID;\n return this.classIdCache;\n } catch {\n this.classIdCache = BEDROCK_ADDONS_CLASS_ID;\n return this.classIdCache;\n }\n }\n\n async search(query: string): Promise<SourceSearchHit[]> {\n const classId = (await this.resolveClassId()) ?? BEDROCK_ADDONS_CLASS_ID;\n const q = {\n gameId: this.gameId(),\n classId,\n searchFilter: query,\n pageSize: this.cfg.pageSize,\n sortField: 2,\n sortOrder: \"desc\",\n };\n\n /* 1) \u5B98\u65B9\u641C\u7D22\uFF08\u90E8\u5206 Studios key \u4F1A\u5BF9 /mods/search \u6052 403\uFF09 */\n try {\n const data = await this.apiGet<{ data: CfMod[] }>(\"/v1/mods/search\", q);\n return mapHits(data.data ?? []);\n } catch (e) {\n const msg = (e as Error).message || \"\";\n if (!/HTTP 403/.test(msg)) throw e;\n }\n\n /* 2) curse.tools \u955C\u50CF\uFF08\u4E0E\u5B98\u65B9\u540C\u8DEF\u5F84\u7EA6\u5B9A\uFF09 */\n const data = await this.fetchJson<{ data: CfMod[] }>(this.searchBase(), \"/mods/search\", q, {\n requireKey: false,\n label: \"search-mirror\",\n });\n return mapHits(data.data ?? []);\n }\n\n async resolveProject(ref: string | number): Promise<SourceSearchHit | null> {\n if (typeof ref === \"number\" || /^\\d+$/.test(String(ref))) {\n const id = Number(ref);\n const data = await this.apiGet<{ data: CfMod }>(`/v1/mods/${id}`, {});\n const m = data.data;\n if (!m) return null;\n return mapHits([m])[0] ?? null;\n }\n const s = String(ref).trim();\n const urlMatch = s.match(/curseforge\\.com\\/minecraft-bedrock\\/[^/]+\\/([^/?#]+)/i);\n const slug = urlMatch?.[1] ?? s;\n const hits = await this.search(slug);\n return hits.find((h) => h.slug === slug) ?? hits[0] ?? null;\n }\n\n async getLatestFile(projectId: number): Promise<SourceFileRef | null> {\n const data = await this.apiGet<{ data: CfFile[] }>(`/v1/mods/${projectId}/files`, {\n pageSize: 50,\n });\n const files = [...(data.data ?? [])];\n files.sort((a, b) => {\n const ra = releaseRank(RELEASE_MAP[a.releaseType ?? 1], this.cfg.preferredReleaseTypes);\n const rb = releaseRank(RELEASE_MAP[b.releaseType ?? 1], this.cfg.preferredReleaseTypes);\n if (ra !== rb) return ra - rb;\n const da = a.fileDate ? Date.parse(a.fileDate) : 0;\n const db = b.fileDate ? Date.parse(b.fileDate) : 0;\n return db - da;\n });\n const best = files[0];\n if (!best) return null;\n let downloadUrl = best.downloadUrl ?? \"\";\n if (!downloadUrl) {\n try {\n const dl = await this.apiGet<{ data: string }>(\n `/v1/mods/${projectId}/files/${best.id}/download-url`,\n {}\n );\n downloadUrl = dl.data ?? \"\";\n } catch {\n /* \u4E0B\u65B9\u7EDF\u4E00\u8BCA\u65AD allowModDistribution */\n }\n }\n if (!downloadUrl) {\n /* \u4F5C\u8005\u5173\u95ED\u7B2C\u4E09\u65B9\u5206\u53D1\u65F6 downloadUrl \u4E3A\u7A7A\u4E14 download-url \u6052 403 \u2014 \u4E0E API key \u65E0\u5173 */\n let allowDist: boolean | undefined;\n let slug = String(projectId);\n try {\n const mod = await this.apiGet<{ data: CfMod }>(`/v1/mods/${projectId}`, {});\n allowDist = mod.data?.allowModDistribution;\n if (mod.data?.slug) slug = mod.data.slug;\n } catch {\n /* ignore */\n }\n if (allowDist === false) {\n throw new Error(\n `CurseForge\u300C${slug}\u300D\u4F5C\u8005\u5173\u95ED\u4E86\u7B2C\u4E09\u65B9\u5206\u53D1\uFF08allowModDistribution=false\uFF09\uFF0CAPI \u65E0\u6CD5\u4E0B\u8F7D\u3002` +\n `\u8BF7\u624B\u52A8\u4ECE https://www.curseforge.com/minecraft-bedrock/addons/${slug} \u4E0B\u8F7D\u540E\u653E\u5165 packs/inbox\uFF0C\u6216\u8054\u7CFB\u4F5C\u8005\u5F00\u542F\u5206\u53D1\u3002`\n );\n }\n throw new Error(\n `CurseForge \u65E0\u6CD5\u89E3\u6790\u4E0B\u8F7D\u5730\u5740\uFF08project=${projectId} file=${best.id}\uFF09\u3002` +\n `\u82E5\u5B98\u65B9\u9875\u53EF\u4E0B\u800C\u6B64\u5904\u5931\u8D25\uFF0C\u591A\u534A\u662F\u4F5C\u8005\u9650\u5236\u4E86 API \u5206\u53D1\u3002`\n );\n }\n const out: SourceFileRef = {\n provider: \"curseforge\",\n projectId,\n fileId: best.id,\n fileName: best.fileName,\n displayName: best.displayName,\n downloadUrl,\n };\n if (best.fileDate) out.fileDate = best.fileDate;\n const rt = RELEASE_MAP[best.releaseType ?? 1];\n if (rt) out.releaseType = rt;\n return out;\n }\n\n async download(\n file: SourceFileRef,\n destPath: string,\n onProgress?: (dl: number, total: number) => void\n ): Promise<void> {\n const bar = createTerminalProgress({\n stream: process.stderr,\n format: `\u4E0B\u8F7D ${file.fileName} | {bar} | {percentage}% | {value}/{total} MB | {speed}`,\n });\n const onByteProgress = bindByteProgressToBar(bar, {\n speedSampleMs: 250,\n ...(onProgress ? { onProgress } : {}),\n });\n try {\n await httpDownload(file.downloadUrl, destPath, {\n headers: this.headers(true),\n onProgress: onByteProgress,\n });\n } finally {\n if (bar.active) bar.stop();\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["data"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/pack-update/service.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/pack-update/service.ts"],"names":[],"mappings":"AAIA,OAAO,EAWL,KAAK,gBAAgB,EACtB,MAAM,iCAAiC,CAAC;AAsHzC,2BAA2B;AAC3B,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwHhB;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBjE;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgCjF;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAsB1C;AA4TD,wBAAsB,gBAAgB,CAAC,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDnG;AAED,0BAA0B;AAC1B,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAS9D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD"}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { confirm, isCancel } from "@clack/prompts";
|
|
2
2
|
import {
|
|
3
|
-
discoverPackRoots,
|
|
4
3
|
enableInstalledPack,
|
|
5
4
|
ensureVersionGreaterThan,
|
|
6
|
-
extractArchiveToTemp,
|
|
7
5
|
findInstalledPackById,
|
|
8
6
|
installPackDirectory,
|
|
9
7
|
listInstalledWorldPacks,
|
|
10
8
|
readPackDependencyUuids,
|
|
11
9
|
readPackManifestInfo,
|
|
10
|
+
resolvePackRoots,
|
|
12
11
|
worldPackParentDir
|
|
13
12
|
} from "@sfmc-bds/bds-tools/world-packs";
|
|
14
13
|
import fs from "node:fs";
|
|
@@ -329,14 +328,14 @@ async function prepareCheck(bpUuid, binding, cfg, packs, downloadArchive) {
|
|
|
329
328
|
const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "sfmc-pack-upd-"));
|
|
330
329
|
const archiveFile = path.join(stagingDir, file.fileName || "pack.zip");
|
|
331
330
|
await provider.download(file, archiveFile);
|
|
332
|
-
const
|
|
333
|
-
const roots =
|
|
331
|
+
const resolved = await resolvePackRoots(archiveFile);
|
|
332
|
+
const roots = resolved.roots;
|
|
334
333
|
const bpRoot = roots.find((r) => readPackManifestInfo(r)?.kind === "behavior");
|
|
335
334
|
const remoteBpInfo = bpRoot ? readPackManifestInfo(bpRoot) : null;
|
|
336
335
|
if (!remoteBpInfo) {
|
|
336
|
+
resolved.dispose();
|
|
337
337
|
try {
|
|
338
338
|
fs.rmSync(stagingDir, { recursive: true, force: true });
|
|
339
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
340
339
|
} catch {
|
|
341
340
|
}
|
|
342
341
|
return withLocalBp(
|
|
@@ -373,13 +372,19 @@ async function prepareCheck(bpUuid, binding, cfg, packs, downloadArchive) {
|
|
|
373
372
|
binding,
|
|
374
373
|
remoteBpInfo,
|
|
375
374
|
remoteRoots: roots,
|
|
376
|
-
|
|
377
|
-
|
|
375
|
+
stagingDir,
|
|
376
|
+
disposeRoots: resolved.dispose
|
|
378
377
|
},
|
|
379
378
|
localBp
|
|
380
379
|
);
|
|
381
380
|
}
|
|
382
381
|
function cleanupCheck(r) {
|
|
382
|
+
if (r.disposeRoots) {
|
|
383
|
+
try {
|
|
384
|
+
r.disposeRoots();
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
}
|
|
383
388
|
for (const d of [r.tempDir, r.stagingDir]) {
|
|
384
389
|
if (!d) continue;
|
|
385
390
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/pack-update/service.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * pack-update \u7F16\u6392\uFF1A\u63A2\u6D4B\u7ED1\u5B9A / \u68C0\u67E5 / \u5E94\u7528\u66F4\u65B0\n */\nimport { confirm, isCancel } from \"@clack/prompts\";\nimport {\n discoverPackRoots,\n enableInstalledPack,\n ensureVersionGreaterThan,\n extractArchiveToTemp,\n findInstalledPackById,\n installPackDirectory,\n listInstalledWorldPacks,\n readPackDependencyUuids,\n readPackManifestInfo,\n worldPackParentDir,\n type InstalledWorldPack,\n type PackManifestInfo,\n} from \"@sfmc-bds/bds-tools/world-packs\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { t } from \"../i18n/index.js\";\nimport { pushLog } from \"../logs.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { c } from \"../theme.js\";\nimport { getBinding, listBindings, packSourcesPath, setBinding } from \"./bindings.js\";\nimport {\n ensurePackUpdateConfigFile,\n getPackMatchConfig,\n loadPackUpdateConfig,\n packUpdateConfigPath,\n} from \"./config.js\";\nimport {\n createPackSourceProvider,\n providerShortLabel,\n resolveConfiguredPackProvider,\n} from \"./providers/index.js\";\nimport type {\n PackSourceBinding,\n PackSourceProvider,\n PackUpdateConfig,\n SemVer3,\n SourceSearchHit,\n} from \"./types.js\";\nimport {\n decideVersionPolicy,\n buildSearchQueries,\n buildSearchQueriesFromSources,\n packSourceScore,\n} from \"./version-policy.js\";\n\nfunction logPack(text: string, level: \"info\" | \"warn\" | \"error\" | \"success\" = \"info\"): void {\n pushLog(text, \"pack\", level);\n}\n\nfunction fmtVer(v: SemVer3): string {\n return v.join(\".\");\n}\n\n/** \u7ED1\u5B9A\u542F\u7528\u6001\u6587\u6848\uFF1AbindOk / sources list \u5171\u7528\uFF08DRY\uFF09\uFF0C\u8D70 packs.list i18n */\nfunction bindingEnabledLabel(enabled: boolean): string {\n return enabled ? t(\"packs.list.on\").trim() : t(\"packs.list.off\").trim();\n}\n\n/** \u672A\u914D\u7F6E\u6E90\u65F6\u7684\u7EDF\u4E00\u6587\u6848\uFF08DRY\uFF1A\u5165\u53E3\u52FF\u5404\u81EA\u62FC needKey\uFF1B\u6587\u6848\u6E90\u65E0\u5173 \u2014 OCP\uFF09 */\nfunction needKeyText(): string {\n return t(\"packUpdate.needKey\", { path: packUpdateConfigPath() });\n}\n\n/** bindOk \u53C2\u6570\u552F\u4E00\u6784\u9020\u70B9\uFF08probe / bind \u5171\u7528 \u2014 DRY\uFF09\uFF0C\u62A5\u544A\u5B9E\u9645 binding.enabled\uFF08LSP\uFF09 */\nfunction bindOkParams(opts: {\n uuid: string;\n provider: PackSourceBinding[\"provider\"] | SourceSearchHit[\"provider\"];\n slug: string;\n enabled: boolean;\n}): Record<string, string> {\n return {\n uuid: opts.uuid,\n provider: providerShortLabel(opts.provider),\n slug: opts.slug,\n enabled: bindingEnabledLabel(opts.enabled),\n path: packSourcesPath(),\n };\n}\n\n/** \u5C31\u5730\u8865\u4E01\u5E76\u843D\u76D8\uFF08prepareCheck \u591A\u51FA\u53E3\u5171\u7528 \u2014 DRY\uFF1B\u52FF\u6563\u843D Object.assign+setBinding\uFF09 */\nfunction touchBinding(bpUuid: string, binding: PackSourceBinding, patch?: Partial<PackSourceBinding>): void {\n if (patch) Object.assign(binding, patch);\n setBinding(bpUuid, binding);\n}\n\n/** \u8BE5 fileId \u662F\u5426\u5DF2\u6210\u529F\u5199\u5165\u4E16\u754C\u76EE\u5F55\uFF08DRY\uFF1AprepareCheck \u591A\u5904\u52FF\u624B\u5199 null/!==\uFF09 */\nfunction isFileIdApplied(binding: PackSourceBinding, fileId: number): boolean {\n return binding.lastAppliedFileId != null && binding.lastAppliedFileId === fileId;\n}\n\n/** \u591A\u67E5\u8BE2\u641C\u7D22 + \u7EFC\u5408\u6253\u5206\u6392\u5E8F\uFF08probe / searchRemote \u5171\u7528\uFF09 */\nasync function searchAndRankHits(\n provider: PackSourceProvider,\n queries: string[],\n stripFolderTags: boolean\n): Promise<Array<{ hit: SourceSearchHit; score: number }>> {\n const byId = new Map<number, SourceSearchHit>();\n for (const q of queries) {\n const hits = await provider.search(q);\n for (const h of hits) byId.set(h.projectId, h);\n }\n return [...byId.values()]\n .map((h) => ({\n hit: h,\n score: Math.max(...queries.map((q) => packSourceScore(q, h, stripFolderTags))),\n }))\n .sort((a, b) => b.score - a.score);\n}\n\nfunction makeBindingFromHit(\n hit: SourceSearchHit,\n pairedResourceUuid: string | null,\n opts?: { prev?: PackSourceBinding | null; defaultEnabled: boolean }\n): PackSourceBinding {\n const prev = opts?.prev;\n return {\n /* \u91CD\u7ED1\u4FDD\u7559\u539F enabled\uFF1B\u65B0\u5EFA\u8D70\u914D\u7F6E\u5951\u7EA6 defaultBindingEnabled\uFF08LSP\uFF09 */\n enabled: prev?.enabled ?? opts?.defaultEnabled ?? false,\n provider: hit.provider,\n projectId: hit.projectId,\n slug: hit.slug,\n websiteUrl: hit.websiteUrl,\n pairedResourceUuid,\n lastFileId: prev?.lastFileId ?? null,\n lastCheckedAt: null,\n lastAppliedFileId: prev?.lastAppliedFileId ?? null,\n };\n}\n\n/** \u4ECE\u5DF2\u5B89\u88C5 BP \u63D0\u53D6\u914D\u5BF9 RP uuid */\nexport function pairedRpUuidFromBpDir(bpDir: string): string | null {\n const deps = readPackDependencyUuids(bpDir);\n return deps[0] ?? null;\n}\n\nexport async function probeSourceAfterInstall(opts: {\n info: PackManifestInfo;\n packDir?: string;\n /** \u5B89\u88C5\u540E\u7684\u6587\u4EF6\u5939\u540D\uFF08\u4F18\u5148\u4E8E basename(packDir)\uFF09 */\n folderName?: string;\n interactive?: boolean;\n}): Promise<void> {\n const cfg = loadPackUpdateConfig();\n if (!cfg.enabled || !cfg.probeSourceAfterInstall) return;\n if (opts.info.kind !== \"behavior\") return;\n\n ensurePackUpdateConfigFile();\n const provider = resolveConfiguredPackProvider(cfg);\n if (!provider) {\n logPack(needKeyText(), \"warn\");\n return;\n }\n\n const match = getPackMatchConfig(cfg);\n /* header \u5E38\u672C\u5730\u5316\uFF1B\u6587\u4EF6\u5939\u540D\u5F80\u5F80\u542B\u62C9\u4E01\u6838\u5FC3 \u2014 \u4E24\u6E90\u5206\u522B\u6D3E\u751F\u518D\u5408\u5E76\uFF0C\u6709\u62C9\u4E01\u5219\u4E0D\u641C\u7EAF\u4E2D\u6587 */\n const folderName =\n (opts.folderName && String(opts.folderName).trim()) ||\n (opts.packDir ? path.basename(opts.packDir) : \"\");\n const plan = buildSearchQueriesFromSources(\n [\n { id: \"header\", raw: opts.info.name },\n { id: \"folder\", raw: folderName },\n ],\n match.stripFolderTags\n );\n const queries = plan.queries;\n if (queries.length === 0) {\n logPack(t(\"packUpdate.probeNoName\"), \"warn\");\n return;\n }\n\n logPack(\n t(\"packUpdate.probeQueries\", {\n header: opts.info.name || \"-\",\n folder: folderName || \"-\",\n queries: queries.join(\" | \"),\n }),\n \"info\"\n );\n\n let scored: Array<{ hit: SourceSearchHit; score: number }>;\n try {\n scored = await searchAndRankHits(provider, queries, match.stripFolderTags);\n } catch (e) {\n logPack(t(\"packUpdate.probeFail\", { message: (e as Error).message }), \"warn\");\n return;\n }\n\n if (scored.length === 0) {\n logPack(t(\"packUpdate.probeMiss\", { name: queries.join(\", \") }), \"info\");\n return;\n }\n\n const primary = queries.find((q) => /[A-Za-z]/.test(q)) ?? queries[0]!;\n const best = scored[0]!;\n if (best.score < match.nameMinScore) {\n logPack(\n t(\"packUpdate.probeLowScore\", {\n name: primary,\n hit: `${best.hit.name} (${best.hit.slug})`,\n score: best.score.toFixed(2),\n url: best.hit.websiteUrl,\n }),\n \"info\"\n );\n return;\n }\n\n logPack(\n t(\"packUpdate.probeHit\", {\n name: `${opts.info.name} / ${folderName || \"-\"}`,\n hit: `${best.hit.name} [${best.hit.slug}]`,\n url: best.hit.websiteUrl,\n score: best.score.toFixed(2),\n }),\n \"success\"\n );\n logPack(t(\"packUpdate.editHint\", { path: packSourcesPath() }), \"info\");\n\n const interactive = opts.interactive ?? !!process.stdin.isTTY;\n let accept = false;\n if (interactive && cfg.askConfirmOnBind && process.stdin.isTTY) {\n const ans = await confirm({\n message: t(\"packUpdate.confirmBind\", { hit: best.hit.name }),\n initialValue: true,\n });\n if (isCancel(ans)) return;\n accept = !!ans;\n } else {\n /* \u975E TTY / BDS \u6536\u4EF6\u7BB1 / askConfirmOnBind=false\uFF1A\u547D\u4E2D\u5373\u5199\u5165\uFF0C\u907F\u514D\u63A2\u6D4B\u6210\u529F\u5374\u65E0 pack-sources.json */\n accept = true;\n logPack(\n t(\"packUpdate.probeAutoBind\", {\n provider: providerShortLabel(best.hit.provider),\n slug: best.hit.slug,\n path: packSourcesPath(),\n }),\n \"info\"\n );\n }\n\n if (!accept) {\n logPack(t(\"packUpdate.bindSkipped\"), \"info\");\n return;\n }\n\n const paired = (opts.packDir ? pairedRpUuidFromBpDir(opts.packDir) : null) ?? null;\n const binding = makeBindingFromHit(best.hit, paired, { defaultEnabled: cfg.defaultBindingEnabled });\n setBinding(opts.info.uuid, binding);\n logPack(\n t(\n \"packUpdate.bindOk\",\n bindOkParams({\n uuid: opts.info.uuid,\n provider: best.hit.provider,\n slug: best.hit.slug,\n enabled: binding.enabled,\n })\n ),\n \"success\"\n );\n}\n\nexport async function searchRemote(query: string): Promise<string> {\n const cfg = loadPackUpdateConfig();\n const provider = resolveConfiguredPackProvider(cfg);\n if (!provider) {\n return c.yellow(needKeyText());\n }\n const match = getPackMatchConfig(cfg);\n const queries = buildSearchQueries(query, match.stripFolderTags);\n const ranked = await searchAndRankHits(provider, queries, match.stripFolderTags);\n if (ranked.length === 0) return c.dim(t(\"packUpdate.searchEmpty\", { query }));\n return ranked\n .map(\n ({ hit: h, score }, i) =>\n `${c.cyan(String(i + 1).padStart(2))}. ${h.name} ${c.dim(`id=${h.projectId} slug=${h.slug} score=${score.toFixed(2)}`)}\\n ${h.websiteUrl}`\n )\n .join(\"\\n\");\n}\n\nexport async function bindPackSource(packId: string, ref: string): Promise<string> {\n const cfg = loadPackUpdateConfig();\n const provider = resolveConfiguredPackProvider(cfg);\n if (!provider) {\n return c.yellow(needKeyText());\n }\n const { bdsRoot, levelName } = resolveBdsContext();\n const packs = listInstalledWorldPacks(bdsRoot, levelName);\n const pack = findInstalledPackById(packs, packId);\n if (!pack) return c.red(t(\"packs.notFound\", { id: packId }));\n if (pack.kind !== \"behavior\") return c.red(t(\"packUpdate.bindBpOnly\"));\n\n const hit = await provider.resolveProject(ref);\n if (!hit) return c.red(t(\"packUpdate.resolveFail\", { ref }));\n\n const paired = pairedRpUuidFromBpDir(pack.dir);\n const binding = makeBindingFromHit(hit, paired, {\n prev: getBinding(pack.uuid),\n defaultEnabled: cfg.defaultBindingEnabled,\n });\n setBinding(pack.uuid, binding);\n return c.green(\n t(\n \"packUpdate.bindOk\",\n bindOkParams({\n uuid: pack.uuid,\n provider: hit.provider,\n slug: hit.slug,\n enabled: binding.enabled,\n })\n )\n );\n}\n\nexport function formatSourcesList(): string {\n ensurePackUpdateConfigFile();\n const bindings = listBindings();\n const lines = [\n t(\"packUpdate.sourcesHeader\", {\n config: packUpdateConfigPath(),\n sources: packSourcesPath(),\n }),\n ];\n if (bindings.length === 0) {\n lines.push(c.dim(t(\"packUpdate.sourcesEmpty\")));\n return lines.join(\"\\n\");\n }\n for (const { bpUuid, binding } of bindings) {\n const label = bindingEnabledLabel(binding.enabled);\n const en = binding.enabled ? c.green(label) : c.dim(label);\n const tag = providerShortLabel(binding.provider);\n lines.push(\n ` [${en}] ${bpUuid} ${tag}:${binding.slug || binding.projectId} ${c.dim(binding.websiteUrl || \"\")}`\n );\n }\n return lines.join(\"\\n\");\n}\n\ninterface CheckResult {\n bpUuid: string;\n name: string;\n localVer: SemVer3;\n remoteVer: SemVer3 | null;\n updateAvailable: boolean;\n majorHigher: boolean;\n shouldBumpRp: boolean;\n fileId: number | null;\n message: string;\n binding: PackSourceBinding;\n localBp?: InstalledWorldPack;\n remoteBpInfo?: PackManifestInfo;\n remoteRoots?: string[];\n tempDir?: string;\n /** \u4E0B\u8F7D\u5F52\u6863\u6240\u5728\u7684\u4E34\u65F6 staging \u76EE\u5F55\uFF08\u975E zip \u6587\u4EF6\u8DEF\u5F84\uFF09 */\n stagingDir?: string;\n}\n\nfunction withLocalBp(base: Omit<CheckResult, \"localBp\">, localBp: InstalledWorldPack | undefined): CheckResult {\n return localBp ? { ...base, localBp } : { ...base };\n}\n\nfunction baseCheckFields(\n bpUuid: string,\n name: string,\n localVer: SemVer3,\n binding: PackSourceBinding,\n extras: Partial<CheckResult> & { message: string }\n): Omit<CheckResult, \"localBp\"> {\n return {\n bpUuid,\n name,\n localVer,\n remoteVer: null,\n updateAvailable: false,\n majorHigher: false,\n shouldBumpRp: false,\n fileId: null,\n binding,\n ...extras,\n };\n}\n\nasync function prepareCheck(\n bpUuid: string,\n binding: PackSourceBinding,\n cfg: PackUpdateConfig,\n packs: InstalledWorldPack[],\n downloadArchive: boolean\n): Promise<CheckResult> {\n const localBp = packs.find((p) => p.uuid.toLowerCase() === bpUuid.toLowerCase() && p.kind === \"behavior\");\n const name = localBp?.name ?? bpUuid;\n const localVer: SemVer3 = localBp?.version ?? [0, 0, 0];\n const provider = createPackSourceProvider(cfg, binding.provider);\n\n touchBinding(bpUuid, binding, { lastCheckedAt: new Date().toISOString() });\n\n if (!binding.enabled) {\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, { message: t(\"packUpdate.bindingDisabled\") }),\n localBp\n );\n }\n\n const file = await provider.getLatestFile(binding.projectId);\n if (!file) {\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, { message: t(\"packUpdate.noRemoteFile\") }),\n localBp\n );\n }\n\n /* \u5DF2\u6210\u529F\u5E94\u7528\u540C\u4E00 fileId\uFF1A\u4E0D\u518D\u4E0B\u8F7D */\n if (isFileIdApplied(binding, file.fileId)) {\n touchBinding(bpUuid, binding, { lastFileId: file.fileId });\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, {\n fileId: file.fileId,\n message: t(\"packUpdate.upToDate\"),\n }),\n localBp\n );\n }\n\n if (!downloadArchive) {\n /* \u4EC5\u6587\u4EF6 id \u6BD4\u8F83\u7684\u8F7B\u91CF\u68C0\u67E5\uFF08\u672A apply \u5373\u89C6\u4E3A\u6709\u66F4\u65B0\uFF09 */\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, {\n updateAvailable: true,\n fileId: file.fileId,\n message: t(\"packUpdate.fileNewer\", { file: file.fileName, id: String(file.fileId) }),\n }),\n localBp\n );\n }\n\n const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-pack-upd-\"));\n const archiveFile = path.join(stagingDir, file.fileName || \"pack.zip\");\n await provider.download(file, archiveFile);\n const tempDir = await extractArchiveToTemp(archiveFile);\n const roots = discoverPackRoots(tempDir, { maxDepth: 3 });\n const bpRoot = roots.find((r) => readPackManifestInfo(r)?.kind === \"behavior\");\n const remoteBpInfo = bpRoot ? readPackManifestInfo(bpRoot) : null;\n if (!remoteBpInfo) {\n try {\n fs.rmSync(stagingDir, { recursive: true, force: true });\n fs.rmSync(tempDir, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, {\n fileId: file.fileId,\n message: t(\"packUpdate.remoteNoBp\"),\n }),\n localBp\n );\n }\n\n /*\n * \u80FD\u8D70\u5230\u6B64\u5904\u8BF4\u660E\u8BE5 fileId \u5C1A\u672A\u6210\u529F apply\uFF08\u4E0A\u65B9\u5DF2 early-return\uFF09\u3002\n * - \u8FDC\u7A0B BP \u7248\u672C\u66F4\u9AD8 \u2192 \u8986\u76D6\n * - \u7248\u672C\u672A\u66F4\u9AD8 \u2192 \u4ECD\u8986\u76D6\uFF08\u6C49\u5316\u5305\u7B49\u540C\u7248\u672C\u53F7\u4E0D\u540C\u5185\u5BB9\uFF1B\u52FF\u5728\u672A install \u65F6\u5199 lastAppliedFileId\uFF09\n * RP bump \u89C4\u5219\u96C6\u4E2D\u5728 decideVersionPolicy\uFF08OCP/DRY\uFF1A\u52FF\u5728\u7F16\u6392\u5C42\u590D\u523B policy \u5B57\u6BB5\uFF09\u3002\n */\n const decision = decideVersionPolicy(localVer, remoteBpInfo.version, cfg.versionPolicy, {\n treatAsUpdate: true,\n });\n\n touchBinding(bpUuid, binding, { lastFileId: file.fileId });\n\n const message = decision.remoteNewer\n ? t(\"packUpdate.bpNewer\", {\n local: fmtVer(localVer),\n remote: fmtVer(remoteBpInfo.version),\n })\n : t(\"packUpdate.needSync\", {\n local: fmtVer(localVer),\n remote: fmtVer(remoteBpInfo.version),\n id: String(file.fileId),\n });\n\n return withLocalBp(\n {\n bpUuid,\n name,\n localVer,\n remoteVer: remoteBpInfo.version,\n updateAvailable: true,\n majorHigher: decision.majorHigher,\n shouldBumpRp: decision.shouldBumpRp,\n fileId: file.fileId,\n message,\n binding,\n remoteBpInfo,\n remoteRoots: roots,\n tempDir,\n stagingDir,\n },\n localBp\n );\n}\n\nfunction cleanupCheck(r: CheckResult): void {\n for (const d of [r.tempDir, r.stagingDir]) {\n if (!d) continue;\n try {\n fs.rmSync(d, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n }\n}\n\n/** \u5C1D\u8BD5\u5B89\u88C5\u914D\u5BF9 RP\uFF1Baccept \u4E3A\u8FC7\u6EE4\u8C13\u8BCD\uFF08DRY\uFF1A\u4E24\u5904\u5FAA\u73AF\u5408\u4E00\uFF09 */\nasync function tryInstallResourcePack(opts: {\n rpRoots: string[];\n bdsRoot: string;\n levelName: string;\n folderName?: string;\n accept: (info: PackManifestInfo) => boolean;\n}): Promise<{ info: PackManifestInfo; destDir: string } | null> {\n for (const root of opts.rpRoots) {\n const info = readPackManifestInfo(root);\n if (!info || !opts.accept(info)) continue;\n const rpDest = worldPackParentDir(opts.bdsRoot, opts.levelName, \"resource\");\n const rpInstall = await installPackDirectory({\n srcDir: root,\n destParent: rpDest,\n force: true,\n ...(opts.folderName ? { folderName: opts.folderName } : {}),\n });\n if (rpInstall.ok && rpInstall.info && rpInstall.destDir) {\n return { info: rpInstall.info, destDir: rpInstall.destDir };\n }\n }\n return null;\n}\n\nasync function applyUpdate(r: CheckResult, cfg: PackUpdateConfig): Promise<{ ok: boolean; message: string }> {\n if (!r.updateAvailable || !r.remoteRoots || !r.remoteBpInfo) {\n return { ok: true, message: r.message };\n }\n const { bdsRoot, levelName } = resolveBdsContext();\n const packs = listInstalledWorldPacks(bdsRoot, levelName);\n\n const oldRp =\n r.binding.pairedResourceUuid != null\n ? packs.find((p) => p.kind === \"resource\" && p.uuid.toLowerCase() === r.binding.pairedResourceUuid!.toLowerCase())\n : undefined;\n const oldRpVer: SemVer3 = oldRp?.version ?? [0, 0, 0];\n\n const bpRoot = r.remoteRoots.find((x) => readPackManifestInfo(x)?.kind === \"behavior\");\n const rpRoots = r.remoteRoots.filter((x) => readPackManifestInfo(x)?.kind === \"resource\");\n\n if (!bpRoot) return { ok: false, message: t(\"packUpdate.remoteNoBp\") };\n\n /* \u5B89\u88C5 BP\uFF08force \u8986\u76D6\u540C uuid / \u540C\u6587\u4EF6\u5939\uFF09 */\n const bpDest = worldPackParentDir(bdsRoot, levelName, \"behavior\");\n const bpInstall = await installPackDirectory({\n srcDir: bpRoot,\n destParent: bpDest,\n force: true,\n ...(r.localBp?.folderName ? { folderName: r.localBp.folderName } : {}),\n });\n if (!bpInstall.ok || !bpInstall.info || !bpInstall.destDir) {\n return { ok: false, message: t(\"packUpdate.installFail\", { reason: bpInstall.reason ?? \"?\" }) };\n }\n await enableInstalledPack({ bdsRoot, levelName, info: bpInstall.info });\n logPack(\n t(\"packUpdate.installedBp\", {\n dir: bpInstall.destDir,\n version: fmtVer(bpInstall.info.version),\n }),\n \"success\"\n );\n\n /* \u5B89\u88C5\u914D\u5BF9 RP\uFF1A\u5148\u6309 binding uuid\uFF0C\u518D\u6309\u65B0 BP dependencies */\n let rpInfo: PackManifestInfo | null = null;\n let rpDir: string | null = null;\n const wantRp = r.binding.pairedResourceUuid?.toLowerCase();\n const installed = await tryInstallResourcePack({\n rpRoots,\n bdsRoot,\n levelName,\n ...(oldRp?.folderName ? { folderName: oldRp.folderName } : {}),\n accept: (info) => !wantRp || info.uuid.toLowerCase() === wantRp,\n });\n if (installed) {\n rpInfo = installed.info;\n rpDir = installed.destDir;\n }\n\n if (!rpInfo && rpRoots.length > 0) {\n const deps = readPackDependencyUuids(bpInstall.destDir);\n const fallback = await tryInstallResourcePack({\n rpRoots,\n bdsRoot,\n levelName,\n accept: (info) =>\n deps.length === 0 || deps.some((d) => d.toLowerCase() === info.uuid.toLowerCase()),\n });\n if (fallback) {\n rpInfo = fallback.info;\n rpDir = fallback.destDir;\n r.binding.pairedResourceUuid = fallback.info.uuid;\n }\n }\n\n if (rpInfo && rpDir && r.shouldBumpRp) {\n const next = ensureVersionGreaterThan(rpDir, oldRpVer, cfg.versionPolicy.rpBumpComponent);\n rpInfo = { ...rpInfo, version: next };\n }\n\n if (rpInfo) {\n await enableInstalledPack({ bdsRoot, levelName, info: rpInfo });\n logPack(\n t(\"packUpdate.installedRp\", {\n dir: rpDir ?? \"-\",\n version: fmtVer(rpInfo.version),\n }),\n \"success\"\n );\n } else if (rpRoots.length > 0) {\n logPack(t(\"packUpdate.rpInstallMiss\"), \"warn\");\n }\n\n touchBinding(r.bpUuid, r.binding, {\n lastAppliedFileId: r.fileId,\n lastFileId: r.fileId,\n lastCheckedAt: new Date().toISOString(),\n });\n\n return {\n ok: true,\n message: t(\"packUpdate.applied\", {\n name: r.name,\n bp: fmtVer(bpInstall.info.version),\n rp: rpInfo ? fmtVer(rpInfo.version) : \"-\",\n }),\n };\n}\n\nexport async function checkPackUpdates(opts?: { packId?: string; apply?: boolean }): Promise<string> {\n const cfg = loadPackUpdateConfig();\n if (!cfg.enabled) return c.dim(t(\"packUpdate.disabled\"));\n /* \u5165\u53E3\u9884\u68C0\uFF1A\u4EFB\u4E00\u5DF2\u914D\u7F6E\u6E90\u5373\u53EF\uFF1B\u9010 binding \u4ECD\u6309 binding.provider \u5206\u6D3E\uFF08LSP/OCP\uFF09 */\n if (!resolveConfiguredPackProvider(cfg)) {\n return c.yellow(needKeyText());\n }\n\n const { bdsRoot, levelName } = resolveBdsContext();\n const packs = listInstalledWorldPacks(bdsRoot, levelName);\n let targets = listBindings();\n if (opts?.packId) {\n const pack = findInstalledPackById(packs, opts.packId);\n const uuid = pack?.uuid ?? opts.packId;\n targets = targets.filter((x) => x.bpUuid.toLowerCase() === uuid.toLowerCase());\n if (targets.length === 0) {\n const b = getBinding(uuid);\n if (b) targets = [{ bpUuid: uuid, binding: b }];\n }\n if (targets.length === 0) return c.red(t(\"packUpdate.noBinding\", { id: opts.packId }));\n }\n\n if (targets.length === 0) return c.dim(t(\"packUpdate.sourcesEmpty\"));\n\n const lines: string[] = [];\n for (const { bpUuid, binding } of targets) {\n if (cfg.startup.skipDisabledBindings && !binding.enabled && !opts?.packId) continue;\n let result: CheckResult | null = null;\n try {\n /* \u59CB\u7EC8\u4E0B\u8F7D\u5F52\u6863\u5E76\u6309 BP \u7248\u672C\u6BD4\u8F83 */\n result = await prepareCheck(bpUuid, binding, cfg, packs, true);\n if (opts?.apply && result.updateAvailable) {\n const applied = await applyUpdate(result, cfg);\n lines.push(applied.ok ? c.green(applied.message) : c.red(applied.message));\n } else {\n lines.push(\n result.updateAvailable\n ? c.yellow(`${result.name}: ${result.message}`)\n : c.dim(`${result.name}: ${result.message}`)\n );\n }\n } catch (e) {\n lines.push(c.red(`${bpUuid}: ${(e as Error).message}`));\n if (cfg.startup.failMode === \"abort\") break;\n } finally {\n if (result) cleanupCheck(result);\n }\n if (cfg.startup.delayMsBetweenPacks > 0) {\n await new Promise((r) => setTimeout(r, cfg.startup.delayMsBetweenPacks));\n }\n }\n return lines.join(\"\\n\") || c.dim(t(\"packUpdate.sourcesEmpty\"));\n}\n\n/** BDS \u542F\u52A8\u94A9\u5B50\uFF1A\u9010\u4E2A\u68C0\u67E5\u5E76\u6309\u914D\u7F6E\u5E94\u7528 */\nexport async function runPackUpdatesOnBdsStart(): Promise<void> {\n const cfg = loadPackUpdateConfig();\n if (!cfg.enabled || !cfg.checkOnBdsStart) return;\n try {\n const out = await checkPackUpdates({ apply: cfg.applyOnBdsStart });\n if (out.trim()) logPack(out.replace(/\\x1B\\[[0-9;]*m/g, \"\"), \"info\");\n } catch (e) {\n logPack(t(\"packUpdate.startupFail\", { message: (e as Error).message }), \"warn\");\n }\n}\n\nexport function bindingLabelForUuid(uuid: string): string {\n const b = getBinding(uuid);\n if (!b) return \"src=-\";\n const tag = `${providerShortLabel(b.provider)}:${b.slug || b.projectId}`;\n /* \u4E0E packs list / sources \u4E00\u81F4\uFF1A\u5173\u95ED\u65F6\u4ECD\u663E\u793A\u6E90\uFF0C\u5E76\u6807\u6CE8 off */\n return b.enabled ? `src=${tag}` : `src=${tag}:off`;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * pack-update \u7F16\u6392\uFF1A\u63A2\u6D4B\u7ED1\u5B9A / \u68C0\u67E5 / \u5E94\u7528\u66F4\u65B0\n */\nimport { confirm, isCancel } from \"@clack/prompts\";\nimport {\n enableInstalledPack,\n ensureVersionGreaterThan,\n findInstalledPackById,\n installPackDirectory,\n listInstalledWorldPacks,\n readPackDependencyUuids,\n readPackManifestInfo,\n resolvePackRoots,\n worldPackParentDir,\n type InstalledWorldPack,\n type PackManifestInfo,\n} from \"@sfmc-bds/bds-tools/world-packs\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { t } from \"../i18n/index.js\";\nimport { pushLog } from \"../logs.js\";\nimport { resolveBdsContext } from \"../pack-lifecycle.js\";\nimport { c } from \"../theme.js\";\nimport { getBinding, listBindings, packSourcesPath, setBinding } from \"./bindings.js\";\nimport {\n ensurePackUpdateConfigFile,\n getPackMatchConfig,\n loadPackUpdateConfig,\n packUpdateConfigPath,\n} from \"./config.js\";\nimport {\n createPackSourceProvider,\n providerShortLabel,\n resolveConfiguredPackProvider,\n} from \"./providers/index.js\";\nimport type {\n PackSourceBinding,\n PackSourceProvider,\n PackUpdateConfig,\n SemVer3,\n SourceSearchHit,\n} from \"./types.js\";\nimport {\n decideVersionPolicy,\n buildSearchQueries,\n buildSearchQueriesFromSources,\n packSourceScore,\n} from \"./version-policy.js\";\n\nfunction logPack(text: string, level: \"info\" | \"warn\" | \"error\" | \"success\" = \"info\"): void {\n pushLog(text, \"pack\", level);\n}\n\nfunction fmtVer(v: SemVer3): string {\n return v.join(\".\");\n}\n\n/** \u7ED1\u5B9A\u542F\u7528\u6001\u6587\u6848\uFF1AbindOk / sources list \u5171\u7528\uFF08DRY\uFF09\uFF0C\u8D70 packs.list i18n */\nfunction bindingEnabledLabel(enabled: boolean): string {\n return enabled ? t(\"packs.list.on\").trim() : t(\"packs.list.off\").trim();\n}\n\n/** \u672A\u914D\u7F6E\u6E90\u65F6\u7684\u7EDF\u4E00\u6587\u6848\uFF08DRY\uFF1A\u5165\u53E3\u52FF\u5404\u81EA\u62FC needKey\uFF1B\u6587\u6848\u6E90\u65E0\u5173 \u2014 OCP\uFF09 */\nfunction needKeyText(): string {\n return t(\"packUpdate.needKey\", { path: packUpdateConfigPath() });\n}\n\n/** bindOk \u53C2\u6570\u552F\u4E00\u6784\u9020\u70B9\uFF08probe / bind \u5171\u7528 \u2014 DRY\uFF09\uFF0C\u62A5\u544A\u5B9E\u9645 binding.enabled\uFF08LSP\uFF09 */\nfunction bindOkParams(opts: {\n uuid: string;\n provider: PackSourceBinding[\"provider\"] | SourceSearchHit[\"provider\"];\n slug: string;\n enabled: boolean;\n}): Record<string, string> {\n return {\n uuid: opts.uuid,\n provider: providerShortLabel(opts.provider),\n slug: opts.slug,\n enabled: bindingEnabledLabel(opts.enabled),\n path: packSourcesPath(),\n };\n}\n\n/** \u5C31\u5730\u8865\u4E01\u5E76\u843D\u76D8\uFF08prepareCheck \u591A\u51FA\u53E3\u5171\u7528 \u2014 DRY\uFF1B\u52FF\u6563\u843D Object.assign+setBinding\uFF09 */\nfunction touchBinding(bpUuid: string, binding: PackSourceBinding, patch?: Partial<PackSourceBinding>): void {\n if (patch) Object.assign(binding, patch);\n setBinding(bpUuid, binding);\n}\n\n/** \u8BE5 fileId \u662F\u5426\u5DF2\u6210\u529F\u5199\u5165\u4E16\u754C\u76EE\u5F55\uFF08DRY\uFF1AprepareCheck \u591A\u5904\u52FF\u624B\u5199 null/!==\uFF09 */\nfunction isFileIdApplied(binding: PackSourceBinding, fileId: number): boolean {\n return binding.lastAppliedFileId != null && binding.lastAppliedFileId === fileId;\n}\n\n/** \u591A\u67E5\u8BE2\u641C\u7D22 + \u7EFC\u5408\u6253\u5206\u6392\u5E8F\uFF08probe / searchRemote \u5171\u7528\uFF09 */\nasync function searchAndRankHits(\n provider: PackSourceProvider,\n queries: string[],\n stripFolderTags: boolean\n): Promise<Array<{ hit: SourceSearchHit; score: number }>> {\n const byId = new Map<number, SourceSearchHit>();\n for (const q of queries) {\n const hits = await provider.search(q);\n for (const h of hits) byId.set(h.projectId, h);\n }\n return [...byId.values()]\n .map((h) => ({\n hit: h,\n score: Math.max(...queries.map((q) => packSourceScore(q, h, stripFolderTags))),\n }))\n .sort((a, b) => b.score - a.score);\n}\n\nfunction makeBindingFromHit(\n hit: SourceSearchHit,\n pairedResourceUuid: string | null,\n opts?: { prev?: PackSourceBinding | null; defaultEnabled: boolean }\n): PackSourceBinding {\n const prev = opts?.prev;\n return {\n /* \u91CD\u7ED1\u4FDD\u7559\u539F enabled\uFF1B\u65B0\u5EFA\u8D70\u914D\u7F6E\u5951\u7EA6 defaultBindingEnabled\uFF08LSP\uFF09 */\n enabled: prev?.enabled ?? opts?.defaultEnabled ?? false,\n provider: hit.provider,\n projectId: hit.projectId,\n slug: hit.slug,\n websiteUrl: hit.websiteUrl,\n pairedResourceUuid,\n lastFileId: prev?.lastFileId ?? null,\n lastCheckedAt: null,\n lastAppliedFileId: prev?.lastAppliedFileId ?? null,\n };\n}\n\n/** \u4ECE\u5DF2\u5B89\u88C5 BP \u63D0\u53D6\u914D\u5BF9 RP uuid */\nexport function pairedRpUuidFromBpDir(bpDir: string): string | null {\n const deps = readPackDependencyUuids(bpDir);\n return deps[0] ?? null;\n}\n\nexport async function probeSourceAfterInstall(opts: {\n info: PackManifestInfo;\n packDir?: string;\n /** \u5B89\u88C5\u540E\u7684\u6587\u4EF6\u5939\u540D\uFF08\u4F18\u5148\u4E8E basename(packDir)\uFF09 */\n folderName?: string;\n interactive?: boolean;\n}): Promise<void> {\n const cfg = loadPackUpdateConfig();\n if (!cfg.enabled || !cfg.probeSourceAfterInstall) return;\n if (opts.info.kind !== \"behavior\") return;\n\n ensurePackUpdateConfigFile();\n const provider = resolveConfiguredPackProvider(cfg);\n if (!provider) {\n logPack(needKeyText(), \"warn\");\n return;\n }\n\n const match = getPackMatchConfig(cfg);\n /* header \u5E38\u672C\u5730\u5316\uFF1B\u6587\u4EF6\u5939\u540D\u5F80\u5F80\u542B\u62C9\u4E01\u6838\u5FC3 \u2014 \u4E24\u6E90\u5206\u522B\u6D3E\u751F\u518D\u5408\u5E76\uFF0C\u6709\u62C9\u4E01\u5219\u4E0D\u641C\u7EAF\u4E2D\u6587 */\n const folderName =\n (opts.folderName && String(opts.folderName).trim()) ||\n (opts.packDir ? path.basename(opts.packDir) : \"\");\n const plan = buildSearchQueriesFromSources(\n [\n { id: \"header\", raw: opts.info.name },\n { id: \"folder\", raw: folderName },\n ],\n match.stripFolderTags\n );\n const queries = plan.queries;\n if (queries.length === 0) {\n logPack(t(\"packUpdate.probeNoName\"), \"warn\");\n return;\n }\n\n logPack(\n t(\"packUpdate.probeQueries\", {\n header: opts.info.name || \"-\",\n folder: folderName || \"-\",\n queries: queries.join(\" | \"),\n }),\n \"info\"\n );\n\n let scored: Array<{ hit: SourceSearchHit; score: number }>;\n try {\n scored = await searchAndRankHits(provider, queries, match.stripFolderTags);\n } catch (e) {\n logPack(t(\"packUpdate.probeFail\", { message: (e as Error).message }), \"warn\");\n return;\n }\n\n if (scored.length === 0) {\n logPack(t(\"packUpdate.probeMiss\", { name: queries.join(\", \") }), \"info\");\n return;\n }\n\n const primary = queries.find((q) => /[A-Za-z]/.test(q)) ?? queries[0]!;\n const best = scored[0]!;\n if (best.score < match.nameMinScore) {\n logPack(\n t(\"packUpdate.probeLowScore\", {\n name: primary,\n hit: `${best.hit.name} (${best.hit.slug})`,\n score: best.score.toFixed(2),\n url: best.hit.websiteUrl,\n }),\n \"info\"\n );\n return;\n }\n\n logPack(\n t(\"packUpdate.probeHit\", {\n name: `${opts.info.name} / ${folderName || \"-\"}`,\n hit: `${best.hit.name} [${best.hit.slug}]`,\n url: best.hit.websiteUrl,\n score: best.score.toFixed(2),\n }),\n \"success\"\n );\n logPack(t(\"packUpdate.editHint\", { path: packSourcesPath() }), \"info\");\n\n const interactive = opts.interactive ?? !!process.stdin.isTTY;\n let accept = false;\n if (interactive && cfg.askConfirmOnBind && process.stdin.isTTY) {\n const ans = await confirm({\n message: t(\"packUpdate.confirmBind\", { hit: best.hit.name }),\n initialValue: true,\n });\n if (isCancel(ans)) return;\n accept = !!ans;\n } else {\n /* \u975E TTY / BDS \u6536\u4EF6\u7BB1 / askConfirmOnBind=false\uFF1A\u547D\u4E2D\u5373\u5199\u5165\uFF0C\u907F\u514D\u63A2\u6D4B\u6210\u529F\u5374\u65E0 pack-sources.json */\n accept = true;\n logPack(\n t(\"packUpdate.probeAutoBind\", {\n provider: providerShortLabel(best.hit.provider),\n slug: best.hit.slug,\n path: packSourcesPath(),\n }),\n \"info\"\n );\n }\n\n if (!accept) {\n logPack(t(\"packUpdate.bindSkipped\"), \"info\");\n return;\n }\n\n const paired = (opts.packDir ? pairedRpUuidFromBpDir(opts.packDir) : null) ?? null;\n const binding = makeBindingFromHit(best.hit, paired, { defaultEnabled: cfg.defaultBindingEnabled });\n setBinding(opts.info.uuid, binding);\n logPack(\n t(\n \"packUpdate.bindOk\",\n bindOkParams({\n uuid: opts.info.uuid,\n provider: best.hit.provider,\n slug: best.hit.slug,\n enabled: binding.enabled,\n })\n ),\n \"success\"\n );\n}\n\nexport async function searchRemote(query: string): Promise<string> {\n const cfg = loadPackUpdateConfig();\n const provider = resolveConfiguredPackProvider(cfg);\n if (!provider) {\n return c.yellow(needKeyText());\n }\n const match = getPackMatchConfig(cfg);\n const queries = buildSearchQueries(query, match.stripFolderTags);\n const ranked = await searchAndRankHits(provider, queries, match.stripFolderTags);\n if (ranked.length === 0) return c.dim(t(\"packUpdate.searchEmpty\", { query }));\n return ranked\n .map(\n ({ hit: h, score }, i) =>\n `${c.cyan(String(i + 1).padStart(2))}. ${h.name} ${c.dim(`id=${h.projectId} slug=${h.slug} score=${score.toFixed(2)}`)}\\n ${h.websiteUrl}`\n )\n .join(\"\\n\");\n}\n\nexport async function bindPackSource(packId: string, ref: string): Promise<string> {\n const cfg = loadPackUpdateConfig();\n const provider = resolveConfiguredPackProvider(cfg);\n if (!provider) {\n return c.yellow(needKeyText());\n }\n const { bdsRoot, levelName } = resolveBdsContext();\n const packs = listInstalledWorldPacks(bdsRoot, levelName);\n const pack = findInstalledPackById(packs, packId);\n if (!pack) return c.red(t(\"packs.notFound\", { id: packId }));\n if (pack.kind !== \"behavior\") return c.red(t(\"packUpdate.bindBpOnly\"));\n\n const hit = await provider.resolveProject(ref);\n if (!hit) return c.red(t(\"packUpdate.resolveFail\", { ref }));\n\n const paired = pairedRpUuidFromBpDir(pack.dir);\n const binding = makeBindingFromHit(hit, paired, {\n prev: getBinding(pack.uuid),\n defaultEnabled: cfg.defaultBindingEnabled,\n });\n setBinding(pack.uuid, binding);\n return c.green(\n t(\n \"packUpdate.bindOk\",\n bindOkParams({\n uuid: pack.uuid,\n provider: hit.provider,\n slug: hit.slug,\n enabled: binding.enabled,\n })\n )\n );\n}\n\nexport function formatSourcesList(): string {\n ensurePackUpdateConfigFile();\n const bindings = listBindings();\n const lines = [\n t(\"packUpdate.sourcesHeader\", {\n config: packUpdateConfigPath(),\n sources: packSourcesPath(),\n }),\n ];\n if (bindings.length === 0) {\n lines.push(c.dim(t(\"packUpdate.sourcesEmpty\")));\n return lines.join(\"\\n\");\n }\n for (const { bpUuid, binding } of bindings) {\n const label = bindingEnabledLabel(binding.enabled);\n const en = binding.enabled ? c.green(label) : c.dim(label);\n const tag = providerShortLabel(binding.provider);\n lines.push(\n ` [${en}] ${bpUuid} ${tag}:${binding.slug || binding.projectId} ${c.dim(binding.websiteUrl || \"\")}`\n );\n }\n return lines.join(\"\\n\");\n}\n\ninterface CheckResult {\n bpUuid: string;\n name: string;\n localVer: SemVer3;\n remoteVer: SemVer3 | null;\n updateAvailable: boolean;\n majorHigher: boolean;\n shouldBumpRp: boolean;\n fileId: number | null;\n message: string;\n binding: PackSourceBinding;\n localBp?: InstalledWorldPack;\n remoteBpInfo?: PackManifestInfo;\n remoteRoots?: string[];\n tempDir?: string;\n /** \u4E0B\u8F7D\u5F52\u6863\u6240\u5728\u7684\u4E34\u65F6 staging \u76EE\u5F55\uFF08\u975E zip \u6587\u4EF6\u8DEF\u5F84\uFF09 */\n stagingDir?: string;\n /** resolvePackRoots \u521B\u5EFA\u7684\u4E34\u65F6\u6811\u6E05\u7406 */\n disposeRoots?: () => void;\n}\n\nfunction withLocalBp(base: Omit<CheckResult, \"localBp\">, localBp: InstalledWorldPack | undefined): CheckResult {\n return localBp ? { ...base, localBp } : { ...base };\n}\n\nfunction baseCheckFields(\n bpUuid: string,\n name: string,\n localVer: SemVer3,\n binding: PackSourceBinding,\n extras: Partial<CheckResult> & { message: string }\n): Omit<CheckResult, \"localBp\"> {\n return {\n bpUuid,\n name,\n localVer,\n remoteVer: null,\n updateAvailable: false,\n majorHigher: false,\n shouldBumpRp: false,\n fileId: null,\n binding,\n ...extras,\n };\n}\n\nasync function prepareCheck(\n bpUuid: string,\n binding: PackSourceBinding,\n cfg: PackUpdateConfig,\n packs: InstalledWorldPack[],\n downloadArchive: boolean\n): Promise<CheckResult> {\n const localBp = packs.find((p) => p.uuid.toLowerCase() === bpUuid.toLowerCase() && p.kind === \"behavior\");\n const name = localBp?.name ?? bpUuid;\n const localVer: SemVer3 = localBp?.version ?? [0, 0, 0];\n const provider = createPackSourceProvider(cfg, binding.provider);\n\n touchBinding(bpUuid, binding, { lastCheckedAt: new Date().toISOString() });\n\n if (!binding.enabled) {\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, { message: t(\"packUpdate.bindingDisabled\") }),\n localBp\n );\n }\n\n const file = await provider.getLatestFile(binding.projectId);\n if (!file) {\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, { message: t(\"packUpdate.noRemoteFile\") }),\n localBp\n );\n }\n\n /* \u5DF2\u6210\u529F\u5E94\u7528\u540C\u4E00 fileId\uFF1A\u4E0D\u518D\u4E0B\u8F7D */\n if (isFileIdApplied(binding, file.fileId)) {\n touchBinding(bpUuid, binding, { lastFileId: file.fileId });\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, {\n fileId: file.fileId,\n message: t(\"packUpdate.upToDate\"),\n }),\n localBp\n );\n }\n\n if (!downloadArchive) {\n /* \u4EC5\u6587\u4EF6 id \u6BD4\u8F83\u7684\u8F7B\u91CF\u68C0\u67E5\uFF08\u672A apply \u5373\u89C6\u4E3A\u6709\u66F4\u65B0\uFF09 */\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, {\n updateAvailable: true,\n fileId: file.fileId,\n message: t(\"packUpdate.fileNewer\", { file: file.fileName, id: String(file.fileId) }),\n }),\n localBp\n );\n }\n\n const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sfmc-pack-upd-\"));\n const archiveFile = path.join(stagingDir, file.fileName || \"pack.zip\");\n await provider.download(file, archiveFile);\n const resolved = await resolvePackRoots(archiveFile);\n const roots = resolved.roots;\n const bpRoot = roots.find((r) => readPackManifestInfo(r)?.kind === \"behavior\");\n const remoteBpInfo = bpRoot ? readPackManifestInfo(bpRoot) : null;\n if (!remoteBpInfo) {\n resolved.dispose();\n try {\n fs.rmSync(stagingDir, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n return withLocalBp(\n baseCheckFields(bpUuid, name, localVer, binding, {\n fileId: file.fileId,\n message: t(\"packUpdate.remoteNoBp\"),\n }),\n localBp\n );\n }\n\n /*\n * \u80FD\u8D70\u5230\u6B64\u5904\u8BF4\u660E\u8BE5 fileId \u5C1A\u672A\u6210\u529F apply\uFF08\u4E0A\u65B9\u5DF2 early-return\uFF09\u3002\n * - \u8FDC\u7A0B BP \u7248\u672C\u66F4\u9AD8 \u2192 \u8986\u76D6\n * - \u7248\u672C\u672A\u66F4\u9AD8 \u2192 \u4ECD\u8986\u76D6\uFF08\u6C49\u5316\u5305\u7B49\u540C\u7248\u672C\u53F7\u4E0D\u540C\u5185\u5BB9\uFF1B\u52FF\u5728\u672A install \u65F6\u5199 lastAppliedFileId\uFF09\n * RP bump \u89C4\u5219\u96C6\u4E2D\u5728 decideVersionPolicy\uFF08OCP/DRY\uFF1A\u52FF\u5728\u7F16\u6392\u5C42\u590D\u523B policy \u5B57\u6BB5\uFF09\u3002\n */\n const decision = decideVersionPolicy(localVer, remoteBpInfo.version, cfg.versionPolicy, {\n treatAsUpdate: true,\n });\n\n touchBinding(bpUuid, binding, { lastFileId: file.fileId });\n\n const message = decision.remoteNewer\n ? t(\"packUpdate.bpNewer\", {\n local: fmtVer(localVer),\n remote: fmtVer(remoteBpInfo.version),\n })\n : t(\"packUpdate.needSync\", {\n local: fmtVer(localVer),\n remote: fmtVer(remoteBpInfo.version),\n id: String(file.fileId),\n });\n\n return withLocalBp(\n {\n bpUuid,\n name,\n localVer,\n remoteVer: remoteBpInfo.version,\n updateAvailable: true,\n majorHigher: decision.majorHigher,\n shouldBumpRp: decision.shouldBumpRp,\n fileId: file.fileId,\n message,\n binding,\n remoteBpInfo,\n remoteRoots: roots,\n stagingDir,\n disposeRoots: resolved.dispose,\n },\n localBp\n );\n}\n\nfunction cleanupCheck(r: CheckResult): void {\n if (r.disposeRoots) {\n try {\n r.disposeRoots();\n } catch {\n /* ignore */\n }\n }\n for (const d of [r.tempDir, r.stagingDir]) {\n if (!d) continue;\n try {\n fs.rmSync(d, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n }\n}\n\n/** \u5C1D\u8BD5\u5B89\u88C5\u914D\u5BF9 RP\uFF1Baccept \u4E3A\u8FC7\u6EE4\u8C13\u8BCD\uFF08DRY\uFF1A\u4E24\u5904\u5FAA\u73AF\u5408\u4E00\uFF09 */\nasync function tryInstallResourcePack(opts: {\n rpRoots: string[];\n bdsRoot: string;\n levelName: string;\n folderName?: string;\n accept: (info: PackManifestInfo) => boolean;\n}): Promise<{ info: PackManifestInfo; destDir: string } | null> {\n for (const root of opts.rpRoots) {\n const info = readPackManifestInfo(root);\n if (!info || !opts.accept(info)) continue;\n const rpDest = worldPackParentDir(opts.bdsRoot, opts.levelName, \"resource\");\n const rpInstall = await installPackDirectory({\n srcDir: root,\n destParent: rpDest,\n force: true,\n ...(opts.folderName ? { folderName: opts.folderName } : {}),\n });\n if (rpInstall.ok && rpInstall.info && rpInstall.destDir) {\n return { info: rpInstall.info, destDir: rpInstall.destDir };\n }\n }\n return null;\n}\n\nasync function applyUpdate(r: CheckResult, cfg: PackUpdateConfig): Promise<{ ok: boolean; message: string }> {\n if (!r.updateAvailable || !r.remoteRoots || !r.remoteBpInfo) {\n return { ok: true, message: r.message };\n }\n const { bdsRoot, levelName } = resolveBdsContext();\n const packs = listInstalledWorldPacks(bdsRoot, levelName);\n\n const oldRp =\n r.binding.pairedResourceUuid != null\n ? packs.find((p) => p.kind === \"resource\" && p.uuid.toLowerCase() === r.binding.pairedResourceUuid!.toLowerCase())\n : undefined;\n const oldRpVer: SemVer3 = oldRp?.version ?? [0, 0, 0];\n\n const bpRoot = r.remoteRoots.find((x) => readPackManifestInfo(x)?.kind === \"behavior\");\n const rpRoots = r.remoteRoots.filter((x) => readPackManifestInfo(x)?.kind === \"resource\");\n\n if (!bpRoot) return { ok: false, message: t(\"packUpdate.remoteNoBp\") };\n\n /* \u5B89\u88C5 BP\uFF08force \u8986\u76D6\u540C uuid / \u540C\u6587\u4EF6\u5939\uFF09 */\n const bpDest = worldPackParentDir(bdsRoot, levelName, \"behavior\");\n const bpInstall = await installPackDirectory({\n srcDir: bpRoot,\n destParent: bpDest,\n force: true,\n ...(r.localBp?.folderName ? { folderName: r.localBp.folderName } : {}),\n });\n if (!bpInstall.ok || !bpInstall.info || !bpInstall.destDir) {\n return { ok: false, message: t(\"packUpdate.installFail\", { reason: bpInstall.reason ?? \"?\" }) };\n }\n await enableInstalledPack({ bdsRoot, levelName, info: bpInstall.info });\n logPack(\n t(\"packUpdate.installedBp\", {\n dir: bpInstall.destDir,\n version: fmtVer(bpInstall.info.version),\n }),\n \"success\"\n );\n\n /* \u5B89\u88C5\u914D\u5BF9 RP\uFF1A\u5148\u6309 binding uuid\uFF0C\u518D\u6309\u65B0 BP dependencies */\n let rpInfo: PackManifestInfo | null = null;\n let rpDir: string | null = null;\n const wantRp = r.binding.pairedResourceUuid?.toLowerCase();\n const installed = await tryInstallResourcePack({\n rpRoots,\n bdsRoot,\n levelName,\n ...(oldRp?.folderName ? { folderName: oldRp.folderName } : {}),\n accept: (info) => !wantRp || info.uuid.toLowerCase() === wantRp,\n });\n if (installed) {\n rpInfo = installed.info;\n rpDir = installed.destDir;\n }\n\n if (!rpInfo && rpRoots.length > 0) {\n const deps = readPackDependencyUuids(bpInstall.destDir);\n const fallback = await tryInstallResourcePack({\n rpRoots,\n bdsRoot,\n levelName,\n accept: (info) =>\n deps.length === 0 || deps.some((d) => d.toLowerCase() === info.uuid.toLowerCase()),\n });\n if (fallback) {\n rpInfo = fallback.info;\n rpDir = fallback.destDir;\n r.binding.pairedResourceUuid = fallback.info.uuid;\n }\n }\n\n /* \u542F\u7528\u7248\u672C = bump(max(\u65B0\u5305, \u65E7 RP))\uFF0C\u5355\u4E00\u89C4\u5219\u89E6\u53D1\u5BA2\u6237\u7AEF\u5237\u65B0 */\n if (rpInfo && rpDir && r.shouldBumpRp) {\n const next = ensureVersionGreaterThan(rpDir, oldRpVer, cfg.versionPolicy.rpBumpComponent);\n rpInfo = { ...rpInfo, version: next };\n }\n\n if (rpInfo) {\n await enableInstalledPack({ bdsRoot, levelName, info: rpInfo });\n logPack(\n t(\"packUpdate.installedRp\", {\n dir: rpDir ?? \"-\",\n version: fmtVer(rpInfo.version),\n }),\n \"success\"\n );\n } else if (rpRoots.length > 0) {\n logPack(t(\"packUpdate.rpInstallMiss\"), \"warn\");\n }\n\n touchBinding(r.bpUuid, r.binding, {\n lastAppliedFileId: r.fileId,\n lastFileId: r.fileId,\n lastCheckedAt: new Date().toISOString(),\n });\n\n return {\n ok: true,\n message: t(\"packUpdate.applied\", {\n name: r.name,\n bp: fmtVer(bpInstall.info.version),\n rp: rpInfo ? fmtVer(rpInfo.version) : \"-\",\n }),\n };\n}\n\nexport async function checkPackUpdates(opts?: { packId?: string; apply?: boolean }): Promise<string> {\n const cfg = loadPackUpdateConfig();\n if (!cfg.enabled) return c.dim(t(\"packUpdate.disabled\"));\n /* \u5165\u53E3\u9884\u68C0\uFF1A\u4EFB\u4E00\u5DF2\u914D\u7F6E\u6E90\u5373\u53EF\uFF1B\u9010 binding \u4ECD\u6309 binding.provider \u5206\u6D3E\uFF08LSP/OCP\uFF09 */\n if (!resolveConfiguredPackProvider(cfg)) {\n return c.yellow(needKeyText());\n }\n\n const { bdsRoot, levelName } = resolveBdsContext();\n const packs = listInstalledWorldPacks(bdsRoot, levelName);\n let targets = listBindings();\n if (opts?.packId) {\n const pack = findInstalledPackById(packs, opts.packId);\n const uuid = pack?.uuid ?? opts.packId;\n targets = targets.filter((x) => x.bpUuid.toLowerCase() === uuid.toLowerCase());\n if (targets.length === 0) {\n const b = getBinding(uuid);\n if (b) targets = [{ bpUuid: uuid, binding: b }];\n }\n if (targets.length === 0) return c.red(t(\"packUpdate.noBinding\", { id: opts.packId }));\n }\n\n if (targets.length === 0) return c.dim(t(\"packUpdate.sourcesEmpty\"));\n\n const lines: string[] = [];\n for (const { bpUuid, binding } of targets) {\n if (cfg.startup.skipDisabledBindings && !binding.enabled && !opts?.packId) continue;\n let result: CheckResult | null = null;\n try {\n /* \u59CB\u7EC8\u4E0B\u8F7D\u5F52\u6863\u5E76\u6309 BP \u7248\u672C\u6BD4\u8F83 */\n result = await prepareCheck(bpUuid, binding, cfg, packs, true);\n if (opts?.apply && result.updateAvailable) {\n const applied = await applyUpdate(result, cfg);\n lines.push(applied.ok ? c.green(applied.message) : c.red(applied.message));\n } else {\n lines.push(\n result.updateAvailable\n ? c.yellow(`${result.name}: ${result.message}`)\n : c.dim(`${result.name}: ${result.message}`)\n );\n }\n } catch (e) {\n lines.push(c.red(`${bpUuid}: ${(e as Error).message}`));\n if (cfg.startup.failMode === \"abort\") break;\n } finally {\n if (result) cleanupCheck(result);\n }\n if (cfg.startup.delayMsBetweenPacks > 0) {\n await new Promise((r) => setTimeout(r, cfg.startup.delayMsBetweenPacks));\n }\n }\n return lines.join(\"\\n\") || c.dim(t(\"packUpdate.sourcesEmpty\"));\n}\n\n/** BDS \u542F\u52A8\u94A9\u5B50\uFF1A\u9010\u4E2A\u68C0\u67E5\u5E76\u6309\u914D\u7F6E\u5E94\u7528 */\nexport async function runPackUpdatesOnBdsStart(): Promise<void> {\n const cfg = loadPackUpdateConfig();\n if (!cfg.enabled || !cfg.checkOnBdsStart) return;\n try {\n const out = await checkPackUpdates({ apply: cfg.applyOnBdsStart });\n if (out.trim()) logPack(out.replace(/\\x1B\\[[0-9;]*m/g, \"\"), \"info\");\n } catch (e) {\n logPack(t(\"packUpdate.startupFail\", { message: (e as Error).message }), \"warn\");\n }\n}\n\nexport function bindingLabelForUuid(uuid: string): string {\n const b = getBinding(uuid);\n if (!b) return \"src=-\";\n const tag = `${providerShortLabel(b.provider)}:${b.slug || b.projectId}`;\n /* \u4E0E packs list / sources \u4E00\u81F4\uFF1A\u5173\u95ED\u65F6\u4ECD\u663E\u793A\u6E90\uFF0C\u5E76\u6807\u6CE8 off */\n return b.enabled ? `src=${tag}` : `src=${tag}:off`;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 版本策略:以 BP 为准比较;同 major 更新时抬高 RP 版本触发客户端刷新
|
|
3
3
|
*/
|
|
4
|
+
import { bumpSemVer3, maxSemVer3, nextEnabledVersion } from "@sfmc-bds/bds-tools/world-packs";
|
|
4
5
|
import type { SemVer3, VersionCompareResult, VersionPolicyConfig } from "./types.js";
|
|
6
|
+
/** 归一化为 -1 | 0 | 1,供策略比较 */
|
|
5
7
|
export declare function compareSemVer3(a: SemVer3, b: SemVer3): number;
|
|
6
8
|
export declare function isNewer(remote: SemVer3, local: SemVer3): boolean;
|
|
9
|
+
export { bumpSemVer3, maxSemVer3, nextEnabledVersion };
|
|
7
10
|
/**
|
|
8
11
|
* 根据本地/远程 BP 版本与策略,决定是否更新以及是否额外 bump RP。
|
|
9
12
|
* `treatAsUpdate`:同版本/未更高但需强制同步写入时(如 fileId 尚未 apply)也走更新侧 RP bump 规则(OCP:策略集中于此,勿在编排层复刻)。
|
|
@@ -11,8 +14,6 @@ export declare function isNewer(remote: SemVer3, local: SemVer3): boolean;
|
|
|
11
14
|
export declare function decideVersionPolicy(localBp: SemVer3, remoteBp: SemVer3, policy: VersionPolicyConfig, opts?: {
|
|
12
15
|
treatAsUpdate?: boolean;
|
|
13
16
|
}): VersionCompareResult;
|
|
14
|
-
/** 生成严格大于 floor 的下一版本(按 patch 或 minor 抬一级) */
|
|
15
|
-
export declare function nextVersionGreaterThan(current: SemVer3, floor: SemVer3, component?: "patch" | "minor"): SemVer3;
|
|
16
17
|
/** 中日韩与拉丁粘连时插入空格:拔刀剑Slash → 拔刀剑 Slash */
|
|
17
18
|
export declare function insertCjkLatinBoundaries(name: string): string;
|
|
18
19
|
/** 去掉整词包角色标记(末尾 BP/RP/Addon 等) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-policy.d.ts","sourceRoot":"","sources":["../../src/pack-update/version-policy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAErF,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"version-policy.d.ts","sourceRoot":"","sources":["../../src/pack-update/version-policy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,WAAW,EAEX,UAAU,EACV,kBAAkB,EACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAErF,4BAA4B;AAC5B,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAG7D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhE;AAED,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,MAAM,EAAE,mBAAmB,EAC3B,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,oBAAoB,CAatB;AAMD,yCAAyC;AACzC,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,kCAAkC;AAClC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,iCAAiC;AACjC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,UAAO,GAAG,MAAM,CAUlF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,UAAO,GAAG,MAAM,CAKpF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,UAAO,GAAG,MAAM,EAAE,CAgC/E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,UAAO,GAAG,MAAM,CAS9E;AAED,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAChC,eAAe,UAAO,EACtB,UAAU,SAAK,GACd,MAAM,EAAE,CAMV;AAED,MAAM,MAAM,iBAAiB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG;IAC5B,6BAA6B;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB;IACnB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,eAAe,UAAO,EACtB,UAAU,SAAK,GACd,eAAe,CA4EjB;AAED,kCAAkC;AAClC,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAY3D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACnC,eAAe,UAAO,GACrB,MAAM,CAcR"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bumpSemVer3,
|
|
3
|
+
compareSemVer3 as compareSemVer3Raw,
|
|
4
|
+
maxSemVer3,
|
|
5
|
+
nextEnabledVersion
|
|
6
|
+
} from "@sfmc-bds/bds-tools/world-packs";
|
|
1
7
|
function compareSemVer3(a, b) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
if (d !== 0) return d > 0 ? 1 : -1;
|
|
5
|
-
}
|
|
6
|
-
return 0;
|
|
8
|
+
const d = compareSemVer3Raw(a, b);
|
|
9
|
+
return d > 0 ? 1 : d < 0 ? -1 : 0;
|
|
7
10
|
}
|
|
8
11
|
function isNewer(remote, local) {
|
|
9
12
|
return compareSemVer3(remote, local) > 0;
|
|
@@ -22,17 +25,6 @@ function decideVersionPolicy(localBp, remoteBp, policy, opts) {
|
|
|
22
25
|
}
|
|
23
26
|
return { remoteNewer, majorHigher, shouldBumpRp };
|
|
24
27
|
}
|
|
25
|
-
function nextVersionGreaterThan(current, floor, component = "patch") {
|
|
26
|
-
let next = component === "minor" ? [current[0], current[1] + 1, 0] : [current[0], current[1], current[2] + 1];
|
|
27
|
-
while (compareSemVer3(next, floor) <= 0) {
|
|
28
|
-
if (component === "minor") {
|
|
29
|
-
next = [next[0], next[1] + 1, 0];
|
|
30
|
-
} else {
|
|
31
|
-
next = [next[0], next[1], next[2] + 1];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return next;
|
|
35
|
-
}
|
|
36
28
|
const PACK_ROLE_TOKEN = /^(?:bp|rp|ba|behavior|behaviours?|resource|resources|pack|packs|addon|addons|mcpack|mcaddon|behavior.?pack|resource.?pack|行为包|资源包|附加包|基岩|bedrock)$/iu;
|
|
37
29
|
function insertCjkLatinBoundaries(name) {
|
|
38
30
|
return String(name ?? "").replace(/([\u3400-\u9fff\uF900-\uFAFF])([A-Za-z])/g, "$1 $2").replace(/([A-Za-z])([\u3400-\u9fff\uF900-\uFAFF])/g, "$1 $2");
|
|
@@ -197,14 +189,16 @@ function packSourceScore(query, hit, stripFolderTags = true) {
|
|
|
197
189
|
export {
|
|
198
190
|
buildSearchQueries,
|
|
199
191
|
buildSearchQueriesFromSources,
|
|
192
|
+
bumpSemVer3,
|
|
200
193
|
collectQuerySeeds,
|
|
201
194
|
compareSemVer3,
|
|
202
195
|
decideVersionPolicy,
|
|
203
196
|
extractLatinPhrase,
|
|
204
197
|
insertCjkLatinBoundaries,
|
|
205
198
|
isNewer,
|
|
199
|
+
maxSemVer3,
|
|
206
200
|
nameSimilarity,
|
|
207
|
-
|
|
201
|
+
nextEnabledVersion,
|
|
208
202
|
normalizePackSearchName,
|
|
209
203
|
packSourceScore,
|
|
210
204
|
preprocessPackNameRaw,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/pack-update/version-policy.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u7248\u672C\u7B56\u7565\uFF1A\u4EE5 BP \u4E3A\u51C6\u6BD4\u8F83\uFF1B\u540C major \u66F4\u65B0\u65F6\u62AC\u9AD8 RP \u7248\u672C\u89E6\u53D1\u5BA2\u6237\u7AEF\u5237\u65B0\n */\nimport type { SemVer3, VersionCompareResult, VersionPolicyConfig } from \"./types.js\";\n\nexport function compareSemVer3(a: SemVer3, b: SemVer3): number {\n for (let i = 0; i < 3; i++) {\n const d = (a[i] ?? 0) - (b[i] ?? 0);\n if (d !== 0) return d > 0 ? 1 : -1;\n }\n return 0;\n}\n\nexport function isNewer(remote: SemVer3, local: SemVer3): boolean {\n return compareSemVer3(remote, local) > 0;\n}\n\n/**\n * \u6839\u636E\u672C\u5730/\u8FDC\u7A0B BP \u7248\u672C\u4E0E\u7B56\u7565\uFF0C\u51B3\u5B9A\u662F\u5426\u66F4\u65B0\u4EE5\u53CA\u662F\u5426\u989D\u5916 bump RP\u3002\n * `treatAsUpdate`\uFF1A\u540C\u7248\u672C/\u672A\u66F4\u9AD8\u4F46\u9700\u5F3A\u5236\u540C\u6B65\u5199\u5165\u65F6\uFF08\u5982 fileId \u5C1A\u672A apply\uFF09\u4E5F\u8D70\u66F4\u65B0\u4FA7 RP bump \u89C4\u5219\uFF08OCP\uFF1A\u7B56\u7565\u96C6\u4E2D\u4E8E\u6B64\uFF0C\u52FF\u5728\u7F16\u6392\u5C42\u590D\u523B\uFF09\u3002\n */\nexport function decideVersionPolicy(\n localBp: SemVer3,\n remoteBp: SemVer3,\n policy: VersionPolicyConfig,\n opts?: { treatAsUpdate?: boolean }\n): VersionCompareResult {\n const remoteNewer = isNewer(remoteBp, localBp);\n const majorHigher = remoteBp[0] > localBp[0];\n const asUpdate = remoteNewer || Boolean(opts?.treatAsUpdate);\n let shouldBumpRp = false;\n if (asUpdate && policy.onUpdateOverwriteBoth) {\n if (majorHigher && policy.majorHigherSkipRpBump) {\n shouldBumpRp = false;\n } else if (policy.rpBumpWhenSameMajor) {\n shouldBumpRp = true;\n }\n }\n return { remoteNewer, majorHigher, shouldBumpRp };\n}\n\n/** \u751F\u6210\u4E25\u683C\u5927\u4E8E floor \u7684\u4E0B\u4E00\u7248\u672C\uFF08\u6309 patch \u6216 minor \u62AC\u4E00\u7EA7\uFF09 */\nexport function nextVersionGreaterThan(\n current: SemVer3,\n floor: SemVer3,\n component: \"patch\" | \"minor\" = \"patch\"\n): SemVer3 {\n let next: SemVer3 =\n component === \"minor\"\n ? [current[0], current[1] + 1, 0]\n : [current[0], current[1], current[2] + 1];\n while (compareSemVer3(next, floor) <= 0) {\n if (component === \"minor\") {\n next = [next[0], next[1] + 1, 0];\n } else {\n next = [next[0], next[1], next[2] + 1];\n }\n }\n return next;\n}\n\n/** \u5305\u7C7B\u578B/\u6E20\u9053\u7B49\u566A\u97F3 token\uFF08\u6574\u8BCD\u53BB\u6389\uFF0C\u52FF\u5220\u4EA7\u54C1\u540D\uFF09 */\nconst PACK_ROLE_TOKEN =\n /^(?:bp|rp|ba|behavior|behaviours?|resource|resources|pack|packs|addon|addons|mcpack|mcaddon|behavior.?pack|resource.?pack|\u884C\u4E3A\u5305|\u8D44\u6E90\u5305|\u9644\u52A0\u5305|\u57FA\u5CA9|bedrock)$/iu;\n\n/** \u4E2D\u65E5\u97E9\u4E0E\u62C9\u4E01\u7C98\u8FDE\u65F6\u63D2\u5165\u7A7A\u683C\uFF1A\u62D4\u5200\u5251Slash \u2192 \u62D4\u5200\u5251 Slash */\nexport function insertCjkLatinBoundaries(name: string): string {\n return String(name ?? \"\")\n .replace(/([\\u3400-\\u9fff\\uF900-\\uFAFF])([A-Za-z])/g, \"$1 $2\")\n .replace(/([A-Za-z])([\\u3400-\\u9fff\\uF900-\\uFAFF])/g, \"$1 $2\");\n}\n\n/** \u53BB\u6389\u6574\u8BCD\u5305\u89D2\u8272\u6807\u8BB0\uFF08\u672B\u5C3E BP/RP/Addon \u7B49\uFF09 */\nexport function stripPackRoleTokens(name: string): string {\n return String(name ?? \"\")\n .split(/[\\s_]+/)\n .filter((t) => t && !PACK_ROLE_TOKEN.test(t))\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** \u53BB\u6389 v4 / 1.21.100 \u4E00\u7C7B\u7248\u672C\u5C3E\u5DF4 */\nexport function stripVersionTokens(name: string): string {\n return String(name ?? \"\")\n .replace(/\\bv\\d+(?:\\.\\d+)*\\b/gi, \" \")\n .replace(/\\b\\d+\\.\\d+(?:\\.\\d+)?\\b/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** \u4EC5\u4FDD\u7559\u62C9\u4E01\u8BCD\uFF08CF slug/search \u4E3B\u8DEF\u5F84\uFF09 */\nexport function extractLatinPhrase(name: string): string {\n const words = String(name ?? \"\").match(/[A-Za-z][A-Za-z0-9]*/g);\n return words ? words.join(\" \") : \"\";\n}\n\n/**\n * \u5171\u4EAB\u9884\u5904\u7406\uFF1A\u00A7\u7801\u3001\u65B9\u62EC\u53F7\u6807\u7B7E\u3001\u6269\u5C55\u540D\u3001CJK/\u62C9\u4E01\u5206\u754C\u3001\u4E0B\u5212\u7EBF\u2192\u7A7A\u683C\u3002\n * normalize / collectQuerySeeds \u5171\u7528\uFF0C\u907F\u514D\u4E24\u5904\u5404\u5199\u4E00\u904D\uFF08DRY\uFF09\u3002\n */\nexport function preprocessPackNameRaw(name: string, stripFolderTags = true): string {\n let s = String(name ?? \"\");\n s = s.replace(/\u00A7[0-9a-zA-Z]/g, \"\");\n if (stripFolderTags) {\n s = s.replace(/\\[[^\\]]*]/g, \" \");\n }\n s = s.replace(/\\.(zip|mcpack|mcaddon)$/i, \"\");\n s = insertCjkLatinBoundaries(s);\n s = s.replace(/[_]+/g, \" \").replace(/\\s+/g, \" \").trim();\n return s;\n}\n\n/**\n * \u57FA\u7840\u6E05\u6D17\uFF1A\u9884\u5904\u7406 + \u5305\u89D2\u8272 + \u7248\u672C\u53F7\u3002\n * \u4F8B\uFF1A\"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\" \u2192 \"\u62D4\u5200\u5251 Slash Blade\"\n */\nexport function normalizePackSearchName(name: string, stripFolderTags = true): string {\n let s = preprocessPackNameRaw(name, stripFolderTags);\n s = stripPackRoleTokens(s);\n s = stripVersionTokens(s);\n return s;\n}\n\n/**\n * \u4ECE\u539F\u59CB\u6587\u4EF6\u5939\u540D/\u5C55\u793A\u540D\u6536\u96C6\u591A\u7EA7\u6E05\u6D17\u79CD\u5B50\uFF08\u7531\u810F\u5230\u51C0\uFF09\u3002\n * \u4F8B\uFF1A\"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\"\n * \u2192 \u62D4\u5200\u5251 Slash Blade v4 BP \u2192 Slash Blade v4 BP \u2192 Slash Blade v4 \u2192 Slash Blade\n */\nexport function collectQuerySeeds(raw: string, stripFolderTags = true): string[] {\n const seeds: string[] = [];\n const push = (q: string): void => {\n const t = q.replace(/\\s+/g, \" \").trim();\n if (!t) return;\n if (!seeds.some((x) => x.toLowerCase() === t.toLowerCase())) seeds.push(t);\n };\n\n const s = preprocessPackNameRaw(raw, stripFolderTags);\n push(s);\n\n const noRole = stripPackRoleTokens(s);\n push(noRole);\n push(stripVersionTokens(s));\n push(stripVersionTokens(noRole));\n\n const latin = extractLatinPhrase(s);\n push(latin);\n const latinNoRole = stripPackRoleTokens(latin);\n push(latinNoRole);\n const latinCore = stripVersionTokens(latinNoRole);\n push(latinCore);\n\n /* \u62C9\u4E01\u6838\u5FC3\u518D\u9010\u7EA7\u7F29\u77ED\uFF0C\u81F3\u5C11\u4FDD\u7559 2 \u4E2A\u8BCD\uFF08\u907F\u514D\u5355\u72EC\u641C Blade \u8FC7\u6CDB\uFF09 */\n let tokens = latinCore.split(/\\s+/).filter(Boolean);\n while (tokens.length >= 2) {\n push(tokens.join(\" \"));\n tokens = tokens.slice(0, -1);\n }\n\n push(normalizePackSearchName(raw, stripFolderTags));\n return seeds;\n}\n\n/**\n * \u4ECE\u5C55\u793A\u540D\u63A8\u5BFC CF slug \u5019\u9009\uFF08\u65E0\u7A7A\u683C\u3001\u5C0F\u5199\u3001\u8FDE\u5B57\u7B26\uFF09\u3002\n * \u4F8B\uFF1A\"Slash Blade v4 BP\" \u2192 \"slash-blade\"\n */\nexport function toCfSlugCandidate(name: string, stripFolderTags = true): string {\n const base = normalizePackSearchName(name, stripFolderTags);\n /* slug \u4FA7\u51E0\u4E4E\u603B\u662F\u62C9\u4E01\u7247\u6BB5\uFF1B\u4FDD\u7559\u5B57\u6BCD\u6570\u5B57\uFF0C\u5176\u4F59\u53D8\u8FDE\u5B57\u7B26 */\n let s = base\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-+/g, \"-\");\n return s;\n}\n\n/** Title-Case \u8FDE\u5B57\u7B26\uFF1Aslash-blade \u2192 Slash-Blade\uFF08\u90E8\u5206 CF \u641C\u7D22\u66F4\u5403\u8FD9\u4E2A\uFF09 */\nexport function toCfTitleSlug(slug: string): string {\n return String(slug ?? \"\")\n .split(\"-\")\n .filter(Boolean)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(\"-\");\n}\n\n/**\n * \u6D3E\u751F\u4E00\u7EC4\u641C\u7D22\u8BCD\uFF1A\u591A\u6E90\u8F93\u5165 \u00D7 \u591A\u7EA7\u6E05\u6D17\u79CD\u5B50 \u00D7\uFF08\u5C55\u793A\u540D / slug / Title-Slug / slug-addon\uFF09\u3002\n * `name` \u53EF\u4E3A\u5B57\u7B26\u4E32\u6216\u6570\u7EC4\uFF08\u5982 header.name + \u6587\u4EF6\u5939\u540D\uFF09\u3002\n *\n * \u89C4\u5219\uFF1A\u53EA\u8981\u5B58\u5728\u542B\u62C9\u4E01\u5B57\u6BCD\u7684\u5019\u9009\uFF0C\u5C31**\u4E22\u5F03\u7EAF CJK \u67E5\u8BE2**\uFF08CF Bedrock \u51E0\u4E4E\u4E0D\u9760\u4E2D\u6587\u641C\uFF09\u3002\n */\nexport function buildSearchQueries(\n name: string | readonly string[],\n stripFolderTags = true,\n maxQueries = 14\n): string[] {\n const inputs = (Array.isArray(name) ? name : [name])\n .map((x) => String(x ?? \"\").trim())\n .filter(Boolean)\n .map((raw, i) => ({ id: `src${i}`, raw }));\n return buildSearchQueriesFromSources(inputs, stripFolderTags, maxQueries).queries;\n}\n\nexport type SearchQuerySource = { id: string; raw: string };\n\nexport type SearchQueryPlan = {\n /** \u6700\u7EC8\u53D1\u7ED9 CF \u7684\u67E5\u8BE2\uFF08\u5DF2\u53BB\u91CD\u3001\u6392\u5E8F\u3001\u622A\u65AD\uFF09 */\n queries: string[];\n /** \u5404\u6E90\u539F\u59CB\u8F93\u5165\uFF08\u4FBF\u4E8E\u65E5\u5FD7\uFF09 */\n sources: SearchQuerySource[];\n /** \u6BCF\u6E90\u8D21\u732E\u4E86\u54EA\u4E9B\u8BCD\uFF08\u622A\u65AD\u524D\uFF0C\u4FBF\u4E8E\u786E\u8BA4\u53CC\u6E90\u90FD\u53C2\u4E0E\uFF09 */\n perSource: Record<string, string[]>;\n};\n\n/**\n * \u6309\u6E90\u5206\u522B\u6D3E\u751F\uFF0C\u518D\u5408\u5E76\uFF1A\u4FDD\u8BC1 header / \u6587\u4EF6\u5939\u540D\u90FD\u4F1A\u8D21\u732E\u5019\u9009\uFF0C\u800C\u975E\u6DF7\u6210\u4E00\u9505\u88AB\u622A\u65AD\u504F\u79D1\u3002\n */\nexport function buildSearchQueriesFromSources(\n sources: readonly SearchQuerySource[],\n stripFolderTags = true,\n maxQueries = 14\n): SearchQueryPlan {\n const cleaned = sources\n .map((s) => ({ id: s.id, raw: String(s.raw ?? \"\").trim() }))\n .filter((s) => s.raw);\n\n const hasCjk = (q: string): boolean => /[\\u3400-\\u9fff]/.test(q);\n const hasLatin = (q: string): boolean => /[A-Za-z]/.test(q);\n const kindRank = (q: string): number => {\n if (/^[a-z0-9]+(?:-[a-z0-9]+)*-addon$/.test(q)) return 0;\n if (/^[a-z0-9]+(?:-[a-z0-9]+)+$/.test(q)) return 1;\n if (/^[A-Z][a-z0-9]*(?:-[A-Z][a-z0-9]*)+$/.test(q)) return 2;\n if (hasCjk(q) && !hasLatin(q)) return 5;\n if (hasCjk(q)) return 4;\n return 3;\n };\n const sortQueries = (list: string[]): string[] =>\n [...list].sort((a, b) => {\n const ka = kindRank(a);\n const kb = kindRank(b);\n if (ka !== kb) return ka - kb;\n const ta = a.split(/[\\s\\-]+/).filter(Boolean).length;\n const tb = b.split(/[\\s\\-]+/).filter(Boolean).length;\n if (ta !== tb) return ta - tb;\n return a.length - b.length;\n });\n\n const expandOne = (raw: string): string[] => {\n const out: string[] = [];\n const push = (q: string): void => {\n const t = q.trim();\n if (!t) return;\n if (!out.some((x) => x.toLowerCase() === t.toLowerCase())) out.push(t);\n };\n for (const seed of collectQuerySeeds(raw, stripFolderTags)) {\n push(seed);\n const slug = toCfSlugCandidate(seed, false);\n push(slug);\n if (slug) {\n push(toCfTitleSlug(slug));\n if (!slug.endsWith(\"-addon\")) push(`${slug}-addon`);\n }\n }\n return sortQueries(out);\n };\n\n const perSource: Record<string, string[]> = {};\n const perSourcePreferred: string[][] = [];\n for (const src of cleaned) {\n const all = expandOne(src.raw);\n /* \u5355\u6E90\u5185\uFF1A\u6709\u62C9\u4E01\u5219\u4E22\u6389\u7EAF\u4E2D\u6587 */\n const latinish = all.filter((q) => hasLatin(q));\n const preferred = latinish.length > 0 ? latinish : all;\n perSource[src.id] = preferred;\n perSourcePreferred.push(preferred);\n }\n\n /* \u8F6E\u8BE2\u5408\u5E76\u5404\u6E90\uFF0C\u907F\u514D\u67D0\u4E00\u6E90\u5360\u6EE1\u914D\u989D\u5BFC\u81F4\u53E6\u4E00\u6E90\u5B8C\u5168\u6CA1\u641C */\n const merged: string[] = [];\n const pushMerged = (q: string): void => {\n if (!q) return;\n if (merged.some((x) => x.toLowerCase() === q.toLowerCase())) return;\n merged.push(q);\n };\n const maxLen = Math.max(0, ...perSourcePreferred.map((x) => x.length));\n for (let i = 0; i < maxLen; i++) {\n for (const list of perSourcePreferred) {\n if (i < list.length) pushMerged(list[i]!);\n }\n }\n\n /* \u5168\u5C40\u518D\u6EE4\u4E00\u6B21\uFF1A\u6574\u4F53\u5DF2\u6709\u62C9\u4E01\u65F6\uFF0C\u4E22\u6389\u6DF7\u8FDB\u6765\u7684\u7EAF CJK */\n const anyLatin = merged.some((q) => hasLatin(q));\n const filtered = anyLatin ? merged.filter((q) => hasLatin(q)) : merged;\n const queries = sortQueries(filtered).slice(0, Math.max(1, maxQueries));\n\n return { queries, sources: cleaned, perSource };\n}\n\n/** \u7B80\u5355\u76F8\u4F3C\u5EA6\uFF1A0~1\uFF08\u57FA\u4E8E\u5171\u540C token \u4E0E\u5305\u542B\u5173\u7CFB\uFF09 */\nexport function nameSimilarity(a: string, b: string): number {\n const na = normalizePackSearchName(a).toLowerCase();\n const nb = normalizePackSearchName(b).toLowerCase();\n if (!na || !nb) return 0;\n if (na === nb) return 1;\n if (na.includes(nb) || nb.includes(na)) return 0.85;\n const ta = new Set(na.split(/[\\s_\\-]+/).filter(Boolean));\n const tb = new Set(nb.split(/[\\s_\\-]+/).filter(Boolean));\n if (ta.size === 0 || tb.size === 0) return 0;\n let inter = 0;\n for (const t of ta) if (tb.has(t)) inter++;\n return inter / Math.max(ta.size, tb.size);\n}\n\n/**\n * \u7EFC\u5408\u5C55\u793A\u540D + CF slug \u6253\u5206\u3002\n * slug \u65E0\u7A7A\u683C\uFF08slash-blade-addon\uFF09\uFF0C\u4E0E\u672C\u5730\u300CSlash Blade v4\u300D\u5BF9\u9F50\u65F6\u6743\u91CD\u5927\u4E8E\u7EAF name\u3002\n */\nexport function packSourceScore(\n query: string,\n hit: { name: string; slug: string },\n stripFolderTags = true\n): number {\n const byName = nameSimilarity(query, hit.name);\n const qSlug = toCfSlugCandidate(query, stripFolderTags);\n const hSlug = String(hit.slug ?? \"\")\n .toLowerCase()\n .replace(/^-+|-+$/g, \"\");\n let bySlug = 0;\n if (qSlug && hSlug) {\n if (hSlug === qSlug) bySlug = 1;\n else if (hSlug === `${qSlug}-addon` || hSlug.startsWith(`${qSlug}-`)) bySlug = 0.96;\n else if (hSlug.includes(qSlug) || qSlug.includes(hSlug)) bySlug = 0.88;\n else bySlug = nameSimilarity(qSlug.replace(/-/g, \" \"), hSlug.replace(/-/g, \" \"));\n }\n return Math.max(byName, bySlug);\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * \u7248\u672C\u7B56\u7565\uFF1A\u4EE5 BP \u4E3A\u51C6\u6BD4\u8F83\uFF1B\u540C major \u66F4\u65B0\u65F6\u62AC\u9AD8 RP \u7248\u672C\u89E6\u53D1\u5BA2\u6237\u7AEF\u5237\u65B0\n */\nimport {\n bumpSemVer3,\n compareSemVer3 as compareSemVer3Raw,\n maxSemVer3,\n nextEnabledVersion,\n} from \"@sfmc-bds/bds-tools/world-packs\";\nimport type { SemVer3, VersionCompareResult, VersionPolicyConfig } from \"./types.js\";\n\n/** \u5F52\u4E00\u5316\u4E3A -1 | 0 | 1\uFF0C\u4F9B\u7B56\u7565\u6BD4\u8F83 */\nexport function compareSemVer3(a: SemVer3, b: SemVer3): number {\n const d = compareSemVer3Raw(a, b);\n return d > 0 ? 1 : d < 0 ? -1 : 0;\n}\n\nexport function isNewer(remote: SemVer3, local: SemVer3): boolean {\n return compareSemVer3(remote, local) > 0;\n}\n\nexport { bumpSemVer3, maxSemVer3, nextEnabledVersion };\n\n/**\n * \u6839\u636E\u672C\u5730/\u8FDC\u7A0B BP \u7248\u672C\u4E0E\u7B56\u7565\uFF0C\u51B3\u5B9A\u662F\u5426\u66F4\u65B0\u4EE5\u53CA\u662F\u5426\u989D\u5916 bump RP\u3002\n * `treatAsUpdate`\uFF1A\u540C\u7248\u672C/\u672A\u66F4\u9AD8\u4F46\u9700\u5F3A\u5236\u540C\u6B65\u5199\u5165\u65F6\uFF08\u5982 fileId \u5C1A\u672A apply\uFF09\u4E5F\u8D70\u66F4\u65B0\u4FA7 RP bump \u89C4\u5219\uFF08OCP\uFF1A\u7B56\u7565\u96C6\u4E2D\u4E8E\u6B64\uFF0C\u52FF\u5728\u7F16\u6392\u5C42\u590D\u523B\uFF09\u3002\n */\nexport function decideVersionPolicy(\n localBp: SemVer3,\n remoteBp: SemVer3,\n policy: VersionPolicyConfig,\n opts?: { treatAsUpdate?: boolean }\n): VersionCompareResult {\n const remoteNewer = isNewer(remoteBp, localBp);\n const majorHigher = remoteBp[0] > localBp[0];\n const asUpdate = remoteNewer || Boolean(opts?.treatAsUpdate);\n let shouldBumpRp = false;\n if (asUpdate && policy.onUpdateOverwriteBoth) {\n if (majorHigher && policy.majorHigherSkipRpBump) {\n shouldBumpRp = false;\n } else if (policy.rpBumpWhenSameMajor) {\n shouldBumpRp = true;\n }\n }\n return { remoteNewer, majorHigher, shouldBumpRp };\n}\n\n/** \u5305\u7C7B\u578B/\u6E20\u9053\u7B49\u566A\u97F3 token\uFF08\u6574\u8BCD\u53BB\u6389\uFF0C\u52FF\u5220\u4EA7\u54C1\u540D\uFF09 */\nconst PACK_ROLE_TOKEN =\n /^(?:bp|rp|ba|behavior|behaviours?|resource|resources|pack|packs|addon|addons|mcpack|mcaddon|behavior.?pack|resource.?pack|\u884C\u4E3A\u5305|\u8D44\u6E90\u5305|\u9644\u52A0\u5305|\u57FA\u5CA9|bedrock)$/iu;\n\n/** \u4E2D\u65E5\u97E9\u4E0E\u62C9\u4E01\u7C98\u8FDE\u65F6\u63D2\u5165\u7A7A\u683C\uFF1A\u62D4\u5200\u5251Slash \u2192 \u62D4\u5200\u5251 Slash */\nexport function insertCjkLatinBoundaries(name: string): string {\n return String(name ?? \"\")\n .replace(/([\\u3400-\\u9fff\\uF900-\\uFAFF])([A-Za-z])/g, \"$1 $2\")\n .replace(/([A-Za-z])([\\u3400-\\u9fff\\uF900-\\uFAFF])/g, \"$1 $2\");\n}\n\n/** \u53BB\u6389\u6574\u8BCD\u5305\u89D2\u8272\u6807\u8BB0\uFF08\u672B\u5C3E BP/RP/Addon \u7B49\uFF09 */\nexport function stripPackRoleTokens(name: string): string {\n return String(name ?? \"\")\n .split(/[\\s_]+/)\n .filter((t) => t && !PACK_ROLE_TOKEN.test(t))\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** \u53BB\u6389 v4 / 1.21.100 \u4E00\u7C7B\u7248\u672C\u5C3E\u5DF4 */\nexport function stripVersionTokens(name: string): string {\n return String(name ?? \"\")\n .replace(/\\bv\\d+(?:\\.\\d+)*\\b/gi, \" \")\n .replace(/\\b\\d+\\.\\d+(?:\\.\\d+)?\\b/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** \u4EC5\u4FDD\u7559\u62C9\u4E01\u8BCD\uFF08CF slug/search \u4E3B\u8DEF\u5F84\uFF09 */\nexport function extractLatinPhrase(name: string): string {\n const words = String(name ?? \"\").match(/[A-Za-z][A-Za-z0-9]*/g);\n return words ? words.join(\" \") : \"\";\n}\n\n/**\n * \u5171\u4EAB\u9884\u5904\u7406\uFF1A\u00A7\u7801\u3001\u65B9\u62EC\u53F7\u6807\u7B7E\u3001\u6269\u5C55\u540D\u3001CJK/\u62C9\u4E01\u5206\u754C\u3001\u4E0B\u5212\u7EBF\u2192\u7A7A\u683C\u3002\n * normalize / collectQuerySeeds \u5171\u7528\uFF0C\u907F\u514D\u4E24\u5904\u5404\u5199\u4E00\u904D\uFF08DRY\uFF09\u3002\n */\nexport function preprocessPackNameRaw(name: string, stripFolderTags = true): string {\n let s = String(name ?? \"\");\n s = s.replace(/\u00A7[0-9a-zA-Z]/g, \"\");\n if (stripFolderTags) {\n s = s.replace(/\\[[^\\]]*]/g, \" \");\n }\n s = s.replace(/\\.(zip|mcpack|mcaddon)$/i, \"\");\n s = insertCjkLatinBoundaries(s);\n s = s.replace(/[_]+/g, \" \").replace(/\\s+/g, \" \").trim();\n return s;\n}\n\n/**\n * \u57FA\u7840\u6E05\u6D17\uFF1A\u9884\u5904\u7406 + \u5305\u89D2\u8272 + \u7248\u672C\u53F7\u3002\n * \u4F8B\uFF1A\"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\" \u2192 \"\u62D4\u5200\u5251 Slash Blade\"\n */\nexport function normalizePackSearchName(name: string, stripFolderTags = true): string {\n let s = preprocessPackNameRaw(name, stripFolderTags);\n s = stripPackRoleTokens(s);\n s = stripVersionTokens(s);\n return s;\n}\n\n/**\n * \u4ECE\u539F\u59CB\u6587\u4EF6\u5939\u540D/\u5C55\u793A\u540D\u6536\u96C6\u591A\u7EA7\u6E05\u6D17\u79CD\u5B50\uFF08\u7531\u810F\u5230\u51C0\uFF09\u3002\n * \u4F8B\uFF1A\"[BP] [BA] [\u73A9\u6CD5] \u62D4\u5200\u5251Slash Blade v4 BP\"\n * \u2192 \u62D4\u5200\u5251 Slash Blade v4 BP \u2192 Slash Blade v4 BP \u2192 Slash Blade v4 \u2192 Slash Blade\n */\nexport function collectQuerySeeds(raw: string, stripFolderTags = true): string[] {\n const seeds: string[] = [];\n const push = (q: string): void => {\n const t = q.replace(/\\s+/g, \" \").trim();\n if (!t) return;\n if (!seeds.some((x) => x.toLowerCase() === t.toLowerCase())) seeds.push(t);\n };\n\n const s = preprocessPackNameRaw(raw, stripFolderTags);\n push(s);\n\n const noRole = stripPackRoleTokens(s);\n push(noRole);\n push(stripVersionTokens(s));\n push(stripVersionTokens(noRole));\n\n const latin = extractLatinPhrase(s);\n push(latin);\n const latinNoRole = stripPackRoleTokens(latin);\n push(latinNoRole);\n const latinCore = stripVersionTokens(latinNoRole);\n push(latinCore);\n\n /* \u62C9\u4E01\u6838\u5FC3\u518D\u9010\u7EA7\u7F29\u77ED\uFF0C\u81F3\u5C11\u4FDD\u7559 2 \u4E2A\u8BCD\uFF08\u907F\u514D\u5355\u72EC\u641C Blade \u8FC7\u6CDB\uFF09 */\n let tokens = latinCore.split(/\\s+/).filter(Boolean);\n while (tokens.length >= 2) {\n push(tokens.join(\" \"));\n tokens = tokens.slice(0, -1);\n }\n\n push(normalizePackSearchName(raw, stripFolderTags));\n return seeds;\n}\n\n/**\n * \u4ECE\u5C55\u793A\u540D\u63A8\u5BFC CF slug \u5019\u9009\uFF08\u65E0\u7A7A\u683C\u3001\u5C0F\u5199\u3001\u8FDE\u5B57\u7B26\uFF09\u3002\n * \u4F8B\uFF1A\"Slash Blade v4 BP\" \u2192 \"slash-blade\"\n */\nexport function toCfSlugCandidate(name: string, stripFolderTags = true): string {\n const base = normalizePackSearchName(name, stripFolderTags);\n /* slug \u4FA7\u51E0\u4E4E\u603B\u662F\u62C9\u4E01\u7247\u6BB5\uFF1B\u4FDD\u7559\u5B57\u6BCD\u6570\u5B57\uFF0C\u5176\u4F59\u53D8\u8FDE\u5B57\u7B26 */\n let s = base\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-+/g, \"-\");\n return s;\n}\n\n/** Title-Case \u8FDE\u5B57\u7B26\uFF1Aslash-blade \u2192 Slash-Blade\uFF08\u90E8\u5206 CF \u641C\u7D22\u66F4\u5403\u8FD9\u4E2A\uFF09 */\nexport function toCfTitleSlug(slug: string): string {\n return String(slug ?? \"\")\n .split(\"-\")\n .filter(Boolean)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(\"-\");\n}\n\n/**\n * \u6D3E\u751F\u4E00\u7EC4\u641C\u7D22\u8BCD\uFF1A\u591A\u6E90\u8F93\u5165 \u00D7 \u591A\u7EA7\u6E05\u6D17\u79CD\u5B50 \u00D7\uFF08\u5C55\u793A\u540D / slug / Title-Slug / slug-addon\uFF09\u3002\n * `name` \u53EF\u4E3A\u5B57\u7B26\u4E32\u6216\u6570\u7EC4\uFF08\u5982 header.name + \u6587\u4EF6\u5939\u540D\uFF09\u3002\n *\n * \u89C4\u5219\uFF1A\u53EA\u8981\u5B58\u5728\u542B\u62C9\u4E01\u5B57\u6BCD\u7684\u5019\u9009\uFF0C\u5C31**\u4E22\u5F03\u7EAF CJK \u67E5\u8BE2**\uFF08CF Bedrock \u51E0\u4E4E\u4E0D\u9760\u4E2D\u6587\u641C\uFF09\u3002\n */\nexport function buildSearchQueries(\n name: string | readonly string[],\n stripFolderTags = true,\n maxQueries = 14\n): string[] {\n const inputs = (Array.isArray(name) ? name : [name])\n .map((x) => String(x ?? \"\").trim())\n .filter(Boolean)\n .map((raw, i) => ({ id: `src${i}`, raw }));\n return buildSearchQueriesFromSources(inputs, stripFolderTags, maxQueries).queries;\n}\n\nexport type SearchQuerySource = { id: string; raw: string };\n\nexport type SearchQueryPlan = {\n /** \u6700\u7EC8\u53D1\u7ED9 CF \u7684\u67E5\u8BE2\uFF08\u5DF2\u53BB\u91CD\u3001\u6392\u5E8F\u3001\u622A\u65AD\uFF09 */\n queries: string[];\n /** \u5404\u6E90\u539F\u59CB\u8F93\u5165\uFF08\u4FBF\u4E8E\u65E5\u5FD7\uFF09 */\n sources: SearchQuerySource[];\n /** \u6BCF\u6E90\u8D21\u732E\u4E86\u54EA\u4E9B\u8BCD\uFF08\u622A\u65AD\u524D\uFF0C\u4FBF\u4E8E\u786E\u8BA4\u53CC\u6E90\u90FD\u53C2\u4E0E\uFF09 */\n perSource: Record<string, string[]>;\n};\n\n/**\n * \u6309\u6E90\u5206\u522B\u6D3E\u751F\uFF0C\u518D\u5408\u5E76\uFF1A\u4FDD\u8BC1 header / \u6587\u4EF6\u5939\u540D\u90FD\u4F1A\u8D21\u732E\u5019\u9009\uFF0C\u800C\u975E\u6DF7\u6210\u4E00\u9505\u88AB\u622A\u65AD\u504F\u79D1\u3002\n */\nexport function buildSearchQueriesFromSources(\n sources: readonly SearchQuerySource[],\n stripFolderTags = true,\n maxQueries = 14\n): SearchQueryPlan {\n const cleaned = sources\n .map((s) => ({ id: s.id, raw: String(s.raw ?? \"\").trim() }))\n .filter((s) => s.raw);\n\n const hasCjk = (q: string): boolean => /[\\u3400-\\u9fff]/.test(q);\n const hasLatin = (q: string): boolean => /[A-Za-z]/.test(q);\n const kindRank = (q: string): number => {\n if (/^[a-z0-9]+(?:-[a-z0-9]+)*-addon$/.test(q)) return 0;\n if (/^[a-z0-9]+(?:-[a-z0-9]+)+$/.test(q)) return 1;\n if (/^[A-Z][a-z0-9]*(?:-[A-Z][a-z0-9]*)+$/.test(q)) return 2;\n if (hasCjk(q) && !hasLatin(q)) return 5;\n if (hasCjk(q)) return 4;\n return 3;\n };\n const sortQueries = (list: string[]): string[] =>\n [...list].sort((a, b) => {\n const ka = kindRank(a);\n const kb = kindRank(b);\n if (ka !== kb) return ka - kb;\n const ta = a.split(/[\\s\\-]+/).filter(Boolean).length;\n const tb = b.split(/[\\s\\-]+/).filter(Boolean).length;\n if (ta !== tb) return ta - tb;\n return a.length - b.length;\n });\n\n const expandOne = (raw: string): string[] => {\n const out: string[] = [];\n const push = (q: string): void => {\n const t = q.trim();\n if (!t) return;\n if (!out.some((x) => x.toLowerCase() === t.toLowerCase())) out.push(t);\n };\n for (const seed of collectQuerySeeds(raw, stripFolderTags)) {\n push(seed);\n const slug = toCfSlugCandidate(seed, false);\n push(slug);\n if (slug) {\n push(toCfTitleSlug(slug));\n if (!slug.endsWith(\"-addon\")) push(`${slug}-addon`);\n }\n }\n return sortQueries(out);\n };\n\n const perSource: Record<string, string[]> = {};\n const perSourcePreferred: string[][] = [];\n for (const src of cleaned) {\n const all = expandOne(src.raw);\n /* \u5355\u6E90\u5185\uFF1A\u6709\u62C9\u4E01\u5219\u4E22\u6389\u7EAF\u4E2D\u6587 */\n const latinish = all.filter((q) => hasLatin(q));\n const preferred = latinish.length > 0 ? latinish : all;\n perSource[src.id] = preferred;\n perSourcePreferred.push(preferred);\n }\n\n /* \u8F6E\u8BE2\u5408\u5E76\u5404\u6E90\uFF0C\u907F\u514D\u67D0\u4E00\u6E90\u5360\u6EE1\u914D\u989D\u5BFC\u81F4\u53E6\u4E00\u6E90\u5B8C\u5168\u6CA1\u641C */\n const merged: string[] = [];\n const pushMerged = (q: string): void => {\n if (!q) return;\n if (merged.some((x) => x.toLowerCase() === q.toLowerCase())) return;\n merged.push(q);\n };\n const maxLen = Math.max(0, ...perSourcePreferred.map((x) => x.length));\n for (let i = 0; i < maxLen; i++) {\n for (const list of perSourcePreferred) {\n if (i < list.length) pushMerged(list[i]!);\n }\n }\n\n /* \u5168\u5C40\u518D\u6EE4\u4E00\u6B21\uFF1A\u6574\u4F53\u5DF2\u6709\u62C9\u4E01\u65F6\uFF0C\u4E22\u6389\u6DF7\u8FDB\u6765\u7684\u7EAF CJK */\n const anyLatin = merged.some((q) => hasLatin(q));\n const filtered = anyLatin ? merged.filter((q) => hasLatin(q)) : merged;\n const queries = sortQueries(filtered).slice(0, Math.max(1, maxQueries));\n\n return { queries, sources: cleaned, perSource };\n}\n\n/** \u7B80\u5355\u76F8\u4F3C\u5EA6\uFF1A0~1\uFF08\u57FA\u4E8E\u5171\u540C token \u4E0E\u5305\u542B\u5173\u7CFB\uFF09 */\nexport function nameSimilarity(a: string, b: string): number {\n const na = normalizePackSearchName(a).toLowerCase();\n const nb = normalizePackSearchName(b).toLowerCase();\n if (!na || !nb) return 0;\n if (na === nb) return 1;\n if (na.includes(nb) || nb.includes(na)) return 0.85;\n const ta = new Set(na.split(/[\\s_\\-]+/).filter(Boolean));\n const tb = new Set(nb.split(/[\\s_\\-]+/).filter(Boolean));\n if (ta.size === 0 || tb.size === 0) return 0;\n let inter = 0;\n for (const t of ta) if (tb.has(t)) inter++;\n return inter / Math.max(ta.size, tb.size);\n}\n\n/**\n * \u7EFC\u5408\u5C55\u793A\u540D + CF slug \u6253\u5206\u3002\n * slug \u65E0\u7A7A\u683C\uFF08slash-blade-addon\uFF09\uFF0C\u4E0E\u672C\u5730\u300CSlash Blade v4\u300D\u5BF9\u9F50\u65F6\u6743\u91CD\u5927\u4E8E\u7EAF name\u3002\n */\nexport function packSourceScore(\n query: string,\n hit: { name: string; slug: string },\n stripFolderTags = true\n): number {\n const byName = nameSimilarity(query, hit.name);\n const qSlug = toCfSlugCandidate(query, stripFolderTags);\n const hSlug = String(hit.slug ?? \"\")\n .toLowerCase()\n .replace(/^-+|-+$/g, \"\");\n let bySlug = 0;\n if (qSlug && hSlug) {\n if (hSlug === qSlug) bySlug = 1;\n else if (hSlug === `${qSlug}-addon` || hSlug.startsWith(`${qSlug}-`)) bySlug = 0.96;\n else if (hSlug.includes(qSlug) || qSlug.includes(hSlug)) bySlug = 0.88;\n else bySlug = nameSimilarity(qSlug.replace(/-/g, \" \"), hSlug.replace(/-/g, \" \"));\n }\n return Math.max(byName, bySlug);\n}\n"],
|
|
5
|
+
"mappings": "AAGA;AAAA,EACE;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,OACK;AAIA,SAAS,eAAe,GAAY,GAAoB;AAC7D,QAAM,IAAI,kBAAkB,GAAG,CAAC;AAChC,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK;AAClC;AAEO,SAAS,QAAQ,QAAiB,OAAyB;AAChE,SAAO,eAAe,QAAQ,KAAK,IAAI;AACzC;AAQO,SAAS,oBACd,SACA,UACA,QACA,MACsB;AACtB,QAAM,cAAc,QAAQ,UAAU,OAAO;AAC7C,QAAM,cAAc,SAAS,CAAC,IAAI,QAAQ,CAAC;AAC3C,QAAM,WAAW,eAAe,QAAQ,MAAM,aAAa;AAC3D,MAAI,eAAe;AACnB,MAAI,YAAY,OAAO,uBAAuB;AAC5C,QAAI,eAAe,OAAO,uBAAuB;AAC/C,qBAAe;AAAA,IACjB,WAAW,OAAO,qBAAqB;AACrC,qBAAe;AAAA,IACjB;AAAA,EACF;AACA,SAAO,EAAE,aAAa,aAAa,aAAa;AAClD;AAGA,MAAM,kBACJ;AAGK,SAAS,yBAAyB,MAAsB;AAC7D,SAAO,OAAO,QAAQ,EAAE,EACrB,QAAQ,6CAA6C,OAAO,EAC5D,QAAQ,6CAA6C,OAAO;AACjE;AAGO,SAAS,oBAAoB,MAAsB;AACxD,SAAO,OAAO,QAAQ,EAAE,EACrB,MAAM,QAAQ,EACd,OAAO,CAAC,MAAM,KAAK,CAAC,gBAAgB,KAAK,CAAC,CAAC,EAC3C,KAAK,GAAG,EACR,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAGO,SAAS,mBAAmB,MAAsB;AACvD,SAAO,OAAO,QAAQ,EAAE,EACrB,QAAQ,wBAAwB,GAAG,EACnC,QAAQ,2BAA2B,GAAG,EACtC,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAGO,SAAS,mBAAmB,MAAsB;AACvD,QAAM,QAAQ,OAAO,QAAQ,EAAE,EAAE,MAAM,uBAAuB;AAC9D,SAAO,QAAQ,MAAM,KAAK,GAAG,IAAI;AACnC;AAMO,SAAS,sBAAsB,MAAc,kBAAkB,MAAc;AAClF,MAAI,IAAI,OAAO,QAAQ,EAAE;AACzB,MAAI,EAAE,QAAQ,iBAAiB,EAAE;AACjC,MAAI,iBAAiB;AACnB,QAAI,EAAE,QAAQ,cAAc,GAAG;AAAA,EACjC;AACA,MAAI,EAAE,QAAQ,4BAA4B,EAAE;AAC5C,MAAI,yBAAyB,CAAC;AAC9B,MAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACtD,SAAO;AACT;AAMO,SAAS,wBAAwB,MAAc,kBAAkB,MAAc;AACpF,MAAI,IAAI,sBAAsB,MAAM,eAAe;AACnD,MAAI,oBAAoB,CAAC;AACzB,MAAI,mBAAmB,CAAC;AACxB,SAAO;AACT;AAOO,SAAS,kBAAkB,KAAa,kBAAkB,MAAgB;AAC/E,QAAM,QAAkB,CAAC;AACzB,QAAM,OAAO,CAAC,MAAoB;AAChC,UAAM,IAAI,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACtC,QAAI,CAAC,EAAG;AACR,QAAI,CAAC,MAAM,KAAK,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE,YAAY,CAAC,EAAG,OAAM,KAAK,CAAC;AAAA,EAC3E;AAEA,QAAM,IAAI,sBAAsB,KAAK,eAAe;AACpD,OAAK,CAAC;AAEN,QAAM,SAAS,oBAAoB,CAAC;AACpC,OAAK,MAAM;AACX,OAAK,mBAAmB,CAAC,CAAC;AAC1B,OAAK,mBAAmB,MAAM,CAAC;AAE/B,QAAM,QAAQ,mBAAmB,CAAC;AAClC,OAAK,KAAK;AACV,QAAM,cAAc,oBAAoB,KAAK;AAC7C,OAAK,WAAW;AAChB,QAAM,YAAY,mBAAmB,WAAW;AAChD,OAAK,SAAS;AAGd,MAAI,SAAS,UAAU,MAAM,KAAK,EAAE,OAAO,OAAO;AAClD,SAAO,OAAO,UAAU,GAAG;AACzB,SAAK,OAAO,KAAK,GAAG,CAAC;AACrB,aAAS,OAAO,MAAM,GAAG,EAAE;AAAA,EAC7B;AAEA,OAAK,wBAAwB,KAAK,eAAe,CAAC;AAClD,SAAO;AACT;AAMO,SAAS,kBAAkB,MAAc,kBAAkB,MAAc;AAC9E,QAAM,OAAO,wBAAwB,MAAM,eAAe;AAE1D,MAAI,IAAI,KACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE,EACtB,QAAQ,OAAO,GAAG;AACrB,SAAO;AACT;AAGO,SAAS,cAAc,MAAsB;AAClD,SAAO,OAAO,QAAQ,EAAE,EACrB,MAAM,GAAG,EACT,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY,CAAC,EAC/D,KAAK,GAAG;AACb;AAQO,SAAS,mBACd,MACA,kBAAkB,MAClB,aAAa,IACH;AACV,QAAM,UAAU,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,GAC/C,IAAI,CAAC,MAAM,OAAO,KAAK,EAAE,EAAE,KAAK,CAAC,EACjC,OAAO,OAAO,EACd,IAAI,CAAC,KAAK,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE;AAC3C,SAAO,8BAA8B,QAAQ,iBAAiB,UAAU,EAAE;AAC5E;AAgBO,SAAS,8BACd,SACA,kBAAkB,MAClB,aAAa,IACI;AACjB,QAAM,UAAU,QACb,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAC1D,OAAO,CAAC,MAAM,EAAE,GAAG;AAEtB,QAAM,SAAS,CAAC,MAAuB,kBAAkB,KAAK,CAAC;AAC/D,QAAM,WAAW,CAAC,MAAuB,WAAW,KAAK,CAAC;AAC1D,QAAM,WAAW,CAAC,MAAsB;AACtC,QAAI,mCAAmC,KAAK,CAAC,EAAG,QAAO;AACvD,QAAI,6BAA6B,KAAK,CAAC,EAAG,QAAO;AACjD,QAAI,uCAAuC,KAAK,CAAC,EAAG,QAAO;AAC3D,QAAI,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAG,QAAO;AACtC,QAAI,OAAO,CAAC,EAAG,QAAO;AACtB,WAAO;AAAA,EACT;AACA,QAAM,cAAc,CAAC,SACnB,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM;AACvB,UAAM,KAAK,SAAS,CAAC;AACrB,UAAM,KAAK,SAAS,CAAC;AACrB,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,UAAM,KAAK,EAAE,MAAM,SAAS,EAAE,OAAO,OAAO,EAAE;AAC9C,UAAM,KAAK,EAAE,MAAM,SAAS,EAAE,OAAO,OAAO,EAAE;AAC9C,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,WAAO,EAAE,SAAS,EAAE;AAAA,EACtB,CAAC;AAEH,QAAM,YAAY,CAAC,QAA0B;AAC3C,UAAM,MAAgB,CAAC;AACvB,UAAM,OAAO,CAAC,MAAoB;AAChC,YAAM,IAAI,EAAE,KAAK;AACjB,UAAI,CAAC,EAAG;AACR,UAAI,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE,YAAY,CAAC,EAAG,KAAI,KAAK,CAAC;AAAA,IACvE;AACA,eAAW,QAAQ,kBAAkB,KAAK,eAAe,GAAG;AAC1D,WAAK,IAAI;AACT,YAAM,OAAO,kBAAkB,MAAM,KAAK;AAC1C,WAAK,IAAI;AACT,UAAI,MAAM;AACR,aAAK,cAAc,IAAI,CAAC;AACxB,YAAI,CAAC,KAAK,SAAS,QAAQ,EAAG,MAAK,GAAG,IAAI,QAAQ;AAAA,MACpD;AAAA,IACF;AACA,WAAO,YAAY,GAAG;AAAA,EACxB;AAEA,QAAM,YAAsC,CAAC;AAC7C,QAAM,qBAAiC,CAAC;AACxC,aAAW,OAAO,SAAS;AACzB,UAAM,MAAM,UAAU,IAAI,GAAG;AAE7B,UAAM,WAAW,IAAI,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC;AAC9C,UAAM,YAAY,SAAS,SAAS,IAAI,WAAW;AACnD,cAAU,IAAI,EAAE,IAAI;AACpB,uBAAmB,KAAK,SAAS;AAAA,EACnC;AAGA,QAAM,SAAmB,CAAC;AAC1B,QAAM,aAAa,CAAC,MAAoB;AACtC,QAAI,CAAC,EAAG;AACR,QAAI,OAAO,KAAK,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE,YAAY,CAAC,EAAG;AAC7D,WAAO,KAAK,CAAC;AAAA,EACf;AACA,QAAM,SAAS,KAAK,IAAI,GAAG,GAAG,mBAAmB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AACrE,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,eAAW,QAAQ,oBAAoB;AACrC,UAAI,IAAI,KAAK,OAAQ,YAAW,KAAK,CAAC,CAAE;AAAA,IAC1C;AAAA,EACF;AAGA,QAAM,WAAW,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC;AAC/C,QAAM,WAAW,WAAW,OAAO,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC,IAAI;AAChE,QAAM,UAAU,YAAY,QAAQ,EAAE,MAAM,GAAG,KAAK,IAAI,GAAG,UAAU,CAAC;AAEtE,SAAO,EAAE,SAAS,SAAS,SAAS,UAAU;AAChD;AAGO,SAAS,eAAe,GAAW,GAAmB;AAC3D,QAAM,KAAK,wBAAwB,CAAC,EAAE,YAAY;AAClD,QAAM,KAAK,wBAAwB,CAAC,EAAE,YAAY;AAClD,MAAI,CAAC,MAAM,CAAC,GAAI,QAAO;AACvB,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,GAAG,SAAS,EAAE,KAAK,GAAG,SAAS,EAAE,EAAG,QAAO;AAC/C,QAAM,KAAK,IAAI,IAAI,GAAG,MAAM,UAAU,EAAE,OAAO,OAAO,CAAC;AACvD,QAAM,KAAK,IAAI,IAAI,GAAG,MAAM,UAAU,EAAE,OAAO,OAAO,CAAC;AACvD,MAAI,GAAG,SAAS,KAAK,GAAG,SAAS,EAAG,QAAO;AAC3C,MAAI,QAAQ;AACZ,aAAW,KAAK,GAAI,KAAI,GAAG,IAAI,CAAC,EAAG;AACnC,SAAO,QAAQ,KAAK,IAAI,GAAG,MAAM,GAAG,IAAI;AAC1C;AAMO,SAAS,gBACd,OACA,KACA,kBAAkB,MACV;AACR,QAAM,SAAS,eAAe,OAAO,IAAI,IAAI;AAC7C,QAAM,QAAQ,kBAAkB,OAAO,eAAe;AACtD,QAAM,QAAQ,OAAO,IAAI,QAAQ,EAAE,EAChC,YAAY,EACZ,QAAQ,YAAY,EAAE;AACzB,MAAI,SAAS;AACb,MAAI,SAAS,OAAO;AAClB,QAAI,UAAU,MAAO,UAAS;AAAA,aACrB,UAAU,GAAG,KAAK,YAAY,MAAM,WAAW,GAAG,KAAK,GAAG,EAAG,UAAS;AAAA,aACtE,MAAM,SAAS,KAAK,KAAK,MAAM,SAAS,KAAK,EAAG,UAAS;AAAA,QAC7D,UAAS,eAAe,MAAM,QAAQ,MAAM,GAAG,GAAG,MAAM,QAAQ,MAAM,GAAG,CAAC;AAAA,EACjF;AACA,SAAO,KAAK,IAAI,QAAQ,MAAM;AAChC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/world-packs.d.ts
CHANGED
|
@@ -5,6 +5,21 @@ export declare function isPacksCommand(cmd: string | undefined): cmd is string;
|
|
|
5
5
|
export declare function packsInboxDir(): string;
|
|
6
6
|
/** 平台聚合包不可经 packs uninstall 卸出(策略集中,CLI 只消费) */
|
|
7
7
|
export declare function isProtectedSfmcPack(pack: Pick<InstalledWorldPack, "folderName">): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* 按 CLI id 列表解析待卸载包(DIP:解析与 TTY/确认/执行分离,便于单测)。
|
|
10
|
+
* - 任一 id 找不到 → not_found
|
|
11
|
+
* - 任一命中受保护包 → protected(与单 id 中止契约一致,LSP)
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveUninstallTargets(packs: InstalledWorldPack[], ids: string[]): {
|
|
14
|
+
status: "ok";
|
|
15
|
+
selected: InstalledWorldPack[];
|
|
16
|
+
} | {
|
|
17
|
+
status: "not_found";
|
|
18
|
+
missing: string[];
|
|
19
|
+
} | {
|
|
20
|
+
status: "protected";
|
|
21
|
+
folder: string;
|
|
22
|
+
};
|
|
8
23
|
/**
|
|
9
24
|
* 扫描收件箱并安装。空收件箱时不打日志(启动钩子友好)。
|
|
10
25
|
*/
|