@sfmc-bds/cli 0.2.0-beta.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +663 -0
- package/README.md +4 -5
- package/dist/bds-runtime-version.d.ts +3 -0
- package/dist/bds-runtime-version.d.ts.map +1 -0
- package/dist/bds-runtime-version.js +15 -0
- package/dist/bds-runtime-version.js.map +7 -0
- package/dist/command-surface.js +3 -3
- package/dist/command-surface.js.map +2 -2
- package/dist/commands.d.ts +57 -4
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +184 -68
- package/dist/commands.js.map +2 -2
- package/dist/directory-picker.d.ts +27 -0
- package/dist/directory-picker.d.ts.map +1 -0
- package/dist/directory-picker.js +112 -0
- package/dist/directory-picker.js.map +7 -0
- package/dist/help-text.d.ts.map +1 -1
- package/dist/help-text.js +1 -5
- package/dist/help-text.js.map +2 -2
- package/dist/i18n/locales/en.d.ts +49 -14
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +49 -15
- 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 +50 -16
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +2 -2
- package/dist/interactive-prompts.d.ts +1 -2
- package/dist/interactive-prompts.d.ts.map +1 -1
- package/dist/interactive-prompts.js +12 -23
- package/dist/interactive-prompts.js.map +3 -3
- package/dist/llbot-launch.d.ts +20 -0
- package/dist/llbot-launch.d.ts.map +1 -0
- package/dist/llbot-launch.js +40 -0
- package/dist/llbot-launch.js.map +7 -0
- package/dist/log-filter.d.ts +18 -2
- package/dist/log-filter.d.ts.map +1 -1
- package/dist/log-filter.js +54 -4
- package/dist/log-filter.js.map +2 -2
- package/dist/log-translator.d.ts +36 -0
- package/dist/log-translator.d.ts.map +1 -0
- package/dist/log-translator.js +279 -0
- package/dist/log-translator.js.map +7 -0
- package/dist/logs.d.ts +2 -0
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +24 -11
- package/dist/logs.js.map +2 -2
- package/dist/main.js +9 -6
- package/dist/main.js.map +2 -2
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +22 -8
- package/dist/module-commands.js.map +2 -2
- package/dist/module-fingerprint.d.ts.map +1 -1
- package/dist/module-fingerprint.js +1 -0
- package/dist/module-fingerprint.js.map +2 -2
- package/dist/module-pack-build.d.ts +14 -4
- package/dist/module-pack-build.d.ts.map +1 -1
- package/dist/module-pack-build.js +81 -108
- package/dist/module-pack-build.js.map +2 -2
- package/dist/module-toggle.d.ts +1 -1
- package/dist/module-toggle.d.ts.map +1 -1
- package/dist/module-toggle.js.map +1 -1
- package/dist/node-service-probe.d.ts +18 -0
- package/dist/node-service-probe.d.ts.map +1 -0
- package/dist/node-service-probe.js +97 -0
- package/dist/node-service-probe.js.map +7 -0
- package/dist/pack-lifecycle.d.ts +15 -1
- package/dist/pack-lifecycle.d.ts.map +1 -1
- package/dist/pack-lifecycle.js +249 -16
- package/dist/pack-lifecycle.js.map +2 -2
- package/dist/player-session.d.ts +13 -0
- package/dist/player-session.d.ts.map +1 -0
- package/dist/player-session.js +26 -0
- package/dist/player-session.js.map +7 -0
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -1
- package/dist/registry.js.map +2 -2
- package/dist/repl-windows/format-display.d.ts.map +1 -1
- package/dist/repl-windows/format-display.js +5 -1
- package/dist/repl-windows/format-display.js.map +2 -2
- package/dist/repl-windows/host.d.ts +6 -3
- package/dist/repl-windows/host.d.ts.map +1 -1
- package/dist/repl-windows/host.js +12 -6
- package/dist/repl-windows/host.js.map +2 -2
- package/dist/repl-windows/index.d.ts +1 -0
- package/dist/repl-windows/index.d.ts.map +1 -1
- package/dist/repl-windows/index.js +3 -0
- package/dist/repl-windows/index.js.map +2 -2
- package/dist/repl-windows/service-window.d.ts +1 -1
- package/dist/repl-windows/service-window.d.ts.map +1 -1
- package/dist/repl-windows/service-window.js +9 -1
- package/dist/repl-windows/service-window.js.map +2 -2
- package/dist/repl-windows/sfmc-window.d.ts +7 -0
- package/dist/repl-windows/sfmc-window.d.ts.map +1 -0
- package/dist/repl-windows/sfmc-window.js +28 -0
- package/dist/repl-windows/sfmc-window.js.map +7 -0
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +37 -22
- package/dist/repl.js.map +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +15 -2
- package/dist/runtime.js.map +2 -2
- package/dist/send-target.d.ts +2 -0
- package/dist/send-target.d.ts.map +1 -1
- package/dist/send-target.js +12 -2
- package/dist/send-target.js.map +2 -2
- package/dist/services.d.ts +58 -5
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +273 -50
- package/dist/services.js.map +2 -2
- package/dist/sfmc-modules-root.d.ts.map +1 -1
- package/dist/sfmc-modules-root.js +6 -2
- package/dist/sfmc-modules-root.js.map +2 -2
- package/dist/ui-command.d.ts +6 -0
- package/dist/ui-command.d.ts.map +1 -0
- package/dist/ui-command.js +68 -0
- package/dist/ui-command.js.map +7 -0
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +95 -32
- package/dist/wizard.js.map +2 -2
- package/dist/world-packs.d.ts +2 -0
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +161 -18
- package/dist/world-packs.js.map +2 -2
- package/package.json +21 -15
- package/scripts/module-install/check-modules.mjs +178 -0
- package/scripts/module-install/fetch-module.mjs +1083 -0
- package/scripts/module-install/lib/catalog.mjs +96 -0
- package/scripts/module-install/lib/config-seeding.mjs +128 -0
- package/scripts/module-install/lib/io.mjs +37 -0
- package/scripts/module-install/lib/link-from.mjs +80 -0
- package/scripts/module-install/lib/lock.mjs +78 -0
- package/scripts/module-install/lib/npm-resolver.mjs +55 -0
- package/scripts/module-install/lib/packages.mjs +136 -0
- package/scripts/module-install/lib/paths.mjs +48 -0
- package/scripts/module-install/lib/registry-index.mjs +50 -0
- package/dist/cmd-remote.d.ts +0 -13
- package/dist/cmd-remote.d.ts.map +0 -1
- package/dist/cmd-remote.js +0 -38
- package/dist/cmd-remote.js.map +0 -7
- package/dist/remote-agent.d.ts +0 -18
- package/dist/remote-agent.d.ts.map +0 -1
- package/dist/remote-agent.js +0 -198
- package/dist/remote-agent.js.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/module-commands.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * sfmc module-commands \u2014 runtime CLI for inspecting and managing modules\n * already on disk under `modules/packages/<id>/`.\n *\n * \u9876\u5C42\u547D\u4EE4\u522B\u540D:`module` / `mod`(\u7531 main.ts / repl.ts \u5171\u540C\u8BC6\u522B)\u3002\n * \u5B50\u547D\u4EE4\u901A\u9053\u95E8\u7981\u89C1 command-surface.ts\uFF08dispatch \u524D\u7531 main/repl \u5224\u5B9A\uFF09\u3002\n */\n\nimport fs from \"node:fs/promises\";\nimport { existsSync, lstatSync, readdirSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport {\n configPath,\n modulePath,\n readJson,\n writeJson,\n type Catalog,\n type DBConfig,\n type ModuleLock,\n} from \"@sfmc-bds/sdk/node/config\";\nimport {\n isDevAccentModuleSub,\n listVisibleModuleSubs,\n type CommandMode,\n} from \"./command-surface.js\";\nimport { failResult, okResult, type CliResult } from \"./cli-result.js\";\nimport { t } from \"./i18n/index.js\";\nimport { c } from \"./theme.js\";\nimport { ROOT, resolveFetchModule } from \"./runtime.js\";\nimport { dirFingerprint } from \"./module-fingerprint.js\";\nimport {\n applyLockEnabled,\n finalizeToggle,\n resolveToggleTarget,\n type ToggleCandidate,\n type ToggleNotify,\n} from \"./module-toggle.js\";\nimport {\n DEFAULT_REGISTRY_REPO,\n DEFAULT_REGISTRY_TAG,\n findUnknownModules,\n resolveRegistryIndex,\n} from \"./registry.js\";\n\n/** \u9876\u5C42\u547D\u4EE4\u540D(\u4E3B\u540D + \u77ED\u522B\u540D),\u4F9B\u5E2E\u52A9 / \u8865\u5168 / \u5206\u53D1\u5171\u7528\u3002 */\nexport const MODULE_CMD_NAMES = [\"module\", \"mod\"] as const;\n\nexport type ModuleCmdName = (typeof MODULE_CMD_NAMES)[number];\n\n/** \u5224\u65AD\u662F\u5426\u4E3A module \u9876\u5C42\u547D\u4EE4(\u542B\u522B\u540D);\u907F\u514D main/repl \u518D\u786C\u7F16\u7801 case\u3002 */\nexport function isModuleCommand(cmd: string | undefined): cmd is ModuleCmdName {\n return !!cmd && (MODULE_CMD_NAMES as readonly string[]).includes(cmd);\n}\n\n/** \u5F00\u53D1\u8005\u6837\u5F0F\u5B50\u547D\u4EE4\uFF08\u84DD\u6807\uFF0C\u975E\u95E8\u7981\uFF09\u3002 */\nexport const DEV_ACCENT_MODULE_SUBCOMMANDS = [\"build\", \"reload\"] as const;\n\n/** \u5F53\u524D\u901A\u9053\u4E0B\u53EF\u89C1\u7684 module \u5B50\u547D\u4EE4\uFF08\u81EA\u52A8\u8865\u5168 / usage\uFF09\u3002 */\nexport function getVisibleModuleSubcommands(mode: CommandMode): readonly string[] {\n return listVisibleModuleSubs(mode);\n}\n\n/** sub \u662F\u5426\u4E3A\u5F00\u53D1\u8005\u84DD\u6807\uFF08help \u7740\u8272\uFF09\u3002 */\nexport function isDeveloperSubcommand(sub: string | undefined): boolean {\n return isDevAccentModuleSub(sub);\n}\n\n/** Usage \u884C\u4E3B\u540D|\u522B\u540D(\u4E0E MODULE_CMD_NAMES \u540C\u6E90,\u907F\u514D\u4E0E\u5E2E\u52A9\u6587\u6848\u6F02\u79FB)\u3002 */\nexport function moduleUsage(mode: CommandMode = \"argv\"): string {\n return t(\"mod.usage\", {\n cmds: MODULE_CMD_NAMES.join(\"|\"),\n subs: getVisibleModuleSubcommands(mode).join(\"|\"),\n });\n}\n\n/** Where modules live on disk. */\nfunction modulesDir(): string {\n return path.join(ROOT, \"modules\", \"packages\");\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n}\n\nfunction shortHash(h: string): string {\n return h.slice(0, 8) + \"\u2026\" + h.slice(-8);\n}\n\ninterface ModuleManifest {\n schemaVersion?: number;\n id?: string;\n handlers?: string[];\n routes?: Array<{ method: string; path: string; handler: string }>;\n migrations?: Array<{ name: string; version: number }>;\n notes?: string;\n}\n\ninterface InstalledModule {\n id: string;\n path: string;\n manifest: ModuleManifest | null;\n totalBytes: number;\n fileCount: number;\n fingerprint: string;\n}\n\n/** Enumerate every installed module by scanning `modules/packages/<id>/`. */\nasync function scanInstalled(): Promise<InstalledModule[]> {\n const dir = modulesDir();\n if (!existsSync(dir)) return [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n const out: InstalledModule[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const id = e.name;\n const modPath = path.join(dir, id);\n const manifestPath = path.join(modPath, \"sapi\", \"manifest.json\");\n let manifest: ModuleManifest | null = null;\n if (existsSync(manifestPath)) {\n try {\n manifest = JSON.parse(await fs.readFile(manifestPath, \"utf8\")) as ModuleManifest;\n } catch {\n /* corrupt manifest is not fatal \u2014 just skip its fields */\n }\n }\n const { totalBytes, fileCount } = await dirSize(modPath);\n const fingerprint = await dirFingerprint(modPath);\n out.push({ id, path: modPath, manifest, totalBytes, fileCount, fingerprint });\n }\n out.sort((a, b) => a.id.localeCompare(b.id));\n return out;\n}\n\nasync function dirSize(dir: string): Promise<{ totalBytes: number; fileCount: number }> {\n let totalBytes = 0;\n let fileCount = 0;\n async function walk(p: string): Promise<void> {\n for (const e of await fs.readdir(p, { withFileTypes: true })) {\n const child = path.join(p, e.name);\n if (e.isDirectory()) await walk(child);\n else if (e.isFile()) {\n const s = await fs.stat(child);\n totalBytes += s.size;\n fileCount++;\n }\n }\n }\n await walk(dir);\n return { totalBytes, fileCount };\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * list\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleList(_args: string[]): Promise<string> {\n const installed = await scanInstalled();\n if (installed.length === 0) {\n return c.dim(t(\"mod.noneInstalled\", { dir: modulesDir() }));\n }\n const lock =\n (readJson<ModuleLock>(modulePath(path.join(ROOT, \"modules\"), \"module-lock.json\")) ?? {\n version: 1,\n modules: {},\n }) as ModuleLock;\n const ids = installed.map((m) => m.id);\n const unknown = new Set(await findUnknownModules(ids));\n const lines: string[] = [c.bold(`\\n${t(\"mod.list.title\")}`), c.dim(` ${modulesDir()}`)];\n const header = ` ${\"id\".padEnd(24)}${\"state\".padEnd(8)}${\"files\".padEnd(8)}${\"size\".padEnd(10)}${\"fingerprint\"}`;\n lines.push(c.dim(header));\n for (const m of installed) {\n const logicalId = typeof m.manifest?.id === \"string\" && m.manifest.id ? m.manifest.id : m.id;\n const enabled = lock.modules?.[logicalId]?.enabled === true;\n const stateCol = (enabled ? c.green(\"on\") : c.dim(\"off\")).padEnd(8);\n let mark: string;\n if (!m.manifest) {\n mark = c.yellow(\"\u25CB\");\n } else if (unknown.has(m.id)) {\n mark = c.yellow(\"?\");\n } else {\n mark = enabled ? c.green(\"\u25CF\") : c.dim(\"\u25CB\");\n }\n const idLabel = logicalId !== m.id ? `${m.id}(${logicalId})` : m.id;\n lines.push(\n ` ${mark} ${idLabel.padEnd(22)}${stateCol}${String(m.fileCount).padEnd(8)}${fmtBytes(m.totalBytes).padEnd(10)}${shortHash(m.fingerprint)}`\n );\n }\n lines.push(c.dim(`\\n tip: ${MODULE_CMD_NAMES[1] ?? \"mod\"} enable|disable <logicalId>`));\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Walk `modules/packages/<id>/` and print a one-line yellow warning for each\n * id that isn't in the first-party registry. Intended for the REPL startup\n * hook so users immediately see modules they installed from somewhere else.\n *\n * Best-effort: registry unreachable \u2192 no warning (no false positives).\n */\nexport async function scanAndWarnUnknown(): Promise<string> {\n const installed = await scanInstalled();\n if (installed.length === 0) return \"\";\n const unknown = await findUnknownModules(installed.map((m) => m.id));\n if (unknown.length === 0) return \"\";\n const list = unknown.map((id) => ` ${c.yellow(\"?\")} ${id}`).join(\"\\n\");\n return `${c.yellow(\"[sfmc] modules installed from unknown publisher \u2014 verify before use:\")}\\n${list}\\n`;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * search \u2014 \u62C9\u53D6 first-party registry;\u5E26 id \u67E5\u5355\u6761 registry info\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/**\n * \u62C9\u53D6 first-party registry \u6A21\u5757\u5217\u8868;\u5E26 id \u65F6\u5C55\u793A\u8BE5\u6761\u76EE\u7684 registry info\u3002\n * \u4E0E\u672C\u5730 `info`(\u5DF2\u5B89\u88C5\u78C1\u76D8\u8BE6\u60C5)\u533A\u5206:`search` \u770B registry,`info` \u770B\u672C\u673A packages\u3002\n */\nexport async function cmdModuleSearch(args: string[]): Promise<string> {\n const query = args[0];\n const { index, stale } = await resolveRegistryIndex({ force: true });\n const ids = Object.keys(index).sort((a, b) => a.localeCompare(b));\n\n if (ids.length === 0) {\n return c.red(\n `\\nRegistry empty or unreachable (${DEFAULT_REGISTRY_REPO}@${DEFAULT_REGISTRY_TAG}).\\n` +\n `Check network, or: mod install <id> --from github:owner/repo@tag\\n`\n );\n }\n\n const staleNote = stale ? c.yellow(\" (offline \u2014 showing cached index)\\n\") : \"\";\n\n /* \u65E0\u53C2\u6570:\u5217\u51FA\u5168\u90E8 */\n if (!query) {\n const installed = new Set(listInstalledModuleIdsSync());\n const lines: string[] = [\n c.bold(`\\nFirst-party registry (${DEFAULT_REGISTRY_REPO}@${DEFAULT_REGISTRY_TAG}) \u2014 ${ids.length} modules`),\n ];\n if (staleNote) lines.push(staleNote.trimEnd());\n lines.push(c.dim(` ${\"id\".padEnd(28)}${\"source\".padEnd(40)}local`));\n for (const id of ids) {\n const e = index[id]!;\n const src = `${e.repo}@${e.tag}`;\n const local = installed.has(id) ? c.green(\"\u25CF\") : c.dim(\"\u25CB\");\n lines.push(` ${local} ${id.padEnd(26)}${src.padEnd(40)}${installed.has(id) ? \"installed\" : \"\"}`);\n }\n lines.push(c.dim(`\\n tip: sfmc mod search <id> \u2192 registry info`));\n lines.push(c.dim(` sfmc mod install <id> \u2192 download + catalog sync`));\n return lines.join(\"\\n\") + \"\\n\";\n }\n\n /* \u5E26 id:\u67E5\u5355\u6761 registry info */\n const entry = index[query];\n if (!entry) {\n const hints = ids.filter((id) => id.includes(query) || query.includes(id)).slice(0, 8);\n const hintBlock =\n hints.length > 0\n ? c.dim(`\\n Did you mean:\\n`) + hints.map((h) => ` ${h}`).join(\"\\n\")\n : c.dim(`\\n Known ids: ${ids.slice(0, 12).join(\", \")}${ids.length > 12 ? \", \u2026\" : \"\"}`);\n return c.red(t(\"mod.notInRegistry\", { query })) + hintBlock + \"\\n\";\n }\n\n const installedPath = path.join(modulesDir(), query);\n const isInstalled = existsSync(installedPath);\n const lines: string[] = [c.bold(`\\n${query}`)];\n if (staleNote) lines.push(staleNote.trimEnd());\n lines.push(` registry : ${DEFAULT_REGISTRY_REPO}@${DEFAULT_REGISTRY_TAG}`);\n lines.push(` repo : ${entry.repo}`);\n lines.push(` tag : ${entry.tag}`);\n lines.push(` source : github:${entry.repo}@${entry.tag}`);\n lines.push(` github : https://github.com/${entry.repo}/tree/${entry.tag}`);\n lines.push(\n ` local : ${isInstalled ? c.green(`installed @ ${installedPath}`) : c.dim(\"not installed\")}`\n );\n\n if (!isInstalled) {\n lines.push(c.dim(`\\n install: sfmc mod install ${query}`));\n } else {\n lines.push(c.dim(`\\n details: sfmc mod info ${query}`));\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * info\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleInfo(args: string[]): Promise<string> {\n const id = args[0];\n if (!id) return c.yellow(t(\"mod.info.usage\"));\n const all = await scanInstalled();\n const m = all.find((x) => x.id === id);\n if (!m) return c.red(t(\"mod.notInstalledAt\", { id, path: path.join(modulesDir(), id) }));\n const lines: string[] = [c.bold(`\\n${id}`)];\n lines.push(` path : ${m.path}`);\n lines.push(` files : ${m.fileCount}`);\n lines.push(` size : ${fmtBytes(m.totalBytes)}`);\n lines.push(` fingerprint : ${m.fingerprint}`);\n if (m.manifest) {\n lines.push(` schemaVer : ${m.manifest.schemaVersion ?? \"(none)\"}`);\n lines.push(` routes : ${m.manifest.routes?.length ?? 0}`);\n if (m.manifest.routes?.length) {\n for (const r of m.manifest.routes) lines.push(c.dim(` ${r.method.padEnd(7)} ${r.path.padEnd(36)} ${r.handler}`));\n }\n lines.push(` migrations : ${m.manifest.migrations?.length ?? 0}`);\n if (m.manifest.migrations?.length) {\n for (const mg of m.manifest.migrations) lines.push(c.dim(` v${mg.version} ${mg.name}`));\n }\n if (m.manifest.notes) lines.push(` notes : ${c.dim(m.manifest.notes)}`);\n } else {\n lines.push(c.yellow(` manifest : (missing or unreadable)`));\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * verify\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleVerify(args: string[]): Promise<string> {\n const id = args[0];\n if (id) {\n const all = await scanInstalled();\n const m = all.find((x) => x.id === id);\n if (!m) return c.red(t(\"mod.notInstalled\", { id }));\n return c.green(t(\"mod.verifyOk\", { id, fp: m.fingerprint }));\n }\n const all = await scanInstalled();\n const lines = [c.bold(\"\\nVerifying installed modules\")];\n for (const m of all) {\n lines.push(` ${m.id.padEnd(28)} ${shortHash(m.fingerprint)}`);\n }\n if (all.length === 0) lines.push(c.dim(\" (none)\"));\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * install \u2014 shells out to tools/fetch-module.mjs\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * enable / disable \u2014 \u672C\u5730\u5199 module-lock.json\uFF1Bdb \u5728\u7EBF\u65F6 best-effort \u70ED\u540C\u6B65\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nfunction readDbConfig(): DBConfig {\n return (readJson<DBConfig>(configPath(ROOT, \"db_config.json\")) ?? {}) as DBConfig;\n}\n\nfunction moduleLockPath(): string {\n return modulePath(path.join(ROOT, \"modules\"), \"module-lock.json\");\n}\n\nfunction catalogPathOnDisk(): string {\n return modulePath(path.join(ROOT, \"modules\"), \"catalog.json\");\n}\n\n/** \u5DF2\u88C5\u5305 + catalog \u6295\u5F71 \u2192 \u542F\u505C\u5019\u9009\uFF08canDisable \u4E0E db \u540C\u6E90\uFF1A\u7701\u7565\u89C6\u4E3A\u53EF\u7981\u7528\uFF09\u3002 */\nfunction buildToggleCandidates(installed: InstalledModule[]): ToggleCandidate[] {\n const catalog = (readJson<Catalog>(catalogPathOnDisk()) ?? {}) as Catalog;\n const rows = Array.isArray(catalog.modules) ? catalog.modules : [];\n const byLogical = new Map<string, Record<string, unknown>>();\n for (const raw of rows) {\n if (!raw || typeof raw !== \"object\") continue;\n const id = String((raw as Record<string, unknown>).id || \"\").trim();\n if (id) byLogical.set(id, raw as Record<string, unknown>);\n }\n return installed.map((m) => {\n const logicalId = typeof m.manifest?.id === \"string\" && m.manifest.id ? m.manifest.id : m.id;\n const raw = byLogical.get(logicalId);\n const configKeyRaw = raw ? String(raw.configKey || raw.config_key || \"\").trim() : \"\";\n const canDisable = raw ? raw.canDisable !== false : true;\n const out: ToggleCandidate = { logicalId, folderId: m.id, canDisable };\n if (configKeyRaw) out.configKey = configKeyRaw;\n return out;\n });\n}\n\nfunction writeLocalModuleEnabled(logicalId: string, enabled: boolean): void {\n const lockPath = moduleLockPath();\n const lock =\n (readJson<ModuleLock>(lockPath) ?? {\n version: 1,\n modules: {},\n }) as ModuleLock;\n applyLockEnabled(lock, logicalId, enabled);\n writeJson(lockPath, lock);\n}\n\nasync function notifyDbToggle(logicalId: string, action: \"enable\" | \"disable\"): Promise<ToggleNotify> {\n const cfg = readDbConfig();\n const port = cfg.db_port ?? 3001;\n const token = cfg.http_auth || \"\";\n const url = `http://127.0.0.1:${port}/api/sfmc/modules/${encodeURIComponent(logicalId)}/${action}`;\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n });\n } catch (err) {\n return { ok: false, reason: \"unreachable\", detail: (err as Error).message };\n }\n const text = await res.text();\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n body = text;\n }\n if (!res.ok) {\n const err = (body as { error?: string })?.error ?? `HTTP ${res.status}`;\n return { ok: false, reason: \"http\", detail: err };\n }\n if ((body as { success?: boolean })?.success === false) {\n return { ok: false, reason: \"http\", detail: text };\n }\n return { ok: true };\n}\n\nasync function cmdModuleToggle(query: string, action: \"enable\" | \"disable\"): Promise<CliResult> {\n const installed = await scanInstalled();\n const target = resolveToggleTarget(query, buildToggleCandidates(installed));\n if (!target) {\n return failResult(c.red(t(\"mod.notInstalled\", { id: query })));\n }\n if (action === \"disable\" && !target.canDisable) {\n return failResult(c.red(t(\"mod.cannotDisable\", { id: target.logicalId })));\n }\n\n const enabled = action === \"enable\";\n try {\n writeLocalModuleEnabled(target.logicalId, enabled);\n } catch (err) {\n return failResult(\n c.red(t(\"mod.toggleLockFailed\", { id: target.logicalId, message: (err as Error).message }))\n );\n }\n\n const notify = await notifyDbToggle(target.logicalId, action);\n const fin = finalizeToggle(true, notify);\n const label = action === \"enable\" ? t(\"mod.action.enabled\") : t(\"mod.action.disabled\");\n const head = c.green(t(\"mod.toggleOk\", { label, id: target.logicalId }));\n if (!fin.warnNotify) {\n return okResult(head);\n }\n const detail = notify.ok === false ? (notify.detail ?? notify.reason) : \"\";\n const warn = c.yellow(t(\"mod.toggleDbSkipped\", { detail }));\n return okResult(`${head}\\n${warn}`);\n}\n\nexport async function cmdModuleEnable(args: string[]): Promise<CliResult> {\n const id = args[0];\n if (!id) return failResult(c.yellow(t(\"mod.enable.usage\")));\n return cmdModuleToggle(id, \"enable\");\n}\n\nexport async function cmdModuleDisable(args: string[]): Promise<CliResult> {\n const id = args[0];\n if (!id) return failResult(c.yellow(t(\"mod.disable.usage\")));\n return cmdModuleToggle(id, \"disable\");\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * install \u2014 shells out to tools/fetch-module.mjs\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * \u9884\u68C0 --from \u53D6\u503C\u662F\u5426\u662F\u5408\u6CD5 scheme\uFF1A\n * - npm:@scope/name / npm:<name>\n * - local[:<path>] / local\n * - tgz:<path>\n * - zip:<path>\n * - dir:<abs path>\n * - github:<owner>/<repo>[@tag]\n * - \u88F8\u8DEF\u5F84\uFF1A\u5FC5\u987B\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55\uFF08\u88F8\u6587\u4EF6\u5E94\u8F6C tgz:/zip:\uFF09\n * \u8FD4\u56DE null \u8868\u793A\u5408\u6CD5\uFF1B\u5426\u5219\u8FD4\u56DE\u7528\u6237\u53EF\u8BFB\u7684\u9519\u8BEF\u6587\u6848\u3002\n */\nfunction validateFromScheme(from: string): string | null {\n if (\n from === \"local\" ||\n from.startsWith(\"local:\") ||\n from.startsWith(\"dir:\") ||\n from.startsWith(\"npm:\") ||\n from.startsWith(\"tgz:\") ||\n from.startsWith(\"zip:\") ||\n from.startsWith(\"github:\")\n ) {\n return null;\n }\n if (existsSync(from)) {\n const st = lstatSync(from);\n if (st.isDirectory()) return null;\n return `--from \u88F8\u8DEF\u5F84\u987B\u4E3A\u76EE\u5F55\uFF08\u6587\u4EF6\u8BF7\u7528 --from local:<tgz|zip>\uFF09: ${from}`;\n }\n return t(\"mod.fromUnknown\", { value: from });\n}\n\nexport async function cmdModuleInstall(args: string[]): Promise<string> {\n // \u652F\u6301: install <id> [id2 ...] [--from ...] [--link] [--sha256 ...]\n const flags = parseFlags(args);\n const positional: string[] = [];\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--from\" || args[i] === \"--sha256\") {\n i++;\n continue;\n }\n if (args[i]?.startsWith(\"--from=\") || args[i]?.startsWith(\"--sha256=\")) continue;\n if (args[i]?.startsWith(\"--\")) continue;\n positional.push(args[i]!);\n }\n if (positional.length === 0) {\n return c.yellow(t(\"mod.install.usage\"));\n }\n\n /* scheme \u9884\u68C0\uFF1A\u907F\u514D\u62FC\u5199\u9519\u8BEF\u5EF6\u8FDF\u5230\u5B50\u8FDB\u7A0B\u62A5\u9519 */\n if (flags.from) {\n const err = validateFromScheme(flags.from);\n if (err) return c.red(err);\n }\n\n const fetchScript = resolveFetchModule();\n if (!fetchScript) {\n return c.red(t(\"mod.fetchMissing\"));\n }\n const sub = [\"install\", ...positional];\n if (flags.from) sub.push(\"--from\", flags.from);\n if (flags.sha256) sub.push(\"--sha256\", flags.sha256);\n if (flags.link) sub.push(\"--link\");\n return new Promise<string>((resolve) => {\n const proc = spawn(process.execPath, [fetchScript, ...sub], {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, SFMC_ROOT: ROOT },\n });\n let out = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.on(\"exit\", (code) => {\n resolve(out + (code === 0 ? \"\" : `\\n[exit ${code}]`));\n });\n proc.on(\"error\", (e) => resolve(c.red(`spawn failed: ${e.message}`)));\n });\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * uninstall\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleUninstall(args: string[]): Promise<string> {\n const id = args[0];\n if (!id) return c.yellow(t(\"mod.uninstall.usage\"));\n const fetchScript = resolveFetchModule();\n if (!fetchScript) {\n // \u56DE\u9000:\u4EC5\u5220\u76EE\u5F55(\u65E7\u884C\u4E3A)\n const target = path.join(modulesDir(), id);\n if (!existsSync(target)) return c.yellow(t(\"mod.notInstalledFolder\", { id, path: target }));\n await fs.rm(target, { recursive: true, force: true });\n return c.green(t(\"mod.removed\", { id, path: target }));\n }\n return new Promise<string>((resolve) => {\n const proc = spawn(process.execPath, [fetchScript, \"uninstall\", id], {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, SFMC_ROOT: ROOT },\n });\n let out = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.on(\"exit\", (code) => {\n resolve(out + (code === 0 ? \"\" : `\\n[exit ${code}]`));\n });\n proc.on(\"error\", (e) => resolve(c.red(`spawn failed: ${e.message}`)));\n });\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * CLI flag parsing\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\ninterface InstallFlags {\n from: string | null;\n sha256: string | null;\n link: boolean;\n}\n\nfunction parseFlags(args: string[]): InstallFlags {\n const flags: InstallFlags = { from: null, sha256: null, link: false };\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--from\") flags.from = args[++i] ?? null;\n else if (args[i]?.startsWith(\"--from=\")) flags.from = args[i]!.slice(\"--from=\".length);\n else if (args[i] === \"--sha256\") flags.sha256 = args[++i] ?? null;\n else if (args[i]?.startsWith(\"--sha256=\")) flags.sha256 = args[i]!.slice(\"--sha256=\".length);\n else if (args[i] === \"--link\") flags.link = true;\n }\n return flags;\n}\n\n/**\n * \u7EDF\u4E00\u5206\u53D1 module/mod \u5B50\u547D\u4EE4 \u2014\u2014 CLI(`main.ts`)\u4E0E REPL(`repl.ts`)\u5171\u7528,\n * \u907F\u514D\u4E24\u5904 switch \u6F02\u79FB\u3002\n *\n * \u901A\u9053\u95E8\u7981\uFF08argv/repl\uFF09\u7531\u8C03\u7528\u65B9\u5728 dispatch \u524D\u7ECF command-surface \u5224\u5B9A\uFF1B\n * \u672C\u51FD\u6570\u53EA\u8D1F\u8D23\u5B50\u547D\u4EE4\u8DEF\u7531\u3002`remove` \u4F5C\u4E3A uninstall \u7684\u540C\u4E49\u522B\u540D\u4FDD\u7559\u3002\n *\n * \u4F5C\u8005\u5411 test/watch/publish \u5DF2\u8FC1\u81F3 VS Code \u6269\u5C55\u4E0E @sfmc-bds/devkit\u3002\n */\nexport async function dispatchModuleCommand(sub: string | undefined, args: string[]): Promise<string> {\n switch (sub) {\n case \"list\":\n return cmdModuleList(args);\n case \"search\":\n return cmdModuleSearch(args);\n case \"install\":\n return cmdModuleInstall(args);\n case \"uninstall\":\n case \"remove\":\n return cmdModuleUninstall(args);\n case \"verify\":\n return cmdModuleVerify(args);\n case \"info\":\n return cmdModuleInfo(args);\n case \"enable\":\n return (await cmdModuleEnable(args)).message;\n case \"disable\":\n return (await cmdModuleDisable(args)).message;\n case \"build\": {\n const { cmdModuleBuild } = await import(\"./module-pack-build.js\");\n return cmdModuleBuild(args);\n }\n case \"reload\": {\n const { cmdModuleReload } = await import(\"./module-pack-build.js\");\n return cmdModuleReload(args);\n }\n case \"test\":\n case \"watch\":\n case \"publish\":\n return c.yellow(\n `[mod ${sub}] \u5DF2\u79FB\u81F3 VS Code/Cursor \u6269\u5C55\u300CSFMC Module\u300D\u4E0E @sfmc-bds/devkit\uFF1B\u8FD0\u7EF4\u8BF7\u7528 mod build|reload|install\u3002`\n );\n default:\n return c.yellow(moduleUsage());\n }\n}\n\n/** \u540C\u6B65\u679A\u4E3E\u5DF2\u5B89\u88C5\u6A21\u5757 id,\u4F9B REPL Tab \u8865\u5168(\u4E0D\u8BFB fingerprint,\u5C3D\u91CF\u8F7B\u91CF)\u3002 */\nexport function listInstalledModuleIdsSync(): string[] {\n const dir = modulesDir();\n if (!existsSync(dir)) return [];\n try {\n return readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort((a, b) => a.localeCompare(b));\n } catch {\n return [];\n }\n}"],
|
|
5
|
-
"mappings": "AAQA,OAAO,QAAQ;AACf,SAAS,YAAY,WAAW,mBAAmB;AACnD,OAAO,UAAU;AACjB,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,YAAY,gBAAgC;AACrD,SAAS,SAAS;AAClB,SAAS,SAAS;AAClB,SAAS,MAAM,0BAA0B;AACzC,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGA,MAAM,mBAAmB,CAAC,UAAU,KAAK;AAKzC,SAAS,gBAAgB,KAA+C;AAC7E,SAAO,CAAC,CAAC,OAAQ,iBAAuC,SAAS,GAAG;AACtE;AAGO,MAAM,gCAAgC,CAAC,SAAS,QAAQ;AAGxD,SAAS,4BAA4B,MAAsC;AAChF,SAAO,sBAAsB,IAAI;AACnC;AAGO,SAAS,sBAAsB,KAAkC;AACtE,SAAO,qBAAqB,GAAG;AACjC;AAGO,SAAS,YAAY,OAAoB,QAAgB;AAC9D,SAAO,EAAE,aAAa;AAAA,IACpB,MAAM,iBAAiB,KAAK,GAAG;AAAA,IAC/B,MAAM,4BAA4B,IAAI,EAAE,KAAK,GAAG;AAAA,EAClD,CAAC;AACH;AAGA,SAAS,aAAqB;AAC5B,SAAO,KAAK,KAAK,MAAM,WAAW,UAAU;AAC9C;AAEA,SAAS,SAAS,GAAmB;AACnC,MAAI,IAAI,KAAM,QAAO,GAAG,CAAC;AACzB,MAAI,IAAI,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,QAAQ,CAAC,CAAC;AACpD,SAAO,IAAI,IAAI,OAAO,MAAM,QAAQ,CAAC,CAAC;AACxC;AAEA,SAAS,UAAU,GAAmB;AACpC,SAAO,EAAE,MAAM,GAAG,CAAC,IAAI,WAAM,EAAE,MAAM,EAAE;AACzC;AAqBA,eAAe,gBAA4C;AACzD,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,WAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,QAAM,UAAU,MAAM,GAAG,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAC7D,QAAM,MAAyB,CAAC;AAChC,aAAW,KAAK,SAAS;AACvB,QAAI,CAAC,EAAE,YAAY,EAAG;AACtB,UAAM,KAAK,EAAE;AACb,UAAM,UAAU,KAAK,KAAK,KAAK,EAAE;AACjC,UAAM,eAAe,KAAK,KAAK,SAAS,QAAQ,eAAe;AAC/D,QAAI,WAAkC;AACtC,QAAI,WAAW,YAAY,GAAG;AAC5B,UAAI;AACF,mBAAW,KAAK,MAAM,MAAM,GAAG,SAAS,cAAc,MAAM,CAAC;AAAA,MAC/D,QAAQ;AAAA,MAER;AAAA,IACF;AACA,UAAM,EAAE,YAAY,UAAU,IAAI,MAAM,QAAQ,OAAO;AACvD,UAAM,cAAc,MAAM,eAAe,OAAO;AAChD,QAAI,KAAK,EAAE,IAAI,MAAM,SAAS,UAAU,YAAY,WAAW,YAAY,CAAC;AAAA,EAC9E;AACA,MAAI,KAAK,CAAC,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC;AAC3C,SAAO;AACT;AAEA,eAAe,QAAQ,KAAiE;AACtF,MAAI,aAAa;AACjB,MAAI,YAAY;AAChB,iBAAe,KAAK,GAA0B;AAC5C,eAAW,KAAK,MAAM,GAAG,QAAQ,GAAG,EAAE,eAAe,KAAK,CAAC,GAAG;AAC5D,YAAM,QAAQ,KAAK,KAAK,GAAG,EAAE,IAAI;AACjC,UAAI,EAAE,YAAY,EAAG,OAAM,KAAK,KAAK;AAAA,eAC5B,EAAE,OAAO,GAAG;AACnB,cAAM,IAAI,MAAM,GAAG,KAAK,KAAK;AAC7B,sBAAc,EAAE;AAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,GAAG;AACd,SAAO,EAAE,YAAY,UAAU;AACjC;AAKA,eAAsB,cAAc,OAAkC;AACpE,QAAM,YAAY,MAAM,cAAc;AACtC,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,WAAW,EAAE,CAAC,CAAC;AAAA,EAC5D;AACA,QAAM,OACH,SAAqB,WAAW,KAAK,KAAK,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK;AAAA,IACnF,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AACF,QAAM,MAAM,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE;AACrC,QAAM,UAAU,IAAI,IAAI,MAAM,mBAAmB,GAAG,CAAC;AACrD,QAAM,QAAkB,CAAC,EAAE,KAAK;AAAA,EAAK,EAAE,gBAAgB,CAAC,EAAE,GAAG,EAAE,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;AACvF,QAAM,SAAS,OAAO,KAAK,OAAO,EAAE,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,GAAG,OAAO,OAAO,EAAE,CAAC,GAAG,aAAa;AACjH,QAAM,KAAK,EAAE,IAAI,MAAM,CAAC;AACxB,aAAW,KAAK,WAAW;AACzB,UAAM,YAAY,OAAO,EAAE,UAAU,OAAO,YAAY,EAAE,SAAS,KAAK,EAAE,SAAS,KAAK,EAAE;AAC1F,UAAM,UAAU,KAAK,UAAU,SAAS,GAAG,YAAY;AACvD,UAAM,YAAY,UAAU,EAAE,MAAM,IAAI,IAAI,EAAE,IAAI,KAAK,GAAG,OAAO,CAAC;AAClE,QAAI;AACJ,QAAI,CAAC,EAAE,UAAU;AACf,aAAO,EAAE,OAAO,QAAG;AAAA,IACrB,WAAW,QAAQ,IAAI,EAAE,EAAE,GAAG;AAC5B,aAAO,EAAE,OAAO,GAAG;AAAA,IACrB,OAAO;AACL,aAAO,UAAU,EAAE,MAAM,QAAG,IAAI,EAAE,IAAI,QAAG;AAAA,IAC3C;AACA,UAAM,UAAU,cAAc,EAAE,KAAK,GAAG,EAAE,EAAE,IAAI,SAAS,MAAM,EAAE;AACjE,UAAM;AAAA,MACJ,KAAK,IAAI,IAAI,QAAQ,OAAO,EAAE,CAAC,GAAG,QAAQ,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,UAAU,EAAE,WAAW,CAAC;AAAA,IAC3I;AAAA,EACF;AACA,QAAM,KAAK,EAAE,IAAI;AAAA,SAAY,iBAAiB,CAAC,KAAK,KAAK,6BAA6B,CAAC;AACvF,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AASA,eAAsB,qBAAsC;AAC1D,QAAM,YAAY,MAAM,cAAc;AACtC,MAAI,UAAU,WAAW,EAAG,QAAO;AACnC,QAAM,UAAU,MAAM,mBAAmB,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACnE,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QAAM,OAAO,QAAQ,IAAI,CAAC,OAAO,KAAK,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,IAAI;AACtE,SAAO,GAAG,EAAE,OAAO,2EAAsE,CAAC;AAAA,EAAK,IAAI;AAAA;AACrG;AASA,eAAsB,gBAAgB,MAAiC;AACrE,QAAM,QAAQ,KAAK,CAAC;AACpB,QAAM,EAAE,OAAO,MAAM,IAAI,MAAM,qBAAqB,EAAE,OAAO,KAAK,CAAC;AACnE,QAAM,MAAM,OAAO,KAAK,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AAEhE,MAAI,IAAI,WAAW,GAAG;AACpB,WAAO,EAAE;AAAA,MACP;AAAA,iCAAoC,qBAAqB,IAAI,oBAAoB;AAAA;AAAA;AAAA,IAEnF;AAAA,EACF;AAEA,QAAM,YAAY,QAAQ,EAAE,OAAO,2CAAsC,IAAI;AAG7E,MAAI,CAAC,OAAO;AACV,UAAM,YAAY,IAAI,IAAI,2BAA2B,CAAC;AACtD,UAAMA,SAAkB;AAAA,MACtB,EAAE,KAAK;AAAA,wBAA2B,qBAAqB,IAAI,oBAAoB,YAAO,IAAI,MAAM,UAAU;AAAA,IAC5G;AACA,QAAI,UAAW,CAAAA,OAAM,KAAK,UAAU,QAAQ,CAAC;AAC7C,IAAAA,OAAM,KAAK,EAAE,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC,GAAG,SAAS,OAAO,EAAE,CAAC,OAAO,CAAC;AACrE,eAAW,MAAM,KAAK;AACpB,YAAM,IAAI,MAAM,EAAE;AAClB,YAAM,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,GAAG;AAC9B,YAAM,QAAQ,UAAU,IAAI,EAAE,IAAI,EAAE,MAAM,QAAG,IAAI,EAAE,IAAI,QAAG;AAC1D,MAAAA,OAAM,KAAK,KAAK,KAAK,IAAI,GAAG,OAAO,EAAE,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,GAAG,UAAU,IAAI,EAAE,IAAI,cAAc,EAAE,EAAE;AAAA,IAClG;AACA,IAAAA,OAAM,KAAK,EAAE,IAAI;AAAA,kDAAgD,CAAC;AAClE,IAAAA,OAAM,KAAK,EAAE,IAAI,6DAAwD,CAAC;AAC1E,WAAOA,OAAM,KAAK,IAAI,IAAI;AAAA,EAC5B;AAGA,QAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,CAAC,OAAO;AACV,UAAM,QAAQ,IAAI,OAAO,CAAC,OAAO,GAAG,SAAS,KAAK,KAAK,MAAM,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC;AACrF,UAAM,YACJ,MAAM,SAAS,IACX,EAAE,IAAI;AAAA;AAAA,CAAqB,IAAI,MAAM,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,IACrE,EAAE,IAAI;AAAA,eAAkB,IAAI,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,GAAG,IAAI,SAAS,KAAK,aAAQ,EAAE,EAAE;AAC1F,WAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,CAAC,CAAC,IAAI,YAAY;AAAA,EAChE;AAEA,QAAM,gBAAgB,KAAK,KAAK,WAAW,GAAG,KAAK;AACnD,QAAM,cAAc,WAAW,aAAa;AAC5C,QAAM,QAAkB,CAAC,EAAE,KAAK;AAAA,EAAK,KAAK,EAAE,CAAC;AAC7C,MAAI,UAAW,OAAM,KAAK,UAAU,QAAQ,CAAC;AAC7C,QAAM,KAAK,kBAAkB,qBAAqB,IAAI,oBAAoB,EAAE;AAC5E,QAAM,KAAK,kBAAkB,MAAM,IAAI,EAAE;AACzC,QAAM,KAAK,kBAAkB,MAAM,GAAG,EAAE;AACxC,QAAM,KAAK,yBAAyB,MAAM,IAAI,IAAI,MAAM,GAAG,EAAE;AAC7D,QAAM,KAAK,qCAAqC,MAAM,IAAI,SAAS,MAAM,GAAG,EAAE;AAC9E,QAAM;AAAA,IACJ,kBAAkB,cAAc,EAAE,MAAM,eAAe,aAAa,EAAE,IAAI,EAAE,IAAI,eAAe,CAAC;AAAA,EAClG;AAEA,MAAI,CAAC,aAAa;AAChB,UAAM,KAAK,EAAE,IAAI;AAAA,8BAAiC,KAAK,EAAE,CAAC;AAAA,EAC5D,OAAO;AACL,UAAM,KAAK,EAAE,IAAI;AAAA,2BAA8B,KAAK,EAAE,CAAC;AAAA,EACzD;AACA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAKA,eAAsB,cAAc,MAAiC;AACnE,QAAM,KAAK,KAAK,CAAC;AACjB,MAAI,CAAC,GAAI,QAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC;AAC5C,QAAM,MAAM,MAAM,cAAc;AAChC,QAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACrC,MAAI,CAAC,EAAG,QAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,MAAM,KAAK,KAAK,WAAW,GAAG,EAAE,EAAE,CAAC,CAAC;AACvF,QAAM,QAAkB,CAAC,EAAE,KAAK;AAAA,EAAK,EAAE,EAAE,CAAC;AAC1C,QAAM,KAAK,mBAAmB,EAAE,IAAI,EAAE;AACtC,QAAM,KAAK,mBAAmB,EAAE,SAAS,EAAE;AAC3C,QAAM,KAAK,mBAAmB,SAAS,EAAE,UAAU,CAAC,EAAE;AACtD,QAAM,KAAK,mBAAmB,EAAE,WAAW,EAAE;AAC7C,MAAI,EAAE,UAAU;AACd,UAAM,KAAK,mBAAmB,EAAE,SAAS,iBAAiB,QAAQ,EAAE;AACpE,UAAM,KAAK,mBAAmB,EAAE,SAAS,QAAQ,UAAU,CAAC,EAAE;AAC9D,QAAI,EAAE,SAAS,QAAQ,QAAQ;AAC7B,iBAAW,KAAK,EAAE,SAAS,OAAQ,OAAM,KAAK,EAAE,IAAI,OAAO,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;AAAA,IACpH;AACA,UAAM,KAAK,mBAAmB,EAAE,SAAS,YAAY,UAAU,CAAC,EAAE;AAClE,QAAI,EAAE,SAAS,YAAY,QAAQ;AACjC,iBAAW,MAAM,EAAE,SAAS,WAAY,OAAM,KAAK,EAAE,IAAI,QAAQ,GAAG,OAAO,IAAI,GAAG,IAAI,EAAE,CAAC;AAAA,IAC3F;AACA,QAAI,EAAE,SAAS,MAAO,OAAM,KAAK,mBAAmB,EAAE,IAAI,EAAE,SAAS,KAAK,CAAC,EAAE;AAAA,EAC/E,OAAO;AACL,UAAM,KAAK,EAAE,OAAO,yCAAyC,CAAC;AAAA,EAChE;AACA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAKA,eAAsB,gBAAgB,MAAiC;AACrE,QAAM,KAAK,KAAK,CAAC;AACjB,MAAI,IAAI;AACN,UAAMC,OAAM,MAAM,cAAc;AAChC,UAAM,IAAIA,KAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACrC,QAAI,CAAC,EAAG,QAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;AAClD,WAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,IAAI,EAAE,YAAY,CAAC,CAAC;AAAA,EAC7D;AACA,QAAM,MAAM,MAAM,cAAc;AAChC,QAAM,QAAQ,CAAC,EAAE,KAAK,+BAA+B,CAAC;AACtD,aAAW,KAAK,KAAK;AACnB,UAAM,KAAK,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,UAAU,EAAE,WAAW,CAAC,EAAE;AAAA,EAC/D;AACA,MAAI,IAAI,WAAW,EAAG,OAAM,KAAK,EAAE,IAAI,UAAU,CAAC;AAClD,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAQA,SAAS,eAAyB;AAChC,SAAQ,SAAmB,WAAW,MAAM,gBAAgB,CAAC,KAAK,CAAC;AACrE;AAEA,SAAS,iBAAyB;AAChC,SAAO,WAAW,KAAK,KAAK,MAAM,SAAS,GAAG,kBAAkB;AAClE;AAEA,SAAS,oBAA4B;AACnC,SAAO,WAAW,KAAK,KAAK,MAAM,SAAS,GAAG,cAAc;AAC9D;AAGA,SAAS,sBAAsB,WAAiD;AAC9E,QAAM,UAAW,SAAkB,kBAAkB,CAAC,KAAK,CAAC;AAC5D,QAAM,OAAO,MAAM,QAAQ,QAAQ,OAAO,IAAI,QAAQ,UAAU,CAAC;AACjE,QAAM,YAAY,oBAAI,IAAqC;AAC3D,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,UAAM,KAAK,OAAQ,IAAgC,MAAM,EAAE,EAAE,KAAK;AAClE,QAAI,GAAI,WAAU,IAAI,IAAI,GAA8B;AAAA,EAC1D;AACA,SAAO,UAAU,IAAI,CAAC,MAAM;AAC1B,UAAM,YAAY,OAAO,EAAE,UAAU,OAAO,YAAY,EAAE,SAAS,KAAK,EAAE,SAAS,KAAK,EAAE;AAC1F,UAAM,MAAM,UAAU,IAAI,SAAS;AACnC,UAAM,eAAe,MAAM,OAAO,IAAI,aAAa,IAAI,cAAc,EAAE,EAAE,KAAK,IAAI;AAClF,UAAM,aAAa,MAAM,IAAI,eAAe,QAAQ;AACpD,UAAM,MAAuB,EAAE,WAAW,UAAU,EAAE,IAAI,WAAW;AACrE,QAAI,aAAc,KAAI,YAAY;AAClC,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,wBAAwB,WAAmB,SAAwB;AAC1E,QAAM,WAAW,eAAe;AAChC,QAAM,OACH,SAAqB,QAAQ,KAAK;AAAA,IACjC,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AACF,mBAAiB,MAAM,WAAW,OAAO;AACzC,YAAU,UAAU,IAAI;AAC1B;AAEA,eAAe,eAAe,WAAmB,QAAqD;AACpG,QAAM,MAAM,aAAa;AACzB,QAAM,OAAO,IAAI,WAAW;AAC5B,QAAM,QAAQ,IAAI,aAAa;AAC/B,QAAM,MAAM,oBAAoB,IAAI,qBAAqB,mBAAmB,SAAS,CAAC,IAAI,MAAM;AAChG,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAI,QAAQ,EAAE,eAAe,UAAU,KAAK,GAAG,IAAI,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,QAAQ,eAAe,QAAS,IAAc,QAAQ;AAAA,EAC5E;AACA,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,MAAO,MAA6B,SAAS,QAAQ,IAAI,MAAM;AACrE,WAAO,EAAE,IAAI,OAAO,QAAQ,QAAQ,QAAQ,IAAI;AAAA,EAClD;AACA,MAAK,MAAgC,YAAY,OAAO;AACtD,WAAO,EAAE,IAAI,OAAO,QAAQ,QAAQ,QAAQ,KAAK;AAAA,EACnD;AACA,SAAO,EAAE,IAAI,KAAK;AACpB;AAEA,eAAe,gBAAgB,OAAe,QAAkD;AAC9F,QAAM,YAAY,MAAM,cAAc;AACtC,QAAM,SAAS,oBAAoB,OAAO,sBAAsB,SAAS,CAAC;AAC1E,MAAI,CAAC,QAAQ;AACX,WAAO,WAAW,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC;AAAA,EAC/D;AACA,MAAI,WAAW,aAAa,CAAC,OAAO,YAAY;AAC9C,WAAO,WAAW,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,OAAO,UAAU,CAAC,CAAC,CAAC;AAAA,EAC3E;AAEA,QAAM,UAAU,WAAW;AAC3B,MAAI;AACF,4BAAwB,OAAO,WAAW,OAAO;AAAA,EACnD,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,OAAO,WAAW,SAAU,IAAc,QAAQ,CAAC,CAAC;AAAA,IAC5F;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,eAAe,OAAO,WAAW,MAAM;AAC5D,QAAM,MAAM,eAAe,MAAM,MAAM;AACvC,QAAM,QAAQ,WAAW,WAAW,EAAE,oBAAoB,IAAI,EAAE,qBAAqB;AACrF,QAAM,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,IAAI,OAAO,UAAU,CAAC,CAAC;AACvE,MAAI,CAAC,IAAI,YAAY;AACnB,WAAO,SAAS,IAAI;AAAA,EACtB;AACA,QAAM,SAAS,OAAO,OAAO,QAAS,OAAO,UAAU,OAAO,SAAU;AACxE,QAAM,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,CAAC,CAAC;AAC1D,SAAO,SAAS,GAAG,IAAI;AAAA,EAAK,IAAI,EAAE;AACpC;AAEA,eAAsB,gBAAgB,MAAoC;AACxE,QAAM,KAAK,KAAK,CAAC;AACjB,MAAI,CAAC,GAAI,QAAO,WAAW,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC1D,SAAO,gBAAgB,IAAI,QAAQ;AACrC;AAEA,eAAsB,iBAAiB,MAAoC;AACzE,QAAM,KAAK,KAAK,CAAC;AACjB,MAAI,CAAC,GAAI,QAAO,WAAW,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAC3D,SAAO,gBAAgB,IAAI,SAAS;AACtC;AAiBA,SAAS,mBAAmB,MAA6B;AACvD,MACE,SAAS,WACT,KAAK,WAAW,QAAQ,KACxB,KAAK,WAAW,MAAM,KACtB,KAAK,WAAW,MAAM,KACtB,KAAK,WAAW,MAAM,KACtB,KAAK,WAAW,MAAM,KACtB,KAAK,WAAW,SAAS,GACzB;AACA,WAAO;AAAA,EACT;AACA,MAAI,WAAW,IAAI,GAAG;AACpB,UAAM,KAAK,UAAU,IAAI;AACzB,QAAI,GAAG,YAAY,EAAG,QAAO;AAC7B,WAAO,iHAAgD,IAAI;AAAA,EAC7D;AACA,SAAO,EAAE,mBAAmB,EAAE,OAAO,KAAK,CAAC;AAC7C;AAEA,eAAsB,iBAAiB,MAAiC;AAEtE,QAAM,QAAQ,WAAW,IAAI;AAC7B,QAAM,aAAuB,CAAC;AAC9B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,YAAY;AAClD;AACA;AAAA,IACF;AACA,QAAI,KAAK,CAAC,GAAG,WAAW,SAAS,KAAK,KAAK,CAAC,GAAG,WAAW,WAAW,EAAG;AACxE,QAAI,KAAK,CAAC,GAAG,WAAW,IAAI,EAAG;AAC/B,eAAW,KAAK,KAAK,CAAC,CAAE;AAAA,EAC1B;AACA,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,EAAE,OAAO,EAAE,mBAAmB,CAAC;AAAA,EACxC;AAGA,MAAI,MAAM,MAAM;AACd,UAAM,MAAM,mBAAmB,MAAM,IAAI;AACzC,QAAI,IAAK,QAAO,EAAE,IAAI,GAAG;AAAA,EAC3B;AAEA,QAAM,cAAc,mBAAmB;AACvC,MAAI,CAAC,aAAa;AAChB,WAAO,EAAE,IAAI,EAAE,kBAAkB,CAAC;AAAA,EACpC;AACA,QAAM,MAAM,CAAC,WAAW,GAAG,UAAU;AACrC,MAAI,MAAM,KAAM,KAAI,KAAK,UAAU,MAAM,IAAI;AAC7C,MAAI,MAAM,OAAQ,KAAI,KAAK,YAAY,MAAM,MAAM;AACnD,MAAI,MAAM,KAAM,KAAI,KAAK,QAAQ;AACjC,SAAO,IAAI,QAAgB,CAAC,YAAY;AACtC,UAAM,OAAO,MAAM,QAAQ,UAAU,CAAC,aAAa,GAAG,GAAG,GAAG;AAAA,MAC1D,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,KAAK,EAAE,GAAG,QAAQ,KAAK,WAAW,KAAK;AAAA,IACzC,CAAC;AACD,QAAI,MAAM;AACV,SAAK,QAAQ,GAAG,QAAQ,CAAC,MAAc;AACrC,aAAO,EAAE,SAAS;AAAA,IACpB,CAAC;AACD,SAAK,QAAQ,GAAG,QAAQ,CAAC,MAAc;AACrC,aAAO,EAAE,SAAS;AAAA,IACpB,CAAC;AACD,SAAK,GAAG,QAAQ,CAAC,SAAS;AACxB,cAAQ,OAAO,SAAS,IAAI,KAAK;AAAA,QAAW,IAAI,IAAI;AAAA,IACtD,CAAC;AACD,SAAK,GAAG,SAAS,CAAC,MAAM,QAAQ,EAAE,IAAI,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC;AAAA,EACtE,CAAC;AACH;AAKA,eAAsB,mBAAmB,MAAiC;AACxE,QAAM,KAAK,KAAK,CAAC;AACjB,MAAI,CAAC,GAAI,QAAO,EAAE,OAAO,EAAE,qBAAqB,CAAC;AACjD,QAAM,cAAc,mBAAmB;AACvC,MAAI,CAAC,aAAa;AAEhB,UAAM,SAAS,KAAK,KAAK,WAAW,GAAG,EAAE;AACzC,QAAI,CAAC,WAAW,MAAM,EAAG,QAAO,EAAE,OAAO,EAAE,0BAA0B,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1F,UAAM,GAAG,GAAG,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpD,WAAO,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC;AAAA,EACvD;AACA,SAAO,IAAI,QAAgB,CAAC,YAAY;AACtC,UAAM,OAAO,MAAM,QAAQ,UAAU,CAAC,aAAa,aAAa,EAAE,GAAG;AAAA,MACnE,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,KAAK,EAAE,GAAG,QAAQ,KAAK,WAAW,KAAK;AAAA,IACzC,CAAC;AACD,QAAI,MAAM;AACV,SAAK,QAAQ,GAAG,QAAQ,CAAC,MAAc;AACrC,aAAO,EAAE,SAAS;AAAA,IACpB,CAAC;AACD,SAAK,QAAQ,GAAG,QAAQ,CAAC,MAAc;AACrC,aAAO,EAAE,SAAS;AAAA,IACpB,CAAC;AACD,SAAK,GAAG,QAAQ,CAAC,SAAS;AACxB,cAAQ,OAAO,SAAS,IAAI,KAAK;AAAA,QAAW,IAAI,IAAI;AAAA,IACtD,CAAC;AACD,SAAK,GAAG,SAAS,CAAC,MAAM,QAAQ,EAAE,IAAI,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC;AAAA,EACtE,CAAC;AACH;AAWA,SAAS,WAAW,MAA8B;AAChD,QAAM,QAAsB,EAAE,MAAM,MAAM,QAAQ,MAAM,MAAM,MAAM;AACpE,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,MAAM,SAAU,OAAM,OAAO,KAAK,EAAE,CAAC,KAAK;AAAA,aAC3C,KAAK,CAAC,GAAG,WAAW,SAAS,EAAG,OAAM,OAAO,KAAK,CAAC,EAAG,MAAM,UAAU,MAAM;AAAA,aAC5E,KAAK,CAAC,MAAM,WAAY,OAAM,SAAS,KAAK,EAAE,CAAC,KAAK;AAAA,aACpD,KAAK,CAAC,GAAG,WAAW,WAAW,EAAG,OAAM,SAAS,KAAK,CAAC,EAAG,MAAM,YAAY,MAAM;AAAA,aAClF,KAAK,CAAC,MAAM,SAAU,OAAM,OAAO;AAAA,EAC9C;AACA,SAAO;AACT;AAWA,eAAsB,sBAAsB,KAAyB,MAAiC;AACpG,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO,cAAc,IAAI;AAAA,IAC3B,KAAK;AACH,aAAO,gBAAgB,IAAI;AAAA,IAC7B,KAAK;AACH,aAAO,iBAAiB,IAAI;AAAA,IAC9B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,mBAAmB,IAAI;AAAA,IAChC,KAAK;AACH,aAAO,gBAAgB,IAAI;AAAA,IAC7B,KAAK;AACH,aAAO,cAAc,IAAI;AAAA,IAC3B,KAAK;AACH,cAAQ,MAAM,gBAAgB,IAAI,GAAG;AAAA,IACvC,KAAK;AACH,cAAQ,MAAM,iBAAiB,IAAI,GAAG;AAAA,IACxC,KAAK,SAAS;AACZ,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,wBAAwB;AAChE,aAAO,eAAe,IAAI;AAAA,IAC5B;AAAA,IACA,KAAK,UAAU;AACb,YAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,wBAAwB;AACjE,aAAO,gBAAgB,IAAI;AAAA,IAC7B;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE;AAAA,QACP,QAAQ,GAAG;AAAA,MACb;AAAA,IACF;AACE,aAAO,EAAE,OAAO,YAAY,CAAC;AAAA,EACjC;AACF;AAGO,SAAS,6BAAuC;AACrD,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,WAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,MAAI;AACF,WAAO,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,EAC5C,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7B,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;",
|
|
4
|
+
"sourcesContent": ["/**\n * sfmc module-commands \u2014 runtime CLI for inspecting and managing modules\n * already on disk under `modules/packages/<id>/`.\n *\n * \u9876\u5C42\u547D\u4EE4\u522B\u540D:`module` / `mod`(\u7531 main.ts / repl.ts \u5171\u540C\u8BC6\u522B)\u3002\n * \u5B50\u547D\u4EE4\u901A\u9053\u95E8\u7981\u89C1 command-surface.ts\uFF08dispatch \u524D\u7531 main/repl \u5224\u5B9A\uFF09\u3002\n */\n\nimport fs from \"node:fs/promises\";\nimport { existsSync, lstatSync, readdirSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport {\n configPath,\n modulePath,\n readJson,\n writeJson,\n type Catalog,\n type DBConfig,\n type ModuleLock,\n} from \"@sfmc-bds/sdk/node/config\";\nimport {\n isDevAccentModuleSub,\n listVisibleModuleSubs,\n type CommandMode,\n} from \"./command-surface.js\";\nimport { failResult, okResult, type CliResult } from \"./cli-result.js\";\nimport { t } from \"./i18n/index.js\";\nimport { c } from \"./theme.js\";\nimport { ROOT, resolveFetchModule } from \"./runtime.js\";\nimport { dirFingerprint } from \"./module-fingerprint.js\";\nimport {\n applyLockEnabled,\n finalizeToggle,\n resolveToggleTarget,\n type ToggleCandidate,\n type ToggleNotify,\n} from \"./module-toggle.js\";\nimport {\n DEFAULT_REGISTRY_REPO,\n DEFAULT_REGISTRY_TAG,\n findUnknownModules,\n resolveRegistryIndex,\n} from \"./registry.js\";\n\n/** \u9876\u5C42\u547D\u4EE4\u540D(\u4E3B\u540D + \u77ED\u522B\u540D),\u4F9B\u5E2E\u52A9 / \u8865\u5168 / \u5206\u53D1\u5171\u7528\u3002 */\nexport const MODULE_CMD_NAMES = [\"module\", \"mod\"] as const;\n\nexport type ModuleCmdName = (typeof MODULE_CMD_NAMES)[number];\n\n/** \u5224\u65AD\u662F\u5426\u4E3A module \u9876\u5C42\u547D\u4EE4(\u542B\u522B\u540D);\u907F\u514D main/repl \u518D\u786C\u7F16\u7801 case\u3002 */\nexport function isModuleCommand(cmd: string | undefined): cmd is ModuleCmdName {\n return !!cmd && (MODULE_CMD_NAMES as readonly string[]).includes(cmd);\n}\n\n/** \u5F00\u53D1\u8005\u6837\u5F0F\u5B50\u547D\u4EE4\uFF08\u84DD\u6807\uFF0C\u975E\u95E8\u7981\uFF09\u3002 */\nexport const DEV_ACCENT_MODULE_SUBCOMMANDS = [\"build\", \"reload\"] as const;\n\n/** \u5F53\u524D\u901A\u9053\u4E0B\u53EF\u89C1\u7684 module \u5B50\u547D\u4EE4\uFF08\u81EA\u52A8\u8865\u5168 / usage\uFF09\u3002 */\nexport function getVisibleModuleSubcommands(mode: CommandMode): readonly string[] {\n return listVisibleModuleSubs(mode);\n}\n\n/** sub \u662F\u5426\u4E3A\u5F00\u53D1\u8005\u84DD\u6807\uFF08help \u7740\u8272\uFF09\u3002 */\nexport function isDeveloperSubcommand(sub: string | undefined): boolean {\n return isDevAccentModuleSub(sub);\n}\n\n/** Usage \u884C\u4E3B\u540D|\u522B\u540D(\u4E0E MODULE_CMD_NAMES \u540C\u6E90,\u907F\u514D\u4E0E\u5E2E\u52A9\u6587\u6848\u6F02\u79FB)\u3002 */\nexport function moduleUsage(mode: CommandMode = \"argv\"): string {\n return t(\"mod.usage\", {\n cmds: MODULE_CMD_NAMES.join(\"|\"),\n subs: getVisibleModuleSubcommands(mode).join(\"|\"),\n });\n}\n\n/** Where modules live on disk. */\nfunction modulesDir(): string {\n return path.join(ROOT, \"modules\", \"packages\");\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n}\n\nfunction shortHash(h: string): string {\n return h.slice(0, 8) + \"\u2026\" + h.slice(-8);\n}\n\ninterface ModuleManifest {\n schemaVersion?: number;\n id?: string;\n handlers?: string[];\n routes?: Array<{ method: string; path: string; handler: string }>;\n migrations?: Array<{ name: string; version: number }>;\n notes?: string;\n}\n\ninterface InstalledModule {\n id: string;\n path: string;\n manifest: ModuleManifest | null;\n totalBytes: number;\n fileCount: number;\n fingerprint: string;\n}\n\n/** Enumerate every installed module by scanning `modules/packages/<id>/`. */\nasync function scanInstalled(): Promise<InstalledModule[]> {\n const dir = modulesDir();\n if (!existsSync(dir)) return [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n const out: InstalledModule[] = [];\n for (const e of entries) {\n const id = e.name;\n const modPath = path.join(dir, id);\n try {\n if (!statSync(modPath).isDirectory()) continue;\n } catch {\n continue;\n }\n const manifestPath = path.join(modPath, \"sapi\", \"manifest.json\");\n let manifest: ModuleManifest | null = null;\n if (existsSync(manifestPath)) {\n try {\n manifest = JSON.parse(await fs.readFile(manifestPath, \"utf8\")) as ModuleManifest;\n } catch {\n /* corrupt manifest is not fatal \u2014 just skip its fields */\n }\n }\n const { totalBytes, fileCount } = await dirSize(modPath);\n const fingerprint = await dirFingerprint(modPath);\n out.push({ id, path: modPath, manifest, totalBytes, fileCount, fingerprint });\n }\n out.sort((a, b) => a.id.localeCompare(b.id));\n return out;\n}\n\nasync function dirSize(dir: string): Promise<{ totalBytes: number; fileCount: number }> {\n let totalBytes = 0;\n let fileCount = 0;\n async function walk(p: string): Promise<void> {\n for (const e of await fs.readdir(p, { withFileTypes: true })) {\n if (e.name.startsWith(\".\") || e.name === \"node_modules\" || e.name === \"dist\") continue;\n const child = path.join(p, e.name);\n if (e.isDirectory()) await walk(child);\n else if (e.isFile()) {\n const s = await fs.stat(child);\n totalBytes += s.size;\n fileCount++;\n }\n }\n }\n await walk(dir);\n return { totalBytes, fileCount };\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * list\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleList(_args: string[]): Promise<string> {\n const installed = await scanInstalled();\n if (installed.length === 0) {\n return c.dim(t(\"mod.noneInstalled\", { dir: modulesDir() }));\n }\n const lock =\n (readJson<ModuleLock>(modulePath(path.join(ROOT, \"modules\"), \"module-lock.json\")) ?? {\n version: 1,\n modules: {},\n }) as ModuleLock;\n const ids = installed.map((m) => m.id);\n const unknown = new Set(await findUnknownModules(ids));\n const lines: string[] = [c.bold(`\\n${t(\"mod.list.title\")}`), c.dim(` ${modulesDir()}`)];\n const header = ` ${\"id\".padEnd(28)}${\"state\".padEnd(8)}${\"files\".padEnd(8)}${\"size\".padEnd(10)}${\"fingerprint\"}`;\n lines.push(c.dim(header));\n for (const m of installed) {\n const logicalId = typeof m.manifest?.id === \"string\" && m.manifest.id ? m.manifest.id : m.id;\n const enabled = lock.modules?.[logicalId]?.enabled === true;\n const stateCol = (enabled ? c.green(\"on\") : c.dim(\"off\")).padEnd(8);\n let mark: string;\n if (!m.manifest) {\n mark = c.yellow(\"\u25CB\");\n } else if (unknown.has(m.id)) {\n mark = c.yellow(\"?\");\n } else {\n mark = enabled ? c.green(\"\u25CF\") : c.dim(\"\u25CB\");\n }\n const idLabel = logicalId !== m.id ? `${m.id}(${logicalId})` : m.id;\n lines.push(\n ` ${mark} ${idLabel.padEnd(26)} ${stateCol}${String(m.fileCount).padEnd(8)}${fmtBytes(m.totalBytes).padEnd(10)}${shortHash(m.fingerprint)}`\n );\n }\n lines.push(c.dim(`\\n tip: ${MODULE_CMD_NAMES[1] ?? \"mod\"} enable|disable <logicalId>`));\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Walk `modules/packages/<id>/` and print a one-line yellow warning for each\n * id that isn't in the first-party registry. Intended for the REPL startup\n * hook so users immediately see modules they installed from somewhere else.\n *\n * Best-effort: registry unreachable \u2192 no warning (no false positives).\n */\nexport async function scanAndWarnUnknown(): Promise<string> {\n const installed = await scanInstalled();\n if (installed.length === 0) return \"\";\n const unknown = await findUnknownModules(installed.map((m) => m.id));\n if (unknown.length === 0) return \"\";\n const list = unknown.map((id) => ` ${c.yellow(\"?\")} ${id}`).join(\"\\n\");\n return `${c.yellow(\"[sfmc] modules installed from unknown publisher \u2014 verify before use:\")}\\n${list}\\n`;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * search \u2014 \u62C9\u53D6 first-party registry;\u5E26 id \u67E5\u5355\u6761 registry info\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/**\n * \u62C9\u53D6 first-party registry \u6A21\u5757\u5217\u8868;\u5E26 id \u65F6\u5C55\u793A\u8BE5\u6761\u76EE\u7684 registry info\u3002\n * \u4E0E\u672C\u5730 `info`(\u5DF2\u5B89\u88C5\u78C1\u76D8\u8BE6\u60C5)\u533A\u5206:`search` \u770B registry,`info` \u770B\u672C\u673A packages\u3002\n */\nexport async function cmdModuleSearch(args: string[]): Promise<string> {\n const query = args[0];\n const { index, stale } = await resolveRegistryIndex({ force: true });\n const ids = Object.keys(index).sort((a, b) => a.localeCompare(b));\n\n if (ids.length === 0) {\n return c.red(\n `\\nRegistry empty or unreachable (${DEFAULT_REGISTRY_REPO}@${DEFAULT_REGISTRY_TAG}).\\n` +\n `Check network, or: mod install <id> --from github:owner/repo@tag\\n`\n );\n }\n\n const staleNote = stale ? c.yellow(\" (offline \u2014 showing cached index)\\n\") : \"\";\n\n /* \u65E0\u53C2\u6570:\u5217\u51FA\u5168\u90E8 */\n if (!query) {\n const installed = new Set(listInstalledModuleIdsSync());\n const lines: string[] = [\n c.bold(`\\nFirst-party registry (${DEFAULT_REGISTRY_REPO}@${DEFAULT_REGISTRY_TAG}) \u2014 ${ids.length} modules`),\n ];\n if (staleNote) lines.push(staleNote.trimEnd());\n lines.push(c.dim(` ${\"id\".padEnd(28)}${\"source\".padEnd(40)}local`));\n for (const id of ids) {\n const e = index[id]!;\n const src = `${e.repo}@${e.tag}`;\n const local = installed.has(id) ? c.green(\"\u25CF\") : c.dim(\"\u25CB\");\n lines.push(` ${local} ${id.padEnd(26)}${src.padEnd(40)}${installed.has(id) ? \"installed\" : \"\"}`);\n }\n lines.push(c.dim(`\\n tip: sfmc mod search <id> \u2192 registry info`));\n lines.push(c.dim(` sfmc mod install <id> \u2192 download + catalog sync`));\n return lines.join(\"\\n\") + \"\\n\";\n }\n\n /* \u5E26 id:\u67E5\u5355\u6761 registry info */\n const entry = index[query];\n if (!entry) {\n const hints = ids.filter((id) => id.includes(query) || query.includes(id)).slice(0, 8);\n const hintBlock =\n hints.length > 0\n ? c.dim(`\\n Did you mean:\\n`) + hints.map((h) => ` ${h}`).join(\"\\n\")\n : c.dim(`\\n Known ids: ${ids.slice(0, 12).join(\", \")}${ids.length > 12 ? \", \u2026\" : \"\"}`);\n return c.red(t(\"mod.notInRegistry\", { query })) + hintBlock + \"\\n\";\n }\n\n const installedPath = path.join(modulesDir(), query);\n const isInstalled = existsSync(installedPath);\n const lines: string[] = [c.bold(`\\n${query}`)];\n if (staleNote) lines.push(staleNote.trimEnd());\n lines.push(` registry : ${DEFAULT_REGISTRY_REPO}@${DEFAULT_REGISTRY_TAG}`);\n lines.push(` repo : ${entry.repo}`);\n lines.push(` tag : ${entry.tag}`);\n lines.push(` source : github:${entry.repo}@${entry.tag}`);\n lines.push(` github : https://github.com/${entry.repo}/tree/${entry.tag}`);\n lines.push(\n ` local : ${isInstalled ? c.green(`installed @ ${installedPath}`) : c.dim(\"not installed\")}`\n );\n\n if (!isInstalled) {\n lines.push(c.dim(`\\n install: sfmc mod install ${query}`));\n } else {\n lines.push(c.dim(`\\n details: sfmc mod info ${query}`));\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * info\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleInfo(args: string[]): Promise<string> {\n const id = args[0];\n if (!id) return c.yellow(t(\"mod.info.usage\"));\n const all = await scanInstalled();\n const m = all.find((x) => x.id === id);\n if (!m) return c.red(t(\"mod.notInstalledAt\", { id, path: path.join(modulesDir(), id) }));\n const lines: string[] = [c.bold(`\\n${id}`)];\n lines.push(` path : ${m.path}`);\n lines.push(` files : ${m.fileCount}`);\n lines.push(` size : ${fmtBytes(m.totalBytes)}`);\n lines.push(` fingerprint : ${m.fingerprint}`);\n if (m.manifest) {\n lines.push(` schemaVer : ${m.manifest.schemaVersion ?? \"(none)\"}`);\n lines.push(` routes : ${m.manifest.routes?.length ?? 0}`);\n if (m.manifest.routes?.length) {\n for (const r of m.manifest.routes) lines.push(c.dim(` ${r.method.padEnd(7)} ${r.path.padEnd(36)} ${r.handler}`));\n }\n lines.push(` migrations : ${m.manifest.migrations?.length ?? 0}`);\n if (m.manifest.migrations?.length) {\n for (const mg of m.manifest.migrations) lines.push(c.dim(` v${mg.version} ${mg.name}`));\n }\n if (m.manifest.notes) lines.push(` notes : ${c.dim(m.manifest.notes)}`);\n } else {\n lines.push(c.yellow(` manifest : (missing or unreadable)`));\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * verify\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleVerify(args: string[]): Promise<string> {\n const id = args[0];\n if (id) {\n const all = await scanInstalled();\n const m = all.find((x) => x.id === id);\n if (!m) return c.red(t(\"mod.notInstalled\", { id }));\n return c.green(t(\"mod.verifyOk\", { id, fp: m.fingerprint }));\n }\n const all = await scanInstalled();\n const lines = [c.bold(\"\\nVerifying installed modules\")];\n for (const m of all) {\n lines.push(` ${m.id.padEnd(28)} ${shortHash(m.fingerprint)}`);\n }\n if (all.length === 0) lines.push(c.dim(\" (none)\"));\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * install \u2014 shells out to scripts/module-install/fetch-module.mjs\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * enable / disable \u2014 \u672C\u5730\u5199 module-lock.json\uFF1Bdb \u5728\u7EBF\u65F6 best-effort \u70ED\u540C\u6B65\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nfunction readDbConfig(): DBConfig {\n return (readJson<DBConfig>(configPath(ROOT, \"db_config.json\")) ?? {}) as DBConfig;\n}\n\nfunction moduleLockPath(): string {\n return modulePath(path.join(ROOT, \"modules\"), \"module-lock.json\");\n}\n\nfunction catalogPathOnDisk(): string {\n return modulePath(path.join(ROOT, \"modules\"), \"catalog.json\");\n}\n\n/** \u5DF2\u88C5\u5305 + catalog \u6295\u5F71 \u2192 \u542F\u505C\u5019\u9009\uFF08canDisable \u4E0E db \u540C\u6E90\uFF1A\u7701\u7565\u89C6\u4E3A\u53EF\u7981\u7528\uFF09\u3002 */\nfunction buildToggleCandidates(installed: InstalledModule[]): ToggleCandidate[] {\n const catalog = (readJson<Catalog>(catalogPathOnDisk()) ?? {\n version: 1,\n modules: [],\n }) as Catalog;\n const rows = Array.isArray(catalog.modules) ? catalog.modules : [];\n const byLogical = new Map<string, (typeof rows)[number]>();\n for (const raw of rows) {\n if (!raw || typeof raw !== \"object\") continue;\n const id = String(raw.id || \"\").trim();\n if (id) byLogical.set(id, raw);\n }\n return installed.map((m) => {\n const logicalId = typeof m.manifest?.id === \"string\" && m.manifest.id ? m.manifest.id : m.id;\n const raw = byLogical.get(logicalId);\n const configKeyRaw = raw ? String(raw.configKey || \"\").trim() : \"\";\n const canDisable = raw ? raw.canDisable !== false : true;\n const out: ToggleCandidate = { logicalId, folderId: m.id, canDisable };\n if (configKeyRaw) out.configKey = configKeyRaw;\n return out;\n });\n}\n\nfunction writeLocalModuleEnabled(logicalId: string, enabled: boolean): void {\n const lockPath = moduleLockPath();\n const lock =\n (readJson<ModuleLock>(lockPath) ?? {\n version: 1,\n modules: {},\n }) as ModuleLock;\n applyLockEnabled(lock, logicalId, enabled);\n writeJson(lockPath, lock);\n}\n\nasync function notifyDbToggle(logicalId: string, action: \"enable\" | \"disable\"): Promise<ToggleNotify> {\n const cfg = readDbConfig();\n const port = cfg.db_port ?? 3001;\n const token = cfg.http_auth || \"\";\n const url = `http://127.0.0.1:${port}/api/sfmc/modules/${encodeURIComponent(logicalId)}/${action}`;\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n });\n } catch (err) {\n return { ok: false, reason: \"unreachable\", detail: (err as Error).message };\n }\n const text = await res.text();\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n body = text;\n }\n if (!res.ok) {\n const err = (body as { error?: string })?.error ?? `HTTP ${res.status}`;\n return { ok: false, reason: \"http\", detail: err };\n }\n if ((body as { success?: boolean })?.success === false) {\n return { ok: false, reason: \"http\", detail: text };\n }\n return { ok: true };\n}\n\nasync function cmdModuleToggle(query: string, action: \"enable\" | \"disable\"): Promise<CliResult> {\n const installed = await scanInstalled();\n const target = resolveToggleTarget(query, buildToggleCandidates(installed));\n if (!target) {\n return failResult(c.red(t(\"mod.notInstalled\", { id: query })));\n }\n if (action === \"disable\" && !target.canDisable) {\n return failResult(c.red(t(\"mod.cannotDisable\", { id: target.logicalId })));\n }\n\n const enabled = action === \"enable\";\n try {\n writeLocalModuleEnabled(target.logicalId, enabled);\n } catch (err) {\n return failResult(\n c.red(t(\"mod.toggleLockFailed\", { id: target.logicalId, message: (err as Error).message }))\n );\n }\n\n const notify = await notifyDbToggle(target.logicalId, action);\n const fin = finalizeToggle(true, notify);\n const label = action === \"enable\" ? t(\"mod.action.enabled\") : t(\"mod.action.disabled\");\n const head = c.green(t(\"mod.toggleOk\", { label, id: target.logicalId }));\n if (!fin.warnNotify) {\n return okResult(head);\n }\n const detail = notify.ok === false ? (notify.detail ?? notify.reason) : \"\";\n const warn = c.yellow(t(\"mod.toggleDbSkipped\", { detail }));\n return okResult(`${head}\\n${warn}`);\n}\n\nexport async function cmdModuleEnable(args: string[]): Promise<CliResult> {\n const id = args[0];\n if (!id) return failResult(c.yellow(t(\"mod.enable.usage\")));\n return cmdModuleToggle(id, \"enable\");\n}\n\nexport async function cmdModuleDisable(args: string[]): Promise<CliResult> {\n const id = args[0];\n if (!id) return failResult(c.yellow(t(\"mod.disable.usage\")));\n return cmdModuleToggle(id, \"disable\");\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * install \u2014 shells out to scripts/module-install/fetch-module.mjs\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * \u9884\u68C0 --from \u53D6\u503C\u662F\u5426\u662F\u5408\u6CD5 scheme\uFF1A\n * - npm:@scope/name / npm:<name>\n * - local[:<path>] / local\n * - tgz:<path>\n * - zip:<path>\n * - dir:<abs path>\n * - github:<owner>/<repo>[@tag]\n * - \u88F8\u8DEF\u5F84\uFF1A\u5FC5\u987B\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55\uFF08\u88F8\u6587\u4EF6\u5E94\u8F6C tgz:/zip:\uFF09\n * \u8FD4\u56DE null \u8868\u793A\u5408\u6CD5\uFF1B\u5426\u5219\u8FD4\u56DE\u7528\u6237\u53EF\u8BFB\u7684\u9519\u8BEF\u6587\u6848\u3002\n */\nfunction validateFromScheme(from: string): string | null {\n if (\n from === \"local\" ||\n from.startsWith(\"local:\") ||\n from.startsWith(\"dir:\") ||\n from.startsWith(\"npm:\") ||\n from.startsWith(\"tgz:\") ||\n from.startsWith(\"zip:\") ||\n from.startsWith(\"github:\")\n ) {\n return null;\n }\n if (existsSync(from)) {\n const st = lstatSync(from);\n if (st.isDirectory()) return null;\n return `--from \u88F8\u8DEF\u5F84\u987B\u4E3A\u76EE\u5F55\uFF08\u6587\u4EF6\u8BF7\u7528 --from local:<tgz|zip>\uFF09: ${from}`;\n }\n return t(\"mod.fromUnknown\", { value: from });\n}\n\nexport async function cmdModuleInstall(args: string[]): Promise<string> {\n // \u652F\u6301: install <id> [id2 ...] [--from ...] [--link] [--sha256 ...]\n const flags = parseFlags(args);\n const positional: string[] = [];\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--from\" || args[i] === \"--sha256\") {\n i++;\n continue;\n }\n if (args[i]?.startsWith(\"--from=\") || args[i]?.startsWith(\"--sha256=\")) continue;\n if (args[i]?.startsWith(\"--\")) continue;\n positional.push(args[i]!);\n }\n if (positional.length === 0) {\n return c.yellow(t(\"mod.install.usage\"));\n }\n\n /* scheme \u9884\u68C0\uFF1A\u907F\u514D\u62FC\u5199\u9519\u8BEF\u5EF6\u8FDF\u5230\u5B50\u8FDB\u7A0B\u62A5\u9519 */\n if (flags.from) {\n const err = validateFromScheme(flags.from);\n if (err) return c.red(err);\n }\n\n const fetchScript = resolveFetchModule();\n if (!fetchScript) {\n return c.red(t(\"mod.fetchMissing\"));\n }\n const sub = [\"install\", ...positional];\n if (flags.from) sub.push(\"--from\", flags.from);\n if (flags.sha256) sub.push(\"--sha256\", flags.sha256);\n if (flags.link) sub.push(\"--link\");\n return new Promise<string>((resolve) => {\n const proc = spawn(process.execPath, [fetchScript, ...sub], {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, SFMC_ROOT: ROOT },\n });\n let out = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.on(\"exit\", (code) => {\n resolve(out + (code === 0 ? \"\" : `\\n[exit ${code}]`));\n });\n proc.on(\"error\", (e) => resolve(c.red(`spawn failed: ${e.message}`)));\n });\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * uninstall\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModuleUninstall(args: string[]): Promise<string> {\n const id = args[0];\n if (!id) return c.yellow(t(\"mod.uninstall.usage\"));\n const fetchScript = resolveFetchModule();\n if (!fetchScript) {\n // \u56DE\u9000:\u4EC5\u5220\u76EE\u5F55(\u65E7\u884C\u4E3A)\n const target = path.join(modulesDir(), id);\n if (!existsSync(target)) return c.yellow(t(\"mod.notInstalledFolder\", { id, path: target }));\n await fs.rm(target, { recursive: true, force: true });\n return c.green(t(\"mod.removed\", { id, path: target }));\n }\n return new Promise<string>((resolve) => {\n const proc = spawn(process.execPath, [fetchScript, \"uninstall\", id], {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, SFMC_ROOT: ROOT },\n });\n let out = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n out += d.toString();\n });\n proc.on(\"exit\", (code) => {\n resolve(out + (code === 0 ? \"\" : `\\n[exit ${code}]`));\n });\n proc.on(\"error\", (e) => resolve(c.red(`spawn failed: ${e.message}`)));\n });\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * CLI flag parsing\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\ninterface InstallFlags {\n from: string | null;\n sha256: string | null;\n link: boolean;\n}\n\nfunction parseFlags(args: string[]): InstallFlags {\n const flags: InstallFlags = { from: null, sha256: null, link: false };\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--from\") flags.from = args[++i] ?? null;\n else if (args[i]?.startsWith(\"--from=\")) flags.from = args[i]!.slice(\"--from=\".length);\n else if (args[i] === \"--sha256\") flags.sha256 = args[++i] ?? null;\n else if (args[i]?.startsWith(\"--sha256=\")) flags.sha256 = args[i]!.slice(\"--sha256=\".length);\n else if (args[i] === \"--link\") flags.link = true;\n }\n return flags;\n}\n\n/**\n * \u7EDF\u4E00\u5206\u53D1 module/mod \u5B50\u547D\u4EE4 \u2014\u2014 CLI(`main.ts`)\u4E0E REPL(`repl.ts`)\u5171\u7528,\n * \u907F\u514D\u4E24\u5904 switch \u6F02\u79FB\u3002\n *\n * \u901A\u9053\u95E8\u7981\uFF08argv/repl\uFF09\u7531\u8C03\u7528\u65B9\u5728 dispatch \u524D\u7ECF command-surface \u5224\u5B9A\uFF1B\n * \u672C\u51FD\u6570\u53EA\u8D1F\u8D23\u5B50\u547D\u4EE4\u8DEF\u7531\u3002`remove` \u4F5C\u4E3A uninstall \u7684\u540C\u4E49\u522B\u540D\u4FDD\u7559\u3002\n *\n * \u4F5C\u8005\u5411 test/watch/publish \u5DF2\u8FC1\u81F3 VS Code \u6269\u5C55\u4E0E @sfmc-bds/devkit\u3002\n */\nexport async function dispatchModuleCommand(sub: string | undefined, args: string[]): Promise<string> {\n switch (sub) {\n case \"list\":\n return cmdModuleList(args);\n case \"search\":\n return cmdModuleSearch(args);\n case \"install\":\n return cmdModuleInstall(args);\n case \"uninstall\":\n case \"remove\":\n return cmdModuleUninstall(args);\n case \"verify\":\n return cmdModuleVerify(args);\n case \"info\":\n return cmdModuleInfo(args);\n case \"enable\":\n return (await cmdModuleEnable(args)).message;\n case \"disable\":\n return (await cmdModuleDisable(args)).message;\n case \"build\": {\n const { cmdModuleBuild } = await import(\"./module-pack-build.js\");\n return cmdModuleBuild(args);\n }\n case \"reload\": {\n const { cmdModuleReload } = await import(\"./module-pack-build.js\");\n return cmdModuleReload(args);\n }\n case \"test\":\n case \"watch\":\n case \"publish\":\n return c.yellow(\n `[mod ${sub}] \u5DF2\u79FB\u81F3\u6269\u5C55\u300CSFMC Module\u300D\u5168\u5468\u671F\uFF08Create/Test/Link/Watch/Publish\uFF09\uFF1B\u5EFA\u4ED3\u8BF7\u7528 pnpm dlx @sfmc-bds/create-module@latest\uFF1B\u8FD0\u7EF4\u8BF7\u7528 mod build|reload|install\u3002`\n );\n default:\n return c.yellow(moduleUsage());\n }\n}\n\n/** \u540C\u6B65\u679A\u4E3E\u5DF2\u5B89\u88C5\u6A21\u5757 id,\u4F9B REPL Tab \u8865\u5168(\u4E0D\u8BFB fingerprint,\u5C3D\u91CF\u8F7B\u91CF)\u3002 */\nexport function listInstalledModuleIdsSync(): string[] {\n const dir = modulesDir();\n if (!existsSync(dir)) return [];\n try {\n return readdirSync(dir, { withFileTypes: true })\n .filter((e) => {\n try {\n return statSync(path.join(dir, e.name)).isDirectory();\n } catch {\n return false;\n }\n })\n .map((e) => e.name)\n .sort((a, b) => a.localeCompare(b));\n } catch {\n return [];\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["lines", "all"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-fingerprint.d.ts","sourceRoot":"","sources":["../src/module-fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,qGAAqG;AACrG,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"module-fingerprint.d.ts","sourceRoot":"","sources":["../src/module-fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,qGAAqG;AACrG,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBrE"}
|
|
@@ -9,6 +9,7 @@ async function dirFingerprint(rootDir) {
|
|
|
9
9
|
const items = await fs.readdir(full, { withFileTypes: true });
|
|
10
10
|
const sorted = items.sort((a, b) => a.name.localeCompare(b.name));
|
|
11
11
|
for (const it of sorted) {
|
|
12
|
+
if (it.name.startsWith(".") || it.name === "node_modules" || it.name === "dist") continue;
|
|
12
13
|
const child = rel ? `${rel}/${it.name}` : it.name;
|
|
13
14
|
if (it.isDirectory()) await walk(child);
|
|
14
15
|
else if (it.isFile()) entries.push(child);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/module-fingerprint.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * module-fingerprint.ts \u2014 \u6A21\u5757\u76EE\u5F55 canonical SHA-256\n * (\u4E0E\u539F\u5148 module-commands \u5185 dirFingerprint \u7B97\u6CD5\u4E00\u81F4,\u4F9B catalog / verify \u5171\u7528)\u3002\n */\n\nimport { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/** Compute the canonical SHA-256 of a module directory (POSIX `find ... | sha256sum` compatible). */\nexport async function dirFingerprint(rootDir: string): Promise<string> {\n const hash = createHash(\"sha256\");\n const entries: string[] = [];\n async function walk(rel: string): Promise<void> {\n const full = path.join(rootDir, rel);\n const items = await fs.readdir(full, { withFileTypes: true });\n const sorted = items.sort((a, b) => a.name.localeCompare(b.name));\n for (const it of sorted) {\n const child = rel ? `${rel}/${it.name}` : it.name;\n if (it.isDirectory()) await walk(child);\n else if (it.isFile()) entries.push(child);\n }\n }\n await walk(\"\");\n entries.sort();\n for (const rel of entries) {\n const data = await fs.readFile(path.join(rootDir, rel));\n hash.update(rel.replaceAll(\"\\\\\", \"/\"));\n hash.update(\"\\n\");\n hash.update(data);\n hash.update(\"\\n\");\n }\n return hash.digest(\"hex\");\n}\n"],
|
|
5
|
-
"mappings": "AAKA,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,eAAsB,eAAe,SAAkC;AACrE,QAAM,OAAO,WAAW,QAAQ;AAChC,QAAM,UAAoB,CAAC;AAC3B,iBAAe,KAAK,KAA4B;AAC9C,UAAM,OAAO,KAAK,KAAK,SAAS,GAAG;AACnC,UAAM,QAAQ,MAAM,GAAG,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC5D,UAAM,SAAS,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAChE,eAAW,MAAM,QAAQ;AACvB,YAAM,QAAQ,MAAM,GAAG,GAAG,IAAI,GAAG,IAAI,KAAK,GAAG;AAC7C,UAAI,GAAG,YAAY,EAAG,OAAM,KAAK,KAAK;AAAA,eAC7B,GAAG,OAAO,EAAG,SAAQ,KAAK,KAAK;AAAA,IAC1C;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AACb,UAAQ,KAAK;AACb,aAAW,OAAO,SAAS;AACzB,UAAM,OAAO,MAAM,GAAG,SAAS,KAAK,KAAK,SAAS,GAAG,CAAC;AACtD,SAAK,OAAO,IAAI,WAAW,MAAM,GAAG,CAAC;AACrC,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,IAAI;AAAA,EAClB;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;",
|
|
4
|
+
"sourcesContent": ["/**\n * module-fingerprint.ts \u2014 \u6A21\u5757\u76EE\u5F55 canonical SHA-256\n * (\u4E0E\u539F\u5148 module-commands \u5185 dirFingerprint \u7B97\u6CD5\u4E00\u81F4,\u4F9B catalog / verify \u5171\u7528)\u3002\n */\n\nimport { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/** Compute the canonical SHA-256 of a module directory (POSIX `find ... | sha256sum` compatible). */\nexport async function dirFingerprint(rootDir: string): Promise<string> {\n const hash = createHash(\"sha256\");\n const entries: string[] = [];\n async function walk(rel: string): Promise<void> {\n const full = path.join(rootDir, rel);\n const items = await fs.readdir(full, { withFileTypes: true });\n const sorted = items.sort((a, b) => a.name.localeCompare(b.name));\n for (const it of sorted) {\n if (it.name.startsWith(\".\") || it.name === \"node_modules\" || it.name === \"dist\") continue;\n const child = rel ? `${rel}/${it.name}` : it.name;\n if (it.isDirectory()) await walk(child);\n else if (it.isFile()) entries.push(child);\n }\n }\n await walk(\"\");\n entries.sort();\n for (const rel of entries) {\n const data = await fs.readFile(path.join(rootDir, rel));\n hash.update(rel.replaceAll(\"\\\\\", \"/\"));\n hash.update(\"\\n\");\n hash.update(data);\n hash.update(\"\\n\");\n }\n return hash.digest(\"hex\");\n}\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,eAAsB,eAAe,SAAkC;AACrE,QAAM,OAAO,WAAW,QAAQ;AAChC,QAAM,UAAoB,CAAC;AAC3B,iBAAe,KAAK,KAA4B;AAC9C,UAAM,OAAO,KAAK,KAAK,SAAS,GAAG;AACnC,UAAM,QAAQ,MAAM,GAAG,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC5D,UAAM,SAAS,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAChE,eAAW,MAAM,QAAQ;AACvB,UAAI,GAAG,KAAK,WAAW,GAAG,KAAK,GAAG,SAAS,kBAAkB,GAAG,SAAS,OAAQ;AACjF,YAAM,QAAQ,MAAM,GAAG,GAAG,IAAI,GAAG,IAAI,KAAK,GAAG;AAC7C,UAAI,GAAG,YAAY,EAAG,OAAM,KAAK,KAAK;AAAA,eAC7B,GAAG,OAAO,EAAG,SAAQ,KAAK,KAAK;AAAA,IAC1C;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AACb,UAAQ,KAAK;AACb,aAAW,OAAO,SAAS;AACzB,UAAM,OAAO,MAAM,GAAG,SAAS,KAAK,KAAK,SAAS,GAAG,CAAC;AACtD,SAAK,OAAO,IAAI,WAAW,MAAM,GAAG,CAAC;AACrC,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,IAAI;AAAA,EAClB;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
import { type DeployCatalog } from "./pack-lifecycle.js";
|
|
2
|
+
export type BuildModulePacksResult = {
|
|
3
|
+
success: boolean;
|
|
4
|
+
message: string;
|
|
5
|
+
catalog?: DeployCatalog;
|
|
6
|
+
};
|
|
1
7
|
/**
|
|
2
|
-
*
|
|
8
|
+
* 组装 BP + RP 纯逻辑(不部署)。
|
|
3
9
|
* 仅当 catalog 与世界内已部署不一致时执行;否则直接打"已同步"。
|
|
4
10
|
*/
|
|
5
|
-
export declare function
|
|
11
|
+
export declare function buildModulePacks(force?: boolean): Promise<BuildModulePacksResult>;
|
|
12
|
+
/**
|
|
13
|
+
* `sfmc mod build` —— 组装 BP + RP(不部署)。
|
|
14
|
+
*/
|
|
15
|
+
export declare function cmdModuleBuild(_args?: string[]): Promise<string>;
|
|
6
16
|
/**
|
|
7
|
-
* `sfmc mod reload [--build-only]` —— 组装 + 部署 + 清理过期 + 写权限 + (默认)发 reload 到 BDS。
|
|
17
|
+
* `sfmc mod reload [--build-only] [--force]` —— 组装 + 部署 + 清理过期 + 写权限 + (默认)发 reload 到 BDS。
|
|
8
18
|
*/
|
|
9
|
-
export declare function cmdModuleReload(args
|
|
19
|
+
export declare function cmdModuleReload(args?: string[]): Promise<string>;
|
|
10
20
|
//# sourceMappingURL=module-pack-build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-pack-build.d.ts","sourceRoot":"","sources":["../src/module-pack-build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module-pack-build.d.ts","sourceRoot":"","sources":["../src/module-pack-build.ts"],"names":[],"mappings":"AAsBA,OAAO,EAgBL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAsS7B,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB,CAAC;AAEF;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAyDrF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAsD1E"}
|
|
@@ -1,35 +1,36 @@
|
|
|
1
|
+
import { writeJson } from "@sfmc-bds/sdk/node/config";
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { existsSync
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
3
4
|
import fs from "node:fs/promises";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import process from "node:process";
|
|
6
|
-
import {
|
|
7
|
+
import { t } from "./i18n/index.js";
|
|
8
|
+
import { pushLog } from "./logs.js";
|
|
7
9
|
import {
|
|
8
10
|
BP_NAME,
|
|
9
|
-
RP_NAME,
|
|
10
11
|
DEPLOY_CATALOG_NAME,
|
|
12
|
+
RP_NAME,
|
|
11
13
|
bpOut,
|
|
12
14
|
bpSrc,
|
|
13
|
-
rpOut,
|
|
14
15
|
buildRoot,
|
|
15
|
-
computeDesiredCatalog,
|
|
16
|
-
readDeployedCatalog,
|
|
17
16
|
catalogsEqual,
|
|
18
|
-
|
|
17
|
+
computeDesiredCatalog,
|
|
18
|
+
createSdkResolvePlugin,
|
|
19
19
|
deployedBpDir,
|
|
20
20
|
formatPackLoadInfo,
|
|
21
|
+
readDeployedCatalog,
|
|
22
|
+
resolveBdsContext,
|
|
23
|
+
rpOut,
|
|
21
24
|
scanLocalModules
|
|
22
25
|
} from "./pack-lifecycle.js";
|
|
23
|
-
import { ROOT, resolveServiceScript } from "./runtime.js";
|
|
26
|
+
import { ROOT, getRoot, resolveSdkPackageRoot, resolveServiceScript } from "./runtime.js";
|
|
24
27
|
import { c } from "./theme.js";
|
|
25
|
-
import { t } from "./i18n/index.js";
|
|
26
|
-
import { pushLog } from "./logs.js";
|
|
27
28
|
function spawnPackManager(args) {
|
|
28
29
|
return new Promise((resolve) => {
|
|
29
30
|
const script = resolveServiceScript("pack-manager");
|
|
30
31
|
const proc = spawn(process.execPath, [script, ...args], {
|
|
31
32
|
stdio: ["ignore", "pipe", "pipe"],
|
|
32
|
-
env: { ...process.env, SFMC_ROOT:
|
|
33
|
+
env: { ...process.env, SFMC_ROOT: getRoot(), SFMC_SERVICE: "pack-manager" }
|
|
33
34
|
});
|
|
34
35
|
let output = "";
|
|
35
36
|
proc.stdout?.on("data", (d) => {
|
|
@@ -42,7 +43,7 @@ function spawnPackManager(args) {
|
|
|
42
43
|
proc.on("error", (e) => resolve({ code: 1, output: `${output}${e.message}` }));
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
|
-
async function bundleBehaviorPackScript() {
|
|
46
|
+
async function bundleBehaviorPackScript(dbPort) {
|
|
46
47
|
const mods = await scanLocalModules();
|
|
47
48
|
const entries = mods.filter((m) => m.enabled && m.entryPath).map((m) => m.entryPath);
|
|
48
49
|
const outFile = path.join(bpSrc(), "scripts", "main.js");
|
|
@@ -53,21 +54,25 @@ async function bundleBehaviorPackScript() {
|
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
const { build } = await import("esbuild");
|
|
56
|
-
const sdkRoot =
|
|
57
|
+
const sdkRoot = resolveSdkPackageRoot();
|
|
57
58
|
await build({
|
|
58
|
-
|
|
59
|
+
stdin: {
|
|
60
|
+
contents: [
|
|
61
|
+
'import "sfmc:host";',
|
|
62
|
+
...entries.map((e) => `import ${JSON.stringify(path.resolve(e).replace(/\\/g, "/"))};`)
|
|
63
|
+
].join("\n"),
|
|
64
|
+
resolveDir: ROOT,
|
|
65
|
+
sourcefile: "bootstrap.ts",
|
|
66
|
+
loader: "ts"
|
|
67
|
+
},
|
|
59
68
|
outfile: outFile,
|
|
60
69
|
bundle: true,
|
|
61
70
|
platform: "neutral",
|
|
62
71
|
format: "esm",
|
|
63
72
|
target: "es2022",
|
|
64
73
|
logLevel: "warning",
|
|
65
|
-
sourcemap:
|
|
74
|
+
sourcemap: true,
|
|
66
75
|
external: ["@minecraft/*"],
|
|
67
|
-
// BDS host 启动:与 module-loader barrel 分离(DIP),须在模块 register 之前执行
|
|
68
|
-
banner: {
|
|
69
|
-
js: 'import { installHostBootstrap } from "@sfmc-bds/sdk/module-loader/install";\ninstallHostBootstrap();\n'
|
|
70
|
-
},
|
|
71
76
|
tsconfigRaw: JSON.stringify({
|
|
72
77
|
compilerOptions: {
|
|
73
78
|
module: "ESNext",
|
|
@@ -77,47 +82,10 @@ async function bundleBehaviorPackScript() {
|
|
|
77
82
|
skipLibCheck: true
|
|
78
83
|
}
|
|
79
84
|
}),
|
|
80
|
-
plugins: [createSdkResolvePlugin(sdkRoot)]
|
|
85
|
+
plugins: [createSdkResolvePlugin(sdkRoot, dbPort)]
|
|
81
86
|
});
|
|
82
87
|
pushLog(`esbuild bundled ${entries.length} entr(y/ies)`, "pack", "info");
|
|
83
88
|
}
|
|
84
|
-
async function resolveSdkRootForEsbuild() {
|
|
85
|
-
const { resolveSdkPackageRoot } = await import("./runtime.js");
|
|
86
|
-
return resolveSdkPackageRoot();
|
|
87
|
-
}
|
|
88
|
-
function createSdkResolvePlugin(sdkRoot) {
|
|
89
|
-
const pkg = JSON.parse(readFileSync(path.join(sdkRoot, "package.json"), "utf8"));
|
|
90
|
-
const exportsMap = pkg.exports ?? {};
|
|
91
|
-
function resolveExportSubpath(subpath) {
|
|
92
|
-
const key = subpath === "" ? "." : `./${subpath}`;
|
|
93
|
-
const entry = exportsMap[key];
|
|
94
|
-
if (!entry) return null;
|
|
95
|
-
const rel = typeof entry === "string" ? entry : entry.import ?? entry.default;
|
|
96
|
-
if (!rel || typeof rel !== "string") return null;
|
|
97
|
-
const abs = path.join(sdkRoot, rel);
|
|
98
|
-
return existsSync(abs) ? abs : null;
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
name: "sfmc-sdk-resolve",
|
|
102
|
-
setup(build) {
|
|
103
|
-
build.onResolve({ filter: /^@sfmc(?:-bds)?\/sdk(?:\/|$)/ }, (args) => {
|
|
104
|
-
const normalized = args.path.replace(/^@sfmc\/sdk/, "@sfmc-bds/sdk");
|
|
105
|
-
const sub = normalized === "@sfmc-bds/sdk" ? "" : normalized.slice("@sfmc-bds/sdk/".length);
|
|
106
|
-
const resolved = resolveExportSubpath(sub);
|
|
107
|
-
if (!resolved) {
|
|
108
|
-
return {
|
|
109
|
-
errors: [
|
|
110
|
-
{
|
|
111
|
-
text: `Cannot resolve ${args.path} under SDK at ${sdkRoot} (export "./${sub || "."}" missing or file absent; run sdk:build?)`
|
|
112
|
-
}
|
|
113
|
-
]
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
return { path: resolved };
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
89
|
async function spawnAssembleBp(catalog) {
|
|
122
90
|
const args = [
|
|
123
91
|
"assemble-bp",
|
|
@@ -133,6 +101,12 @@ async function spawnAssembleBp(catalog) {
|
|
|
133
101
|
catalog.bpVersion.join(",")
|
|
134
102
|
];
|
|
135
103
|
if (catalog.bpModuleUuid) args.push("--module-uuid", catalog.bpModuleUuid);
|
|
104
|
+
if (catalog.dependencies && catalog.dependencies.length > 0) {
|
|
105
|
+
const depsFile = path.join(buildRoot(), "bp-dependencies.json");
|
|
106
|
+
await fs.mkdir(buildRoot(), { recursive: true });
|
|
107
|
+
await fs.writeFile(depsFile, JSON.stringify(catalog.dependencies), "utf8");
|
|
108
|
+
args.push("--dependencies-json", depsFile);
|
|
109
|
+
}
|
|
136
110
|
const r = await spawnPackManager(args);
|
|
137
111
|
if (r.code === 0) {
|
|
138
112
|
pushLog(`assembled BP uuid=${catalog.bpUuid}`, "pack", "info");
|
|
@@ -164,11 +138,7 @@ async function spawnAssembleRp(catalog, rpDirs) {
|
|
|
164
138
|
if (catalog.rpModuleUuid) args.push("--module-uuid", catalog.rpModuleUuid);
|
|
165
139
|
const r = await spawnPackManager(args);
|
|
166
140
|
if (r.code === 0) {
|
|
167
|
-
pushLog(
|
|
168
|
-
`assembled RP uuid=${catalog.rpUuid} (${Object.keys(rpDirs).length} modules)`,
|
|
169
|
-
"pack",
|
|
170
|
-
"info"
|
|
171
|
-
);
|
|
141
|
+
pushLog(`assembled RP uuid=${catalog.rpUuid} (${Object.keys(rpDirs).length} modules)`, "pack", "info");
|
|
172
142
|
}
|
|
173
143
|
return r;
|
|
174
144
|
}
|
|
@@ -218,11 +188,7 @@ async function spawnEnablePacks(catalog) {
|
|
|
218
188
|
const bpR = await spawnPackManager(bpArgs);
|
|
219
189
|
output += bpR.output;
|
|
220
190
|
if (bpR.code !== 0) return { code: bpR.code, output };
|
|
221
|
-
pushLog(
|
|
222
|
-
`enabled behavior pack ${catalog.bpUuid} in world list`,
|
|
223
|
-
"pack",
|
|
224
|
-
"info"
|
|
225
|
-
);
|
|
191
|
+
pushLog(`enabled behavior pack ${catalog.bpUuid} in world list`, "pack", "info");
|
|
226
192
|
if (catalog.rpUuid && catalog.rpVersion) {
|
|
227
193
|
const rpArgs = [
|
|
228
194
|
"enable-pack",
|
|
@@ -240,11 +206,7 @@ async function spawnEnablePacks(catalog) {
|
|
|
240
206
|
const rpR = await spawnPackManager(rpArgs);
|
|
241
207
|
output += rpR.output;
|
|
242
208
|
if (rpR.code !== 0) return { code: rpR.code, output };
|
|
243
|
-
pushLog(
|
|
244
|
-
`enabled resource pack ${catalog.rpUuid} in world list`,
|
|
245
|
-
"pack",
|
|
246
|
-
"info"
|
|
247
|
-
);
|
|
209
|
+
pushLog(`enabled resource pack ${catalog.rpUuid} in world list`, "pack", "info");
|
|
248
210
|
}
|
|
249
211
|
return { code: 0, output };
|
|
250
212
|
}
|
|
@@ -269,11 +231,7 @@ async function spawnDisableStale(current, bdsRoot, levelName) {
|
|
|
269
231
|
if (r.code === 0) {
|
|
270
232
|
pushLog(`disabled stale resource pack ${staleRp}`, "pack", "info");
|
|
271
233
|
} else {
|
|
272
|
-
pushLog(
|
|
273
|
-
`disable stale RP ${staleRp} failed: ${r.output.trim()}`,
|
|
274
|
-
"pack",
|
|
275
|
-
"warn"
|
|
276
|
-
);
|
|
234
|
+
pushLog(`disable stale RP ${staleRp} failed: ${r.output.trim()}`, "pack", "warn");
|
|
277
235
|
}
|
|
278
236
|
}
|
|
279
237
|
for (const staleBp of previous.bp) {
|
|
@@ -294,11 +252,7 @@ async function spawnDisableStale(current, bdsRoot, levelName) {
|
|
|
294
252
|
if (r.code === 0) {
|
|
295
253
|
pushLog(`disabled stale behavior pack ${staleBp}`, "pack", "info");
|
|
296
254
|
} else {
|
|
297
|
-
pushLog(
|
|
298
|
-
`disable stale BP ${staleBp} failed: ${r.output.trim()}`,
|
|
299
|
-
"pack",
|
|
300
|
-
"warn"
|
|
301
|
-
);
|
|
255
|
+
pushLog(`disable stale BP ${staleBp} failed: ${r.output.trim()}`, "pack", "warn");
|
|
302
256
|
}
|
|
303
257
|
}
|
|
304
258
|
}
|
|
@@ -330,29 +284,23 @@ async function collectDeployedPackUuids(bdsRoot, levelName) {
|
|
|
330
284
|
}
|
|
331
285
|
async function spawnEnsurePermission(catalog) {
|
|
332
286
|
const { bdsRoot } = resolveBdsContext();
|
|
333
|
-
const r = await spawnPackManager([
|
|
334
|
-
"ensure-permission",
|
|
335
|
-
"--bds-root",
|
|
336
|
-
bdsRoot,
|
|
337
|
-
"--pack-id",
|
|
338
|
-
catalog.bpUuid
|
|
339
|
-
]);
|
|
287
|
+
const r = await spawnPackManager(["ensure-permission", "--bds-root", bdsRoot, "--pack-id", catalog.bpUuid]);
|
|
340
288
|
return r;
|
|
341
289
|
}
|
|
342
|
-
async function
|
|
290
|
+
async function buildModulePacks(force = false) {
|
|
343
291
|
try {
|
|
344
292
|
const { bdsRoot, levelName } = resolveBdsContext();
|
|
345
293
|
const deployed = readDeployedCatalog(bdsRoot, levelName);
|
|
346
294
|
const desired = await computeDesiredCatalog(deployed ? reusePackIds(deployed) : void 0);
|
|
347
|
-
if (deployed && catalogsEqual(desired, deployed)) {
|
|
348
|
-
return
|
|
295
|
+
if (!force && deployed && catalogsEqual(desired, deployed)) {
|
|
296
|
+
return {
|
|
297
|
+
success: true,
|
|
298
|
+
message: formatPackLoadInfo(desired, false),
|
|
299
|
+
catalog: deployed
|
|
300
|
+
};
|
|
349
301
|
}
|
|
350
|
-
pushLog(
|
|
351
|
-
|
|
352
|
-
"pack",
|
|
353
|
-
"info"
|
|
354
|
-
);
|
|
355
|
-
await bundleBehaviorPackScript();
|
|
302
|
+
pushLog(`building BP/RP (modules=${Object.keys(desired.modules).length})\u2026`, "pack", "info");
|
|
303
|
+
await bundleBehaviorPackScript(desired.dbPort);
|
|
356
304
|
const mods = await scanLocalModules();
|
|
357
305
|
const rpDirs = {};
|
|
358
306
|
for (const m of mods) {
|
|
@@ -360,29 +308,53 @@ async function cmdModuleBuild(_args) {
|
|
|
360
308
|
rpDirs[m.folderId] = path.join("modules", "packages", m.folderId, "resource_pack");
|
|
361
309
|
}
|
|
362
310
|
const bpR = await spawnAssembleBp(desired);
|
|
363
|
-
if (bpR.code !== 0)
|
|
311
|
+
if (bpR.code !== 0) {
|
|
312
|
+
return {
|
|
313
|
+
success: false,
|
|
314
|
+
message: c.red(bpR.output.trim() || `assemble-bp exit ${bpR.code}`)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
364
317
|
const rpR = await spawnAssembleRp(desired, rpDirs);
|
|
365
|
-
if (rpR.code !== 0)
|
|
318
|
+
if (rpR.code !== 0) {
|
|
319
|
+
return {
|
|
320
|
+
success: false,
|
|
321
|
+
message: c.red(rpR.output.trim() || `assemble-rp exit ${rpR.code}`)
|
|
322
|
+
};
|
|
323
|
+
}
|
|
366
324
|
desired.generatedAt = Date.now();
|
|
367
325
|
if (Object.keys(rpDirs).length === 0) {
|
|
368
326
|
desired.rpUuid = null;
|
|
369
327
|
desired.rpVersion = null;
|
|
370
328
|
}
|
|
371
329
|
writeJson(path.join(bpOut(), DEPLOY_CATALOG_NAME), desired);
|
|
372
|
-
return
|
|
330
|
+
return {
|
|
331
|
+
success: true,
|
|
332
|
+
message: formatPackLoadInfo(desired, true),
|
|
333
|
+
catalog: desired
|
|
334
|
+
};
|
|
373
335
|
} catch (e) {
|
|
374
|
-
return
|
|
336
|
+
return {
|
|
337
|
+
success: false,
|
|
338
|
+
message: c.red(e.message)
|
|
339
|
+
};
|
|
375
340
|
}
|
|
376
341
|
}
|
|
377
|
-
async function
|
|
378
|
-
const
|
|
342
|
+
async function cmdModuleBuild(_args = []) {
|
|
343
|
+
const res = await buildModulePacks(true);
|
|
344
|
+
return res.message;
|
|
345
|
+
}
|
|
346
|
+
async function cmdModuleReload(args = []) {
|
|
347
|
+
const buildOnly = args?.includes("--build-only") ?? false;
|
|
348
|
+
const force = args?.includes("--force") || args?.includes("-f");
|
|
379
349
|
const parts = [];
|
|
380
|
-
const
|
|
381
|
-
parts.push(
|
|
382
|
-
if (
|
|
350
|
+
const buildRes = await buildModulePacks(force);
|
|
351
|
+
parts.push(buildRes.message.trimEnd());
|
|
352
|
+
if (!buildRes.success || !buildRes.catalog) {
|
|
353
|
+
return parts.join("\n") + "\n";
|
|
354
|
+
}
|
|
383
355
|
try {
|
|
384
356
|
const { bdsRoot, levelName } = resolveBdsContext();
|
|
385
|
-
const desired =
|
|
357
|
+
const desired = buildRes.catalog;
|
|
386
358
|
const depR = await spawnDeploy(desired);
|
|
387
359
|
if (depR.code !== 0) {
|
|
388
360
|
return parts.join("\n") + "\n" + c.red(depR.output.trim() || `deploy exit ${depR.code}`);
|
|
@@ -428,6 +400,7 @@ function reusePackIds(deployed) {
|
|
|
428
400
|
};
|
|
429
401
|
}
|
|
430
402
|
export {
|
|
403
|
+
buildModulePacks,
|
|
431
404
|
cmdModuleBuild,
|
|
432
405
|
cmdModuleReload
|
|
433
406
|
};
|