@moewolf/moe-icons-cli 0.0.1

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.
Files changed (103) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +32 -0
  3. package/bin/moeicons.js +20 -0
  4. package/dist/api/client.d.ts +42 -0
  5. package/dist/api/client.js +105 -0
  6. package/dist/auth/callback.d.ts +37 -0
  7. package/dist/auth/callback.js +72 -0
  8. package/dist/auth/device-login.d.ts +29 -0
  9. package/dist/auth/device-login.js +74 -0
  10. package/dist/auth/login.d.ts +41 -0
  11. package/dist/auth/login.js +85 -0
  12. package/dist/auth/open-browser.d.ts +2 -0
  13. package/dist/auth/open-browser.js +15 -0
  14. package/dist/auth/pkce.d.ts +17 -0
  15. package/dist/auth/pkce.js +20 -0
  16. package/dist/auth/token-store.d.ts +38 -0
  17. package/dist/auth/token-store.js +126 -0
  18. package/dist/catalog/catalog.d.ts +32 -0
  19. package/dist/catalog/catalog.js +80 -0
  20. package/dist/catalog/catalog.json +9371 -0
  21. package/dist/cli.d.ts +23 -0
  22. package/dist/cli.js +507 -0
  23. package/dist/commands/parser.d.ts +41 -0
  24. package/dist/commands/parser.js +146 -0
  25. package/dist/core/auth.d.ts +32 -0
  26. package/dist/core/auth.js +131 -0
  27. package/dist/core/bitmap-assets.d.ts +29 -0
  28. package/dist/core/bitmap-assets.js +77 -0
  29. package/dist/core/cli-update.d.ts +43 -0
  30. package/dist/core/cli-update.js +71 -0
  31. package/dist/core/context.d.ts +22 -0
  32. package/dist/core/context.js +1 -0
  33. package/dist/core/free-download.d.ts +66 -0
  34. package/dist/core/free-download.js +193 -0
  35. package/dist/core/generate.d.ts +33 -0
  36. package/dist/core/generate.js +285 -0
  37. package/dist/core/icon-names.d.ts +14 -0
  38. package/dist/core/icon-names.js +54 -0
  39. package/dist/core/init.d.ts +12 -0
  40. package/dist/core/init.js +23 -0
  41. package/dist/core/install.d.ts +67 -0
  42. package/dist/core/install.js +117 -0
  43. package/dist/core/library-update.d.ts +24 -0
  44. package/dist/core/library-update.js +161 -0
  45. package/dist/core/manage.d.ts +24 -0
  46. package/dist/core/manage.js +38 -0
  47. package/dist/core/pro-download.d.ts +29 -0
  48. package/dist/core/pro-download.js +112 -0
  49. package/dist/core/pro-install.d.ts +24 -0
  50. package/dist/core/pro-install.js +72 -0
  51. package/dist/core/release-descriptor.d.ts +40 -0
  52. package/dist/core/release-descriptor.js +114 -0
  53. package/dist/core/resource-variant.d.ts +35 -0
  54. package/dist/core/resource-variant.js +70 -0
  55. package/dist/core/signed-artifact.d.ts +29 -0
  56. package/dist/core/signed-artifact.js +81 -0
  57. package/dist/core/target-subtree.d.ts +49 -0
  58. package/dist/core/target-subtree.js +132 -0
  59. package/dist/core/update-policy.d.ts +31 -0
  60. package/dist/core/update-policy.js +27 -0
  61. package/dist/core/version-service.d.ts +26 -0
  62. package/dist/core/version-service.js +71 -0
  63. package/dist/core/wizard.d.ts +49 -0
  64. package/dist/core/wizard.js +71 -0
  65. package/dist/errors/errors.d.ts +34 -0
  66. package/dist/errors/errors.js +39 -0
  67. package/dist/errors/index.d.ts +1 -0
  68. package/dist/errors/index.js +1 -0
  69. package/dist/generator/cn.d.ts +5 -0
  70. package/dist/generator/cn.js +14 -0
  71. package/dist/generator/generate.d.ts +34 -0
  72. package/dist/generator/generate.js +562 -0
  73. package/dist/generator/theme-resolve.d.ts +26 -0
  74. package/dist/generator/theme-resolve.js +100 -0
  75. package/dist/mcp/server.d.ts +58 -0
  76. package/dist/mcp/server.js +176 -0
  77. package/dist/project/config.d.ts +74 -0
  78. package/dist/project/config.js +353 -0
  79. package/dist/project/detect.d.ts +26 -0
  80. package/dist/project/detect.js +104 -0
  81. package/dist/project/install-metadata.d.ts +29 -0
  82. package/dist/project/install-metadata.js +108 -0
  83. package/dist/project/install.d.ts +115 -0
  84. package/dist/project/install.js +537 -0
  85. package/dist/project/project-lock.d.ts +11 -0
  86. package/dist/project/project-lock.js +81 -0
  87. package/dist/project/tailwind.d.ts +51 -0
  88. package/dist/project/tailwind.js +188 -0
  89. package/dist/project/tar-gz.d.ts +12 -0
  90. package/dist/project/tar-gz.js +100 -0
  91. package/dist/tui/primitives.d.ts +36 -0
  92. package/dist/tui/primitives.js +88 -0
  93. package/dist/ui/banner.d.ts +11 -0
  94. package/dist/ui/banner.js +105 -0
  95. package/dist/ui/clack.d.ts +8 -0
  96. package/dist/ui/clack.js +53 -0
  97. package/dist/ui/create-ui.d.ts +14 -0
  98. package/dist/ui/create-ui.js +16 -0
  99. package/dist/ui/non-interactive.d.ts +5 -0
  100. package/dist/ui/non-interactive.js +30 -0
  101. package/dist/ui/stream.d.ts +11 -0
  102. package/dist/ui/stream.js +50 -0
  103. package/package.json +70 -0
@@ -0,0 +1,27 @@
1
+ const VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta))?$/;
2
+ export function parseVersion(value) {
3
+ const match = VERSION.exec(value);
4
+ if (!match)
5
+ return undefined;
6
+ return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]), channel: match[4] ?? "stable" };
7
+ }
8
+ export function decideUpdate(input) {
9
+ if (input.installedTier !== input.remoteTier)
10
+ return { kind: "refuse", reason: "tier-mismatch" };
11
+ const local = parseVersion(input.installedVersion);
12
+ const remote = parseVersion(input.remoteVersion);
13
+ if (!local || !remote)
14
+ return { kind: "refuse", reason: "invalid-version" };
15
+ if (local.channel !== remote.channel)
16
+ return { kind: "refuse", reason: "channel-mismatch" };
17
+ const comparison = remote.major - local.major || remote.minor - local.minor || remote.patch - local.patch;
18
+ if (comparison === 0)
19
+ return { kind: "current" };
20
+ return comparison > 0 ? { kind: "update" } : { kind: "refuse", reason: "downgrade" };
21
+ }
22
+ /** Recheck the downloaded candidate immediately before commit to prevent TOCTOU. */
23
+ export function verifyCandidateIdentity(expected, actual) {
24
+ return expected.tier === actual.tier && expected.version === actual.version &&
25
+ expected.descriptorSha256 === actual.descriptorSha256 && expected.artifactSha256 === actual.artifactSha256 &&
26
+ /^[a-f0-9]{64}$/.test(actual.descriptorSha256) && /^[a-f0-9]{64}$/.test(actual.artifactSha256);
27
+ }
@@ -0,0 +1,26 @@
1
+ export interface PublicTierVersion {
2
+ readonly version: string;
3
+ readonly releasedAt: string;
4
+ readonly descriptorSha256: string;
5
+ }
6
+ export interface PublicLibraryVersions {
7
+ readonly schemaVersion: 1;
8
+ readonly free: PublicTierVersion | null;
9
+ readonly pro: PublicTierVersion | null;
10
+ }
11
+ export declare function fetchLibraryVersions(deps?: {
12
+ fetch?: typeof fetch;
13
+ signal?: AbortSignal;
14
+ timeoutMs?: number;
15
+ }): Promise<PublicLibraryVersions>;
16
+ export declare function fetchMoeiconsVersions(deps?: {
17
+ fetch?: typeof fetch;
18
+ signal?: AbortSignal;
19
+ timeoutMs?: number;
20
+ }): Promise<readonly string[]>;
21
+ /** Keep the interactive startup check cheap when the wizard is opened repeatedly. */
22
+ export declare function fetchMoeiconsVersionsCached(deps?: {
23
+ signal?: AbortSignal;
24
+ timeoutMs?: number;
25
+ }): Promise<readonly string[]>;
26
+ export declare function latestInChannel(current: string, versions: readonly string[]): string | undefined;
@@ -0,0 +1,71 @@
1
+ import { CliError } from "../errors/index.js";
2
+ import { parseVersion } from "./update-policy.js";
3
+ const LIBRARY_VERSIONS_URL = "https://api.moeicons.com/v1/icon-library/versions";
4
+ const NPM_PACKAGE_URL = "https://registry.npmjs.org/@moewolf%2fmoe-icons-cli";
5
+ const SHA256 = /^[a-f0-9]{64}$/;
6
+ const CLI_VERSION_CACHE_TTL_MS = 5 * 60 * 1_000;
7
+ let cliVersionCache;
8
+ async function fixedFetch(url, fetchFn, signal, timeoutMs = 5_000) {
9
+ const controller = new AbortController();
10
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
11
+ const abort = () => controller.abort();
12
+ if (signal?.aborted)
13
+ controller.abort();
14
+ signal?.addEventListener("abort", abort, { once: true });
15
+ try {
16
+ return await fetchFn(url, { method: "GET", headers: { accept: "application/json" }, signal: controller.signal, redirect: "error" });
17
+ }
18
+ catch {
19
+ throw new CliError(signal?.aborted ? "CANCELLED" : "NETWORK_ERROR", signal?.aborted ? "version check cancelled" : "version check failed");
20
+ }
21
+ finally {
22
+ clearTimeout(timer);
23
+ signal?.removeEventListener("abort", abort);
24
+ }
25
+ }
26
+ function tier(value) {
27
+ if (value === null)
28
+ return null;
29
+ if (typeof value !== "object" || value === null || Array.isArray(value))
30
+ return undefined;
31
+ const item = value;
32
+ return typeof item.version === "string" && parseVersion(item.version) && typeof item.releasedAt === "string" &&
33
+ /^\d{4}-\d{2}-\d{2}T.*Z$/.test(item.releasedAt) && typeof item.descriptorSha256 === "string" && SHA256.test(item.descriptorSha256)
34
+ ? item : undefined;
35
+ }
36
+ export async function fetchLibraryVersions(deps = {}) {
37
+ const response = await fixedFetch(LIBRARY_VERSIONS_URL, deps.fetch ?? fetch, deps.signal, deps.timeoutMs);
38
+ if (!response.ok)
39
+ throw new CliError("NETWORK_ERROR", `version check failed with ${response.status}`);
40
+ const value = await response.json();
41
+ const free = tier(value.free);
42
+ const pro = tier(value.pro);
43
+ if (value.schemaVersion !== 1 || free === undefined || pro === undefined || Object.keys(value).some((key) => !["schemaVersion", "free", "pro"].includes(key))) {
44
+ throw new CliError("VALIDATION_ERROR", "invalid icon library versions response");
45
+ }
46
+ return { schemaVersion: 1, free, pro };
47
+ }
48
+ export async function fetchMoeiconsVersions(deps = {}) {
49
+ const response = await fixedFetch(NPM_PACKAGE_URL, deps.fetch ?? fetch, deps.signal, deps.timeoutMs);
50
+ if (!response.ok)
51
+ throw new CliError("NETWORK_ERROR", `CLI version check failed with ${response.status}`);
52
+ const value = await response.json();
53
+ if (typeof value.versions !== "object" || value.versions === null || Array.isArray(value.versions))
54
+ throw new CliError("VALIDATION_ERROR", "invalid npm package metadata");
55
+ return Object.keys(value.versions).filter((version) => parseVersion(version));
56
+ }
57
+ /** Keep the interactive startup check cheap when the wizard is opened repeatedly. */
58
+ export async function fetchMoeiconsVersionsCached(deps = {}) {
59
+ if (cliVersionCache && cliVersionCache.expiresAt > Date.now())
60
+ return cliVersionCache.versions;
61
+ const versions = await fetchMoeiconsVersions(deps);
62
+ cliVersionCache = { versions, expiresAt: Date.now() + CLI_VERSION_CACHE_TTL_MS };
63
+ return versions;
64
+ }
65
+ export function latestInChannel(current, versions) {
66
+ const parsed = parseVersion(current);
67
+ if (!parsed)
68
+ return undefined;
69
+ return versions.map((version) => ({ version, parsed: parseVersion(version) })).filter((item) => item.parsed?.channel === parsed.channel)
70
+ .sort((a, b) => (b.parsed.major - a.parsed.major) || (b.parsed.minor - a.parsed.minor) || (b.parsed.patch - a.parsed.patch))[0]?.version;
71
+ }
@@ -0,0 +1,49 @@
1
+ import type { CommandContext } from "./context.js";
2
+ export type WizardResult = {
3
+ readonly ok: true;
4
+ readonly action: "json-hint";
5
+ readonly message: string;
6
+ } | {
7
+ readonly ok: true;
8
+ readonly action: "install";
9
+ readonly group: "free" | "pro";
10
+ readonly target: "react" | "vue" | "vanilla" | "assets";
11
+ } | {
12
+ readonly ok: true;
13
+ readonly action: "pending";
14
+ readonly flow: "login";
15
+ } | {
16
+ readonly ok: true;
17
+ readonly action: "manage";
18
+ readonly flow: "reload" | "library-update";
19
+ } | {
20
+ readonly ok: true;
21
+ readonly action: "settings";
22
+ readonly flow: "logout" | "cli-update";
23
+ } | {
24
+ readonly ok: false;
25
+ readonly reason: "cancelled";
26
+ };
27
+ export type WizardSessionState = "authenticated" | "signed-out" | "unknown";
28
+ export declare function homeChoices(session: WizardSessionState): readonly [{
29
+ readonly value: "pro";
30
+ readonly label: "Install moeicons pro";
31
+ }, {
32
+ readonly value: "free";
33
+ readonly label: "Install moeicons free";
34
+ }, {
35
+ readonly value: "manage";
36
+ readonly label: "Manage project icons";
37
+ }, ...{
38
+ value: string;
39
+ label: string;
40
+ }[], {
41
+ readonly value: "settings";
42
+ readonly label: "Settings";
43
+ }];
44
+ /** Wizard state machine. No Clack/Commander/process imports. */
45
+ export declare function runWizardUseCase(context: CommandContext, options: {
46
+ readonly json: boolean;
47
+ readonly session?: WizardSessionState;
48
+ readonly getLibraryStatus?: () => Promise<string>;
49
+ }): Promise<WizardResult>;
@@ -0,0 +1,71 @@
1
+ import { detectProject } from "../project/detect.js";
2
+ import { CliError } from "../errors/index.js";
3
+ const JSON_HINT = "interactive wizard unavailable in JSON mode; use install/login/account/groups/generate";
4
+ export function homeChoices(session) {
5
+ return [
6
+ { value: "pro", label: "Install moeicons pro" },
7
+ { value: "free", label: "Install moeicons free" },
8
+ { value: "manage", label: "Manage project icons" },
9
+ ...(session === "authenticated"
10
+ ? []
11
+ : [
12
+ {
13
+ value: "login",
14
+ label: session === "unknown" ? "Login (current status unknown)" : "Login",
15
+ },
16
+ ]),
17
+ { value: "settings", label: "Settings" },
18
+ ];
19
+ }
20
+ /** Wizard state machine. No Clack/Commander/process imports. */
21
+ export async function runWizardUseCase(context, options) {
22
+ if (options.json) {
23
+ return { ok: true, action: "json-hint", message: JSON_HINT };
24
+ }
25
+ const choice = await context.ui.select("Choose an option", homeChoices(options.session ?? "signed-out"), context.signal);
26
+ if (choice === undefined)
27
+ return { ok: false, reason: "cancelled" };
28
+ if (choice === "login")
29
+ return { ok: true, action: "pending", flow: "login" };
30
+ if (choice === "settings") {
31
+ const setting = await context.ui.select("Settings", [
32
+ ...(options.session === "authenticated" ? [{ value: "logout", label: "Log out" }] : []),
33
+ { value: "cli-update", label: "Check for CLI updates" },
34
+ ], context.signal);
35
+ return setting === undefined
36
+ ? { ok: false, reason: "cancelled" }
37
+ : { ok: true, action: "settings", flow: setting };
38
+ }
39
+ const project = detectProject(context.cwd);
40
+ if (!project)
41
+ throw new CliError("VALIDATION_ERROR", "no package.json found in the current directory or parents; run inside a project");
42
+ if (choice === "manage") {
43
+ const status = await options.getLibraryStatus?.();
44
+ const management = await context.ui.select("Manage project icons", [
45
+ { value: "reload", label: "Update project resources" },
46
+ {
47
+ value: "library-update",
48
+ label: `Update icon library version${status ? ` — ${status}` : ""}`,
49
+ },
50
+ ], context.signal);
51
+ return management === undefined
52
+ ? { ok: false, reason: "cancelled" }
53
+ : { ok: true, action: "manage", flow: management };
54
+ }
55
+ if (choice === "free" || choice === "pro") {
56
+ const target = await context.ui.select("Choose an output target", [
57
+ { value: "react", label: "React" },
58
+ { value: "vue", label: "Vue" },
59
+ { value: "vanilla", label: "Vanilla" },
60
+ { value: "assets", label: "Static assets" },
61
+ ], context.signal);
62
+ if (target !== "react" && target !== "vue" && target !== "vanilla" && target !== "assets") {
63
+ return { ok: false, reason: "cancelled" };
64
+ }
65
+ const confirmed = await context.ui.confirm(`Install ${choice} ${target} into ${project.root}?`, context.signal);
66
+ if (confirmed !== true)
67
+ return { ok: false, reason: "cancelled" };
68
+ return { ok: true, action: "install", group: choice, target };
69
+ }
70
+ throw new CliError("VALIDATION_ERROR", `unknown wizard choice: ${choice}`);
71
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Stable error codes and exit-code mapping. CLI processes use exit codes:
3
+ * 0 success/cancel, 1 validation error, 2 auth error, 3 network error,
4
+ * 4 not found, 5 unexpected.
5
+ */
6
+ export type CliErrorCode = "HELP" | "VERSION" | "CANCELLED" | "VALIDATION_ERROR" | "TAILWIND_VERSION_UNSUPPORTED" | "AUTH_ERROR" | "NETWORK_ERROR" | "NOT_FOUND" | "FORBIDDEN" | "NOT_TTY" | "NOT_IMPLEMENTED" | "UNEXPECTED";
7
+ /** Frozen CliErrorCode → process exit code. Register new codes here before use. */
8
+ export declare const CLI_ERROR_EXIT_MAP: {
9
+ readonly HELP: 0;
10
+ readonly VERSION: 0;
11
+ readonly CANCELLED: 0;
12
+ readonly VALIDATION_ERROR: 1;
13
+ readonly TAILWIND_VERSION_UNSUPPORTED: 1;
14
+ readonly NOT_TTY: 1;
15
+ readonly NOT_IMPLEMENTED: 1;
16
+ readonly AUTH_ERROR: 2;
17
+ readonly FORBIDDEN: 2;
18
+ readonly NETWORK_ERROR: 3;
19
+ readonly NOT_FOUND: 4;
20
+ readonly UNEXPECTED: 5;
21
+ };
22
+ export type JsonErrorBody = {
23
+ readonly ok: false;
24
+ readonly code: CliErrorCode;
25
+ readonly message: string;
26
+ };
27
+ export declare class CliError extends Error {
28
+ readonly code: CliErrorCode;
29
+ readonly exitCode: number;
30
+ constructor(code: CliErrorCode, message: string);
31
+ }
32
+ export declare function exitCodeFor(code: CliErrorCode): number;
33
+ export declare function jsonErrorBody(code: CliErrorCode, message: string): JsonErrorBody;
34
+ export declare function isCliError(error: unknown): error is CliError;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Stable error codes and exit-code mapping. CLI processes use exit codes:
3
+ * 0 success/cancel, 1 validation error, 2 auth error, 3 network error,
4
+ * 4 not found, 5 unexpected.
5
+ */
6
+ /** Frozen CliErrorCode → process exit code. Register new codes here before use. */
7
+ export const CLI_ERROR_EXIT_MAP = {
8
+ HELP: 0,
9
+ VERSION: 0,
10
+ CANCELLED: 0,
11
+ VALIDATION_ERROR: 1,
12
+ TAILWIND_VERSION_UNSUPPORTED: 1,
13
+ NOT_TTY: 1,
14
+ NOT_IMPLEMENTED: 1,
15
+ AUTH_ERROR: 2,
16
+ FORBIDDEN: 2,
17
+ NETWORK_ERROR: 3,
18
+ NOT_FOUND: 4,
19
+ UNEXPECTED: 5,
20
+ };
21
+ export class CliError extends Error {
22
+ code;
23
+ exitCode;
24
+ constructor(code, message) {
25
+ super(message);
26
+ this.name = "CliError";
27
+ this.code = code;
28
+ this.exitCode = exitCodeFor(code);
29
+ }
30
+ }
31
+ export function exitCodeFor(code) {
32
+ return CLI_ERROR_EXIT_MAP[code];
33
+ }
34
+ export function jsonErrorBody(code, message) {
35
+ return { ok: false, code, message };
36
+ }
37
+ export function isCliError(error) {
38
+ return error instanceof CliError;
39
+ }
@@ -0,0 +1 @@
1
+ export * from "./errors.js";
@@ -0,0 +1 @@
1
+ export * from "./errors.js";
@@ -0,0 +1,5 @@
1
+ /** Generated helper text for user projects (H1/H2). Versions locked by CLI constants. */
2
+ export declare const CLSX_VERSION_RANGE = "^2.1.1";
3
+ export declare const TAILWIND_MERGE_VERSION_RANGE = "^2.5.2";
4
+ export declare const CN_HELPER_SOURCE = "// Generated by moeicons CLI. Do not edit manually; re-run `moeicons generate`.\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n";
5
+ export declare function sizeToTailwindClass(sizePx: number): string;
@@ -0,0 +1,14 @@
1
+ /** Generated helper text for user projects (H1/H2). Versions locked by CLI constants. */
2
+ export const CLSX_VERSION_RANGE = "^2.1.1";
3
+ export const TAILWIND_MERGE_VERSION_RANGE = "^2.5.2";
4
+ export const CN_HELPER_SOURCE = `// Generated by moeicons CLI. Do not edit manually; re-run \`moeicons generate\`.
5
+ import { clsx, type ClassValue } from "clsx";
6
+ import { twMerge } from "tailwind-merge";
7
+
8
+ export function cn(...inputs: ClassValue[]): string {
9
+ return twMerge(clsx(inputs));
10
+ }
11
+ `;
12
+ export function sizeToTailwindClass(sizePx) {
13
+ return `w-[${sizePx}px] h-[${sizePx}px]`;
14
+ }
@@ -0,0 +1,34 @@
1
+ import { type IconCatalog } from "../catalog/catalog.js";
2
+ import type { MoeiconsConfigFile } from "../project/config.js";
3
+ import { toLibraryExportName, toProxyName } from "../core/icon-names.js";
4
+ export { toLibraryExportName, toProxyName };
5
+ /** @deprecated Use toProxyName; kept so existing generator tests keep compiling. */
6
+ export declare const toPascalCase: typeof toProxyName;
7
+ /**
8
+ * React/Vue proxy generation. Purely returns owned file paths/content for
9
+ * types, registry, provider/plugin, proxies and barrel exports. Rejects
10
+ * duplicate PascalCase names and missing fallback. Bitmap themes use local
11
+ * img wrappers + static asset imports (G1/G4); SVG themes import moe-icons.
12
+ */
13
+ export interface GeneratedFile {
14
+ readonly path: string;
15
+ readonly content: string | Uint8Array;
16
+ }
17
+ export interface GenerationResult {
18
+ readonly ok: true;
19
+ readonly files: GeneratedFile[];
20
+ }
21
+ export interface GenerationError {
22
+ readonly ok: false;
23
+ readonly errors: string[];
24
+ }
25
+ export type GenerationOutcome = GenerationResult | GenerationError;
26
+ /**
27
+ * Plan generated files for a config. Returns only owned paths under the config
28
+ * output dir. Rejects duplicate PascalCase names and a config with no themes.
29
+ * Theme keys stay logical style themes; bitmap resourceVariantId never becomes a theme.
30
+ */
31
+ export declare function planGeneratedFiles(config: MoeiconsConfigFile, outputDir: string, options?: {
32
+ readonly archiveFiles?: Readonly<Record<string, Uint8Array>>;
33
+ readonly catalog?: IconCatalog;
34
+ }): GenerationOutcome;