@fluid-app/fluid-cli-widget 0.1.24 → 0.1.25

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/README.md CHANGED
@@ -16,7 +16,7 @@ fluid widget status
16
16
  fluid widget logs
17
17
  ```
18
18
 
19
- - `fluid widget create <project-name>` — scaffold a standalone widget package project.
19
+ - `fluid widget create <project-name>` — scaffold a standalone worker-only widget package from the bundled canonical template. Pass `--remote-template` only to opt into the GitHub mirror, or `--skip-install` for scaffold-only output.
20
20
  - `fluid widget link` — link the current project to an existing Droplet and package name.
21
21
  - `pnpm dev` — run the generated project's local Remote DOM development endpoints.
22
22
  - `fluid widget build` — validate and build runtime artifacts into `.fluid/widget-dist`.
package/dist/index.d.mts CHANGED
@@ -21,11 +21,8 @@ interface WidgetCreateOptions {
21
21
  readonly droplet?: string;
22
22
  /** Initial widget package version written into manifest.ts. */
23
23
  readonly packageVersion?: string;
24
- /**
25
- * Skip pulling the GitHub starter template and use the CLI's bundled
26
- * template instead. Implied by `--local`. Useful offline or in tests.
27
- */
28
- readonly skipRemoteTemplate?: boolean;
24
+ /** Explicitly use the GitHub starter instead of the bundled template. */
25
+ readonly remoteTemplate?: boolean;
29
26
  }
30
27
  interface WidgetLinkOptions {
31
28
  readonly droplet?: string;
@@ -60,9 +57,35 @@ interface CloneCommandOptions {
60
57
  }
61
58
  declare const cloneCommand: Command;
62
59
  //#endregion
60
+ //#region src/utils/package-manager.d.ts
61
+ declare function installDependencies(cwd: string): Promise<void>;
62
+ //#endregion
63
+ //#region src/utils/github-template.d.ts
64
+ interface GithubTemplateVariables {
65
+ readonly projectName: string;
66
+ readonly widgetScope: string;
67
+ readonly widgetPackageVersion: string;
68
+ }
69
+ /**
70
+ * Clone the GitHub widget template into `targetPath`, strip its git history,
71
+ * and rewrite the baked defaults to the user's values. The repo holds a fully
72
+ * rendered project (no `{{placeholders}}`), so we do targeted, deterministic
73
+ * replacements of the known defaults rather than template interpolation.
74
+ *
75
+ * Returns true on success. Returns false (never throws) when the template
76
+ * couldn't be fetched — git missing, offline, repo unavailable. The caller
77
+ * reports that requested-template failure. The partially-cloned target is
78
+ * cleaned up before returning false.
79
+ */
80
+ declare function tryFetchGithubTemplate(targetPath: string, variables: GithubTemplateVariables): Promise<boolean>;
81
+ //#endregion
63
82
  //#region src/commands/create.d.ts
83
+ interface CreateWidgetProjectDependencies {
84
+ readonly installDependencies: typeof installDependencies;
85
+ readonly tryFetchGithubTemplate: typeof tryFetchGithubTemplate;
86
+ }
64
87
  declare const createCommand: Command;
65
- declare function createWidgetProject(projectName: string, options: WidgetCreateOptions): Promise<void>;
88
+ declare function createWidgetProject(projectName: string, options: WidgetCreateOptions, dependencies?: CreateWidgetProjectDependencies): Promise<void>;
66
89
  //#endregion
67
90
  //#region src/commands/push.d.ts
68
91
  interface PushCommandOptions {
@@ -209,5 +232,5 @@ declare function formatValidationErrors(errors: readonly WidgetCliValidationErro
209
232
  declare const widgetCommand: Command;
210
233
  declare const plugin: FluidPlugin;
211
234
  //#endregion
212
- export { type BuildWidgetOptions, type BuildWidgetPackageOptions, type BuildWidgetPackageResult, type CloneCommandOptions, DEFAULT_WIDGET_DEV_PORT, DEFAULT_WIDGET_OUT_DIR, type FluidWidgetConfig, type LoadedWidgetConfig, type LogsCommandOptions, type PublishCommandOptions, type PublishWidgetPackageDependencies, type PublishWidgetPackageOptions, type PublishWidgetPackageResult, type PushCommandOptions, ROOT_WIDGET_CONFIG_FILE, type StatusCommandOptions, type ValidateWidgetOptions, WIDGET_CONFIG_FILE, WIDGET_DEV_ROUTES, type WidgetCliValidationError, type WidgetCommandOptions, type WidgetCreateOptions, type WidgetDevOptions, type WidgetDevProjectSummary, type WidgetLinkOptions, type WidgetTemplateVariables, WidgetValidationError, type WidgetValidationResult, buildCommand, buildViteDevArgs, buildWidgetPackage, cloneCommand, createCommand, createWidgetProject, plugin as default, devCommand, formatValidationErrors, formatValidationSuccess, formatWidgetConfig, linkCommand, loadWidgetConfig, logsCommand, mergeWidgetConfig, parseWidgetConfigSource, printWidgetDevSummary, publishCommand, publishWidgetPackage, pushCommand, resolveWidgetConfigPath, resolveWidgetDevProject, resolveWidgetSourceConfig, runViteDevServer, statusCommand, validateCommand, validateDropletUuid, validateDropletWidgetProject, widgetCommand, withRootWidgetConfigBridge, writeWidgetConfig };
235
+ export { type BuildWidgetOptions, type BuildWidgetPackageOptions, type BuildWidgetPackageResult, type CloneCommandOptions, type CreateWidgetProjectDependencies, DEFAULT_WIDGET_DEV_PORT, DEFAULT_WIDGET_OUT_DIR, type FluidWidgetConfig, type LoadedWidgetConfig, type LogsCommandOptions, type PublishCommandOptions, type PublishWidgetPackageDependencies, type PublishWidgetPackageOptions, type PublishWidgetPackageResult, type PushCommandOptions, ROOT_WIDGET_CONFIG_FILE, type StatusCommandOptions, type ValidateWidgetOptions, WIDGET_CONFIG_FILE, WIDGET_DEV_ROUTES, type WidgetCliValidationError, type WidgetCommandOptions, type WidgetCreateOptions, type WidgetDevOptions, type WidgetDevProjectSummary, type WidgetLinkOptions, type WidgetTemplateVariables, WidgetValidationError, type WidgetValidationResult, buildCommand, buildViteDevArgs, buildWidgetPackage, cloneCommand, createCommand, createWidgetProject, plugin as default, devCommand, formatValidationErrors, formatValidationSuccess, formatWidgetConfig, linkCommand, loadWidgetConfig, logsCommand, mergeWidgetConfig, parseWidgetConfigSource, printWidgetDevSummary, publishCommand, publishWidgetPackage, pushCommand, resolveWidgetConfigPath, resolveWidgetDevProject, resolveWidgetSourceConfig, runViteDevServer, statusCommand, validateCommand, validateDropletUuid, validateDropletWidgetProject, widgetCommand, withRootWidgetConfigBridge, writeWidgetConfig };
213
236
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/commands/build.ts","../src/commands/clone.ts","../src/commands/create.ts","../src/commands/push.ts","../src/commands/dev.ts","../src/commands/link.ts","../src/commands/logs.ts","../src/commands/publish.ts","../src/commands/status.ts","../src/commands/validate.ts","../src/utils/config.ts","../src/utils/source-package.ts","../src/utils/validation.ts","../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/commands/build.ts","../src/commands/clone.ts","../src/utils/package-manager.ts","../src/utils/github-template.ts","../src/commands/create.ts","../src/commands/push.ts","../src/commands/dev.ts","../src/commands/link.ts","../src/commands/logs.ts","../src/commands/publish.ts","../src/commands/status.ts","../src/commands/validate.ts","../src/utils/config.ts","../src/utils/source-package.ts","../src/utils/validation.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1237,6 +1237,9 @@ const cloneCommand = new Command("clone").description("Clone a widget package's
1237
1237
  }));
1238
1238
  //#endregion
1239
1239
  //#region src/utils/template.ts
1240
+ const EMBEDDED_PORTAL_SDK_VERSION = "0.1.460";
1241
+ const EMBEDDED_CLI_CORE_VERSION = "0.1.14";
1242
+ const EMBEDDED_CLI_WIDGET_VERSION = "0.1.25";
1240
1243
  function getDefaultTemplatePath() {
1241
1244
  return path.join(findPackageRoot(), "templates", "default");
1242
1245
  }
@@ -1259,27 +1262,32 @@ async function copyWidgetTemplate(templatePath, targetPath, variables) {
1259
1262
  for (const skillFile of await getSharedTemplateSkillFiles()) await writeOutputFiles(targetPath, getOutputFilenames(skillFile.relativePath), skillFile.content);
1260
1263
  }
1261
1264
  async function getPortalSdkVersion(options = {}) {
1262
- return getWorkspacePackageVersion(["portal", "sdk"], "^0.1.0", options);
1265
+ return getWorkspacePackageVersion(["portal", "sdk"], EMBEDDED_PORTAL_SDK_VERSION, options);
1263
1266
  }
1264
1267
  async function getPortalCoreVersion(options = {}) {
1265
- return getWorkspacePackageVersion(["portal", "core"], "^0.1.0", options);
1268
+ return getWorkspacePackageVersion(["portal", "core"], void 0, options);
1266
1269
  }
1267
1270
  async function getCliVersion(options = {}) {
1268
- return getWorkspacePackageVersion(["cli", "core"], "^0.1.0", options);
1271
+ return getWorkspacePackageVersion(["cli", "core"], EMBEDDED_CLI_CORE_VERSION, options);
1269
1272
  }
1270
1273
  async function getWidgetCliVersion(options = {}) {
1271
- return getWorkspacePackageVersion(["cli", "widget"], "^0.1.0", options);
1274
+ return getWorkspacePackageVersion(["cli", "widget"], EMBEDDED_CLI_WIDGET_VERSION, options);
1272
1275
  }
1273
- async function getWorkspacePackageVersion(packagePathSegments, fallback, options) {
1276
+ async function getWorkspacePackageVersion(packagePathSegments, embeddedVersion, options) {
1274
1277
  try {
1275
1278
  const packageRoot = findPackageRoot();
1276
1279
  const packagesRoot = path.join(packageRoot, "..", "..");
1277
1280
  const targetPackageRoot = path.join(packagesRoot, ...packagePathSegments);
1278
1281
  if (options.local) return `link:${(options.targetPath ? path.relative(options.targetPath, targetPackageRoot) : targetPackageRoot).replace(/\\/g, "/") || "."}`;
1279
- const content = await readFile(path.join(targetPackageRoot, "package.json"), "utf-8");
1280
- return `^${JSON.parse(content).version ?? fallback.replace(/^\^/, "")}`;
1281
- } catch {
1282
- return fallback;
1282
+ if (embeddedVersion) return embeddedVersion;
1283
+ const packageJsonPath = path.join(targetPackageRoot, "package.json");
1284
+ const content = await readFile(packageJsonPath, "utf-8");
1285
+ const pkg = JSON.parse(content);
1286
+ if (typeof pkg.version !== "string") throw new Error(`Missing version in ${packageJsonPath}`);
1287
+ return pkg.version;
1288
+ } catch (error) {
1289
+ if (embeddedVersion) return embeddedVersion;
1290
+ throw new Error(`Could not resolve the exact template package version for ${packagePathSegments.join("/")}`, { cause: error });
1283
1291
  }
1284
1292
  }
1285
1293
  async function getFiles(dir, baseDir = dir) {
@@ -1384,8 +1392,8 @@ const TEMPLATE_DEFAULTS = {
1384
1392
  * replacements of the known defaults rather than template interpolation.
1385
1393
  *
1386
1394
  * Returns true on success. Returns false (never throws) when the template
1387
- * couldn't be fetched — git missing, offline, repo unavailable — so `create`
1388
- * can fall back to the bundled template. The partially-cloned target is
1395
+ * couldn't be fetched — git missing, offline, repo unavailable. The caller
1396
+ * reports that requested-template failure. The partially-cloned target is
1389
1397
  * cleaned up before returning false.
1390
1398
  */
1391
1399
  async function tryFetchGithubTemplate(targetPath, variables) {
@@ -1453,7 +1461,11 @@ async function replaceInFile(filePath, replacements) {
1453
1461
  //#region src/commands/create.ts
1454
1462
  const DEFAULT_WIDGET_PACKAGE_VERSION = "0.1.0";
1455
1463
  const DEFAULT_WIDGET_SCOPE = "droplet";
1456
- const createCommand = new Command("create").description("Create a standalone Fluid widget project").argument("<project-name>", "Name of the widget project to create").option("--skip-install", "Skip dependency installation").option("-o, --output-dir <dir>", "Directory to create the project in (defaults to cwd)").option("--scope <scope>", "Widget package scope/namespace", DEFAULT_WIDGET_SCOPE).option("--package-version <version>", "Initial widget package version", DEFAULT_WIDGET_PACKAGE_VERSION).option("--local", "Use local monorepo packages via file: links (for development testing)").option("--skip-remote-template", "Use the bundled template instead of pulling the GitHub starter template").option("--droplet <uuid>", "Existing droplet UUID that owns the package").action(async (projectName, options) => {
1464
+ const defaultCreateWidgetProjectDependencies = {
1465
+ installDependencies,
1466
+ tryFetchGithubTemplate
1467
+ };
1468
+ const createCommand = new Command("create").description("Create a standalone Fluid widget project").argument("<project-name>", "Name of the widget project to create").option("--skip-install", "Create the scaffold only; skip dependency installation").option("-o, --output-dir <dir>", "Directory to create the project in (defaults to cwd)").option("--scope <scope>", "Widget package scope/namespace", DEFAULT_WIDGET_SCOPE).option("--package-version <version>", "Initial widget package version", DEFAULT_WIDGET_PACKAGE_VERSION).option("--local", "Use local monorepo packages via file: links (for development testing)").option("--remote-template", "Use the GitHub starter template instead of the bundled template").option("--droplet <uuid>", "Existing droplet UUID that owns the package").action(async (projectName, options) => {
1457
1469
  try {
1458
1470
  await createWidgetProject(projectName, options);
1459
1471
  } catch (err) {
@@ -1463,7 +1475,7 @@ const createCommand = new Command("create").description("Create a standalone Flu
1463
1475
  process.exit(1);
1464
1476
  }
1465
1477
  });
1466
- async function createWidgetProject(projectName, options) {
1478
+ async function createWidgetProject(projectName, options, dependencies = defaultCreateWidgetProjectDependencies) {
1467
1479
  console.log();
1468
1480
  console.log(chalk.bold("Creating a new Fluid widget project"));
1469
1481
  console.log();
@@ -1478,7 +1490,7 @@ async function createWidgetProject(projectName, options) {
1478
1490
  const targetPath = path.join(outputDir, projectName);
1479
1491
  if (await directoryExists(targetPath)) throw new Error(`Directory already exists: ${targetPath}`);
1480
1492
  const templatePath = getDefaultTemplatePath();
1481
- if (!await directoryExists(templatePath)) throw new Error("Default widget template not found.");
1493
+ if (options.remoteTemplate !== true && !await directoryExists(templatePath)) throw new Error("Default widget template not found.");
1482
1494
  const config = mergeWidgetConfig({}, { droplet });
1483
1495
  const widgetScope = options.scope ?? DEFAULT_WIDGET_SCOPE;
1484
1496
  const localOptions = {
@@ -1495,17 +1507,21 @@ async function createWidgetProject(projectName, options) {
1495
1507
  fluidCliVersion: await getCliVersion(localOptions),
1496
1508
  widgetCliVersion: await getWidgetCliVersion(localOptions)
1497
1509
  };
1498
- const useRemoteTemplate = options.local !== true && options.skipRemoteTemplate !== true;
1510
+ if (options.local === true && options.remoteTemplate === true) throw new Error("--remote-template cannot be combined with --local");
1511
+ const useRemoteTemplate = options.remoteTemplate === true;
1499
1512
  let scaffolded = false;
1500
1513
  if (useRemoteTemplate) {
1501
1514
  const remoteSpinner = ora("Fetching widget template from GitHub...").start();
1502
- scaffolded = await tryFetchGithubTemplate(targetPath, {
1515
+ scaffolded = await dependencies.tryFetchGithubTemplate(targetPath, {
1503
1516
  projectName,
1504
1517
  widgetScope,
1505
1518
  widgetPackageVersion: options.packageVersion ?? DEFAULT_WIDGET_PACKAGE_VERSION
1506
1519
  });
1507
1520
  if (scaffolded) remoteSpinner.succeed("Fetched widget template from GitHub");
1508
- else remoteSpinner.warn("Couldn't fetch the GitHub template (git, network, or repo unavailable) — using the bundled template.");
1521
+ else {
1522
+ remoteSpinner.fail("Failed to fetch the GitHub widget template");
1523
+ throw new Error("Couldn't fetch the requested GitHub template. Remove --remote-template to use the bundled template.");
1524
+ }
1509
1525
  }
1510
1526
  const spinner = ora(scaffolded ? "Finalizing widget project..." : "Copying widget template...").start();
1511
1527
  try {
@@ -1520,17 +1536,23 @@ async function createWidgetProject(projectName, options) {
1520
1536
  if (options.skipInstall !== true) {
1521
1537
  spinner.start(`Installing dependencies with ${installCommand}...`);
1522
1538
  try {
1523
- await installDependencies(targetPath);
1539
+ await dependencies.installDependencies(targetPath);
1524
1540
  spinner.succeed("Installed dependencies");
1525
- } catch {
1541
+ } catch (error) {
1526
1542
  spinner.fail("Failed to install dependencies");
1527
1543
  console.log();
1528
- console.log(chalk.yellow("You can install dependencies manually:"));
1544
+ console.log(chalk.yellow(`The scaffold was retained at ${targetPath}.`));
1545
+ console.log(chalk.yellow("Install dependencies manually to continue:"));
1529
1546
  console.log(chalk.cyan(` cd ${formatCdPath(targetPath)}`));
1530
1547
  console.log(chalk.cyan(` ${installCommand}`));
1548
+ throw error;
1531
1549
  }
1532
1550
  }
1533
1551
  console.log();
1552
+ if (options.skipInstall === true) {
1553
+ console.log(chalk.yellow("Scaffold only: dependencies were not installed and must be installed before development."));
1554
+ console.log();
1555
+ }
1534
1556
  console.log(chalk.green.bold("Success!") + ` Created ${chalk.cyan(projectName)}`);
1535
1557
  console.log();
1536
1558
  console.log("Next steps:");
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["isNodeError","isRecord","isRecord","readPackageJson","isRecord","isRecord","isRecord","resolveDroplet"],"sources":["../src/utils/config.ts","../src/utils/validation.ts","../src/utils/source-package.ts","../src/utils/command.ts","../src/utils/package-manager.ts","../src/utils/package-scripts.ts","../src/commands/build.ts","../src/lib/git.ts","../src/utils/git-credential.ts","../src/utils/widget-marker.ts","../src/commands/clone.ts","../src/utils/template.ts","../src/utils/github-template.ts","../src/commands/create.ts","../src/commands/dev.ts","../src/utils/auth-client.ts","../src/utils/droplets.ts","../src/commands/link.ts","../src/utils/droplet-api.ts","../src/commands/logs.ts","../src/commands/publish.ts","../src/utils/me.ts","../src/lib/git-sync.ts","../src/commands/push.ts","../src/commands/status.ts","../src/commands/validate.ts","../src/index.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport const WIDGET_CONFIG_FILE = \"fluid.widget.config.ts\";\n\nexport interface FluidWidgetConfig {\n readonly droplet?: string;\n}\n\nexport interface LoadedWidgetConfig {\n readonly path: string;\n readonly config: Partial<FluidWidgetConfig>;\n}\n\nexport class WidgetConfigParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WidgetConfigParseError\";\n }\n}\n\nexport function resolveWidgetConfigPath(projectDir: string): string {\n return path.join(projectDir, WIDGET_CONFIG_FILE);\n}\n\nexport async function loadWidgetConfig(\n projectDir: string,\n): Promise<LoadedWidgetConfig> {\n const configPath = resolveWidgetConfigPath(projectDir);\n\n let source: string;\n try {\n source = await readFile(configPath, \"utf-8\");\n } catch (err) {\n if (isNodeError(err) && err.code === \"ENOENT\") {\n return { path: configPath, config: {} };\n }\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Unable to read ${WIDGET_CONFIG_FILE}: ${message}`);\n }\n\n return { path: configPath, config: parseWidgetConfigSource(source) };\n}\n\nexport async function writeWidgetConfig(\n projectDir: string,\n config: FluidWidgetConfig,\n): Promise<void> {\n await writeFile(\n resolveWidgetConfigPath(projectDir),\n formatWidgetConfig(config),\n \"utf-8\",\n );\n}\n\nexport function formatWidgetConfig(config: FluidWidgetConfig): string {\n const lines = [\n 'import type { FluidWidgetConfig } from \"@fluid-app/fluid-cli-widget\";',\n 'import { widgetPackage as sourceWidgetPackage } from \"./manifest\";',\n \"\",\n \"const config = {\",\n ];\n\n if (config.droplet) {\n lines.push(` droplet: ${JSON.stringify(config.droplet)},`);\n }\n\n lines.push(\n \"} satisfies FluidWidgetConfig;\",\n \"\",\n \"const widgetConfig: FluidWidgetConfig = config;\",\n \"const packageStableId = widgetConfig.droplet;\",\n \"\",\n \"export const widgetPackage = packageStableId\",\n \" ? {\",\n \" ...sourceWidgetPackage,\",\n \" packageStableId,\",\n \" packageId: `${sourceWidgetPackage.scope}.${packageStableId}` as const,\",\n \" }\",\n \" : sourceWidgetPackage;\",\n \"export const widgetPackages = [widgetPackage] as const;\",\n \"\",\n \"export default config;\",\n \"export const droplet = widgetConfig.droplet;\",\n \"\",\n );\n return lines.join(\"\\n\");\n}\n\nexport function parseWidgetConfigSource(\n source: string,\n): Partial<FluidWidgetConfig> {\n const objectSource = extractConfigObjectLiteral(source);\n const config = parseConfigObjectProperties(objectSource);\n\n return config;\n}\n\nexport function mergeWidgetConfig(\n current: Partial<FluidWidgetConfig>,\n updates: Partial<FluidWidgetConfig>,\n): FluidWidgetConfig {\n const droplet =\n normalizeOptionalString(updates.droplet) ??\n normalizeOptionalString(current.droplet);\n\n return droplet ? { droplet } : {};\n}\n\nexport function validateDropletUuid(dropletUuid: string): string | undefined {\n if (!dropletUuid) return \"Droplet UUID is required.\";\n if (dropletUuid.length > MAX_DROPLET_UUID_LENGTH) {\n return `Droplet UUID must be ${MAX_DROPLET_UUID_LENGTH} characters or fewer.`;\n }\n if (!URL_SAFE_IDENTIFIER_PATTERN.test(dropletUuid)) {\n return (\n \"Droplet UUID must be URL-safe text: letters, numbers, \" +\n \"'_', '~', and '-' only.\"\n );\n }\n return undefined;\n}\n\nfunction extractConfigObjectLiteral(source: string): string {\n const configStart = /\\bconst\\s+config\\s*=\\s*\\{/.exec(source);\n if (!configStart) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} must declare \\`const config = { ... } satisfies FluidWidgetConfig\\`.`,\n );\n }\n\n const openBraceIndex = source.indexOf(\"{\", configStart.index);\n const closeBraceIndex = findMatchingBrace(source, openBraceIndex);\n const suffix = stripComments(source.slice(closeBraceIndex + 1));\n if (!/^\\s*(?:as\\s+const\\s+)?satisfies\\s+FluidWidgetConfig\\s*;/.test(suffix)) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} config object must use \\`satisfies FluidWidgetConfig\\` or \\`as const satisfies FluidWidgetConfig\\`.`,\n );\n }\n\n return stripComments(source.slice(openBraceIndex + 1, closeBraceIndex));\n}\n\nfunction parseConfigObjectProperties(\n objectSource: string,\n): Partial<FluidWidgetConfig> {\n const config: { droplet?: string } = {};\n\n for (const member of splitTopLevelMembers(objectSource)) {\n const trimmedMember = member.trim();\n if (!trimmedMember) continue;\n\n const propertyMatch = /^(droplet)\\s*:\\s*([\\s\\S]+)$/.exec(trimmedMember);\n if (!propertyMatch) {\n const propertyName = /^([A-Za-z_$][\\w$]*)\\s*:/.exec(trimmedMember)?.[1];\n throw new WidgetConfigParseError(\n propertyName\n ? `${WIDGET_CONFIG_FILE} does not support config field ${propertyName}. Supported field is droplet.`\n : `${WIDGET_CONFIG_FILE} config fields must use optional droplet: \"...\" string literal.`,\n );\n }\n\n const propertyName = propertyMatch[1];\n if (propertyName !== \"droplet\") {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} config field could not be parsed.`,\n );\n }\n const valueSource = propertyMatch[2]?.trim() ?? \"\";\n const value = parseStringLiteralValue(valueSource, propertyName);\n if (!value.trim()) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} field ${propertyName} must be a non-empty string literal.`,\n );\n }\n\n if (config.droplet !== undefined) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} field droplet must only be declared once.`,\n );\n }\n config.droplet = value;\n }\n\n return config;\n}\n\nfunction parseStringLiteralValue(\n valueSource: string,\n propertyName: string,\n): string {\n if (valueSource.startsWith('\"') && valueSource.endsWith('\"')) {\n try {\n const parsed = JSON.parse(valueSource) as unknown;\n if (typeof parsed === \"string\") return parsed;\n } catch {\n // Fall through to the actionable error below.\n }\n }\n\n if (valueSource.startsWith(\"'\") && valueSource.endsWith(\"'\")) {\n return parseSingleQuotedStringLiteral(valueSource);\n }\n\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} field ${propertyName} must be a string literal (for example ${propertyName}: \"value\").`,\n );\n}\n\nfunction parseSingleQuotedStringLiteral(valueSource: string): string {\n let value = \"\";\n\n for (let index = 1; index < valueSource.length - 1; index += 1) {\n const char = valueSource[index];\n if (char !== \"\\\\\") {\n value += char;\n continue;\n }\n\n index += 1;\n const escaped = valueSource[index];\n switch (escaped) {\n case \"\\\\\":\n case \"'\":\n case '\"':\n value += escaped;\n break;\n case \"n\":\n value += \"\\n\";\n break;\n case \"r\":\n value += \"\\r\";\n break;\n case \"t\":\n value += \"\\t\";\n break;\n case \"b\":\n value += \"\\b\";\n break;\n case \"f\":\n value += \"\\f\";\n break;\n case \"v\":\n value += \"\\v\";\n break;\n default:\n value += escaped ?? \"\";\n break;\n }\n }\n\n return value;\n}\n\nfunction stripComments(source: string): string {\n let result = \"\";\n let stringQuote: '\"' | \"'\" | \"`\" | undefined;\n let escaped = false;\n let lineComment = false;\n let blockComment = false;\n\n for (let index = 0; index < source.length; index += 1) {\n const char = source[index];\n const nextChar = source[index + 1];\n\n if (lineComment) {\n if (char === \"\\n\" || char === \"\\r\") {\n lineComment = false;\n result += char;\n } else {\n result += \" \";\n }\n continue;\n }\n\n if (blockComment) {\n if (char === \"*\" && nextChar === \"/\") {\n blockComment = false;\n result += \" \";\n index += 1;\n } else if (char === \"\\n\" || char === \"\\r\") {\n result += char;\n } else {\n result += \" \";\n }\n continue;\n }\n\n if (stringQuote) {\n result += char;\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === stringQuote) {\n stringQuote = undefined;\n }\n continue;\n }\n\n if (char === \"/\" && nextChar === \"/\") {\n lineComment = true;\n result += \" \";\n index += 1;\n continue;\n }\n\n if (char === \"/\" && nextChar === \"*\") {\n blockComment = true;\n result += \" \";\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n stringQuote = char;\n }\n result += char;\n }\n\n return result;\n}\n\nfunction splitTopLevelMembers(objectSource: string): string[] {\n const members: string[] = [];\n let memberStart = 0;\n let stringQuote: '\"' | \"'\" | \"`\" | undefined;\n let escaped = false;\n let nestedDepth = 0;\n\n for (let index = 0; index < objectSource.length; index += 1) {\n const char = objectSource[index];\n\n if (stringQuote) {\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === stringQuote) {\n stringQuote = undefined;\n }\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n stringQuote = char;\n continue;\n }\n\n if (char === \"{\" || char === \"[\" || char === \"(\") {\n nestedDepth += 1;\n continue;\n }\n if (char === \"}\" || char === \"]\" || char === \")\") {\n nestedDepth -= 1;\n continue;\n }\n\n if (char === \",\" && nestedDepth === 0) {\n members.push(objectSource.slice(memberStart, index));\n memberStart = index + 1;\n }\n }\n\n members.push(objectSource.slice(memberStart));\n return members;\n}\n\nfunction findMatchingBrace(source: string, openBraceIndex: number): number {\n let depth = 0;\n let stringQuote: '\"' | \"'\" | \"`\" | undefined;\n let escaped = false;\n let lineComment = false;\n let blockComment = false;\n\n for (let index = openBraceIndex; index < source.length; index += 1) {\n const char = source[index];\n const nextChar = source[index + 1];\n\n if (lineComment) {\n if (char === \"\\n\" || char === \"\\r\") lineComment = false;\n continue;\n }\n\n if (blockComment) {\n if (char === \"*\" && nextChar === \"/\") {\n blockComment = false;\n index += 1;\n }\n continue;\n }\n\n if (stringQuote) {\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === stringQuote) {\n stringQuote = undefined;\n }\n continue;\n }\n\n if (char === \"/\" && nextChar === \"/\") {\n lineComment = true;\n index += 1;\n continue;\n }\n\n if (char === \"/\" && nextChar === \"*\") {\n blockComment = true;\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n stringQuote = char;\n continue;\n }\n\n if (char === \"{\") depth += 1;\n if (char === \"}\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} config object is missing a closing brace.`,\n );\n}\n\nfunction normalizeOptionalString(\n value: string | undefined,\n): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\ninterface NodeError extends Error {\n readonly code?: string;\n}\n\nfunction isNodeError(error: unknown): error is NodeError {\n return error instanceof Error && \"code\" in error;\n}\n\nconst MAX_DROPLET_UUID_LENGTH = 256;\nconst URL_SAFE_SEGMENT_SOURCE = \"[A-Za-z0-9][A-Za-z0-9_~-]*\";\nconst URL_SAFE_IDENTIFIER_PATTERN = new RegExp(`^${URL_SAFE_SEGMENT_SOURCE}$`);\n","export interface WidgetCliValidationError {\n readonly path?: string;\n readonly message: string;\n}\n\nexport function formatValidationErrors(\n errors: readonly WidgetCliValidationError[],\n): string {\n if (errors.length === 0) return \"Validation failed.\";\n\n return [\n \"Validation failed:\",\n ...errors.map((error) => {\n const location = error.path ? `${error.path}: ` : \"\";\n return ` - ${location}${error.message}`;\n }),\n ].join(\"\\n\");\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, rm, rmdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n loadSourceWidgetPackages,\n validateSingleSourceWidgetPackage,\n} from \"@fluid-app/fluid-cli-portal\";\nimport {\n WIDGET_CONFIG_FILE,\n loadWidgetConfig,\n validateDropletUuid,\n} from \"./config.js\";\nimport type {\n ValidatedWidgetPackageBuild,\n WidgetPackageValidationError,\n} from \"@fluid-app/fluid-cli-portal\";\nimport { formatValidationErrors } from \"./validation.js\";\n\nexport const DEFAULT_WIDGET_OUT_DIR = \".fluid/widget-dist\";\nexport const ROOT_WIDGET_CONFIG_FILE: string = WIDGET_CONFIG_FILE;\n\nconst SOURCE_CONFIG_CANDIDATES = [\n \"src/widgets.config.ts\",\n \"src/portal.config.ts\",\n \"portal.config.ts\",\n] as const;\n\nexport interface WidgetValidationResult {\n readonly projectDir: string;\n readonly sourceConfigPath?: string;\n readonly validated: ValidatedWidgetPackageBuild;\n}\n\nexport class WidgetValidationError extends Error {\n public readonly errors: readonly WidgetPackageValidationError[];\n\n constructor(errors: readonly WidgetPackageValidationError[]) {\n super(formatValidationErrors(errors));\n this.name = \"WidgetValidationError\";\n this.errors = errors;\n }\n}\n\nexport async function validateDropletWidgetProject(\n projectDir: string,\n packageKeyOverride?: string,\n): Promise<WidgetValidationResult> {\n const resolvedProjectDir = path.resolve(projectDir);\n const sourceConfig = resolveWidgetSourceConfig(resolvedProjectDir);\n if (!sourceConfig) {\n throw new WidgetValidationError([\n {\n code: \"NO_SOURCE_PACKAGE\",\n path: ROOT_WIDGET_CONFIG_FILE,\n message:\n `No widget package config found. Create ${ROOT_WIDGET_CONFIG_FILE} ` +\n \"or src/widgets.config.ts that exports defineWidgetPackage(...).\",\n },\n ]);\n }\n\n const configErrors = await validateRootWidgetConfig(\n resolvedProjectDir,\n packageKeyOverride,\n );\n if (configErrors.length > 0) {\n throw new WidgetValidationError(configErrors);\n }\n\n const sourcePackages = await withRootWidgetConfigBridge(\n resolvedProjectDir,\n async () => {\n const loadResult = await loadSourceWidgetPackages(resolvedProjectDir);\n if (!loadResult.success) {\n throw new WidgetValidationError([\n {\n code: \"INVALID_SOURCE_PACKAGE\",\n path: sourceConfig.relativePath,\n message: appendDetails(\n loadResult.error.message,\n loadResult.error.details,\n ),\n },\n ]);\n }\n return loadResult.value;\n },\n packageKeyOverride,\n );\n\n const validation = validateSingleSourceWidgetPackage(sourcePackages, {\n owner: \"droplet\",\n });\n const errors = [\n ...validation.errors,\n ...validateDropletMetadata(sourcePackages),\n ];\n\n if (!validation.success || !validation.value || errors.length > 0) {\n throw new WidgetValidationError(errors);\n }\n\n return {\n projectDir: resolvedProjectDir,\n sourceConfigPath: sourceConfig.relativePath,\n validated: validation.value,\n };\n}\n\nexport async function withRootWidgetConfigBridge<T>(\n projectDir: string,\n callback: () => Promise<T>,\n packageKeyOverride?: string,\n): Promise<T> {\n const rootConfigPath = path.join(projectDir, ROOT_WIDGET_CONFIG_FILE);\n if (!existsSync(rootConfigPath) || resolvePortalSourceConfig(projectDir)) {\n return callback();\n }\n\n const packageKey =\n packageKeyOverride?.trim() ||\n (await loadWidgetConfig(projectDir)).config.droplet;\n if (!packageKey) {\n throw new Error(\n \"fluid.widget.config.ts must set droplet before validating, building, or publishing.\",\n );\n }\n\n const srcDir = path.join(projectDir, \"src\");\n const bridgePath = path.join(srcDir, \"widgets.config.ts\");\n const srcDirExisted = existsSync(srcDir);\n await mkdir(srcDir, { recursive: true });\n try {\n await writeFile(\n bridgePath,\n createRootWidgetConfigBridgeSource(packageKey),\n {\n encoding: \"utf-8\",\n flag: \"wx\",\n },\n );\n } catch (err) {\n if (isNodeError(err) && err.code === \"EEXIST\") {\n throw new Error(\n `${path.relative(projectDir, bridgePath)} already exists. ` +\n \"Remove this stale Fluid widget CLI bridge file and try again.\",\n );\n }\n throw err;\n }\n\n try {\n return await callback();\n } finally {\n await rm(bridgePath, { force: true }).catch(() => {});\n if (!srcDirExisted) await rmdir(srcDir).catch(() => {});\n }\n}\n\nfunction createRootWidgetConfigBridgeSource(packageKey: string): string {\n return `import { widgetPackage as sourceWidgetPackage } from \"../manifest\";\n\nconst packageKey = ${JSON.stringify(packageKey)};\nconst packageId = sourceWidgetPackage.scope + \".\" + packageKey;\n\nexport const widgetPackage = {\n ...sourceWidgetPackage,\n packageStableId: packageKey,\n packageId,\n};\n\nexport const widgetPackages = [widgetPackage] as const;\nexport default widgetPackage;\n`;\n}\n\nexport function resolveWidgetSourceConfig(\n projectDir: string,\n): { readonly path: string; readonly relativePath: string } | undefined {\n const rootConfig = path.join(projectDir, ROOT_WIDGET_CONFIG_FILE);\n if (existsSync(rootConfig)) {\n return { path: rootConfig, relativePath: ROOT_WIDGET_CONFIG_FILE };\n }\n\n return resolvePortalSourceConfig(projectDir);\n}\n\nexport function formatValidationSuccess(\n result: WidgetValidationResult,\n): string {\n return [\n \"Widget package is valid.\",\n `Config: ${result.sourceConfigPath ?? \"unknown\"}`,\n `Package: ${result.validated.packageId}`,\n `Version: ${result.validated.version}`,\n `Widgets: ${result.validated.widgets.length}`,\n ].join(\"\\n\");\n}\n\nasync function validateRootWidgetConfig(\n projectDir: string,\n packageKeyOverride?: string,\n): Promise<WidgetPackageValidationError[]> {\n const configPath = path.join(projectDir, ROOT_WIDGET_CONFIG_FILE);\n if (!existsSync(configPath)) return [];\n\n try {\n const loaded = await loadWidgetConfig(projectDir);\n const droplet = packageKeyOverride ?? loaded.config.droplet ?? \"\";\n const packageKeyError = validateDropletUuid(droplet);\n if (!packageKeyError) return [];\n\n return [\n {\n code: \"INVALID_PACKAGE_KEY\",\n path: ROOT_WIDGET_CONFIG_FILE,\n message: packageKeyError,\n },\n ];\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return [\n {\n code: \"INVALID_SOURCE_PACKAGE\",\n path: ROOT_WIDGET_CONFIG_FILE,\n message,\n },\n ];\n }\n}\n\nfunction validateDropletMetadata(\n sourcePackages: readonly unknown[],\n): WidgetPackageValidationError[] {\n if (sourcePackages.length !== 1) return [];\n\n const sourcePackage = sourcePackages[0];\n if (!isRecord(sourcePackage)) return [];\n\n const errors: WidgetPackageValidationError[] = [];\n if (sourcePackage[\"packageType\"] !== \"droplet\") {\n errors.push({\n code: \"UNSUPPORTED_OWNER\",\n path: \"packageType\",\n message:\n 'Droplet widget packages must set packageType: \"droplet\" in package metadata.',\n });\n }\n\n if (!isNonEmptyString(sourcePackage[\"packageStableId\"])) {\n errors.push({\n code: \"INVALID_PACKAGE_KEY\",\n path: \"packageStableId\",\n message:\n \"Droplet widget packages must set packageStableId so published widget types remain stable across builds.\",\n });\n }\n\n const widgets = sourcePackage[\"widgets\"];\n if (Array.isArray(widgets)) {\n widgets.forEach((widget, index) => {\n if (!isRecord(widget)) return;\n validateJsonSerializable(\n widget[\"propertySchema\"],\n `widgets[${index}].propertySchema`,\n errors,\n );\n validateJsonSerializable(\n widget[\"defaultProps\"],\n `widgets[${index}].defaultProps`,\n errors,\n );\n });\n }\n\n return errors;\n}\n\nfunction resolvePortalSourceConfig(\n projectDir: string,\n): { readonly path: string; readonly relativePath: string } | undefined {\n for (const relativePath of SOURCE_CONFIG_CANDIDATES) {\n const candidate = path.join(projectDir, relativePath);\n if (existsSync(candidate)) return { path: candidate, relativePath };\n }\n\n return undefined;\n}\n\nfunction validateJsonSerializable(\n value: unknown,\n pathLabel: string,\n errors: WidgetPackageValidationError[],\n): void {\n if (value === undefined) return;\n\n try {\n assertJsonSerializable(value, pathLabel);\n } catch (err) {\n errors.push({\n code: \"INVALID_WIDGET_METADATA\",\n path: pathLabel,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n}\n\nfunction assertJsonSerializable(value: unknown, pathLabel: string): void {\n if (value === null) return;\n\n const valueType = typeof value;\n if (valueType === \"string\" || valueType === \"boolean\") return;\n if (valueType === \"number\") {\n if (Number.isFinite(value)) return;\n throw new Error(`${pathLabel} must not contain NaN or Infinity.`);\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n assertJsonSerializable(item, `${pathLabel}[${index}]`);\n });\n return;\n }\n if (isRecord(value)) {\n for (const [key, item] of Object.entries(value)) {\n if (item === undefined) {\n throw new Error(`${pathLabel}.${key} must not be undefined.`);\n }\n assertJsonSerializable(item, `${pathLabel}.${key}`);\n }\n return;\n }\n\n throw new Error(`${pathLabel} must contain only JSON-serializable values.`);\n}\n\nfunction appendDetails(message: string, details: string | undefined): string {\n return details ? `${message}\\n${details}` : message;\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\ninterface NodeError extends Error {\n readonly code?: string;\n}\n\nfunction isNodeError(error: unknown): error is NodeError {\n return error instanceof Error && \"code\" in error;\n}\n","import chalk from \"chalk\";\n\nexport async function runCliAction(action: () => Promise<void>): Promise<void> {\n try {\n await action();\n } catch (err) {\n console.error(chalk.red(\"Error:\") + \" \" + formatUnknownError(err));\n process.exit(1);\n }\n}\n\nexport function formatUnknownError(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport function getRunCommand(\n script: string,\n cwd: string = process.cwd(),\n): string {\n return `${detectPackageManager(cwd)} run ${script}`;\n}\n\nexport function getInstallCommand(cwd: string = process.cwd()): string {\n return `${detectPackageManager(cwd)} install`;\n}\n\nexport async function installDependencies(cwd: string): Promise<void> {\n const packageManager = detectPackageManager(cwd);\n await runPackageManager(packageManager, [\"install\"], cwd);\n}\n\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(path.join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(path.join(cwd, \"yarn.lock\"))) return \"yarn\";\n if (existsSync(path.join(cwd, \"bun.lockb\"))) return \"bun\";\n if (existsSync(path.join(cwd, \"package-lock.json\"))) return \"npm\";\n\n const invokingPackageManager = readInvokingPackageManager();\n if (invokingPackageManager) return invokingPackageManager;\n\n const declaredPackageManager = readDeclaredPackageManager(cwd);\n if (declaredPackageManager && isCommandAvailable(declaredPackageManager)) {\n return declaredPackageManager;\n }\n\n return findAvailablePackageManager() ?? \"pnpm\";\n}\n\nfunction runPackageManager(\n command: PackageManager,\n args: readonly string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, [...args], {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n child.once(\"error\", (error: Error) => {\n reject(error);\n });\n\n child.once(\"exit\", (code: number | null) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(\n new Error(\n `${command} ${args.join(\" \")} exited with code ${code ?? \"unknown\"}`,\n ),\n );\n });\n });\n}\n\nfunction readInvokingPackageManager(): PackageManager | undefined {\n const userAgent = process.env[\"npm_config_user_agent\"];\n if (!userAgent) return undefined;\n\n const name = userAgent.split(\"/\")[0];\n if (isPackageManager(name)) return name;\n return undefined;\n}\n\nfunction readDeclaredPackageManager(cwd: string): PackageManager | undefined {\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) return undefined;\n\n try {\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf-8\"),\n ) as unknown;\n if (!isRecord(packageJson)) return undefined;\n\n const packageManager = packageJson[\"packageManager\"];\n if (typeof packageManager !== \"string\") return undefined;\n\n const name = packageManager.split(\"@\")[0];\n if (isPackageManager(name)) return name;\n } catch {\n // Malformed package.json is reported by command paths that need to parse it.\n }\n\n return undefined;\n}\n\nfunction findAvailablePackageManager(): PackageManager | undefined {\n for (const packageManager of [\"pnpm\", \"yarn\", \"bun\", \"npm\"] as const) {\n if (isCommandAvailable(packageManager)) return packageManager;\n }\n return undefined;\n}\n\nfunction isCommandAvailable(command: PackageManager): boolean {\n const result = spawnSync(command, [\"--version\"], {\n shell: process.platform === \"win32\",\n stdio: \"ignore\",\n });\n return result.status === 0;\n}\n\nfunction isPackageManager(value: string | undefined): value is PackageManager {\n return (\n value === \"pnpm\" || value === \"yarn\" || value === \"bun\" || value === \"npm\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { detectPackageManager } from \"./package-manager.js\";\n\nexport interface PackageScriptRunResult {\n readonly ran: boolean;\n readonly command?: string;\n}\n\nexport async function runPackageScriptIfAvailable(options: {\n readonly projectDir: string;\n readonly scriptName: string;\n}): Promise<PackageScriptRunResult> {\n const packageJsonPath = path.join(options.projectDir, \"package.json\");\n if (!existsSync(packageJsonPath)) return { ran: false };\n\n const packageJson = await readPackageJson(packageJsonPath);\n if (!hasPackageScript(packageJson, options.scriptName)) return { ran: false };\n\n const packageManager = detectPackageManager(options.projectDir);\n const args = [\"run\", options.scriptName];\n await runCommand(packageManager, args, options.projectDir);\n\n return {\n ran: true,\n command: `${packageManager} ${args.join(\" \")}`,\n };\n}\n\nfunction runCommand(\n command: string,\n args: readonly string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n stdio: \"inherit\",\n env: process.env,\n shell: process.platform === \"win32\",\n });\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(\n new Error(\n signal\n ? `${command} ${args.join(\" \")} exited with signal ${signal}.`\n : `${command} ${args.join(\" \")} exited with code ${code ?? \"unknown\"}.`,\n ),\n );\n });\n });\n}\n\nasync function readPackageJson(packageJsonPath: string): Promise<unknown> {\n const source = await readFile(packageJsonPath, \"utf-8\");\n try {\n return JSON.parse(source) as unknown;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Unable to parse package.json: ${message}`);\n }\n}\n\nfunction hasPackageScript(value: unknown, scriptName: string): boolean {\n if (!isRecord(value)) return false;\n const scripts = value[\"scripts\"];\n if (!isRecord(scripts)) return false;\n return typeof scripts[scriptName] === \"string\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { Command } from \"commander\";\nimport {\n buildSharedWidgetPackage,\n validateWidgetPublishOutDir,\n} from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n DEFAULT_WIDGET_OUT_DIR,\n validateDropletWidgetProject,\n withRootWidgetConfigBridge,\n} from \"../utils/source-package.js\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { runPackageScriptIfAvailable } from \"../utils/package-scripts.js\";\n\nexport interface BuildWidgetOptions {\n readonly outDir?: string;\n readonly skipTypecheck?: boolean;\n}\n\nexport interface BuildWidgetPackageOptions {\n readonly projectDir: string;\n readonly outDir: string;\n readonly skipTypecheck?: boolean;\n}\n\nexport interface BuildWidgetPackageResult {\n readonly outDir: string;\n readonly packageId: string;\n readonly version: string;\n}\n\nexport async function buildWidgetPackage(\n options: BuildWidgetPackageOptions,\n): Promise<BuildWidgetPackageResult> {\n await validateDropletWidgetProject(options.projectDir);\n\n if (options.skipTypecheck !== true) {\n await runPackageScriptIfAvailable({\n projectDir: options.projectDir,\n scriptName: \"typecheck\",\n });\n }\n\n const outDir = validateWidgetPublishOutDir(\n options.projectDir,\n options.outDir,\n );\n const buildResult = await withRootWidgetConfigBridge(options.projectDir, () =>\n buildSharedWidgetPackage({\n projectDir: options.projectDir,\n publishDir: outDir,\n owner: \"droplet\",\n }),\n );\n\n if (!buildResult.success) {\n const details = buildResult.error.details\n ? `\\n${buildResult.error.details}`\n : \"\";\n throw new Error(`${buildResult.error.message}${details}`);\n }\n\n return {\n outDir: buildResult.value.publishDir,\n packageId: buildResult.value.packageId,\n version: buildResult.value.version,\n };\n}\n\nexport const buildCommand: Command = new Command(\"build\")\n .description(\"Validate and build the current droplet widget package\")\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_WIDGET_OUT_DIR,\n )\n .option(\"--skip-typecheck\", \"Skip package typecheck script when present\")\n .action((options: BuildWidgetOptions) => {\n return runCliAction(async () => {\n const outDir = options.outDir ?? DEFAULT_WIDGET_OUT_DIR;\n console.log(chalk.blue.bold(\"Building Fluid widget package\"));\n console.log();\n\n const spinner = ora(\n \"Validating and building widget artifacts...\",\n ).start();\n const result = await buildWidgetPackage({\n projectDir: process.cwd(),\n outDir,\n skipTypecheck: options.skipTypecheck,\n });\n spinner.succeed(\"Built widget runtime artifacts\");\n\n console.log();\n console.log(chalk.gray(\"Package: \") + chalk.white(result.packageId));\n console.log(chalk.gray(\"Version: \") + chalk.white(result.version));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n });\n });\n","/**\n * Git wrapper for the Fluid widget CLI — shells out to the system `git`\n * binary via execa. Mirrors the Mist CLI write path\n * (`packages/cli/mist/src/lib/git.ts`): we deliberately do NOT bundle git or\n * use a pure-JS implementation; users are expected to have git installed and\n * we surface a friendly, actionable error when they don't.\n *\n * Security: a token-bearing `remote_url` from POST .../git_credential must\n * never be logged, persisted, or exposed in the process table. The token is\n * stripped from the URL and handed to git through a GIT_ASKPASS script via env\n * vars (FLUID_GIT_USER / FLUID_GIT_PASS) — so it never appears in argv\n * (visible to `ps aux` / `/proc/<pid>/cmdline`) and is never written to\n * `.git/config`. `-c credential.helper=` stops git from caching it, and\n * `GIT_TERMINAL_PROMPT=0` makes auth fail fast instead of hanging on a prompt.\n */\n\nimport { chmodSync, existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { execa, type ExecaError } from \"execa\";\n\nexport class GitError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"GitError\";\n this.exitCode = exitCode;\n }\n}\n\n/**\n * execa throws ENOENT when the git binary itself is missing — the single most\n * common failure on non-developer machines. Translate it into an actionable\n * message (mirrors Mist Desktop's git-availability guidance) instead of a\n * bare \"git <verb> failed (exit 1)\". Returns null for every other failure so\n * call sites keep their specific messages.\n */\nexport function gitMissingError(err: unknown): GitError | null {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code !== \"ENOENT\") return null;\n return new GitError(\n \"Git isn't installed or isn't on your PATH. Install it and try again:\\n\" +\n \" macOS: xcode-select --install (or `brew install git`)\\n\" +\n \" Windows: https://git-scm.com/download/win\\n\" +\n \" Linux: use your package manager, e.g. `sudo apt-get install git`\\n\" +\n \"Downloads for all platforms: https://git-scm.com/downloads\",\n 127,\n );\n}\n\n/**\n * Split a token-bearing remote URL into the userless URL + creds. Keeps the\n * token off git's argv: we pass `cleanUrl` to git and feed `username` /\n * `password` back through GIT_ASKPASS env vars. If the URL has no embedded\n * credentials, returns empty strings — fine for public repos where git won't\n * invoke askpass.\n */\nfunction splitRemoteCredentials(remoteUrl: string): {\n cleanUrl: string;\n username: string;\n password: string;\n} {\n let u: URL;\n try {\n u = new URL(remoteUrl);\n } catch {\n // Not a URL (e.g. a local filesystem path used for dev/testing). Pass it\n // through untouched — there are no embedded credentials to strip.\n return { cleanUrl: remoteUrl, username: \"\", password: \"\" };\n }\n const username = decodeURIComponent(u.username);\n const password = decodeURIComponent(u.password);\n u.username = \"\";\n u.password = \"\";\n return { cleanUrl: u.toString(), username, password };\n}\n\n/**\n * Write a stub GIT_ASKPASS shell script to a per-process tmpdir and return its\n * path. The script contains no secret — it just echoes back whichever env var\n * (FLUID_GIT_USER / FLUID_GIT_PASS) matches git's prompt. Credentials only\n * live in the spawned git process's env for the duration of the call.\n *\n * One POSIX script for all platforms: Git for Windows runs GIT_ASKPASS through\n * its bundled sh, so a plain sh script works everywhere. Idempotent.\n */\nlet askpassPath: string | null = null;\nfunction ensureAskpassScript(): string {\n if (askpassPath && existsSync(askpassPath)) return askpassPath;\n const dir = path.join(os.tmpdir(), `fluid-widget-askpass-${process.pid}`);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n const p = path.join(dir, \"askpass.sh\");\n writeFileSync(\n p,\n `#!/bin/sh\\ncase \"$1\" in\\n Username*) printf '%s' \"$FLUID_GIT_USER\" ;;\\n *) printf '%s' \"$FLUID_GIT_PASS\" ;;\\nesac\\n`,\n { mode: 0o700 },\n );\n chmodSync(p, 0o700);\n askpassPath = p;\n return askpassPath;\n}\n\n/**\n * Build the spawn env + cleaned URL for a credentialed git invocation. The\n * returned `cleanUrl` has userinfo stripped (safe to pass as argv); the `env`\n * carries GIT_ASKPASS + FLUID_GIT_USER / FLUID_GIT_PASS and\n * GIT_TERMINAL_PROMPT=0.\n */\nfunction gitAuthSpawn(remoteUrl: string): {\n cleanUrl: string;\n env: NodeJS.ProcessEnv;\n} {\n const { cleanUrl, username, password } = splitRemoteCredentials(remoteUrl);\n return {\n cleanUrl,\n env: {\n ...process.env,\n GIT_ASKPASS: ensureAskpassScript(),\n GIT_TERMINAL_PROMPT: \"0\",\n FLUID_GIT_USER: username,\n FLUID_GIT_PASS: password,\n },\n };\n}\n\nfunction wrapGitError(err: unknown, verb: string): GitError {\n const missing = gitMissingError(err);\n if (missing) return missing;\n const e = err as ExecaError;\n return new GitError(\n `git ${verb} failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n}\n\n/** Confirm git is installed. Cheap call once at the start of a git command. */\nexport async function ensureGitAvailable(): Promise<void> {\n try {\n await execa(\"git\", [\"--version\"]);\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n throw new GitError(\n \"`git` is required but couldn't be run. Install it from https://git-scm.com/downloads.\",\n );\n }\n}\n\n/** Is `cwd` inside a git working tree? */\nexport async function isGitRepository(cwd: string): Promise<boolean> {\n try {\n const { stdout } = await execa(\n \"git\",\n [\"rev-parse\", \"--is-inside-work-tree\"],\n { cwd },\n );\n return stdout.trim() === \"true\";\n } catch {\n return false;\n }\n}\n\n/** `git init` (+ set the initial branch to `branch`). No-op if already a repo. */\nexport async function gitInit(cwd: string, branch = \"main\"): Promise<void> {\n try {\n await execa(\"git\", [\"init\", \"--initial-branch\", branch], { cwd });\n } catch (err) {\n // Older gits lack --initial-branch; fall back to a plain init.\n const missing = gitMissingError(err);\n if (missing) throw missing;\n try {\n await execa(\"git\", [\"init\"], { cwd });\n } catch (fallbackErr) {\n throw wrapGitError(fallbackErr, \"init\");\n }\n }\n}\n\n/**\n * `git clone <cleanUrl> <targetDir>`. The original remoteUrl carries a token;\n * gitAuthSpawn strips it from the URL and re-injects it via GIT_ASKPASS.\n */\nexport async function gitClone(\n remoteUrl: string,\n targetDir: string,\n options: {\n readonly depth?: number;\n readonly branch?: string;\n /**\n * Capture git's stderr instead of inheriting it. Used for best-effort\n * clones (e.g. the create template fetch) where the caller handles\n * failure and doesn't want git's raw error text on the console.\n */\n readonly silent?: boolean;\n } = {},\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n const args = [\"-c\", \"credential.helper=\", \"clone\", \"--quiet\"];\n if (options.depth != null) args.push(\"--depth\", String(options.depth));\n if (options.branch) args.push(\"--branch\", options.branch);\n args.push(cleanUrl, targetDir);\n try {\n await execa(\"git\", args, {\n env,\n stdio: options.silent ? \"pipe\" : [\"ignore\", \"inherit\", \"inherit\"],\n });\n } catch (err) {\n throw wrapGitError(err, \"clone\");\n }\n}\n\n/** `git push <remote> HEAD:<branch>` — credentials via GIT_ASKPASS, never argv. */\nexport async function gitPush(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\n \"-c\",\n \"credential.helper=\",\n \"-c\",\n \"http.https://github.com/.extraheader=\",\n \"push\",\n cleanUrl,\n `HEAD:${branch}`,\n ],\n { cwd, env, stdio: [\"ignore\", \"inherit\", \"inherit\"] },\n );\n } catch (err) {\n throw wrapGitError(err, \"push\");\n }\n}\n\n/**\n * Does `branch` exist on the remote? Uses `git ls-remote --heads`, which is\n * the reliable way to tell a genuinely-empty remote (freshly provisioned repo,\n * first push) apart from a connection/auth failure. Returns false only when the\n * remote answered but has no such branch; **throws** on any transport/auth\n * error so callers don't mistake a network blip for \"empty remote\" and skip\n * reconciliation.\n */\nexport async function gitRemoteBranchExists(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<boolean> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n const { stdout } = await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"ls-remote\", \"--heads\", cleanUrl, branch],\n { cwd, env },\n );\n return stdout.trim().length > 0;\n } catch (err) {\n throw wrapGitError(err, \"ls-remote\");\n }\n}\n\n/**\n * Fetch the given branch from the token-bearing remote, writing `FETCH_HEAD`.\n * Throws on failure — callers should first confirm the branch exists with\n * `gitRemoteBranchExists` so a genuinely-empty remote isn't treated as an error.\n */\nexport async function gitFetch(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"fetch\", \"--quiet\", cleanUrl, branch],\n { cwd, env },\n );\n } catch (err) {\n throw wrapGitError(err, \"fetch\");\n }\n}\n\n/**\n * Count commits in local HEAD vs `FETCH_HEAD` (after `gitFetch`). Returns\n * `{ahead, behind}`. `0/0` means \"in sync\" (or no FETCH_HEAD / no HEAD yet).\n */\nexport async function gitAheadBehindVsFetchHead(\n cwd: string,\n): Promise<{ ahead: number; behind: number }> {\n try {\n const { stdout } = await execa(\n \"git\",\n [\"rev-list\", \"--left-right\", \"--count\", \"HEAD...FETCH_HEAD\"],\n { cwd },\n );\n const [a, b] = stdout.trim().split(/\\s+/);\n const ahead = Number.parseInt(a ?? \"0\", 10);\n const behind = Number.parseInt(b ?? \"0\", 10);\n return {\n ahead: Number.isFinite(ahead) ? ahead : 0,\n behind: Number.isFinite(behind) ? behind : 0,\n };\n } catch {\n return { ahead: 0, behind: 0 };\n }\n}\n\n/** Does `cwd` have any commits yet? (false right after `git init`.) */\nexport async function hasCommits(cwd: string): Promise<boolean> {\n try {\n await execa(\"git\", [\"rev-parse\", \"--verify\", \"HEAD\"], { cwd });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Adopt `FETCH_HEAD` as the current (unborn) branch's base: point the branch\n * ref at it and load its tree into the index, leaving the working tree\n * untouched. The next auto-commit then records the local project tree as a\n * child of the remote history — local files win, remote-only files are\n * recorded as deletions — so the push fast-forwards instead of being\n * rejected for unrelated history. Only call this when `hasCommits` is false;\n * on a repo with local commits it would silently rewrite the branch ref.\n *\n * Returns the number of remote commits adopted.\n */\nexport async function gitAdoptFetchHead(cwd: string): Promise<number> {\n try {\n await execa(\"git\", [\"reset\", \"--mixed\", \"FETCH_HEAD\"], { cwd });\n const { stdout } = await execa(\n \"git\",\n [\"rev-list\", \"--count\", \"FETCH_HEAD\"],\n { cwd },\n );\n const count = Number.parseInt(stdout.trim(), 10);\n return Number.isFinite(count) ? count : 0;\n } catch (err) {\n throw wrapGitError(err, \"adopt remote history\");\n }\n}\n\n/** Fast-forward `HEAD` to `FETCH_HEAD`. Fails if not fast-forwardable. */\nexport async function gitMergeFastForward(cwd: string): Promise<void> {\n try {\n await execa(\"git\", [\"merge\", \"--ff-only\", \"FETCH_HEAD\"], { cwd });\n } catch (err) {\n throw wrapGitError(err, \"fast-forward merge\");\n }\n}\n\n/** Are there uncommitted changes (working tree or index) in this repo? */\nexport async function hasUncommittedChanges(cwd: string): Promise<boolean> {\n try {\n const { stdout } = await execa(\"git\", [\"status\", \"--porcelain\"], { cwd });\n return stdout.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/** Stash working-tree + untracked changes with a tagged message. */\nexport async function gitStash(cwd: string, message: string): Promise<void> {\n try {\n await execa(\n \"git\",\n [\"stash\", \"push\", \"--include-untracked\", \"--message\", message],\n { cwd },\n );\n } catch (err) {\n throw wrapGitError(err, \"stash push\");\n }\n}\n\n/** Pop the most recent stash. Throws on conflict so callers can surface it. */\nexport async function gitStashPop(cwd: string): Promise<void> {\n try {\n await execa(\"git\", [\"stash\", \"pop\"], { cwd });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n \"Couldn't restore your local changes after pulling — the edits collided \" +\n \"with a teammate's. Run `git stash list` and resolve manually.\",\n e.exitCode ?? 1,\n );\n }\n}\n\n/** Read the current HEAD sha, or null if there is no commit yet. */\nexport async function getHeadSha(cwd: string): Promise<string | null> {\n try {\n const { stdout } = await execa(\"git\", [\"rev-parse\", \"HEAD\"], { cwd });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\nexport interface GitCommitIdentity {\n readonly name: string;\n readonly email: string;\n}\n\nconst DEFAULT_COMMIT_IDENTITY: GitCommitIdentity = {\n name: \"Fluid CLI\",\n email: \"cli@fluid.app\",\n};\n\n/**\n * `git add -A && git commit -m <message>` in `cwd`.\n *\n * The widget \"push\" UX is \"ship my changes\" — the user shouldn't need to know\n * about staging or commit messages. This bundles working-tree edits into one\n * commit per push. If the repo has no configured user.name / user.email we\n * pass a synthetic identity so the commit isn't rejected. \"nothing to commit\"\n * is treated as a no-op rather than an error.\n */\nexport async function gitAutoCommit(\n cwd: string,\n message: string,\n identity: GitCommitIdentity = DEFAULT_COMMIT_IDENTITY,\n): Promise<void> {\n try {\n await execa(\"git\", [\"add\", \"-A\"], { cwd });\n } catch (err) {\n throw wrapGitError(err, \"add\");\n }\n\n let hasName = false;\n let hasEmail = false;\n try {\n const r = await execa(\"git\", [\"config\", \"user.name\"], { cwd });\n hasName = r.stdout.trim().length > 0;\n } catch {\n // exit 1 from `git config <key>` just means the key is unset.\n }\n try {\n const r = await execa(\"git\", [\"config\", \"user.email\"], { cwd });\n hasEmail = r.stdout.trim().length > 0;\n } catch {\n // ditto.\n }\n const identityArgs = [\n ...(hasName ? [] : [\"-c\", `user.name=${identity.name}`]),\n ...(hasEmail ? [] : [\"-c\", `user.email=${identity.email}`]),\n ];\n\n try {\n await execa(\"git\", [...identityArgs, \"commit\", \"-m\", message], {\n cwd,\n stdio: [\"ignore\", \"inherit\", \"inherit\"],\n });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n if (typeof e.stderr === \"string\" && /nothing to commit/i.test(e.stderr)) {\n return;\n }\n throw wrapGitError(err, \"commit\");\n }\n}\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\n\n/**\n * A short-lived (~1h) credentialed git remote URL minted by the backend. The\n * `remoteUrl` embeds an installation token and must never be logged,\n * persisted, or written to `.git/config` — hand it straight to the git helpers\n * in `../lib/git.js`, which strip the token off argv via GIT_ASKPASS.\n */\nexport interface WidgetGitCredential {\n readonly remoteUrl: string;\n readonly expiresAt: string | null;\n}\n\ninterface GitCredentialResponse {\n readonly git_credential?: {\n readonly remote_url?: unknown;\n readonly expires_at?: unknown;\n };\n}\n\nexport interface MintWidgetGitCredentialOptions {\n readonly client: FetchClient;\n /**\n * Droplet UUID that owns the widget package. When provided we mint against\n * the droplet-scoped endpoint; otherwise we mint against the company-owned\n * widget package endpoint.\n */\n readonly droplet?: string;\n}\n\n/**\n * Mint a git credential for a widget package.\n *\n * Backend (fluid-commerce PR #19162 — not deployed to prod yet):\n * - droplet-owned: POST /api/droplets/:uuid/widget_package/git_credential\n * - company-owned: POST /api/company/fluid_os/widget_package/git_credential\n * Both respond `{ git_credential: { remote_url, expires_at } }`.\n *\n * Throws the underlying `ApiError` (with `.status`) on failure so callers can\n * decide whether to degrade gracefully (see `isGitSyncUnavailable`).\n */\nexport async function mintWidgetGitCredential(\n options: MintWidgetGitCredentialOptions,\n): Promise<WidgetGitCredential> {\n const path = options.droplet\n ? `/api/droplets/${encodeURIComponent(options.droplet)}/widget_package/git_credential`\n : \"/api/company/fluid_os/widget_package/git_credential\";\n\n const response = await options.client.post<GitCredentialResponse>(path);\n const remoteUrl = response?.git_credential?.remote_url;\n if (typeof remoteUrl !== \"string\" || remoteUrl.length === 0) {\n throw new Error(\n \"The git credential response did not include a remote URL. \" +\n \"Update the Fluid CLI, or contact support if this persists.\",\n );\n }\n const expiresAtRaw = response.git_credential?.expires_at;\n return {\n remoteUrl,\n expiresAt: typeof expiresAtRaw === \"string\" ? expiresAtRaw : null,\n };\n}\n\n/**\n * Sanitize a package key the same way the backend does when naming the repo\n * (`GitSync::Provisioner`): GitHub's repo-name alphabet is `[A-Za-z0-9._-]`,\n * so every other character (including the `~` allowed in package keys) becomes\n * a hyphen. Lets us compare a requested key against the minted repo name.\n */\nexport function sanitizeWidgetPackageKey(key: string): string {\n return key.replace(/[^A-Za-z0-9._-]/g, \"-\");\n}\n\n/**\n * Extract the sanitized package key from a minted widget remote URL. The\n * backend names repos `widget-<sanitized package_key>-<widget_package id>`, so\n * `https://x-access-token:tok@github.com/org/widget-reviews-42.git` → `reviews`.\n * Returns null when the URL doesn't match that shape (never throws; the token\n * in the URL is never logged — only the pathname is read).\n */\nexport function widgetRepoKeyFromRemoteUrl(remoteUrl: string): string | null {\n try {\n const name = new URL(remoteUrl).pathname\n .split(\"/\")\n .pop()\n ?.replace(/\\.git$/, \"\");\n const match = name?.match(/^widget-(.+)-\\d+$/);\n return match?.[1] ?? null;\n } catch {\n return null;\n }\n}\n\n/** Best-effort read of an HTTP status off an unknown thrown error. */\nexport function getErrorStatus(err: unknown): number | undefined {\n if (err && typeof err === \"object\" && \"status\" in err) {\n const status = (err as { status?: unknown }).status;\n if (typeof status === \"number\") return status;\n }\n return undefined;\n}\n\n/**\n * Should a git-credential failure degrade to \"publish artifacts only\" rather\n * than abort? True when the endpoint isn't deployed (404) or the package's git\n * repo isn't provisioned/connected yet (409). Other statuses (auth, 5xx) are\n * genuine errors the caller may still choose to treat as best-effort.\n */\nexport function isGitSyncUnavailable(err: unknown): boolean {\n const status = getErrorStatus(err);\n return status === 404 || status === 409;\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * `.fluid-widget` marker file — written by `fluid widget clone` so future\n * commands (and Mist Desktop) can identify a checked-out widget package repo\n * and know which owner to mint git credentials against. Mirrors Mist's `.mist`\n * marker (which records slug / vendor_name).\n */\nexport const WIDGET_MARKER_FILE = \".fluid-widget\";\n\nexport interface WidgetMarker {\n readonly package_key: string;\n /** Droplet UUID when the package is droplet-owned; omitted for company-owned. */\n readonly droplet?: string;\n}\n\nexport function resolveWidgetMarkerPath(dir: string): string {\n return path.join(dir, WIDGET_MARKER_FILE);\n}\n\nexport function writeWidgetMarker(dir: string, marker: WidgetMarker): void {\n const payload: WidgetMarker = marker.droplet\n ? { package_key: marker.package_key, droplet: marker.droplet }\n : { package_key: marker.package_key };\n writeFileSync(\n resolveWidgetMarkerPath(dir),\n JSON.stringify(payload, null, 2) + \"\\n\",\n \"utf8\",\n );\n}\n\nexport function readWidgetMarker(dir: string): WidgetMarker | null {\n const filePath = resolveWidgetMarkerPath(dir);\n if (!existsSync(filePath)) return null;\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf8\")) as unknown;\n if (!parsed || typeof parsed !== \"object\") return null;\n const obj = parsed as Record<string, unknown>;\n const packageKey = obj[\"package_key\"];\n if (typeof packageKey !== \"string\" || packageKey.length === 0) return null;\n const droplet = obj[\"droplet\"];\n return {\n package_key: packageKey,\n ...(typeof droplet === \"string\" && droplet.length > 0 ? { droplet } : {}),\n };\n } catch {\n return null;\n }\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { ensureGitAvailable, gitClone } from \"../lib/git.js\";\nimport {\n isGitSyncUnavailable,\n mintWidgetGitCredential,\n sanitizeWidgetPackageKey,\n widgetRepoKeyFromRemoteUrl,\n} from \"../utils/git-credential.js\";\nimport { validateDropletUuid } from \"../utils/config.js\";\nimport { writeWidgetMarker } from \"../utils/widget-marker.js\";\nimport {\n getInstallCommand,\n installDependencies,\n} from \"../utils/package-manager.js\";\n\nexport interface CloneCommandOptions {\n readonly droplet?: string;\n readonly dir?: string;\n readonly skipInstall?: boolean;\n}\n\nexport const cloneCommand: Command = new Command(\"clone\")\n .description(\n \"Clone a widget package's git repository (mints a fresh token per call)\",\n )\n .argument(\"<package>\", \"Widget package key to clone\")\n .option(\n \"--droplet <uuid>\",\n \"Droplet UUID that owns the package (defaults to the company-owned package)\",\n )\n .option(\"--dir <dir>\", \"Target directory (defaults to ./<package>/)\")\n .option(\"--skip-install\", \"Skip dependency installation\")\n .action((packageKey: string, options: CloneCommandOptions) =>\n runCliAction(async () => {\n const trimmedPackage = packageKey.trim();\n if (!trimmedPackage) throw new Error(\"A widget package key is required.\");\n\n const droplet = options.droplet?.trim();\n if (droplet) {\n const dropletError = validateDropletUuid(droplet);\n if (dropletError) throw new Error(dropletError);\n }\n\n // Clone is a pure git operation — fail fast with an actionable message\n // when git isn't installed rather than partway through.\n await ensureGitAvailable();\n\n const targetDir = path.resolve(options.dir ?? trimmedPackage);\n if (existsSync(targetDir)) {\n throw new Error(\n `Directory ${targetDir} already exists. Pass --dir or remove it first.`,\n );\n }\n\n // The credential endpoints are scoped to an *owner*, not a package key:\n // a company (or droplet) has exactly one widget package, so the backend\n // resolves the repo from the authenticated company / the droplet uuid —\n // there is no package-key selector to send. `<package>` is therefore a\n // local label used for the target directory name and the `.fluid-widget`\n // marker, mirroring how `fluid mist clone` names by vendor_name.\n const client = createAuthenticatedWidgetPackageClient();\n const spinner = ora(\"Minting git credential…\").start();\n let remoteUrl: string;\n try {\n const cred = await mintWidgetGitCredential({\n client,\n ...(droplet ? { droplet } : {}),\n });\n remoteUrl = cred.remoteUrl;\n } catch (err) {\n spinner.fail(\"Couldn't mint a git credential\");\n if (isGitSyncUnavailable(err)) {\n throw new Error(\n \"Widget git sync isn't available for this package yet. \" +\n \"Publish the package first, or try again once git sync is enabled.\",\n );\n }\n throw err;\n }\n\n // The owner determines the repo, so guard against a requested key that\n // disagrees with what was actually minted — otherwise we'd clone one\n // repo but stamp the marker with a different package name, leaving future\n // push/publish acting on a checkout whose marker and source disagree.\n const mintedKey = widgetRepoKeyFromRemoteUrl(remoteUrl);\n if (!mintedKey) {\n // Fail closed: an unparseable repo name means we can't prove the\n // checkout matches the requested key, and a wrong marker would leave\n // future push/publish acting on the wrong package.\n spinner.fail(\"Couldn't verify the owner's widget repository\");\n throw new Error(\n \"The minted git repository URL did not match the expected widget \" +\n \"repository format, so the CLI cannot safely write a package \" +\n \"marker. Update the Fluid CLI, or contact support if this persists.\",\n );\n }\n if (mintedKey !== sanitizeWidgetPackageKey(trimmedPackage)) {\n spinner.fail(\"Requested package does not match the owner's repository\");\n throw new Error(\n `The ${droplet ? \"droplet\" : \"company\"}'s widget package is ` +\n `\"${mintedKey}\", not \"${trimmedPackage}\". Re-run with the correct ` +\n `package key (or --droplet), so the checkout and its marker agree.`,\n );\n }\n\n spinner.text = `Cloning into ${path.basename(targetDir)}/…`;\n try {\n // Token-bearing URL is passed inline only — never written to .git/config.\n await gitClone(remoteUrl, targetDir);\n } catch (err) {\n spinner.fail(\"git clone failed\");\n throw err;\n }\n\n // Drop a `.fluid-widget` marker so future commands (and Mist Desktop)\n // know the owner without re-parsing config.\n writeWidgetMarker(targetDir, {\n package_key: trimmedPackage,\n ...(droplet ? { droplet } : {}),\n });\n\n spinner.succeed(`Cloned into ${chalk.cyan(targetDir)}`);\n\n // A cloned checkout is unrunnable until dependencies land (`widget dev`\n // needs the project's own Vite) — install here like `create` does so\n // clone-then-run works without a manual step in between.\n const installCommand = getInstallCommand(targetDir);\n if (options.skipInstall !== true) {\n spinner.start(`Installing dependencies with ${installCommand}...`);\n try {\n await installDependencies(targetDir);\n spinner.succeed(\"Installed dependencies\");\n } catch {\n spinner.fail(\"Failed to install dependencies\");\n console.log();\n console.log(chalk.yellow(\"You can install dependencies manually:\"));\n console.log(chalk.cyan(` ${installCommand}`));\n }\n }\n\n console.log(\n chalk.dim(` cd ${path.relative(process.cwd(), targetDir) || \".\"}`),\n );\n if (options.skipInstall === true) {\n console.log(chalk.dim(` ${installCommand}`));\n }\n }),\n );\n","import { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { WidgetTemplateVariables } from \"../types.js\";\n\nexport function getDefaultTemplatePath(): string {\n return path.join(findPackageRoot(), \"templates\", \"default\");\n}\n\nexport async function directoryExists(filePath: string): Promise<boolean> {\n try {\n const stats = await stat(filePath);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function copyWidgetTemplate(\n templatePath: string,\n targetPath: string,\n variables: WidgetTemplateVariables,\n): Promise<void> {\n const files = await getFiles(templatePath);\n\n for (const file of files) {\n const sourcePath = path.join(templatePath, file);\n const isTemplate = file.endsWith(\".template\");\n const outputFiles = getOutputFilenames(file);\n\n const content = await readFile(sourcePath, \"utf-8\");\n const processed = isTemplate ? renderTemplate(content, variables) : content;\n\n await writeOutputFiles(targetPath, outputFiles, processed);\n }\n\n for (const skillFile of await getSharedTemplateSkillFiles()) {\n await writeOutputFiles(\n targetPath,\n getOutputFilenames(skillFile.relativePath),\n skillFile.content,\n );\n }\n}\n\nexport async function getPortalSdkVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion([\"portal\", \"sdk\"], \"^0.1.0\", options);\n}\n\nexport async function getPortalCoreVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion([\"portal\", \"core\"], \"^0.1.0\", options);\n}\n\nexport async function getCliVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion([\"cli\", \"core\"], \"^0.1.0\", options);\n}\n\nexport async function getWidgetCliVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion([\"cli\", \"widget\"], \"^0.1.0\", options);\n}\n\nasync function getWorkspacePackageVersion(\n packagePathSegments: readonly string[],\n fallback: string,\n options: { readonly local?: boolean; readonly targetPath?: string },\n): Promise<string> {\n try {\n const packageRoot = findPackageRoot();\n const packagesRoot = path.join(packageRoot, \"..\", \"..\");\n const targetPackageRoot = path.join(packagesRoot, ...packagePathSegments);\n\n if (options.local) {\n const linkPath = (\n options.targetPath\n ? path.relative(options.targetPath, targetPackageRoot)\n : targetPackageRoot\n ).replace(/\\\\/g, \"/\");\n return `link:${linkPath || \".\"}`;\n }\n\n const packageJsonPath = path.join(targetPackageRoot, \"package.json\");\n const content = await readFile(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n return `^${pkg.version ?? fallback.replace(/^\\^/, \"\")}`;\n } catch {\n return fallback;\n }\n}\n\nasync function getFiles(dir: string, baseDir = dir): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await getFiles(fullPath, baseDir)));\n } else {\n files.push(path.relative(baseDir, fullPath));\n }\n }\n\n return files;\n}\n\ninterface TemplateSkillFile {\n readonly relativePath: string;\n readonly content: string;\n}\n\nasync function getSharedTemplateSkillFiles(): Promise<TemplateSkillFile[]> {\n const packageRoot = findFluidCliPackageRoot();\n const skillsRoot = path.join(packageRoot, \"template-skills\");\n const files = await getFiles(skillsRoot);\n\n return Promise.all(\n files.map(async (file) => ({\n relativePath: path.join(\"skills\", file),\n content: await readFile(path.join(skillsRoot, file), \"utf-8\"),\n })),\n );\n}\n\nfunction findFluidCliPackageRoot(): string {\n const workspacePackageRoot = path.join(findPackageRoot(), \"..\", \"core\");\n if (existsSync(path.join(workspacePackageRoot, \"template-skills\"))) {\n return workspacePackageRoot;\n }\n\n let dir = path.dirname(\n fileURLToPath(import.meta.resolve(\"@fluid-app/fluid-cli\")),\n );\n while (!existsSync(path.join(dir, \"package.json\"))) {\n const parent = path.dirname(dir);\n if (parent === dir)\n throw new Error(\"Could not find Fluid CLI package root\");\n dir = parent;\n }\n return dir;\n}\n\nfunction renderTemplate(\n content: string,\n variables: WidgetTemplateVariables,\n): string {\n const withConditionals = content.replace(\n /{{\\s*#if\\s+([a-zA-Z0-9_]+)\\s*}}([\\s\\S]*?){{\\s*\\/if\\s*}}/g,\n (match, key, block) => {\n if (!isTemplateVariableKey(key)) return match;\n return variables[key] ? String(block) : \"\";\n },\n );\n\n return withConditionals.replace(\n /{{\\s*([a-zA-Z0-9_]+)\\s*}}/g,\n (match, key) => {\n if (isTemplateVariableKey(key)) return variables[key] ?? \"\";\n return match;\n },\n );\n}\n\nfunction isTemplateVariableKey(\n key: string,\n): key is keyof WidgetTemplateVariables {\n return [\n \"projectName\",\n \"widgetScope\",\n \"widgetPackageVersion\",\n \"sdkVersion\",\n \"localCoreVersion\",\n \"fluidCliVersion\",\n \"widgetCliVersion\",\n \"droplet\",\n ].includes(key);\n}\n\nasync function writeOutputFiles(\n targetPath: string,\n outputFiles: readonly string[],\n content: string,\n): Promise<void> {\n for (const outputFile of outputFiles) {\n const destinationPath = path.join(targetPath, outputFile);\n await mkdir(path.dirname(destinationPath), { recursive: true });\n await writeFile(destinationPath, content, \"utf-8\");\n }\n}\n\nfunction getOutputFilenames(filename: string): string[] {\n const outputFilename = getOutputFilename(filename);\n const normalized = outputFilename.replace(/\\\\/g, \"/\");\n\n if (normalized === \"AGENTS.md\") return [\"AGENTS.md\", \"CLAUDE.md\"];\n\n if (normalized.startsWith(\"skills/\")) {\n return [\n path.join(\".agents\", outputFilename),\n path.join(\".claude\", outputFilename),\n ];\n }\n\n return [outputFilename];\n}\n\nfunction getOutputFilename(filename: string): string {\n return filename.endsWith(\".template\")\n ? filename.slice(0, -\".template\".length)\n : filename;\n}\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (!existsSync(path.join(dir, \"package.json\"))) {\n const parent = path.dirname(dir);\n if (parent === dir)\n throw new Error(\"Could not find widget CLI package root\");\n dir = parent;\n }\n return dir;\n}\n","import { cp, mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { ensureGitAvailable, gitClone } from \"../lib/git.js\";\n\n/**\n * The canonical widget starter lives on GitHub so widget projects share the\n * same \"invisible git\" collaboration model Mist apps have. `fluid widget\n * create` prefers this template (teams get updates without a CLI release) and\n * falls back to the bundled template when git/network/the repo is unavailable.\n */\nexport const DEFAULT_WIDGET_TEMPLATE_REPO_URL =\n \"https://github.com/Fluid-WeCommerce/widget-template.git\";\n\n/**\n * The template repo to clone. Overridable via `FLUID_WIDGET_TEMPLATE_REPO`\n * (read at call time so tests can point at a local repo). Falls back to the\n * canonical GitHub template.\n */\nexport function widgetTemplateRepoUrl(): string {\n return (\n process.env[\"FLUID_WIDGET_TEMPLATE_REPO\"] ??\n DEFAULT_WIDGET_TEMPLATE_REPO_URL\n );\n}\n\n/**\n * The defaults baked into the GitHub template's rendered files. `create`\n * rewrites these to the user's chosen values after cloning. Keep in sync with\n * `scripts/render-template-repo.mts`.\n */\nexport const TEMPLATE_DEFAULTS = {\n projectName: \"my-widget\",\n widgetScope: \"droplet\",\n widgetPackageVersion: \"0.1.0\",\n} as const;\n\nexport interface GithubTemplateVariables {\n readonly projectName: string;\n readonly widgetScope: string;\n readonly widgetPackageVersion: string;\n}\n\n/**\n * Clone the GitHub widget template into `targetPath`, strip its git history,\n * and rewrite the baked defaults to the user's values. The repo holds a fully\n * rendered project (no `{{placeholders}}`), so we do targeted, deterministic\n * replacements of the known defaults rather than template interpolation.\n *\n * Returns true on success. Returns false (never throws) when the template\n * couldn't be fetched — git missing, offline, repo unavailable — so `create`\n * can fall back to the bundled template. The partially-cloned target is\n * cleaned up before returning false.\n */\nexport async function tryFetchGithubTemplate(\n targetPath: string,\n variables: GithubTemplateVariables,\n): Promise<boolean> {\n let tempDir: string | undefined;\n try {\n await ensureGitAvailable();\n tempDir = await mkdtemp(path.join(os.tmpdir(), \"fluid-widget-template-\"));\n const clonePath = path.join(tempDir, \"template\");\n await gitClone(widgetTemplateRepoUrl(), clonePath, {\n depth: 1,\n branch: \"main\",\n silent: true,\n });\n\n // Strip git history: generate-from-template semantics — the new project\n // gets its own (invisible) repo later via `fluid widget push`.\n await rm(path.join(clonePath, \".git\"), { recursive: true, force: true });\n\n await cp(clonePath, targetPath, { recursive: true });\n await applyTemplateRenames(targetPath, variables);\n return true;\n } catch {\n // Any failure → clean up and let the caller fall back to the bundled\n // template. create must never hard-fail just because git/network is down.\n await rm(targetPath, { recursive: true, force: true }).catch(() => {});\n return false;\n } finally {\n if (tempDir)\n await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/**\n * Rewrite the template's baked defaults (project name, scope, version) to the\n * user's chosen values across the small set of files that reference them.\n * Missing files are skipped — the template can evolve without breaking this.\n */\nasync function applyTemplateRenames(\n targetPath: string,\n variables: GithubTemplateVariables,\n): Promise<void> {\n const { projectName, widgetScope, widgetPackageVersion } = variables;\n\n await replaceInFile(path.join(targetPath, \"package.json\"), [\n [\n `\"name\": ${JSON.stringify(TEMPLATE_DEFAULTS.projectName)}`,\n `\"name\": ${JSON.stringify(projectName)}`,\n ],\n ]);\n\n await replaceInFile(path.join(targetPath, \"index.html\"), [\n [\n `<title>${TEMPLATE_DEFAULTS.projectName}</title>`,\n `<title>${projectName}</title>`,\n ],\n ]);\n\n await replaceInFile(path.join(targetPath, \"README.md\"), [\n [`# ${TEMPLATE_DEFAULTS.projectName}\\n`, `# ${projectName}\\n`],\n ]);\n\n await replaceInFile(path.join(targetPath, \"manifest.ts\"), [\n [\n `scope: ${JSON.stringify(TEMPLATE_DEFAULTS.widgetScope)},`,\n `scope: ${JSON.stringify(widgetScope)},`,\n ],\n [\n `version: ${JSON.stringify(TEMPLATE_DEFAULTS.widgetPackageVersion)},`,\n `version: ${JSON.stringify(widgetPackageVersion)},`,\n ],\n ]);\n}\n\n/**\n * Replace the first occurrence of each `[from, to]` pair in a file. No-op when\n * `from` isn't present (or `from === to`), so re-running is harmless and an\n * unchanged default (e.g. scope already \"droplet\") isn't a failure.\n */\nasync function replaceInFile(\n filePath: string,\n replacements: ReadonlyArray<readonly [string, string]>,\n): Promise<void> {\n if (!existsSync(filePath)) return;\n let content = await readFile(filePath, \"utf8\");\n let changed = false;\n for (const [from, to] of replacements) {\n if (from === to) continue;\n const index = content.indexOf(from);\n if (index === -1) continue;\n content = content.slice(0, index) + to + content.slice(index + from.length);\n changed = true;\n }\n if (changed) await writeFile(filePath, content, \"utf8\");\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport path from \"node:path\";\nimport type { WidgetCreateOptions } from \"../types.js\";\nimport {\n copyWidgetTemplate,\n directoryExists,\n getCliVersion,\n getDefaultTemplatePath,\n getPortalCoreVersion,\n getPortalSdkVersion,\n getWidgetCliVersion,\n} from \"../utils/template.js\";\nimport {\n getInstallCommand,\n getRunCommand,\n installDependencies,\n} from \"../utils/package-manager.js\";\nimport {\n mergeWidgetConfig,\n validateDropletUuid,\n writeWidgetConfig,\n} from \"../utils/config.js\";\nimport { tryFetchGithubTemplate } from \"../utils/github-template.js\";\n\nconst DEFAULT_WIDGET_PACKAGE_VERSION = \"0.1.0\";\nconst DEFAULT_WIDGET_SCOPE = \"droplet\";\n\nexport const createCommand: Command = new Command(\"create\")\n .description(\"Create a standalone Fluid widget project\")\n .argument(\"<project-name>\", \"Name of the widget project to create\")\n .option(\"--skip-install\", \"Skip dependency installation\")\n .option(\n \"-o, --output-dir <dir>\",\n \"Directory to create the project in (defaults to cwd)\",\n )\n .option(\n \"--scope <scope>\",\n \"Widget package scope/namespace\",\n DEFAULT_WIDGET_SCOPE,\n )\n .option(\n \"--package-version <version>\",\n \"Initial widget package version\",\n DEFAULT_WIDGET_PACKAGE_VERSION,\n )\n .option(\n \"--local\",\n \"Use local monorepo packages via file: links (for development testing)\",\n )\n .option(\n \"--skip-remote-template\",\n \"Use the bundled template instead of pulling the GitHub starter template\",\n )\n .option(\"--droplet <uuid>\", \"Existing droplet UUID that owns the package\")\n .action(async (projectName: string, options: WidgetCreateOptions) => {\n try {\n await createWidgetProject(projectName, options);\n } catch (err) {\n console.log();\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n process.exit(1);\n }\n });\n\nexport async function createWidgetProject(\n projectName: string,\n options: WidgetCreateOptions,\n): Promise<void> {\n console.log();\n console.log(chalk.bold(\"Creating a new Fluid widget project\"));\n console.log();\n\n const projectNameError = validateProjectName(projectName);\n if (projectNameError) throw new Error(projectNameError);\n\n const droplet = options.droplet?.trim();\n if (droplet) {\n const dropletError = validateDropletUuid(droplet);\n if (dropletError) throw new Error(dropletError);\n }\n\n const outputDir = path.resolve(options.outputDir ?? process.cwd());\n const targetPath = path.join(outputDir, projectName);\n if (await directoryExists(targetPath)) {\n throw new Error(`Directory already exists: ${targetPath}`);\n }\n\n const templatePath = getDefaultTemplatePath();\n if (!(await directoryExists(templatePath))) {\n throw new Error(\"Default widget template not found.\");\n }\n\n const config = mergeWidgetConfig({}, { droplet });\n const widgetScope = options.scope ?? DEFAULT_WIDGET_SCOPE;\n const localOptions = { local: options.local === true, targetPath };\n const variables = {\n projectName,\n droplet: config.droplet,\n widgetScope,\n widgetPackageVersion:\n options.packageVersion ?? DEFAULT_WIDGET_PACKAGE_VERSION,\n sdkVersion: await getPortalSdkVersion(localOptions),\n localCoreVersion: options.local\n ? await getPortalCoreVersion(localOptions)\n : undefined,\n fluidCliVersion: await getCliVersion(localOptions),\n widgetCliVersion: await getWidgetCliVersion(localOptions),\n };\n\n // Prefer the GitHub starter template so teams pick up template updates\n // without a CLI release and new projects share the widget git model. Fall\n // back to the bundled template (with a printed warning) when git/network/the\n // repo is unavailable, or when it can't apply (--local needs file: links the\n // rendered repo can't provide). create must never hard-fail offline.\n const useRemoteTemplate =\n options.local !== true && options.skipRemoteTemplate !== true;\n\n let scaffolded = false;\n if (useRemoteTemplate) {\n const remoteSpinner = ora(\n \"Fetching widget template from GitHub...\",\n ).start();\n scaffolded = await tryFetchGithubTemplate(targetPath, {\n projectName,\n widgetScope,\n widgetPackageVersion:\n options.packageVersion ?? DEFAULT_WIDGET_PACKAGE_VERSION,\n });\n if (scaffolded) {\n remoteSpinner.succeed(\"Fetched widget template from GitHub\");\n } else {\n remoteSpinner.warn(\n \"Couldn't fetch the GitHub template (git, network, or repo unavailable) — using the bundled template.\",\n );\n }\n }\n\n const spinner = ora(\n scaffolded ? \"Finalizing widget project...\" : \"Copying widget template...\",\n ).start();\n try {\n if (!scaffolded) {\n await copyWidgetTemplate(templatePath, targetPath, variables);\n }\n await writeWidgetConfig(targetPath, config);\n spinner.succeed(\n scaffolded ? \"Prepared widget project\" : \"Copied widget template\",\n );\n } catch (err) {\n spinner.fail(\"Failed to create widget project\");\n throw err;\n }\n\n const installCommand = getInstallCommand(targetPath);\n if (options.skipInstall !== true) {\n spinner.start(`Installing dependencies with ${installCommand}...`);\n try {\n await installDependencies(targetPath);\n spinner.succeed(\"Installed dependencies\");\n } catch {\n spinner.fail(\"Failed to install dependencies\");\n console.log();\n console.log(chalk.yellow(\"You can install dependencies manually:\"));\n console.log(chalk.cyan(` cd ${formatCdPath(targetPath)}`));\n console.log(chalk.cyan(` ${installCommand}`));\n }\n }\n\n console.log();\n console.log(\n chalk.green.bold(\"Success!\") + ` Created ${chalk.cyan(projectName)}`,\n );\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.cyan(` cd ${formatCdPath(targetPath)}`));\n if (options.skipInstall === true) {\n console.log(chalk.cyan(` ${installCommand}`));\n }\n if (!config.droplet) {\n console.log(chalk.cyan(\" fluid widget link\"));\n }\n console.log(chalk.cyan(` ${getRunCommand(\"dev\", targetPath)}`));\n console.log();\n console.log(\n \"Edit \" + chalk.cyan(\"manifest.ts\") + \" to customize your widget package.\",\n );\n console.log(\n chalk.dim(\n \"This command only creates local project files; it does not create a droplet.\",\n ),\n );\n console.log();\n}\n\nfunction validateProjectName(projectName: string): string | undefined {\n if (!projectName) return \"Project name is required.\";\n if (!/^[a-z0-9][a-z0-9-]*$/.test(projectName)) {\n return \"Project name must contain only lowercase letters, numbers, and hyphens.\";\n }\n return undefined;\n}\n\nfunction formatCdPath(targetPath: string): string {\n return path.relative(process.cwd(), targetPath) || \".\";\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { runCliAction } from \"../utils/command.js\";\nimport {\n getInstallCommand,\n installDependencies,\n} from \"../utils/package-manager.js\";\n\nexport const DEFAULT_WIDGET_DEV_PORT = 5174;\n\nexport const WIDGET_DEV_ROUTES = [\n \"/__widget-packages__\",\n \"/__runtime-entry__\",\n] as const;\n\nexport interface WidgetDevOptions {\n readonly port?: string;\n readonly host?: boolean | string;\n readonly mode?: string;\n}\n\nexport interface WidgetDevProjectSummary {\n readonly projectDir: string;\n readonly packageName: string;\n readonly viteConfigPath: string;\n readonly localUrl: string;\n readonly target: string;\n readonly mode: string;\n readonly routes: readonly string[];\n}\n\nexport const devCommand: Command = new Command(\"dev\")\n .description(\"Start the local Fluid widget development endpoints\")\n .option(\n \"-p, --port <port>\",\n \"Port to run the widget dev server on\",\n String(DEFAULT_WIDGET_DEV_PORT),\n )\n .option(\"--host [host]\", \"Expose the dev server to the network\")\n .option(\"--mode <mode>\", \"Vite mode to run\", \"development\")\n .action((options: WidgetDevOptions) => {\n return runCliAction(async () => {\n const projectDir = process.cwd();\n const summary = await resolveWidgetDevProject(projectDir, options);\n\n printWidgetDevSummary(summary);\n await runViteDevServer(projectDir, options);\n });\n });\n\nexport async function resolveWidgetDevProject(\n projectDir: string,\n options: WidgetDevOptions = {},\n): Promise<WidgetDevProjectSummary> {\n const resolvedProjectDir = path.resolve(projectDir);\n const packageJsonPath = path.join(resolvedProjectDir, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n throw new Error(\n \"No package.json found. Run this command from a Fluid widget project directory.\",\n );\n }\n\n const packageJson = await readPackageJson(packageJsonPath);\n const packageName = readPackageName(packageJson) ?? path.basename(projectDir);\n\n const viteConfigPath = path.join(resolvedProjectDir, \"vite.config.ts\");\n if (!existsSync(viteConfigPath)) {\n throw new Error(\n \"No vite.config.ts found. Run this command from a Fluid widget project directory.\",\n );\n }\n\n const port = parsePort(options.port ?? String(DEFAULT_WIDGET_DEV_PORT));\n const host = normalizeHostOption(options.host);\n const mode = normalizeMode(options.mode);\n\n return {\n projectDir: resolvedProjectDir,\n packageName,\n viteConfigPath,\n localUrl: formatLocalUrl(port, host),\n target: packageName,\n mode,\n routes: WIDGET_DEV_ROUTES,\n };\n}\n\nexport function buildViteDevArgs(options: WidgetDevOptions = {}): string[] {\n const port = parsePort(options.port ?? String(DEFAULT_WIDGET_DEV_PORT));\n const host = normalizeHostOption(options.host);\n const mode = normalizeMode(options.mode);\n const args = [\"--port\", String(port), \"--mode\", mode];\n\n if (host) {\n args.push(\"--host\", host);\n }\n\n return args;\n}\n\nexport function printWidgetDevSummary(summary: WidgetDevProjectSummary): void {\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Dev\"));\n console.log(chalk.gray(\"Local: \") + chalk.cyan(summary.localUrl));\n console.log(chalk.gray(\"Target: \") + chalk.white(summary.target));\n console.log(chalk.gray(\"Mode: \") + chalk.white(summary.mode));\n console.log(chalk.gray(\"Routes:\"));\n for (const route of summary.routes) {\n console.log(chalk.gray(\" - \") + chalk.cyan(route));\n }\n console.log();\n}\n\nexport async function runViteDevServer(\n projectDir: string,\n options: WidgetDevOptions = {},\n): Promise<void> {\n let viteCliPath = resolveViteCliPath(projectDir);\n if (!viteCliPath) {\n // Cloned checkouts arrive without node_modules (`fluid widget clone` is a\n // pure git operation) and agent-scaffolded projects may skip the install\n // too. Install once here instead of bouncing the user to a manual step.\n const installCommand = getInstallCommand(projectDir);\n console.log(\n chalk.yellow(\n `Vite is not installed yet — running ${installCommand} first...`,\n ),\n );\n try {\n await installDependencies(projectDir);\n } catch {\n // Fall through to the resolution check below for the actionable error.\n }\n viteCliPath = resolveViteCliPath(projectDir);\n }\n if (!viteCliPath) {\n throw new Error(\n `Unable to find Vite in node_modules. Run \\`${getInstallCommand(projectDir)}\\` in ${projectDir}, then retry.`,\n );\n }\n\n await runNodeScript(viteCliPath, buildViteDevArgs(options), projectDir);\n}\n\nfunction resolveViteCliPath(projectDir: string): string | undefined {\n const viteCliPath = path.join(\n projectDir,\n \"node_modules\",\n \"vite\",\n \"bin\",\n \"vite.js\",\n );\n return existsSync(viteCliPath) ? viteCliPath : undefined;\n}\n\nasync function readPackageJson(packageJsonPath: string): Promise<unknown> {\n try {\n return JSON.parse(await readFile(packageJsonPath, \"utf-8\")) as unknown;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Unable to read package.json: ${message}`);\n }\n}\n\nfunction readPackageName(packageJson: unknown): string | undefined {\n if (!isRecord(packageJson)) return undefined;\n const name = packageJson[\"name\"];\n if (typeof name !== \"string\") return undefined;\n const trimmed = name.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction parsePort(value: string): number {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(\"Port must be an integer between 1 and 65535.\");\n }\n return port;\n}\n\nfunction normalizeHostOption(\n host: WidgetDevOptions[\"host\"],\n): string | undefined {\n if (host === undefined || host === false) return undefined;\n if (host === true) return \"0.0.0.0\";\n\n const trimmed = host.trim();\n return trimmed.length > 0 ? trimmed : \"0.0.0.0\";\n}\n\nfunction normalizeMode(mode: string | undefined): string {\n const trimmed = mode?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : \"development\";\n}\n\nfunction formatLocalUrl(port: number, host: string | undefined): string {\n const displayHost = host && host !== \"0.0.0.0\" ? host : \"localhost\";\n return `http://${displayHost}:${port}`;\n}\n\nfunction runNodeScript(\n scriptPath: string,\n args: readonly string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(process.execPath, [scriptPath, ...args], {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code, signal) => {\n if (code === 0 || signal === \"SIGINT\" || signal === \"SIGTERM\") {\n resolve();\n return;\n }\n\n reject(\n new Error(\n signal\n ? `Vite dev server exited with signal ${signal}.`\n : `Vite dev server exited with code ${code ?? \"unknown\"}.`,\n ),\n );\n });\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\n\nexport interface AuthenticatedClientResult {\n readonly client: FetchClient;\n}\n\nexport function createAuthenticatedClient(): AuthenticatedClientResult {\n return { client: createAuthenticatedWidgetPackageClient() };\n}\n","import prompts from \"prompts\";\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport type { Choice } from \"prompts\";\n\nexport interface DropletChoice {\n readonly uuid: string;\n readonly name: string;\n}\n\nconst MAX_DROPLET_PAGES = 100;\n\nexport async function promptForDroplet(\n client: FetchClient,\n): Promise<string | undefined> {\n const droplets = await listDroplets(client);\n\n if (droplets.length === 0) {\n throw new Error(\n \"No droplets were found for this account. Create a droplet in Fluid first, then run this command again.\",\n );\n }\n\n const response = await prompts({\n type: \"autocomplete\",\n name: \"droplet\",\n message: \"Select the droplet that owns this widget package\",\n choices: droplets.map((droplet) => ({\n title: `${droplet.name} (${droplet.uuid})`,\n value: droplet.uuid,\n })),\n suggest: (input: string, choices: Choice[]) =>\n Promise.resolve(\n input\n ? choices.filter((choice) =>\n choice.title.toLowerCase().includes(input.toLowerCase()),\n )\n : choices,\n ),\n });\n\n return response[\"droplet\"] as string | undefined;\n}\n\nexport async function listDroplets(\n client: FetchClient,\n): Promise<readonly DropletChoice[]> {\n try {\n const firstResponse = await client.get<unknown>(\"/api/droplets\", {\n page: 1,\n });\n const totalPages = Math.min(\n readTotalPages(firstResponse) ?? 1,\n MAX_DROPLET_PAGES,\n );\n const responses = [firstResponse];\n\n for (let page = 2; page <= totalPages; page += 1) {\n responses.push(\n await client.get<unknown>(\"/api/droplets\", {\n page,\n }),\n );\n }\n\n return responses.flatMap(normalizeDropletsResponse);\n } catch (err) {\n if (isApiLikeError(err)) {\n if (err.status === 401 || err.status === 403) {\n throw new Error(\n \"Your Fluid session has expired. Run `fluid login` and try again.\",\n );\n }\n throw new Error(\n `Could not fetch droplets from Fluid (HTTP ${err.status}). ${err.message}`,\n );\n }\n\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Could not fetch droplets from Fluid. ${message}`);\n }\n}\n\nfunction readTotalPages(response: unknown): number | undefined {\n if (!isRecord(response)) return undefined;\n const meta = response[\"meta\"];\n if (!isRecord(meta)) return undefined;\n const pagination = meta[\"pagination\"];\n if (!isRecord(pagination)) return undefined;\n const totalPages = pagination[\"total_pages\"] ?? pagination[\"totalPages\"];\n if (\n typeof totalPages !== \"number\" ||\n !Number.isInteger(totalPages) ||\n totalPages < 1\n ) {\n return undefined;\n }\n return totalPages;\n}\n\nfunction normalizeDropletsResponse(response: unknown): DropletChoice[] {\n const candidates = extractDropletArray(response);\n return candidates\n .map(normalizeDroplet)\n .filter((droplet): droplet is DropletChoice => droplet !== undefined);\n}\n\nfunction extractDropletArray(response: unknown): readonly unknown[] {\n if (Array.isArray(response)) return response;\n if (!isRecord(response)) return [];\n\n const directDroplets = response[\"droplets\"];\n if (Array.isArray(directDroplets)) return directDroplets;\n\n const data = response[\"data\"];\n if (Array.isArray(data)) return data;\n if (isRecord(data) && Array.isArray(data[\"droplets\"])) {\n return data[\"droplets\"];\n }\n\n return [];\n}\n\nfunction normalizeDroplet(value: unknown): DropletChoice | undefined {\n if (!isRecord(value)) return undefined;\n\n const uuid = readString(value, \"uuid\") ?? readString(value, \"id\");\n if (!uuid) return undefined;\n\n const name =\n readString(value, \"name\") ??\n readString(value, \"title\") ??\n readString(value, \"slug\") ??\n uuid;\n\n return { uuid, name };\n}\n\nfunction readString(\n record: Readonly<Record<string, unknown>>,\n key: string,\n): string | undefined {\n const value = record[key];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction isApiLikeError(\n error: unknown,\n): error is { readonly status: number; readonly message: string } {\n return (\n error instanceof Error &&\n \"status\" in error &&\n typeof (error as { readonly status?: unknown }).status === \"number\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import path from \"node:path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { WidgetLinkOptions } from \"../types.js\";\nimport { createAuthenticatedClient } from \"../utils/auth-client.js\";\nimport { promptForDroplet } from \"../utils/droplets.js\";\nimport {\n WIDGET_CONFIG_FILE,\n loadWidgetConfig,\n mergeWidgetConfig,\n validateDropletUuid,\n writeWidgetConfig,\n} from \"../utils/config.js\";\n\nexport const linkCommand: Command = new Command(\"link\")\n .description(\"Link this widget project to an existing Fluid droplet\")\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .action(async (options: WidgetLinkOptions) => {\n try {\n const projectDir = process.cwd();\n const loaded = await loadWidgetConfig(projectDir);\n\n let droplet = options.droplet?.trim() || undefined;\n if (!droplet) {\n const spinner = ora(\"Fetching droplets...\").start();\n try {\n const { client } = createAuthenticatedClient();\n spinner.stop();\n droplet = await promptForDroplet(client);\n } catch (err) {\n spinner.fail(\"Unable to load droplets\");\n throw err;\n }\n\n if (!droplet) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n }\n\n const nextConfig = mergeWidgetConfig(loaded.config, { droplet });\n const nextDropletError = validateDropletUuid(nextConfig.droplet ?? \"\");\n if (nextDropletError) throw new Error(nextDropletError);\n\n await writeWidgetConfig(projectDir, nextConfig);\n\n console.log();\n console.log(chalk.green(\"Linked widget project.\"));\n console.log(\n chalk.gray(\"Config: \") +\n chalk.cyan(\n path.relative(projectDir, loaded.path) || WIDGET_CONFIG_FILE,\n ),\n );\n console.log(\n chalk.gray(\"Droplet: \") + chalk.white(nextConfig.droplet),\n );\n console.log(\n chalk.gray(\"Package key: \") +\n chalk.white(`${nextConfig.droplet} (derived from droplet)`),\n );\n console.log();\n } catch (err) {\n console.log();\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n process.exit(1);\n }\n });\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\n\nexport interface DropletWidgetVersionSummary {\n readonly packageKey?: string;\n readonly packageId?: string;\n readonly version?: string;\n readonly status?: string;\n readonly createdAt?: string;\n readonly updatedAt?: string;\n readonly artifactCount?: number;\n readonly raw: unknown;\n}\n\nexport interface DropletWidgetLogEntry {\n readonly timestamp?: string;\n readonly level?: string;\n readonly message: string;\n readonly raw: unknown;\n}\n\nexport async function fetchDropletWidgetStatus(options: {\n readonly client: FetchClient;\n readonly droplet: string;\n}): Promise<DropletWidgetVersionSummary[]> {\n const response = await options.client.get<unknown>(\n `/api/droplets/${encodeURIComponent(options.droplet)}/widget_package_versions`,\n );\n return extractArray(response).map(normalizeVersionSummary);\n}\n\nexport async function fetchDropletWidgetLogs(options: {\n readonly client: FetchClient;\n readonly droplet: string;\n readonly limit?: number;\n}): Promise<DropletWidgetLogEntry[]> {\n const response = await options.client.get<unknown>(\n `/api/droplets/${encodeURIComponent(options.droplet)}/widget_package_versions/logs`,\n options.limit ? { limit: options.limit } : undefined,\n );\n return extractArray(response).map(normalizeLogEntry);\n}\n\nexport function formatStatusRows(\n versions: readonly DropletWidgetVersionSummary[],\n): string {\n if (versions.length === 0) return \"No widget package versions found.\";\n\n return versions\n .map((version) => {\n const identity =\n version.packageId ?? version.packageKey ?? \"unknown-package\";\n const release = version.version ?? \"unknown-version\";\n const status = version.status ?? \"unknown\";\n const updated = version.updatedAt ?? version.createdAt ?? \"unknown time\";\n const artifacts =\n version.artifactCount === undefined\n ? \"unknown artifacts\"\n : `${version.artifactCount} artifact${version.artifactCount === 1 ? \"\" : \"s\"}`;\n return `${identity}@${release} — ${status} — ${artifacts} — ${updated}`;\n })\n .join(\"\\n\");\n}\n\nexport function formatLogRows(logs: readonly DropletWidgetLogEntry[]): string {\n if (logs.length === 0) return \"No widget package logs found.\";\n\n return logs\n .map((entry) => {\n const timestamp = entry.timestamp ?? \"unknown time\";\n const level = entry.level ? entry.level.toUpperCase() : \"INFO\";\n return `[${timestamp}] ${level} ${entry.message}`;\n })\n .join(\"\\n\");\n}\n\nfunction normalizeVersionSummary(value: unknown): DropletWidgetVersionSummary {\n const record = unwrapKnownNestedRecord(value);\n const artifacts = readArray(record, \"artifacts\");\n return {\n packageKey: readFirstString(record, [\"package_key\", \"packageKey\"]),\n packageId: readFirstString(record, [\"package_id\", \"packageId\"]),\n version: readFirstString(record, [\"version\", \"name\"]),\n status: readFirstString(record, [\"status\", \"state\"]),\n createdAt: readFirstString(record, [\"created_at\", \"createdAt\"]),\n updatedAt: readFirstString(record, [\"updated_at\", \"updatedAt\"]),\n ...(artifacts ? { artifactCount: artifacts.length } : {}),\n raw: value,\n };\n}\n\nfunction normalizeLogEntry(value: unknown): DropletWidgetLogEntry {\n const record = unwrapKnownNestedRecord(value);\n return {\n timestamp: readFirstString(record, [\n \"timestamp\",\n \"created_at\",\n \"createdAt\",\n ]),\n level: readFirstString(record, [\"level\", \"severity\"]),\n message:\n readFirstString(record, [\"message\", \"event\", \"status\", \"state\"]) ??\n JSON.stringify(value),\n raw: value,\n };\n}\n\nfunction extractArray(value: unknown): unknown[] {\n if (Array.isArray(value)) return value;\n if (!isRecord(value)) return [];\n\n for (const key of [\n \"widget_package_versions\",\n \"widgetPackageVersions\",\n \"versions\",\n \"logs\",\n \"events\",\n \"data\",\n ] as const) {\n const nested = value[key];\n if (Array.isArray(nested)) return nested;\n }\n\n return [value];\n}\n\nfunction unwrapKnownNestedRecord(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) return {};\n for (const key of [\n \"widget_package_version\",\n \"widgetPackageVersion\",\n \"version\",\n \"log\",\n \"event\",\n ] as const) {\n const nested = value[key];\n if (isRecord(nested)) return nested;\n }\n return value;\n}\n\nfunction readArray(\n record: Record<string, unknown>,\n key: string,\n): readonly unknown[] | undefined {\n const value = record[key];\n return Array.isArray(value) ? value : undefined;\n}\n\nfunction readFirstString(\n record: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value;\n if (typeof value === \"number\" && Number.isFinite(value))\n return String(value);\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { Command } from \"commander\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport { loadWidgetConfig, validateDropletUuid } from \"../utils/config.js\";\nimport { fetchDropletWidgetLogs, formatLogRows } from \"../utils/droplet-api.js\";\nimport { runCliAction } from \"../utils/command.js\";\n\nexport interface LogsCommandOptions {\n readonly droplet?: string;\n readonly limit?: string;\n readonly json?: boolean;\n}\n\nexport const logsCommand: Command = new Command(\"logs\")\n .description(\"Show recent widget package publish logs for a Droplet\")\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--limit <number>\", \"Maximum number of log entries to request\", \"50\")\n .option(\"--json\", \"Print raw log response as JSON\")\n .action((options: LogsCommandOptions) => {\n return runCliAction(async () => {\n const droplet = await resolveDroplet(process.cwd(), options.droplet);\n const limit = parseLimit(options.limit);\n const logs = await fetchDropletWidgetLogs({\n client: createAuthenticatedWidgetPackageClient(),\n droplet,\n limit,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n logs.map((entry) => entry.raw),\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(chalk.blue.bold(`Widget logs for droplet ${droplet}`));\n console.log();\n console.log(formatLogRows(logs));\n });\n });\n\nasync function resolveDroplet(\n projectDir: string,\n override: string | undefined,\n): Promise<string> {\n const droplet =\n override?.trim() || (await loadWidgetConfig(projectDir)).config.droplet;\n if (droplet?.trim()) {\n const trimmedDroplet = droplet.trim();\n const dropletError = validateDropletUuid(trimmedDroplet);\n if (dropletError) throw new Error(dropletError);\n return trimmedDroplet;\n }\n\n throw new Error(\n \"Missing droplet UUID. Pass --droplet <uuid> or set droplet in fluid.widget.config.ts.\",\n );\n}\n\nfunction parseLimit(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number(value);\n if (Number.isInteger(parsed) && parsed > 0 && parsed <= 500) return parsed;\n throw new Error(\"--limit must be an integer between 1 and 500.\");\n}\n","import { Command } from \"commander\";\nimport {\n createAuthenticatedWidgetPackageClient,\n printDryRunSessionPayload,\n printRuntimeOnlyNotice,\n printWidgetPublishSummary,\n publishWidgetRuntimeArtifacts,\n} from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n DEFAULT_WIDGET_OUT_DIR,\n validateDropletWidgetProject,\n withRootWidgetConfigBridge,\n} from \"../utils/source-package.js\";\nimport { loadWidgetConfig, validateDropletUuid } from \"../utils/config.js\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { runPackageScriptIfAvailable } from \"../utils/package-scripts.js\";\n\nexport interface PublishWidgetPackageOptions {\n readonly projectDir: string;\n readonly outDir: string;\n readonly droplet?: string;\n readonly dryRun?: boolean;\n readonly skipTypecheck?: boolean;\n readonly client?: unknown;\n}\n\nexport interface PublishWidgetPackageResult {\n readonly dryRun: boolean;\n readonly uploaded: boolean;\n readonly outDir: string;\n readonly droplet?: string;\n}\n\nexport interface PublishWidgetPackageDependencies {\n readonly buildWidgetPackage: (options: {\n readonly projectDir: string;\n readonly outDir: string;\n }) => Promise<void>;\n readonly uploadWidgetPackage: (options: {\n readonly outDir: string;\n readonly droplet?: string;\n readonly client?: unknown;\n }) => Promise<void>;\n}\n\nexport async function publishWidgetPackage(\n options: PublishWidgetPackageOptions,\n dependencies?: PublishWidgetPackageDependencies,\n): Promise<PublishWidgetPackageResult> {\n if (dependencies) {\n await dependencies.buildWidgetPackage({\n projectDir: options.projectDir,\n outDir: options.outDir,\n });\n\n const dryRun = options.dryRun === true;\n if (dryRun) {\n return { dryRun, uploaded: false, outDir: options.outDir };\n }\n\n await dependencies.uploadWidgetPackage({\n outDir: options.outDir,\n droplet: options.droplet,\n client: options.client,\n });\n return { dryRun, uploaded: true, outDir: options.outDir };\n }\n\n const droplet = await resolvePublishDroplet(\n options.projectDir,\n options.droplet,\n );\n\n await validateDropletWidgetProject(options.projectDir, droplet);\n if (options.skipTypecheck !== true) {\n await runPackageScriptIfAvailable({\n projectDir: options.projectDir,\n scriptName: \"typecheck\",\n });\n }\n\n const dryRun = options.dryRun === true;\n await withRootWidgetConfigBridge(\n options.projectDir,\n () =>\n publishWidgetRuntimeArtifacts({\n projectDir: options.projectDir,\n outDir: options.outDir,\n buildOwner: \"droplet\",\n uploadOwner: { kind: \"droplet\", uuid: droplet },\n dryRun,\n ...(dryRun ? {} : { client: createAuthenticatedWidgetPackageClient() }),\n }),\n droplet,\n );\n\n return {\n dryRun,\n uploaded: !dryRun,\n outDir: options.outDir,\n droplet,\n };\n}\n\nexport interface PublishCommandOptions {\n readonly outDir?: string;\n readonly droplet?: string;\n readonly dryRun?: boolean;\n readonly skipTypecheck?: boolean;\n}\n\nexport const publishCommand: Command = new Command(\"publish\")\n .description(\"Publish a Fluid widget package\")\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_WIDGET_OUT_DIR,\n )\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--dry-run\", \"Build and validate without uploading\")\n .option(\"--skip-typecheck\", \"Skip package typecheck script when present\")\n .action((options: PublishCommandOptions) => {\n return runCliAction(async () => {\n const projectDir = process.cwd();\n const outDir = options.outDir ?? DEFAULT_WIDGET_OUT_DIR;\n const droplet = await resolvePublishDroplet(projectDir, options.droplet);\n const dryRun = options.dryRun === true;\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Publish\"));\n console.log();\n printRuntimeOnlyNotice();\n console.log(chalk.gray(\"Droplet: \") + chalk.white(droplet));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n if (dryRun) {\n console.log(chalk.yellow(\"Dry run: no upload will be created.\"));\n }\n console.log();\n\n const validateSpinner = ora(\"Validating widget package...\").start();\n await validateDropletWidgetProject(projectDir, droplet);\n validateSpinner.succeed(\"Validated widget package\");\n\n if (options.skipTypecheck !== true) {\n const typecheckSpinner = ora(\"Running package typecheck...\").start();\n const typecheck = await runPackageScriptIfAvailable({\n projectDir,\n scriptName: \"typecheck\",\n });\n if (typecheck.ran) {\n typecheckSpinner.succeed(\"Package typecheck passed\");\n } else {\n typecheckSpinner.info(\"No typecheck script found; skipping\");\n }\n }\n\n const publishSpinner = ora(\n dryRun\n ? \"Building and preparing dry-run upload payload...\"\n : \"Building and publishing widget artifacts...\",\n ).start();\n\n const result = await withRootWidgetConfigBridge(\n projectDir,\n () =>\n publishWidgetRuntimeArtifacts({\n projectDir,\n outDir,\n buildOwner: \"droplet\",\n uploadOwner: { kind: \"droplet\", uuid: droplet },\n dryRun,\n ...(dryRun\n ? {}\n : { client: createAuthenticatedWidgetPackageClient() }),\n }),\n droplet,\n );\n\n publishSpinner.succeed(\n dryRun ? \"Prepared dry-run upload payload\" : \"Published widget package\",\n );\n\n if (dryRun) {\n console.log(\n chalk.yellow(\"Dry run complete — upload session was not requested.\"),\n );\n console.log();\n printDryRunSessionPayload(result);\n }\n\n printWidgetPublishSummary({\n title: dryRun ? \"Widget publish dry run\" : \"Widget publish\",\n ownerLabel: `droplet ${droplet}`,\n outDir,\n result,\n });\n });\n });\n\nexport async function resolvePublishDroplet(\n projectDir: string,\n override: string | undefined,\n): Promise<string> {\n const droplet =\n override?.trim() || (await loadWidgetConfig(projectDir)).config.droplet;\n if (droplet?.trim()) {\n const trimmedDroplet = droplet.trim();\n const dropletError = validateDropletUuid(trimmedDroplet);\n if (dropletError) throw new Error(dropletError);\n return trimmedDroplet;\n }\n\n throw new Error(\n \"Missing droplet UUID. Pass --droplet <uuid> or set droplet in fluid.widget.config.ts.\",\n );\n}\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\n\n/**\n * `GET /api/me` — the authenticated user's identity, used to stamp auto-commit\n * messages with `<name>: <msg> (<public_id>)` so collaboration history traces\n * back to a real person. Best-effort: push still commits if this fails.\n */\nexport interface CurrentUser {\n readonly name: string | null;\n readonly publicId: string | null;\n}\n\ninterface MeResponse {\n readonly id?: unknown;\n readonly public_id?: unknown;\n readonly full_name?: unknown;\n readonly first_name?: unknown;\n readonly last_name?: unknown;\n readonly email?: unknown;\n}\n\nfunction str(value: unknown): string | null {\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n return null;\n}\n\nexport async function fetchCurrentUser(\n client: FetchClient,\n): Promise<CurrentUser> {\n const raw = await client.get<MeResponse>(\"/api/me\");\n const composed = [str(raw.first_name), str(raw.last_name)]\n .filter((part): part is string => part !== null)\n .join(\" \")\n .trim();\n const idValue =\n str(raw.public_id) ??\n (typeof raw.id === \"number\" && Number.isFinite(raw.id)\n ? String(raw.id)\n : null);\n return {\n name:\n str(raw.full_name) ??\n (composed.length > 0 ? composed : null) ??\n str(raw.email),\n publicId: idValue,\n };\n}\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport {\n gitAdoptFetchHead,\n gitAheadBehindVsFetchHead,\n gitAutoCommit,\n gitFetch,\n gitInit,\n gitMergeFastForward,\n gitPush,\n gitRemoteBranchExists,\n gitStash,\n gitStashPop,\n hasCommits,\n hasUncommittedChanges,\n isGitRepository,\n type GitCommitIdentity,\n} from \"./git.js\";\nimport { mintWidgetGitCredential } from \"../utils/git-credential.js\";\nimport { fetchCurrentUser } from \"../utils/me.js\";\n\nexport interface SyncWidgetGitRepoOptions {\n readonly cwd: string;\n readonly client: FetchClient;\n /** Droplet UUID that owns the package; omitted for company-owned packages. */\n readonly droplet?: string;\n readonly branch?: string;\n /** Base auto-commit message (before the author/public-id stamp). */\n readonly message?: string;\n /** Skip the auto-commit step and push existing commits only. */\n readonly commit?: boolean;\n}\n\nexport type SyncWidgetGitRepoResult =\n | {\n readonly kind: \"synced\";\n readonly pulled: number;\n readonly committed: boolean;\n }\n | {\n readonly kind: \"diverged\";\n readonly ahead: number;\n readonly behind: number;\n };\n\n/**\n * Sync a widget project's invisible git repo: mint a credential, reconcile\n * with origin (fast-forward pull when safe), auto-commit working-tree changes\n * with an author-stamped message, and push HEAD to the branch.\n *\n * Mirrors the Mist CLI write path (`packages/cli/mist/src/commands/push.ts`).\n * Throws on hard failures (mint error, diverged history is returned rather\n * than thrown so the caller can message it); the token-bearing remote URL is\n * only ever handed to the git helpers, never logged or persisted.\n */\nexport async function syncWidgetGitRepo(\n options: SyncWidgetGitRepoOptions,\n): Promise<SyncWidgetGitRepoResult> {\n const { cwd, client } = options;\n const branch = options.branch ?? \"main\";\n\n // Ensure a local repo exists — projects created via `fluid widget create`\n // have their git history stripped, so first push initializes one.\n if (!(await isGitRepository(cwd))) {\n await gitInit(cwd, branch);\n }\n\n // Mint one credential for the whole sync — tokens live ~1h, far beyond a\n // push. Minting again mid-flow would reintroduce a degrade window AFTER\n // the auto-commit: a 404/409 there reads as \"sync unavailable\" to the\n // caller, which would publish artifacts while the fresh commit stays\n // local. With a single mint, unavailability can only surface before any\n // local or remote mutation.\n const cred = await mintWidgetGitCredential({\n client,\n droplet: options.droplet,\n });\n\n // Reconcile against the remote before committing. `gitRemoteBranchExists`\n // and `gitFetch` both throw on transport/auth failure (propagated to the\n // caller as a hard error) so a network blip is never mistaken for an empty\n // remote — that would skip drift detection and let us push over a\n // collaborator's work. We only skip reconciliation when the branch\n // genuinely doesn't exist yet (freshly provisioned repo, first push).\n let pulled = 0;\n const branchExists = await gitRemoteBranchExists(cwd, cred.remoteUrl, branch);\n if (branchExists) {\n await gitFetch(cwd, cred.remoteUrl, branch);\n if (await hasCommits(cwd)) {\n const { ahead, behind } = await gitAheadBehindVsFetchHead(cwd);\n if (behind > 0 && ahead > 0) {\n return { kind: \"diverged\", ahead, behind };\n }\n if (behind > 0) {\n const wasDirty = await hasUncommittedChanges(cwd);\n if (wasDirty) await gitStash(cwd, \"fluid-widget-push: pre-pull stash\");\n try {\n await gitMergeFastForward(cwd);\n } finally {\n if (wasDirty) await gitStashPop(cwd); // throws on conflict\n }\n pulled = behind;\n }\n } else {\n // Brand-new local repo (`create` strips git history) but the remote\n // branch already has commits — the backend provisions repos with an\n // auto-init README (or starter-template) commit. Adopt that history\n // as the local base so the auto-commit below lands on top of it and\n // the push fast-forwards; a fresh root commit here would be rejected\n // as unrelated history.\n pulled = await gitAdoptFetchHead(cwd);\n }\n }\n\n // Auto-commit working-tree changes (unless --no-commit).\n let committed = false;\n if (options.commit !== false && (await hasUncommittedChanges(cwd))) {\n const message = await buildCommitMessage(client, options.message);\n await gitAutoCommit(cwd, message, await resolveCommitIdentity(client));\n committed = true;\n }\n\n await gitPush(cwd, cred.remoteUrl, branch);\n\n return { kind: \"synced\", pulled, committed };\n}\n\nconst DEFAULT_MESSAGE_PREFIX = \"Publish from Fluid widget CLI\";\n\nfunction timestamp(): string {\n return new Date().toISOString().slice(0, 19).replace(\"T\", \" \");\n}\n\n/**\n * Build the auto-commit message, stamped as `<name>: <msg> (<public_id>)` so\n * collaboration history traces back to a real person. Best-effort: a failed or\n * slow /api/me still yields a usable bare message.\n */\nasync function buildCommitMessage(\n client: FetchClient,\n base?: string,\n): Promise<string> {\n const baseMessage = base ?? `${DEFAULT_MESSAGE_PREFIX} · ${timestamp()}`;\n try {\n const me = await withTimeout(fetchCurrentUser(client), 5_000);\n const namePrefix = me.name ? `${me.name}: ` : \"\";\n const idSuffix = me.publicId ? ` (${me.publicId})` : \"\";\n return `${namePrefix}${baseMessage}${idSuffix}`;\n } catch {\n return baseMessage;\n }\n}\n\n/** Prefer the Fluid user for the git author when the repo has no identity. */\nasync function resolveCommitIdentity(\n client: FetchClient,\n): Promise<GitCommitIdentity | undefined> {\n try {\n const me = await withTimeout(fetchCurrentUser(client), 5_000);\n if (me.name) {\n return { name: me.name, email: \"cli@fluid.app\" };\n }\n } catch {\n // Fall through to the git.ts default identity.\n }\n return undefined;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms),\n ),\n ]);\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport { DEFAULT_WIDGET_OUT_DIR } from \"../utils/source-package.js\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { syncWidgetGitRepo } from \"../lib/git-sync.js\";\nimport { GitError } from \"../lib/git.js\";\nimport { isGitSyncUnavailable } from \"../utils/git-credential.js\";\nimport { publishWidgetPackage, resolvePublishDroplet } from \"./publish.js\";\n\nexport interface PushCommandOptions {\n readonly outDir?: string;\n readonly droplet?: string;\n readonly dryRun?: boolean;\n readonly skipTypecheck?: boolean;\n readonly branch?: string;\n readonly message?: string;\n /** Set false by `--no-commit`: push existing commits without auto-committing. */\n readonly commit?: boolean;\n /** Sync the git repo but skip the build + publish pipeline. */\n readonly skipPublish?: boolean;\n}\n\nexport const pushCommand: Command = new Command(\"push\")\n .description(\n \"Sync the widget's git repository (commit + push), then build and publish\",\n )\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_WIDGET_OUT_DIR,\n )\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--branch <name>\", \"Branch to push (default: main)\")\n .option(\n \"-m, --message <message>\",\n \"Commit message for the auto-commit (default: timestamped Publish)\",\n )\n .option(\n \"--no-commit\",\n \"Skip the auto-commit step (push existing commits only)\",\n )\n .option(\n \"--skip-publish\",\n \"Sync the git repository only; skip build + publish\",\n )\n .option(\"--dry-run\", \"Build and validate without uploading (publish step)\")\n .option(\"--skip-typecheck\", \"Skip package typecheck script when present\")\n .action((options: PushCommandOptions) =>\n runCliAction(async () => {\n const projectDir = process.cwd();\n const outDir = options.outDir ?? DEFAULT_WIDGET_OUT_DIR;\n const droplet = await resolvePublishDroplet(projectDir, options.droplet);\n const branch = options.branch ?? \"main\";\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Push\"));\n console.log(chalk.gray(\"Droplet: \") + chalk.white(droplet));\n console.log();\n\n // --- Git sync phase -------------------------------------------------\n // Degrade to publish-only ONLY when git sync isn't in play: the backend\n // endpoint isn't deployed yet (404/409) or git isn't installed. Every\n // other failure — diverged history, stash-pop conflict, auth failure\n // after a local commit, rejected push — aborts BEFORE publish, so we\n // never leave artifacts published while the source repo is unsynced or\n // the local checkout is in a broken git state.\n const client = createAuthenticatedWidgetPackageClient();\n const syncSpinner = ora(\"Syncing widget repository…\").start();\n try {\n const result = await syncWidgetGitRepo({\n cwd: projectDir,\n client,\n droplet,\n branch,\n ...(options.message ? { message: options.message } : {}),\n ...(options.commit === false ? { commit: false } : {}),\n });\n if (result.kind === \"diverged\") {\n syncSpinner.fail(\n `Your local history and origin/${branch} have diverged ` +\n `(${result.ahead} ahead, ${result.behind} behind).`,\n );\n throw new Error(\n \"Resolve in a terminal with `git pull --rebase`, fix any conflicts, \" +\n \"then re-run `fluid widget push`. Nothing was published.\",\n );\n }\n const parts: string[] = [];\n if (result.pulled > 0) {\n parts.push(\n `pulled ${result.pulled} commit${result.pulled === 1 ? \"\" : \"s\"}`,\n );\n }\n parts.push(result.committed ? \"committed + pushed\" : \"pushed\");\n syncSpinner.succeed(`Synced widget repository (${parts.join(\", \")})`);\n } catch (err) {\n if (isGitSyncUnavailable(err)) {\n syncSpinner.info(\n \"Widget git sync isn't available yet — publishing artifacts only.\",\n );\n } else if (err instanceof GitError && err.exitCode === 127) {\n syncSpinner.warn(err.message);\n console.log(\n chalk.yellow(\n \"Skipping git sync (git unavailable); publishing artifacts only.\",\n ),\n );\n } else {\n // Hard failure — stop before publishing so source and artifacts\n // don't drift out of sync.\n if (syncSpinner.isSpinning) syncSpinner.fail(\"Git sync failed\");\n throw err;\n }\n }\n\n if (options.skipPublish === true) {\n console.log();\n console.log(chalk.dim(\"Skipped build + publish (--skip-publish).\"));\n return;\n }\n\n // --- Publish phase ---------------------------------------------------\n const dryRun = options.dryRun === true;\n const publishSpinner = ora(\n dryRun\n ? \"Building and preparing dry-run upload payload…\"\n : \"Building and publishing widget artifacts…\",\n ).start();\n try {\n await publishWidgetPackage({\n projectDir,\n outDir,\n droplet,\n dryRun,\n skipTypecheck: options.skipTypecheck === true,\n });\n publishSpinner.succeed(\n dryRun\n ? \"Prepared dry-run upload payload\"\n : \"Published widget package\",\n );\n } catch (err) {\n publishSpinner.fail(\"Publish failed\");\n throw err;\n }\n\n console.log();\n console.log(chalk.green.bold(\"Done.\"));\n }),\n );\n","import { Command } from \"commander\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport { loadWidgetConfig, validateDropletUuid } from \"../utils/config.js\";\nimport {\n fetchDropletWidgetStatus,\n formatStatusRows,\n} from \"../utils/droplet-api.js\";\nimport { runCliAction } from \"../utils/command.js\";\n\nexport interface StatusCommandOptions {\n readonly droplet?: string;\n readonly json?: boolean;\n}\n\nexport const statusCommand: Command = new Command(\"status\")\n .description(\"Show published widget package status for a Droplet\")\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--json\", \"Print raw status response as JSON\")\n .action((options: StatusCommandOptions) => {\n return runCliAction(async () => {\n const droplet = await resolveDroplet(process.cwd(), options.droplet);\n const versions = await fetchDropletWidgetStatus({\n client: createAuthenticatedWidgetPackageClient(),\n droplet,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n versions.map((version) => version.raw),\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(chalk.blue.bold(`Widget status for droplet ${droplet}`));\n console.log();\n console.log(formatStatusRows(versions));\n });\n });\n\nasync function resolveDroplet(\n projectDir: string,\n override: string | undefined,\n): Promise<string> {\n const droplet =\n override?.trim() || (await loadWidgetConfig(projectDir)).config.droplet;\n if (droplet?.trim()) {\n const trimmedDroplet = droplet.trim();\n const dropletError = validateDropletUuid(trimmedDroplet);\n if (dropletError) throw new Error(dropletError);\n return trimmedDroplet;\n }\n\n throw new Error(\n \"Missing droplet UUID. Pass --droplet <uuid> or set droplet in fluid.widget.config.ts.\",\n );\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport {\n formatValidationSuccess,\n validateDropletWidgetProject,\n} from \"../utils/source-package.js\";\nimport { runCliAction } from \"../utils/command.js\";\n\nexport interface ValidateWidgetOptions {\n readonly json?: boolean;\n}\n\nexport const validateCommand: Command = new Command(\"validate\")\n .description(\"Validate the current droplet widget package\")\n .option(\"--json\", \"Print machine-readable validation output\")\n .action((options: ValidateWidgetOptions) => {\n return runCliAction(async () => {\n const result = await validateDropletWidgetProject(process.cwd());\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n valid: true,\n config: result.sourceConfigPath,\n packageId: result.validated.packageId,\n version: result.validated.version,\n widgets: result.validated.widgets.map((widget) => ({\n name: widget.name,\n type: widget.type,\n })),\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(chalk.green(formatValidationSuccess(result)));\n });\n });\n","import { Command } from \"commander\";\nimport type { FluidPlugin, PluginContext } from \"@fluid-app/fluid-cli\";\nimport { buildCommand } from \"./commands/build.js\";\nimport { cloneCommand } from \"./commands/clone.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { linkCommand } from \"./commands/link.js\";\nimport { logsCommand } from \"./commands/logs.js\";\nimport { publishCommand } from \"./commands/publish.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { validateCommand } from \"./commands/validate.js\";\n\nexport const widgetCommand: Command = new Command(\"widget\")\n .description(\n \"Create, preview, link, validate, build, publish, push, and clone standalone Fluid widgets\",\n )\n .addCommand(createCommand)\n .addCommand(cloneCommand)\n .addCommand(devCommand)\n .addCommand(linkCommand)\n .addCommand(validateCommand)\n .addCommand(buildCommand)\n .addCommand(publishCommand)\n .addCommand(pushCommand)\n .addCommand(statusCommand)\n .addCommand(logsCommand);\n\nconst plugin: FluidPlugin = {\n name: \"@fluid-app/fluid-cli-widget\",\n version: \"0.1.0\",\n register(ctx: PluginContext) {\n const existingWidgetCommand = findCommand(ctx.program, \"widget\");\n if (existingWidgetCommand) {\n addCommandIfMissing(existingWidgetCommand, createCommand);\n addCommandIfMissing(existingWidgetCommand, cloneCommand);\n addCommandIfMissing(existingWidgetCommand, devCommand);\n addCommandIfMissing(existingWidgetCommand, linkCommand);\n addCommandIfMissing(existingWidgetCommand, validateCommand);\n addCommandIfMissing(existingWidgetCommand, buildCommand);\n addCommandIfMissing(existingWidgetCommand, publishCommand);\n addCommandIfMissing(existingWidgetCommand, pushCommand);\n addCommandIfMissing(existingWidgetCommand, statusCommand);\n addCommandIfMissing(existingWidgetCommand, logsCommand);\n return;\n }\n\n ctx.program.addCommand(widgetCommand);\n },\n};\n\nexport default plugin;\n\nexport type {\n WidgetCommandOptions,\n WidgetCreateOptions,\n WidgetLinkOptions,\n WidgetTemplateVariables,\n} from \"./types.js\";\nexport { buildCommand, buildWidgetPackage } from \"./commands/build.js\";\nexport type {\n BuildWidgetOptions,\n BuildWidgetPackageOptions,\n BuildWidgetPackageResult,\n} from \"./commands/build.js\";\nexport { cloneCommand } from \"./commands/clone.js\";\nexport type { CloneCommandOptions } from \"./commands/clone.js\";\nexport { createCommand, createWidgetProject } from \"./commands/create.js\";\nexport { pushCommand } from \"./commands/push.js\";\nexport type { PushCommandOptions } from \"./commands/push.js\";\nexport {\n DEFAULT_WIDGET_DEV_PORT,\n WIDGET_DEV_ROUTES,\n buildViteDevArgs,\n devCommand,\n printWidgetDevSummary,\n resolveWidgetDevProject,\n runViteDevServer,\n} from \"./commands/dev.js\";\nexport type {\n WidgetDevOptions,\n WidgetDevProjectSummary,\n} from \"./commands/dev.js\";\nexport { linkCommand } from \"./commands/link.js\";\nexport { logsCommand } from \"./commands/logs.js\";\nexport type { LogsCommandOptions } from \"./commands/logs.js\";\nexport { publishCommand, publishWidgetPackage } from \"./commands/publish.js\";\nexport type {\n PublishCommandOptions,\n PublishWidgetPackageDependencies,\n PublishWidgetPackageOptions,\n PublishWidgetPackageResult,\n} from \"./commands/publish.js\";\nexport { statusCommand } from \"./commands/status.js\";\nexport type { StatusCommandOptions } from \"./commands/status.js\";\nexport { validateCommand } from \"./commands/validate.js\";\nexport type { ValidateWidgetOptions } from \"./commands/validate.js\";\nexport {\n WIDGET_CONFIG_FILE,\n formatWidgetConfig,\n loadWidgetConfig,\n mergeWidgetConfig,\n parseWidgetConfigSource,\n resolveWidgetConfigPath,\n validateDropletUuid,\n writeWidgetConfig,\n type FluidWidgetConfig,\n type LoadedWidgetConfig,\n} from \"./utils/config.js\";\nexport {\n DEFAULT_WIDGET_OUT_DIR,\n ROOT_WIDGET_CONFIG_FILE,\n WidgetValidationError,\n formatValidationSuccess,\n resolveWidgetSourceConfig,\n validateDropletWidgetProject,\n withRootWidgetConfigBridge,\n type WidgetValidationResult,\n} from \"./utils/source-package.js\";\nexport { formatValidationErrors } from \"./utils/validation.js\";\nexport type { WidgetCliValidationError } from \"./utils/validation.js\";\n\nfunction addCommandIfMissing(parent: Command, child: Command): void {\n if (findCommand(parent, child.name())) return;\n parent.addCommand(child);\n}\n\nfunction findCommand(parent: Command, name: string): Command | undefined {\n return parent.commands?.find((command) => command.name() === name);\n}\n"],"mappings":";;;;;;;;;;;;;AAGA,MAAa,qBAAqB;AAWlC,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO;;;AAIhB,SAAgB,wBAAwB,YAA4B;AAClE,QAAO,KAAK,KAAK,YAAY,mBAAmB;;AAGlD,eAAsB,iBACpB,YAC6B;CAC7B,MAAM,aAAa,wBAAwB,WAAW;CAEtD,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,SAAS,YAAY,QAAQ;UACrC,KAAK;AACZ,MAAIA,cAAY,IAAI,IAAI,IAAI,SAAS,SACnC,QAAO;GAAE,MAAM;GAAY,QAAQ,EAAE;GAAE;EAEzC,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,QAAM,IAAI,MAAM,kBAAkB,mBAAmB,IAAI,UAAU;;AAGrE,QAAO;EAAE,MAAM;EAAY,QAAQ,wBAAwB,OAAO;EAAE;;AAGtE,eAAsB,kBACpB,YACA,QACe;AACf,OAAM,UACJ,wBAAwB,WAAW,EACnC,mBAAmB,OAAO,EAC1B,QACD;;AAGH,SAAgB,mBAAmB,QAAmC;CACpE,MAAM,QAAQ;EACZ;EACA;EACA;EACA;EACD;AAED,KAAI,OAAO,QACT,OAAM,KAAK,cAAc,KAAK,UAAU,OAAO,QAAQ,CAAC,GAAG;AAG7D,OAAM,KACJ,kCACA,IACA,mDACA,iDACA,IACA,gDACA,SACA,iCACA,0BACA,gFACA,SACA,4BACA,2DACA,IACA,0BACA,gDACA,GACD;AACD,QAAO,MAAM,KAAK,KAAK;;AAGzB,SAAgB,wBACd,QAC4B;AAI5B,QAFe,4BADM,2BAA2B,OAAO,CACC;;AAK1D,SAAgB,kBACd,SACA,SACmB;CACnB,MAAM,UACJ,wBAAwB,QAAQ,QAAQ,IACxC,wBAAwB,QAAQ,QAAQ;AAE1C,QAAO,UAAU,EAAE,SAAS,GAAG,EAAE;;AAGnC,SAAgB,oBAAoB,aAAyC;AAC3E,KAAI,CAAC,YAAa,QAAO;AACzB,KAAI,YAAY,SAAS,wBACvB,QAAO,wBAAwB,wBAAwB;AAEzD,KAAI,CAAC,4BAA4B,KAAK,YAAY,CAChD,QACE;;AAON,SAAS,2BAA2B,QAAwB;CAC1D,MAAM,cAAc,4BAA4B,KAAK,OAAO;AAC5D,KAAI,CAAC,YACH,OAAM,IAAI,uBACR,GAAG,mBAAmB,uEACvB;CAGH,MAAM,iBAAiB,OAAO,QAAQ,KAAK,YAAY,MAAM;CAC7D,MAAM,kBAAkB,kBAAkB,QAAQ,eAAe;CACjE,MAAM,SAAS,cAAc,OAAO,MAAM,kBAAkB,EAAE,CAAC;AAC/D,KAAI,CAAC,0DAA0D,KAAK,OAAO,CACzE,OAAM,IAAI,uBACR,GAAG,mBAAmB,sGACvB;AAGH,QAAO,cAAc,OAAO,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;;AAGzE,SAAS,4BACP,cAC4B;CAC5B,MAAM,SAA+B,EAAE;AAEvC,MAAK,MAAM,UAAU,qBAAqB,aAAa,EAAE;EACvD,MAAM,gBAAgB,OAAO,MAAM;AACnC,MAAI,CAAC,cAAe;EAEpB,MAAM,gBAAgB,8BAA8B,KAAK,cAAc;AACvE,MAAI,CAAC,eAAe;GAClB,MAAM,eAAe,0BAA0B,KAAK,cAAc,GAAG;AACrE,SAAM,IAAI,uBACR,eACI,GAAG,mBAAmB,iCAAiC,aAAa,iCACpE,GAAG,mBAAmB,iEAC3B;;EAGH,MAAM,eAAe,cAAc;AACnC,MAAI,iBAAiB,UACnB,OAAM,IAAI,uBACR,GAAG,mBAAmB,oCACvB;EAGH,MAAM,QAAQ,wBADM,cAAc,IAAI,MAAM,IAAI,IACG,aAAa;AAChE,MAAI,CAAC,MAAM,MAAM,CACf,OAAM,IAAI,uBACR,GAAG,mBAAmB,SAAS,aAAa,sCAC7C;AAGH,MAAI,OAAO,YAAY,KAAA,EACrB,OAAM,IAAI,uBACR,GAAG,mBAAmB,4CACvB;AAEH,SAAO,UAAU;;AAGnB,QAAO;;AAGT,SAAS,wBACP,aACA,cACQ;AACR,KAAI,YAAY,WAAW,KAAI,IAAI,YAAY,SAAS,KAAI,CAC1D,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,YAAY;AACtC,MAAI,OAAO,WAAW,SAAU,QAAO;SACjC;AAKV,KAAI,YAAY,WAAW,IAAI,IAAI,YAAY,SAAS,IAAI,CAC1D,QAAO,+BAA+B,YAAY;AAGpD,OAAM,IAAI,uBACR,GAAG,mBAAmB,SAAS,aAAa,yCAAyC,aAAa,aACnG;;AAGH,SAAS,+BAA+B,aAA6B;CACnE,IAAI,QAAQ;AAEZ,MAAK,IAAI,QAAQ,GAAG,QAAQ,YAAY,SAAS,GAAG,SAAS,GAAG;EAC9D,MAAM,OAAO,YAAY;AACzB,MAAI,SAAS,MAAM;AACjB,YAAS;AACT;;AAGF,WAAS;EACT,MAAM,UAAU,YAAY;AAC5B,UAAQ,SAAR;GACE,KAAK;GACL,KAAK;GACL,KAAK;AACH,aAAS;AACT;GACF,KAAK;AACH,aAAS;AACT;GACF,KAAK;AACH,aAAS;AACT;GACF,KAAK;AACH,aAAS;AACT;GACF,KAAK;AACH,aAAS;AACT;GACF,KAAK;AACH,aAAS;AACT;GACF,KAAK;AACH,aAAS;AACT;GACF;AACE,aAAS,WAAW;AACpB;;;AAIN,QAAO;;AAGT,SAAS,cAAc,QAAwB;CAC7C,IAAI,SAAS;CACb,IAAI;CACJ,IAAI,UAAU;CACd,IAAI,cAAc;CAClB,IAAI,eAAe;AAEnB,MAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;EACrD,MAAM,OAAO,OAAO;EACpB,MAAM,WAAW,OAAO,QAAQ;AAEhC,MAAI,aAAa;AACf,OAAI,SAAS,QAAQ,SAAS,MAAM;AAClC,kBAAc;AACd,cAAU;SAEV,WAAU;AAEZ;;AAGF,MAAI,cAAc;AAChB,OAAI,SAAS,OAAO,aAAa,KAAK;AACpC,mBAAe;AACf,cAAU;AACV,aAAS;cACA,SAAS,QAAQ,SAAS,KACnC,WAAU;OAEV,WAAU;AAEZ;;AAGF,MAAI,aAAa;AACf,aAAU;AACV,OAAI,QACF,WAAU;YACD,SAAS,KAClB,WAAU;YACD,SAAS,YAClB,eAAc,KAAA;AAEhB;;AAGF,MAAI,SAAS,OAAO,aAAa,KAAK;AACpC,iBAAc;AACd,aAAU;AACV,YAAS;AACT;;AAGF,MAAI,SAAS,OAAO,aAAa,KAAK;AACpC,kBAAe;AACf,aAAU;AACV,YAAS;AACT;;AAGF,MAAI,SAAS,QAAO,SAAS,OAAO,SAAS,IAC3C,eAAc;AAEhB,YAAU;;AAGZ,QAAO;;AAGT,SAAS,qBAAqB,cAAgC;CAC5D,MAAM,UAAoB,EAAE;CAC5B,IAAI,cAAc;CAClB,IAAI;CACJ,IAAI,UAAU;CACd,IAAI,cAAc;AAElB,MAAK,IAAI,QAAQ,GAAG,QAAQ,aAAa,QAAQ,SAAS,GAAG;EAC3D,MAAM,OAAO,aAAa;AAE1B,MAAI,aAAa;AACf,OAAI,QACF,WAAU;YACD,SAAS,KAClB,WAAU;YACD,SAAS,YAClB,eAAc,KAAA;AAEhB;;AAGF,MAAI,SAAS,QAAO,SAAS,OAAO,SAAS,KAAK;AAChD,iBAAc;AACd;;AAGF,MAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD,kBAAe;AACf;;AAEF,MAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD,kBAAe;AACf;;AAGF,MAAI,SAAS,OAAO,gBAAgB,GAAG;AACrC,WAAQ,KAAK,aAAa,MAAM,aAAa,MAAM,CAAC;AACpD,iBAAc,QAAQ;;;AAI1B,SAAQ,KAAK,aAAa,MAAM,YAAY,CAAC;AAC7C,QAAO;;AAGT,SAAS,kBAAkB,QAAgB,gBAAgC;CACzE,IAAI,QAAQ;CACZ,IAAI;CACJ,IAAI,UAAU;CACd,IAAI,cAAc;CAClB,IAAI,eAAe;AAEnB,MAAK,IAAI,QAAQ,gBAAgB,QAAQ,OAAO,QAAQ,SAAS,GAAG;EAClE,MAAM,OAAO,OAAO;EACpB,MAAM,WAAW,OAAO,QAAQ;AAEhC,MAAI,aAAa;AACf,OAAI,SAAS,QAAQ,SAAS,KAAM,eAAc;AAClD;;AAGF,MAAI,cAAc;AAChB,OAAI,SAAS,OAAO,aAAa,KAAK;AACpC,mBAAe;AACf,aAAS;;AAEX;;AAGF,MAAI,aAAa;AACf,OAAI,QACF,WAAU;YACD,SAAS,KAClB,WAAU;YACD,SAAS,YAClB,eAAc,KAAA;AAEhB;;AAGF,MAAI,SAAS,OAAO,aAAa,KAAK;AACpC,iBAAc;AACd,YAAS;AACT;;AAGF,MAAI,SAAS,OAAO,aAAa,KAAK;AACpC,kBAAe;AACf,YAAS;AACT;;AAGF,MAAI,SAAS,QAAO,SAAS,OAAO,SAAS,KAAK;AAChD,iBAAc;AACd;;AAGF,MAAI,SAAS,IAAK,UAAS;AAC3B,MAAI,SAAS,KAAK;AAChB,YAAS;AACT,OAAI,UAAU,EAAG,QAAO;;;AAI5B,OAAM,IAAI,uBACR,GAAG,mBAAmB,4CACvB;;AAGH,SAAS,wBACP,OACoB;CACpB,MAAM,UAAU,OAAO,MAAM;AAC7B,QAAO,UAAU,UAAU,KAAA;;AAO7B,SAASA,cAAY,OAAoC;AACvD,QAAO,iBAAiB,SAAS,UAAU;;AAG7C,MAAM,0BAA0B;AAEhC,MAAM,8BAA8B,IAAI,OAAO,+BAA+B;;;AC5b9E,SAAgB,uBACd,QACQ;AACR,KAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAO,CACL,sBACA,GAAG,OAAO,KAAK,UAAU;AAEvB,SAAO,OADU,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM,KACzB,MAAM;GAC/B,CACH,CAAC,KAAK,KAAK;;;;ACEd,MAAa,yBAAyB;AACtC,MAAa,0BAAkC;AAE/C,MAAM,2BAA2B;CAC/B;CACA;CACA;CACD;AAQD,IAAa,wBAAb,cAA2C,MAAM;CAC/C;CAEA,YAAY,QAAiD;AAC3D,QAAM,uBAAuB,OAAO,CAAC;AACrC,OAAK,OAAO;AACZ,OAAK,SAAS;;;AAIlB,eAAsB,6BACpB,YACA,oBACiC;CACjC,MAAM,qBAAqB,KAAK,QAAQ,WAAW;CACnD,MAAM,eAAe,0BAA0B,mBAAmB;AAClE,KAAI,CAAC,aACH,OAAM,IAAI,sBAAsB,CAC9B;EACE,MAAM;EACN,MAAM;EACN,SACE,0CAA0C,wBAAwB;EAErE,CACF,CAAC;CAGJ,MAAM,eAAe,MAAM,yBACzB,oBACA,mBACD;AACD,KAAI,aAAa,SAAS,EACxB,OAAM,IAAI,sBAAsB,aAAa;CAG/C,MAAM,iBAAiB,MAAM,2BAC3B,oBACA,YAAY;EACV,MAAM,aAAa,MAAM,yBAAyB,mBAAmB;AACrE,MAAI,CAAC,WAAW,QACd,OAAM,IAAI,sBAAsB,CAC9B;GACE,MAAM;GACN,MAAM,aAAa;GACnB,SAAS,cACP,WAAW,MAAM,SACjB,WAAW,MAAM,QAClB;GACF,CACF,CAAC;AAEJ,SAAO,WAAW;IAEpB,mBACD;CAED,MAAM,aAAa,kCAAkC,gBAAgB,EACnE,OAAO,WACR,CAAC;CACF,MAAM,SAAS,CACb,GAAG,WAAW,QACd,GAAG,wBAAwB,eAAe,CAC3C;AAED,KAAI,CAAC,WAAW,WAAW,CAAC,WAAW,SAAS,OAAO,SAAS,EAC9D,OAAM,IAAI,sBAAsB,OAAO;AAGzC,QAAO;EACL,YAAY;EACZ,kBAAkB,aAAa;EAC/B,WAAW,WAAW;EACvB;;AAGH,eAAsB,2BACpB,YACA,UACA,oBACY;AAEZ,KAAI,CAAC,WADkB,KAAK,KAAK,YAAY,wBAAwB,CACtC,IAAI,0BAA0B,WAAW,CACtE,QAAO,UAAU;CAGnB,MAAM,aACJ,oBAAoB,MAAM,KACzB,MAAM,iBAAiB,WAAW,EAAE,OAAO;AAC9C,KAAI,CAAC,WACH,OAAM,IAAI,MACR,sFACD;CAGH,MAAM,SAAS,KAAK,KAAK,YAAY,MAAM;CAC3C,MAAM,aAAa,KAAK,KAAK,QAAQ,oBAAoB;CACzD,MAAM,gBAAgB,WAAW,OAAO;AACxC,OAAM,MAAM,QAAQ,EAAE,WAAW,MAAM,CAAC;AACxC,KAAI;AACF,QAAM,UACJ,YACA,mCAAmC,WAAW,EAC9C;GACE,UAAU;GACV,MAAM;GACP,CACF;UACM,KAAK;AACZ,MAAI,YAAY,IAAI,IAAI,IAAI,SAAS,SACnC,OAAM,IAAI,MACR,GAAG,KAAK,SAAS,YAAY,WAAW,CAAC,gFAE1C;AAEH,QAAM;;AAGR,KAAI;AACF,SAAO,MAAM,UAAU;WACf;AACR,QAAM,GAAG,YAAY,EAAE,OAAO,MAAM,CAAC,CAAC,YAAY,GAAG;AACrD,MAAI,CAAC,cAAe,OAAM,MAAM,OAAO,CAAC,YAAY,GAAG;;;AAI3D,SAAS,mCAAmC,YAA4B;AACtE,QAAO;;qBAEY,KAAK,UAAU,WAAW,CAAC;;;;;;;;;;;;;AAchD,SAAgB,0BACd,YACsE;CACtE,MAAM,aAAa,KAAK,KAAK,YAAY,wBAAwB;AACjE,KAAI,WAAW,WAAW,CACxB,QAAO;EAAE,MAAM;EAAY,cAAc;EAAyB;AAGpE,QAAO,0BAA0B,WAAW;;AAG9C,SAAgB,wBACd,QACQ;AACR,QAAO;EACL;EACA,YAAY,OAAO,oBAAoB;EACvC,YAAY,OAAO,UAAU;EAC7B,YAAY,OAAO,UAAU;EAC7B,YAAY,OAAO,UAAU,QAAQ;EACtC,CAAC,KAAK,KAAK;;AAGd,eAAe,yBACb,YACA,oBACyC;AAEzC,KAAI,CAAC,WADc,KAAK,KAAK,YAAY,wBAAwB,CACtC,CAAE,QAAO,EAAE;AAEtC,KAAI;EACF,MAAM,SAAS,MAAM,iBAAiB,WAAW;EAEjD,MAAM,kBAAkB,oBADR,sBAAsB,OAAO,OAAO,WAAW,GACX;AACpD,MAAI,CAAC,gBAAiB,QAAO,EAAE;AAE/B,SAAO,CACL;GACE,MAAM;GACN,MAAM;GACN,SAAS;GACV,CACF;UACM,KAAK;AAEZ,SAAO,CACL;GACE,MAAM;GACN,MAAM;GACN,SALY,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;GAM7D,CACF;;;AAIL,SAAS,wBACP,gBACgC;AAChC,KAAI,eAAe,WAAW,EAAG,QAAO,EAAE;CAE1C,MAAM,gBAAgB,eAAe;AACrC,KAAI,CAACC,WAAS,cAAc,CAAE,QAAO,EAAE;CAEvC,MAAM,SAAyC,EAAE;AACjD,KAAI,cAAc,mBAAmB,UACnC,QAAO,KAAK;EACV,MAAM;EACN,MAAM;EACN,SACE;EACH,CAAC;AAGJ,KAAI,CAAC,iBAAiB,cAAc,mBAAmB,CACrD,QAAO,KAAK;EACV,MAAM;EACN,MAAM;EACN,SACE;EACH,CAAC;CAGJ,MAAM,UAAU,cAAc;AAC9B,KAAI,MAAM,QAAQ,QAAQ,CACxB,SAAQ,SAAS,QAAQ,UAAU;AACjC,MAAI,CAACA,WAAS,OAAO,CAAE;AACvB,2BACE,OAAO,mBACP,WAAW,MAAM,mBACjB,OACD;AACD,2BACE,OAAO,iBACP,WAAW,MAAM,iBACjB,OACD;GACD;AAGJ,QAAO;;AAGT,SAAS,0BACP,YACsE;AACtE,MAAK,MAAM,gBAAgB,0BAA0B;EACnD,MAAM,YAAY,KAAK,KAAK,YAAY,aAAa;AACrD,MAAI,WAAW,UAAU,CAAE,QAAO;GAAE,MAAM;GAAW;GAAc;;;AAMvE,SAAS,yBACP,OACA,WACA,QACM;AACN,KAAI,UAAU,KAAA,EAAW;AAEzB,KAAI;AACF,yBAAuB,OAAO,UAAU;UACjC,KAAK;AACZ,SAAO,KAAK;GACV,MAAM;GACN,MAAM;GACN,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;GAC1D,CAAC;;;AAIN,SAAS,uBAAuB,OAAgB,WAAyB;AACvE,KAAI,UAAU,KAAM;CAEpB,MAAM,YAAY,OAAO;AACzB,KAAI,cAAc,YAAY,cAAc,UAAW;AACvD,KAAI,cAAc,UAAU;AAC1B,MAAI,OAAO,SAAS,MAAM,CAAE;AAC5B,QAAM,IAAI,MAAM,GAAG,UAAU,oCAAoC;;AAEnE,KAAI,MAAM,QAAQ,MAAM,EAAE;AACxB,QAAM,SAAS,MAAM,UAAU;AAC7B,0BAAuB,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG;IACtD;AACF;;AAEF,KAAIA,WAAS,MAAM,EAAE;AACnB,OAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,MAAM,EAAE;AAC/C,OAAI,SAAS,KAAA,EACX,OAAM,IAAI,MAAM,GAAG,UAAU,GAAG,IAAI,yBAAyB;AAE/D,0BAAuB,MAAM,GAAG,UAAU,GAAG,MAAM;;AAErD;;AAGF,OAAM,IAAI,MAAM,GAAG,UAAU,8CAA8C;;AAG7E,SAAS,cAAc,SAAiB,SAAqC;AAC3E,QAAO,UAAU,GAAG,QAAQ,IAAI,YAAY;;AAG9C,SAAS,iBAAiB,OAAiC;AACzD,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS;;AAG5D,SAASA,WAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAO7E,SAAS,YAAY,OAAoC;AACvD,QAAO,iBAAiB,SAAS,UAAU;;;;AC9V7C,eAAsB,aAAa,QAA4C;AAC7E,KAAI;AACF,QAAM,QAAQ;UACP,KAAK;AACZ,UAAQ,MAAM,MAAM,IAAI,SAAS,GAAG,MAAM,mBAAmB,IAAI,CAAC;AAClE,UAAQ,KAAK,EAAE;;;AAInB,SAAgB,mBAAmB,KAAsB;AACvD,QAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;;;ACNzD,SAAgB,cACd,QACA,MAAc,QAAQ,KAAK,EACnB;AACR,QAAO,GAAG,qBAAqB,IAAI,CAAC,OAAO;;AAG7C,SAAgB,kBAAkB,MAAc,QAAQ,KAAK,EAAU;AACrE,QAAO,GAAG,qBAAqB,IAAI,CAAC;;AAGtC,eAAsB,oBAAoB,KAA4B;AAEpE,OAAM,kBADiB,qBAAqB,IAAI,EACR,CAAC,UAAU,EAAE,IAAI;;AAG3D,SAAgB,qBAAqB,KAA6B;AAChE,KAAI,WAAW,KAAK,KAAK,KAAK,iBAAiB,CAAC,CAAE,QAAO;AACzD,KAAI,WAAW,KAAK,KAAK,KAAK,YAAY,CAAC,CAAE,QAAO;AACpD,KAAI,WAAW,KAAK,KAAK,KAAK,YAAY,CAAC,CAAE,QAAO;AACpD,KAAI,WAAW,KAAK,KAAK,KAAK,oBAAoB,CAAC,CAAE,QAAO;CAE5D,MAAM,yBAAyB,4BAA4B;AAC3D,KAAI,uBAAwB,QAAO;CAEnC,MAAM,yBAAyB,2BAA2B,IAAI;AAC9D,KAAI,0BAA0B,mBAAmB,uBAAuB,CACtE,QAAO;AAGT,QAAO,6BAA6B,IAAI;;AAG1C,SAAS,kBACP,SACA,MACA,KACe;AACf,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,SAAS,CAAC,GAAG,KAAK,EAAE;GACtC;GACA,OAAO;GACP,OAAO,QAAQ,aAAa;GAC7B,CAAC;AAEF,QAAM,KAAK,UAAU,UAAiB;AACpC,UAAO,MAAM;IACb;AAEF,QAAM,KAAK,SAAS,SAAwB;AAC1C,OAAI,SAAS,GAAG;AACd,aAAS;AACT;;AAGF,0BACE,IAAI,MACF,GAAG,QAAQ,GAAG,KAAK,KAAK,IAAI,CAAC,oBAAoB,QAAQ,YAC1D,CACF;IACD;GACF;;AAGJ,SAAS,6BAAyD;CAChE,MAAM,YAAY,QAAQ,IAAI;AAC9B,KAAI,CAAC,UAAW,QAAO,KAAA;CAEvB,MAAM,OAAO,UAAU,MAAM,IAAI,CAAC;AAClC,KAAI,iBAAiB,KAAK,CAAE,QAAO;;AAIrC,SAAS,2BAA2B,KAAyC;CAC3E,MAAM,kBAAkB,KAAK,KAAK,KAAK,eAAe;AACtD,KAAI,CAAC,WAAW,gBAAgB,CAAE,QAAO,KAAA;AAEzC,KAAI;EACF,MAAM,cAAc,KAAK,MACvB,aAAa,iBAAiB,QAAQ,CACvC;AACD,MAAI,CAACC,WAAS,YAAY,CAAE,QAAO,KAAA;EAEnC,MAAM,iBAAiB,YAAY;AACnC,MAAI,OAAO,mBAAmB,SAAU,QAAO,KAAA;EAE/C,MAAM,OAAO,eAAe,MAAM,IAAI,CAAC;AACvC,MAAI,iBAAiB,KAAK,CAAE,QAAO;SAC7B;;AAOV,SAAS,8BAA0D;AACjE,MAAK,MAAM,kBAAkB;EAAC;EAAQ;EAAQ;EAAO;EAAM,CACzD,KAAI,mBAAmB,eAAe,CAAE,QAAO;;AAKnD,SAAS,mBAAmB,SAAkC;AAK5D,QAJe,UAAU,SAAS,CAAC,YAAY,EAAE;EAC/C,OAAO,QAAQ,aAAa;EAC5B,OAAO;EACR,CAAC,CACY,WAAW;;AAG3B,SAAS,iBAAiB,OAAoD;AAC5E,QACE,UAAU,UAAU,UAAU,UAAU,UAAU,SAAS,UAAU;;AAIzE,SAASA,WAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;AChH7E,eAAsB,4BAA4B,SAGd;CAClC,MAAM,kBAAkB,KAAK,KAAK,QAAQ,YAAY,eAAe;AACrE,KAAI,CAAC,WAAW,gBAAgB,CAAE,QAAO,EAAE,KAAK,OAAO;AAGvD,KAAI,CAAC,iBADe,MAAMC,kBAAgB,gBAAgB,EACvB,QAAQ,WAAW,CAAE,QAAO,EAAE,KAAK,OAAO;CAE7E,MAAM,iBAAiB,qBAAqB,QAAQ,WAAW;CAC/D,MAAM,OAAO,CAAC,OAAO,QAAQ,WAAW;AACxC,OAAM,WAAW,gBAAgB,MAAM,QAAQ,WAAW;AAE1D,QAAO;EACL,KAAK;EACL,SAAS,GAAG,eAAe,GAAG,KAAK,KAAK,IAAI;EAC7C;;AAGH,SAAS,WACP,SACA,MACA,KACe;AACf,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,SAAS,MAAM;GACjC;GACA,OAAO;GACP,KAAK,QAAQ;GACb,OAAO,QAAQ,aAAa;GAC7B,CAAC;AAEF,QAAM,GAAG,SAAS,OAAO;AACzB,QAAM,GAAG,SAAS,MAAM,WAAW;AACjC,OAAI,SAAS,GAAG;AACd,aAAS;AACT;;AAGF,0BACE,IAAI,MACF,SACI,GAAG,QAAQ,GAAG,KAAK,KAAK,IAAI,CAAC,sBAAsB,OAAO,KAC1D,GAAG,QAAQ,GAAG,KAAK,KAAK,IAAI,CAAC,oBAAoB,QAAQ,UAAU,GACxE,CACF;IACD;GACF;;AAGJ,eAAeA,kBAAgB,iBAA2C;CACxE,MAAM,SAAS,MAAM,SAAS,iBAAiB,QAAQ;AACvD,KAAI;AACF,SAAO,KAAK,MAAM,OAAO;UAClB,KAAK;EACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,QAAM,IAAI,MAAM,iCAAiC,UAAU;;;AAI/D,SAAS,iBAAiB,OAAgB,YAA6B;AACrE,KAAI,CAACC,WAAS,MAAM,CAAE,QAAO;CAC7B,MAAM,UAAU,MAAM;AACtB,KAAI,CAACA,WAAS,QAAQ,CAAE,QAAO;AAC/B,QAAO,OAAO,QAAQ,gBAAgB;;AAGxC,SAASA,WAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;AChD7E,eAAsB,mBACpB,SACmC;AACnC,OAAM,6BAA6B,QAAQ,WAAW;AAEtD,KAAI,QAAQ,kBAAkB,KAC5B,OAAM,4BAA4B;EAChC,YAAY,QAAQ;EACpB,YAAY;EACb,CAAC;CAGJ,MAAM,SAAS,4BACb,QAAQ,YACR,QAAQ,OACT;CACD,MAAM,cAAc,MAAM,2BAA2B,QAAQ,kBAC3D,yBAAyB;EACvB,YAAY,QAAQ;EACpB,YAAY;EACZ,OAAO;EACR,CAAC,CACH;AAED,KAAI,CAAC,YAAY,SAAS;EACxB,MAAM,UAAU,YAAY,MAAM,UAC9B,KAAK,YAAY,MAAM,YACvB;AACJ,QAAM,IAAI,MAAM,GAAG,YAAY,MAAM,UAAU,UAAU;;AAG3D,QAAO;EACL,QAAQ,YAAY,MAAM;EAC1B,WAAW,YAAY,MAAM;EAC7B,SAAS,YAAY,MAAM;EAC5B;;AAGH,MAAa,eAAwB,IAAI,QAAQ,QAAQ,CACtD,YAAY,wDAAwD,CACpE,OACC,uBACA,oCACA,uBACD,CACA,OAAO,oBAAoB,6CAA6C,CACxE,QAAQ,YAAgC;AACvC,QAAO,aAAa,YAAY;EAC9B,MAAM,SAAS,QAAQ,UAAA;AACvB,UAAQ,IAAI,MAAM,KAAK,KAAK,gCAAgC,CAAC;AAC7D,UAAQ,KAAK;EAEb,MAAM,UAAU,IACd,8CACD,CAAC,OAAO;EACT,MAAM,SAAS,MAAM,mBAAmB;GACtC,YAAY,QAAQ,KAAK;GACzB;GACA,eAAe,QAAQ;GACxB,CAAC;AACF,UAAQ,QAAQ,iCAAiC;AAEjD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,MAAM,OAAO,UAAU,CAAC;AACpE,UAAQ,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,MAAM,OAAO,QAAQ,CAAC;AAClE,UAAQ,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,KAAK,OAAO,CAAC;GACzD;EACF;;;;;;;;;;;;;;;;;;AC9EJ,IAAa,WAAb,cAA8B,MAAM;CAClC;CAEA,YAAY,SAAiB,WAAW,GAAG;AACzC,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,WAAW;;;;;;;;;;AAWpB,SAAgB,gBAAgB,KAA+B;AAE7D,KADc,KAA2C,SAC5C,SAAU,QAAO;AAC9B,QAAO,IAAI,SACT,mTAKA,IACD;;;;;;;;;AAUH,SAAS,uBAAuB,WAI9B;CACA,IAAI;AACJ,KAAI;AACF,MAAI,IAAI,IAAI,UAAU;SAChB;AAGN,SAAO;GAAE,UAAU;GAAW,UAAU;GAAI,UAAU;GAAI;;CAE5D,MAAM,WAAW,mBAAmB,EAAE,SAAS;CAC/C,MAAM,WAAW,mBAAmB,EAAE,SAAS;AAC/C,GAAE,WAAW;AACb,GAAE,WAAW;AACb,QAAO;EAAE,UAAU,EAAE,UAAU;EAAE;EAAU;EAAU;;;;;;;;;;;AAYvD,IAAI,cAA6B;AACjC,SAAS,sBAA8B;AACrC,KAAI,eAAe,WAAW,YAAY,CAAE,QAAO;CACnD,MAAM,MAAM,KAAK,KAAK,GAAG,QAAQ,EAAE,wBAAwB,QAAQ,MAAM;AACzE,KAAI,CAAC,WAAW,IAAI,CAAE,WAAU,KAAK;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CACtE,MAAM,IAAI,KAAK,KAAK,KAAK,aAAa;AACtC,eACE,GACA,yHACA,EAAE,MAAM,KAAO,CAChB;AACD,WAAU,GAAG,IAAM;AACnB,eAAc;AACd,QAAO;;;;;;;;AAST,SAAS,aAAa,WAGpB;CACA,MAAM,EAAE,UAAU,UAAU,aAAa,uBAAuB,UAAU;AAC1E,QAAO;EACL;EACA,KAAK;GACH,GAAG,QAAQ;GACX,aAAa,qBAAqB;GAClC,qBAAqB;GACrB,gBAAgB;GAChB,gBAAgB;GACjB;EACF;;AAGH,SAAS,aAAa,KAAc,MAAwB;CAC1D,MAAM,UAAU,gBAAgB,IAAI;AACpC,KAAI,QAAS,QAAO;CACpB,MAAM,IAAI;AACV,QAAO,IAAI,SACT,OAAO,KAAK,SAAS,EAAE,YAAY,OAAO,UAAU,EAAE,SAAS,KAAK,MACpE,EAAE,YAAY,EACf;;;AAIH,eAAsB,qBAAoC;AACxD,KAAI;AACF,QAAM,MAAM,OAAO,CAAC,YAAY,CAAC;UAC1B,KAAK;EACZ,MAAM,UAAU,gBAAgB,IAAI;AACpC,MAAI,QAAS,OAAM;AACnB,QAAM,IAAI,SACR,wFACD;;;;AAKL,eAAsB,gBAAgB,KAA+B;AACnE,KAAI;EACF,MAAM,EAAE,WAAW,MAAM,MACvB,OACA,CAAC,aAAa,wBAAwB,EACtC,EAAE,KAAK,CACR;AACD,SAAO,OAAO,MAAM,KAAK;SACnB;AACN,SAAO;;;;AAKX,eAAsB,QAAQ,KAAa,SAAS,QAAuB;AACzE,KAAI;AACF,QAAM,MAAM,OAAO;GAAC;GAAQ;GAAoB;GAAO,EAAE,EAAE,KAAK,CAAC;UAC1D,KAAK;EAEZ,MAAM,UAAU,gBAAgB,IAAI;AACpC,MAAI,QAAS,OAAM;AACnB,MAAI;AACF,SAAM,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC;WAC9B,aAAa;AACpB,SAAM,aAAa,aAAa,OAAO;;;;;;;;AAS7C,eAAsB,SACpB,WACA,WACA,UASI,EAAE,EACS;CACf,MAAM,EAAE,UAAU,QAAQ,aAAa,UAAU;CACjD,MAAM,OAAO;EAAC;EAAM;EAAsB;EAAS;EAAU;AAC7D,KAAI,QAAQ,SAAS,KAAM,MAAK,KAAK,WAAW,OAAO,QAAQ,MAAM,CAAC;AACtE,KAAI,QAAQ,OAAQ,MAAK,KAAK,YAAY,QAAQ,OAAO;AACzD,MAAK,KAAK,UAAU,UAAU;AAC9B,KAAI;AACF,QAAM,MAAM,OAAO,MAAM;GACvB;GACA,OAAO,QAAQ,SAAS,SAAS;IAAC;IAAU;IAAW;IAAU;GAClE,CAAC;UACK,KAAK;AACZ,QAAM,aAAa,KAAK,QAAQ;;;;AAKpC,eAAsB,QACpB,KACA,WACA,SAAS,QACM;CACf,MAAM,EAAE,UAAU,QAAQ,aAAa,UAAU;AACjD,KAAI;AACF,QAAM,MACJ,OACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA,QAAQ;GACT,EACD;GAAE;GAAK;GAAK,OAAO;IAAC;IAAU;IAAW;IAAU;GAAE,CACtD;UACM,KAAK;AACZ,QAAM,aAAa,KAAK,OAAO;;;;;;;;;;;AAYnC,eAAsB,sBACpB,KACA,WACA,SAAS,QACS;CAClB,MAAM,EAAE,UAAU,QAAQ,aAAa,UAAU;AACjD,KAAI;EACF,MAAM,EAAE,WAAW,MAAM,MACvB,OACA;GAAC;GAAM;GAAsB;GAAa;GAAW;GAAU;GAAO,EACtE;GAAE;GAAK;GAAK,CACb;AACD,SAAO,OAAO,MAAM,CAAC,SAAS;UACvB,KAAK;AACZ,QAAM,aAAa,KAAK,YAAY;;;;;;;;AASxC,eAAsB,SACpB,KACA,WACA,SAAS,QACM;CACf,MAAM,EAAE,UAAU,QAAQ,aAAa,UAAU;AACjD,KAAI;AACF,QAAM,MACJ,OACA;GAAC;GAAM;GAAsB;GAAS;GAAW;GAAU;GAAO,EAClE;GAAE;GAAK;GAAK,CACb;UACM,KAAK;AACZ,QAAM,aAAa,KAAK,QAAQ;;;;;;;AAQpC,eAAsB,0BACpB,KAC4C;AAC5C,KAAI;EACF,MAAM,EAAE,WAAW,MAAM,MACvB,OACA;GAAC;GAAY;GAAgB;GAAW;GAAoB,EAC5D,EAAE,KAAK,CACR;EACD,MAAM,CAAC,GAAG,KAAK,OAAO,MAAM,CAAC,MAAM,MAAM;EACzC,MAAM,QAAQ,OAAO,SAAS,KAAK,KAAK,GAAG;EAC3C,MAAM,SAAS,OAAO,SAAS,KAAK,KAAK,GAAG;AAC5C,SAAO;GACL,OAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;GACxC,QAAQ,OAAO,SAAS,OAAO,GAAG,SAAS;GAC5C;SACK;AACN,SAAO;GAAE,OAAO;GAAG,QAAQ;GAAG;;;;AAKlC,eAAsB,WAAW,KAA+B;AAC9D,KAAI;AACF,QAAM,MAAM,OAAO;GAAC;GAAa;GAAY;GAAO,EAAE,EAAE,KAAK,CAAC;AAC9D,SAAO;SACD;AACN,SAAO;;;;;;;;;;;;;;AAeX,eAAsB,kBAAkB,KAA8B;AACpE,KAAI;AACF,QAAM,MAAM,OAAO;GAAC;GAAS;GAAW;GAAa,EAAE,EAAE,KAAK,CAAC;EAC/D,MAAM,EAAE,WAAW,MAAM,MACvB,OACA;GAAC;GAAY;GAAW;GAAa,EACrC,EAAE,KAAK,CACR;EACD,MAAM,QAAQ,OAAO,SAAS,OAAO,MAAM,EAAE,GAAG;AAChD,SAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;UACjC,KAAK;AACZ,QAAM,aAAa,KAAK,uBAAuB;;;;AAKnD,eAAsB,oBAAoB,KAA4B;AACpE,KAAI;AACF,QAAM,MAAM,OAAO;GAAC;GAAS;GAAa;GAAa,EAAE,EAAE,KAAK,CAAC;UAC1D,KAAK;AACZ,QAAM,aAAa,KAAK,qBAAqB;;;;AAKjD,eAAsB,sBAAsB,KAA+B;AACzE,KAAI;EACF,MAAM,EAAE,WAAW,MAAM,MAAM,OAAO,CAAC,UAAU,cAAc,EAAE,EAAE,KAAK,CAAC;AACzE,SAAO,OAAO,MAAM,CAAC,SAAS;SACxB;AACN,SAAO;;;;AAKX,eAAsB,SAAS,KAAa,SAAgC;AAC1E,KAAI;AACF,QAAM,MACJ,OACA;GAAC;GAAS;GAAQ;GAAuB;GAAa;GAAQ,EAC9D,EAAE,KAAK,CACR;UACM,KAAK;AACZ,QAAM,aAAa,KAAK,aAAa;;;;AAKzC,eAAsB,YAAY,KAA4B;AAC5D,KAAI;AACF,QAAM,MAAM,OAAO,CAAC,SAAS,MAAM,EAAE,EAAE,KAAK,CAAC;UACtC,KAAK;EACZ,MAAM,UAAU,gBAAgB,IAAI;AACpC,MAAI,QAAS,OAAM;AAEnB,QAAM,IAAI,SACR,wIAFQ,IAIN,YAAY,EACf;;;AAmBL,MAAM,0BAA6C;CACjD,MAAM;CACN,OAAO;CACR;;;;;;;;;;AAWD,eAAsB,cACpB,KACA,SACA,WAA8B,yBACf;AACf,KAAI;AACF,QAAM,MAAM,OAAO,CAAC,OAAO,KAAK,EAAE,EAAE,KAAK,CAAC;UACnC,KAAK;AACZ,QAAM,aAAa,KAAK,MAAM;;CAGhC,IAAI,UAAU;CACd,IAAI,WAAW;AACf,KAAI;AAEF,aADU,MAAM,MAAM,OAAO,CAAC,UAAU,YAAY,EAAE,EAAE,KAAK,CAAC,EAClD,OAAO,MAAM,CAAC,SAAS;SAC7B;AAGR,KAAI;AAEF,cADU,MAAM,MAAM,OAAO,CAAC,UAAU,aAAa,EAAE,EAAE,KAAK,CAAC,EAClD,OAAO,MAAM,CAAC,SAAS;SAC9B;CAGR,MAAM,eAAe,CACnB,GAAI,UAAU,EAAE,GAAG,CAAC,MAAM,aAAa,SAAS,OAAO,EACvD,GAAI,WAAW,EAAE,GAAG,CAAC,MAAM,cAAc,SAAS,QAAQ,CAC3D;AAED,KAAI;AACF,QAAM,MAAM,OAAO;GAAC,GAAG;GAAc;GAAU;GAAM;GAAQ,EAAE;GAC7D;GACA,OAAO;IAAC;IAAU;IAAW;IAAU;GACxC,CAAC;UACK,KAAK;EACZ,MAAM,UAAU,gBAAgB,IAAI;AACpC,MAAI,QAAS,OAAM;EACnB,MAAM,IAAI;AACV,MAAI,OAAO,EAAE,WAAW,YAAY,qBAAqB,KAAK,EAAE,OAAO,CACrE;AAEF,QAAM,aAAa,KAAK,SAAS;;;;;;;;;;;;;;;;ACzarC,eAAsB,wBACpB,SAC8B;CAC9B,MAAM,OAAO,QAAQ,UACjB,iBAAiB,mBAAmB,QAAQ,QAAQ,CAAC,kCACrD;CAEJ,MAAM,WAAW,MAAM,QAAQ,OAAO,KAA4B,KAAK;CACvE,MAAM,YAAY,UAAU,gBAAgB;AAC5C,KAAI,OAAO,cAAc,YAAY,UAAU,WAAW,EACxD,OAAM,IAAI,MACR,uHAED;CAEH,MAAM,eAAe,SAAS,gBAAgB;AAC9C,QAAO;EACL;EACA,WAAW,OAAO,iBAAiB,WAAW,eAAe;EAC9D;;;;;;;;AASH,SAAgB,yBAAyB,KAAqB;AAC5D,QAAO,IAAI,QAAQ,oBAAoB,IAAI;;;;;;;;;AAU7C,SAAgB,2BAA2B,WAAkC;AAC3E,KAAI;AAMF,WALa,IAAI,IAAI,UAAU,CAAC,SAC7B,MAAM,IAAI,CACV,KAAK,EACJ,QAAQ,UAAU,GAAG,GACL,MAAM,oBAAoB,IAC/B,MAAM;SACf;AACN,SAAO;;;;AAKX,SAAgB,eAAe,KAAkC;AAC/D,KAAI,OAAO,OAAO,QAAQ,YAAY,YAAY,KAAK;EACrD,MAAM,SAAU,IAA6B;AAC7C,MAAI,OAAO,WAAW,SAAU,QAAO;;;;;;;;;AAW3C,SAAgB,qBAAqB,KAAuB;CAC1D,MAAM,SAAS,eAAe,IAAI;AAClC,QAAO,WAAW,OAAO,WAAW;;;;;;;;;;ACrGtC,MAAa,qBAAqB;AAQlC,SAAgB,wBAAwB,KAAqB;AAC3D,QAAO,KAAK,KAAK,KAAK,mBAAmB;;AAG3C,SAAgB,kBAAkB,KAAa,QAA4B;CACzE,MAAM,UAAwB,OAAO,UACjC;EAAE,aAAa,OAAO;EAAa,SAAS,OAAO;EAAS,GAC5D,EAAE,aAAa,OAAO,aAAa;AACvC,eACE,wBAAwB,IAAI,EAC5B,KAAK,UAAU,SAAS,MAAM,EAAE,GAAG,MACnC,OACD;;;;ACFH,MAAa,eAAwB,IAAI,QAAQ,QAAQ,CACtD,YACC,yEACD,CACA,SAAS,aAAa,8BAA8B,CACpD,OACC,oBACA,6EACD,CACA,OAAO,eAAe,8CAA8C,CACpE,OAAO,kBAAkB,+BAA+B,CACxD,QAAQ,YAAoB,YAC3B,aAAa,YAAY;CACvB,MAAM,iBAAiB,WAAW,MAAM;AACxC,KAAI,CAAC,eAAgB,OAAM,IAAI,MAAM,oCAAoC;CAEzE,MAAM,UAAU,QAAQ,SAAS,MAAM;AACvC,KAAI,SAAS;EACX,MAAM,eAAe,oBAAoB,QAAQ;AACjD,MAAI,aAAc,OAAM,IAAI,MAAM,aAAa;;AAKjD,OAAM,oBAAoB;CAE1B,MAAM,YAAY,KAAK,QAAQ,QAAQ,OAAO,eAAe;AAC7D,KAAI,WAAW,UAAU,CACvB,OAAM,IAAI,MACR,aAAa,UAAU,iDACxB;CASH,MAAM,SAAS,wCAAwC;CACvD,MAAM,UAAU,IAAI,0BAA0B,CAAC,OAAO;CACtD,IAAI;AACJ,KAAI;AAKF,eAJa,MAAM,wBAAwB;GACzC;GACA,GAAI,UAAU,EAAE,SAAS,GAAG,EAAE;GAC/B,CAAC,EACe;UACV,KAAK;AACZ,UAAQ,KAAK,iCAAiC;AAC9C,MAAI,qBAAqB,IAAI,CAC3B,OAAM,IAAI,MACR,0HAED;AAEH,QAAM;;CAOR,MAAM,YAAY,2BAA2B,UAAU;AACvD,KAAI,CAAC,WAAW;AAId,UAAQ,KAAK,gDAAgD;AAC7D,QAAM,IAAI,MACR,iMAGD;;AAEH,KAAI,cAAc,yBAAyB,eAAe,EAAE;AAC1D,UAAQ,KAAK,0DAA0D;AACvE,QAAM,IAAI,MACR,OAAO,UAAU,YAAY,UAAU,wBACjC,UAAU,UAAU,eAAe,8FAE1C;;AAGH,SAAQ,OAAO,gBAAgB,KAAK,SAAS,UAAU,CAAC;AACxD,KAAI;AAEF,QAAM,SAAS,WAAW,UAAU;UAC7B,KAAK;AACZ,UAAQ,KAAK,mBAAmB;AAChC,QAAM;;AAKR,mBAAkB,WAAW;EAC3B,aAAa;EACb,GAAI,UAAU,EAAE,SAAS,GAAG,EAAE;EAC/B,CAAC;AAEF,SAAQ,QAAQ,eAAe,MAAM,KAAK,UAAU,GAAG;CAKvD,MAAM,iBAAiB,kBAAkB,UAAU;AACnD,KAAI,QAAQ,gBAAgB,MAAM;AAChC,UAAQ,MAAM,gCAAgC,eAAe,KAAK;AAClE,MAAI;AACF,SAAM,oBAAoB,UAAU;AACpC,WAAQ,QAAQ,yBAAyB;UACnC;AACN,WAAQ,KAAK,iCAAiC;AAC9C,WAAQ,KAAK;AACb,WAAQ,IAAI,MAAM,OAAO,yCAAyC,CAAC;AACnE,WAAQ,IAAI,MAAM,KAAK,KAAK,iBAAiB,CAAC;;;AAIlD,SAAQ,IACN,MAAM,IAAI,QAAQ,KAAK,SAAS,QAAQ,KAAK,EAAE,UAAU,IAAI,MAAM,CACpE;AACD,KAAI,QAAQ,gBAAgB,KAC1B,SAAQ,IAAI,MAAM,IAAI,KAAK,iBAAiB,CAAC;EAE/C,CACH;;;ACnJH,SAAgB,yBAAiC;AAC/C,QAAO,KAAK,KAAK,iBAAiB,EAAE,aAAa,UAAU;;AAG7D,eAAsB,gBAAgB,UAAoC;AACxE,KAAI;AAEF,UADc,MAAM,KAAK,SAAS,EACrB,aAAa;SACpB;AACN,SAAO;;;AAIX,eAAsB,mBACpB,cACA,YACA,WACe;CACf,MAAM,QAAQ,MAAM,SAAS,aAAa;AAE1C,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,KAAK,KAAK,cAAc,KAAK;EAChD,MAAM,aAAa,KAAK,SAAS,YAAY;EAC7C,MAAM,cAAc,mBAAmB,KAAK;EAE5C,MAAM,UAAU,MAAM,SAAS,YAAY,QAAQ;AAGnD,QAAM,iBAAiB,YAAY,aAFjB,aAAa,eAAe,SAAS,UAAU,GAAG,QAEV;;AAG5D,MAAK,MAAM,aAAa,MAAM,6BAA6B,CACzD,OAAM,iBACJ,YACA,mBAAmB,UAAU,aAAa,EAC1C,UAAU,QACX;;AAIL,eAAsB,oBACpB,UAGI,EAAE,EACW;AACjB,QAAO,2BAA2B,CAAC,UAAU,MAAM,EAAE,UAAU,QAAQ;;AAGzE,eAAsB,qBACpB,UAGI,EAAE,EACW;AACjB,QAAO,2BAA2B,CAAC,UAAU,OAAO,EAAE,UAAU,QAAQ;;AAG1E,eAAsB,cACpB,UAGI,EAAE,EACW;AACjB,QAAO,2BAA2B,CAAC,OAAO,OAAO,EAAE,UAAU,QAAQ;;AAGvE,eAAsB,oBACpB,UAGI,EAAE,EACW;AACjB,QAAO,2BAA2B,CAAC,OAAO,SAAS,EAAE,UAAU,QAAQ;;AAGzE,eAAe,2BACb,qBACA,UACA,SACiB;AACjB,KAAI;EACF,MAAM,cAAc,iBAAiB;EACrC,MAAM,eAAe,KAAK,KAAK,aAAa,MAAM,KAAK;EACvD,MAAM,oBAAoB,KAAK,KAAK,cAAc,GAAG,oBAAoB;AAEzE,MAAI,QAAQ,MAMV,QAAO,SAJL,QAAQ,aACJ,KAAK,SAAS,QAAQ,YAAY,kBAAkB,GACpD,mBACJ,QAAQ,OAAO,IAAI,IACM;EAI7B,MAAM,UAAU,MAAM,SADE,KAAK,KAAK,mBAAmB,eAAe,EACpB,QAAQ;AAExD,SAAO,IADK,KAAK,MAAM,QAAQ,CAChB,WAAW,SAAS,QAAQ,OAAO,GAAG;SAC/C;AACN,SAAO;;;AAIX,eAAe,SAAS,KAAa,UAAU,KAAwB;CACrE,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,MAAM,CAAC;CAC3D,MAAM,QAAkB,EAAE;AAE1B,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAC3C,MAAI,MAAM,aAAa,CACrB,OAAM,KAAK,GAAI,MAAM,SAAS,UAAU,QAAQ,CAAE;MAElD,OAAM,KAAK,KAAK,SAAS,SAAS,SAAS,CAAC;;AAIhD,QAAO;;AAQT,eAAe,8BAA4D;CACzE,MAAM,cAAc,yBAAyB;CAC7C,MAAM,aAAa,KAAK,KAAK,aAAa,kBAAkB;CAC5D,MAAM,QAAQ,MAAM,SAAS,WAAW;AAExC,QAAO,QAAQ,IACb,MAAM,IAAI,OAAO,UAAU;EACzB,cAAc,KAAK,KAAK,UAAU,KAAK;EACvC,SAAS,MAAM,SAAS,KAAK,KAAK,YAAY,KAAK,EAAE,QAAQ;EAC9D,EAAE,CACJ;;AAGH,SAAS,0BAAkC;CACzC,MAAM,uBAAuB,KAAK,KAAK,iBAAiB,EAAE,MAAM,OAAO;AACvE,KAAI,WAAW,KAAK,KAAK,sBAAsB,kBAAkB,CAAC,CAChE,QAAO;CAGT,IAAI,MAAM,KAAK,QACb,cAAc,OAAO,KAAK,QAAQ,uBAAuB,CAAC,CAC3D;AACD,QAAO,CAAC,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,EAAE;EAClD,MAAM,SAAS,KAAK,QAAQ,IAAI;AAChC,MAAI,WAAW,IACb,OAAM,IAAI,MAAM,wCAAwC;AAC1D,QAAM;;AAER,QAAO;;AAGT,SAAS,eACP,SACA,WACQ;AASR,QARyB,QAAQ,QAC/B,6DACC,OAAO,KAAK,UAAU;AACrB,MAAI,CAAC,sBAAsB,IAAI,CAAE,QAAO;AACxC,SAAO,UAAU,OAAO,OAAO,MAAM,GAAG;GAE3C,CAEuB,QACtB,+BACC,OAAO,QAAQ;AACd,MAAI,sBAAsB,IAAI,CAAE,QAAO,UAAU,QAAQ;AACzD,SAAO;GAEV;;AAGH,SAAS,sBACP,KACsC;AACtC,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,SAAS,IAAI;;AAGjB,eAAe,iBACb,YACA,aACA,SACe;AACf,MAAK,MAAM,cAAc,aAAa;EACpC,MAAM,kBAAkB,KAAK,KAAK,YAAY,WAAW;AACzD,QAAM,MAAM,KAAK,QAAQ,gBAAgB,EAAE,EAAE,WAAW,MAAM,CAAC;AAC/D,QAAM,UAAU,iBAAiB,SAAS,QAAQ;;;AAItD,SAAS,mBAAmB,UAA4B;CACtD,MAAM,iBAAiB,kBAAkB,SAAS;CAClD,MAAM,aAAa,eAAe,QAAQ,OAAO,IAAI;AAErD,KAAI,eAAe,YAAa,QAAO,CAAC,aAAa,YAAY;AAEjE,KAAI,WAAW,WAAW,UAAU,CAClC,QAAO,CACL,KAAK,KAAK,WAAW,eAAe,EACpC,KAAK,KAAK,WAAW,eAAe,CACrC;AAGH,QAAO,CAAC,eAAe;;AAGzB,SAAS,kBAAkB,UAA0B;AACnD,QAAO,SAAS,SAAS,YAAY,GACjC,SAAS,MAAM,GAAG,GAAoB,GACtC;;AAGN,SAAS,kBAA0B;CACjC,IAAI,MAAM,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AACtD,QAAO,CAAC,WAAW,KAAK,KAAK,KAAK,eAAe,CAAC,EAAE;EAClD,MAAM,SAAS,KAAK,QAAQ,IAAI;AAChC,MAAI,WAAW,IACb,OAAM,IAAI,MAAM,yCAAyC;AAC3D,QAAM;;AAER,QAAO;;;;;;;AC5NT,SAAgB,wBAAgC;AAC9C,QACE,QAAQ,IAAI,iCAAA;;;;;;;AAUhB,MAAa,oBAAoB;CAC/B,aAAa;CACb,aAAa;CACb,sBAAsB;CACvB;;;;;;;;;;;;AAmBD,eAAsB,uBACpB,YACA,WACkB;CAClB,IAAI;AACJ,KAAI;AACF,QAAM,oBAAoB;AAC1B,YAAU,MAAM,QAAQ,KAAK,KAAK,GAAG,QAAQ,EAAE,yBAAyB,CAAC;EACzE,MAAM,YAAY,KAAK,KAAK,SAAS,WAAW;AAChD,QAAM,SAAS,uBAAuB,EAAE,WAAW;GACjD,OAAO;GACP,QAAQ;GACR,QAAQ;GACT,CAAC;AAIF,QAAM,GAAG,KAAK,KAAK,WAAW,OAAO,EAAE;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AAExE,QAAM,GAAG,WAAW,YAAY,EAAE,WAAW,MAAM,CAAC;AACpD,QAAM,qBAAqB,YAAY,UAAU;AACjD,SAAO;SACD;AAGN,QAAM,GAAG,YAAY;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC,CAAC,YAAY,GAAG;AACtE,SAAO;WACC;AACR,MAAI,QACF,OAAM,GAAG,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC,CAAC,YAAY,GAAG;;;;;;;;AASzE,eAAe,qBACb,YACA,WACe;CACf,MAAM,EAAE,aAAa,aAAa,yBAAyB;AAE3D,OAAM,cAAc,KAAK,KAAK,YAAY,eAAe,EAAE,CACzD,CACE,WAAW,KAAK,UAAU,kBAAkB,YAAY,IACxD,WAAW,KAAK,UAAU,YAAY,GACvC,CACF,CAAC;AAEF,OAAM,cAAc,KAAK,KAAK,YAAY,aAAa,EAAE,CACvD,CACE,UAAU,kBAAkB,YAAY,WACxC,UAAU,YAAY,UACvB,CACF,CAAC;AAEF,OAAM,cAAc,KAAK,KAAK,YAAY,YAAY,EAAE,CACtD,CAAC,KAAK,kBAAkB,YAAY,KAAK,KAAK,YAAY,IAAI,CAC/D,CAAC;AAEF,OAAM,cAAc,KAAK,KAAK,YAAY,cAAc,EAAE,CACxD,CACE,UAAU,KAAK,UAAU,kBAAkB,YAAY,CAAC,IACxD,UAAU,KAAK,UAAU,YAAY,CAAC,GACvC,EACD,CACE,YAAY,KAAK,UAAU,kBAAkB,qBAAqB,CAAC,IACnE,YAAY,KAAK,UAAU,qBAAqB,CAAC,GAClD,CACF,CAAC;;;;;;;AAQJ,eAAe,cACb,UACA,cACe;AACf,KAAI,CAAC,WAAW,SAAS,CAAE;CAC3B,IAAI,UAAU,MAAM,SAAS,UAAU,OAAO;CAC9C,IAAI,UAAU;AACd,MAAK,MAAM,CAAC,MAAM,OAAO,cAAc;AACrC,MAAI,SAAS,GAAI;EACjB,MAAM,QAAQ,QAAQ,QAAQ,KAAK;AACnC,MAAI,UAAU,GAAI;AAClB,YAAU,QAAQ,MAAM,GAAG,MAAM,GAAG,KAAK,QAAQ,MAAM,QAAQ,KAAK,OAAO;AAC3E,YAAU;;AAEZ,KAAI,QAAS,OAAM,UAAU,UAAU,SAAS,OAAO;;;;AC1HzD,MAAM,iCAAiC;AACvC,MAAM,uBAAuB;AAE7B,MAAa,gBAAyB,IAAI,QAAQ,SAAS,CACxD,YAAY,2CAA2C,CACvD,SAAS,kBAAkB,uCAAuC,CAClE,OAAO,kBAAkB,+BAA+B,CACxD,OACC,0BACA,uDACD,CACA,OACC,mBACA,kCACA,qBACD,CACA,OACC,+BACA,kCACA,+BACD,CACA,OACC,WACA,wEACD,CACA,OACC,0BACA,0EACD,CACA,OAAO,oBAAoB,8CAA8C,CACzE,OAAO,OAAO,aAAqB,YAAiC;AACnE,KAAI;AACF,QAAM,oBAAoB,aAAa,QAAQ;UACxC,KAAK;AACZ,UAAQ,KAAK;AACb,UAAQ,MACN,MAAM,IAAI,SAAS,GACjB,OACC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,EACpD;AACD,UAAQ,KAAK;AACb,UAAQ,KAAK,EAAE;;EAEjB;AAEJ,eAAsB,oBACpB,aACA,SACe;AACf,SAAQ,KAAK;AACb,SAAQ,IAAI,MAAM,KAAK,sCAAsC,CAAC;AAC9D,SAAQ,KAAK;CAEb,MAAM,mBAAmB,oBAAoB,YAAY;AACzD,KAAI,iBAAkB,OAAM,IAAI,MAAM,iBAAiB;CAEvD,MAAM,UAAU,QAAQ,SAAS,MAAM;AACvC,KAAI,SAAS;EACX,MAAM,eAAe,oBAAoB,QAAQ;AACjD,MAAI,aAAc,OAAM,IAAI,MAAM,aAAa;;CAGjD,MAAM,YAAY,KAAK,QAAQ,QAAQ,aAAa,QAAQ,KAAK,CAAC;CAClE,MAAM,aAAa,KAAK,KAAK,WAAW,YAAY;AACpD,KAAI,MAAM,gBAAgB,WAAW,CACnC,OAAM,IAAI,MAAM,6BAA6B,aAAa;CAG5D,MAAM,eAAe,wBAAwB;AAC7C,KAAI,CAAE,MAAM,gBAAgB,aAAa,CACvC,OAAM,IAAI,MAAM,qCAAqC;CAGvD,MAAM,SAAS,kBAAkB,EAAE,EAAE,EAAE,SAAS,CAAC;CACjD,MAAM,cAAc,QAAQ,SAAS;CACrC,MAAM,eAAe;EAAE,OAAO,QAAQ,UAAU;EAAM;EAAY;CAClE,MAAM,YAAY;EAChB;EACA,SAAS,OAAO;EAChB;EACA,sBACE,QAAQ,kBAAkB;EAC5B,YAAY,MAAM,oBAAoB,aAAa;EACnD,kBAAkB,QAAQ,QACtB,MAAM,qBAAqB,aAAa,GACxC,KAAA;EACJ,iBAAiB,MAAM,cAAc,aAAa;EAClD,kBAAkB,MAAM,oBAAoB,aAAa;EAC1D;CAOD,MAAM,oBACJ,QAAQ,UAAU,QAAQ,QAAQ,uBAAuB;CAE3D,IAAI,aAAa;AACjB,KAAI,mBAAmB;EACrB,MAAM,gBAAgB,IACpB,0CACD,CAAC,OAAO;AACT,eAAa,MAAM,uBAAuB,YAAY;GACpD;GACA;GACA,sBACE,QAAQ,kBAAkB;GAC7B,CAAC;AACF,MAAI,WACF,eAAc,QAAQ,sCAAsC;MAE5D,eAAc,KACZ,uGACD;;CAIL,MAAM,UAAU,IACd,aAAa,iCAAiC,6BAC/C,CAAC,OAAO;AACT,KAAI;AACF,MAAI,CAAC,WACH,OAAM,mBAAmB,cAAc,YAAY,UAAU;AAE/D,QAAM,kBAAkB,YAAY,OAAO;AAC3C,UAAQ,QACN,aAAa,4BAA4B,yBAC1C;UACM,KAAK;AACZ,UAAQ,KAAK,kCAAkC;AAC/C,QAAM;;CAGR,MAAM,iBAAiB,kBAAkB,WAAW;AACpD,KAAI,QAAQ,gBAAgB,MAAM;AAChC,UAAQ,MAAM,gCAAgC,eAAe,KAAK;AAClE,MAAI;AACF,SAAM,oBAAoB,WAAW;AACrC,WAAQ,QAAQ,yBAAyB;UACnC;AACN,WAAQ,KAAK,iCAAiC;AAC9C,WAAQ,KAAK;AACb,WAAQ,IAAI,MAAM,OAAO,yCAAyC,CAAC;AACnE,WAAQ,IAAI,MAAM,KAAK,QAAQ,aAAa,WAAW,GAAG,CAAC;AAC3D,WAAQ,IAAI,MAAM,KAAK,KAAK,iBAAiB,CAAC;;;AAIlD,SAAQ,KAAK;AACb,SAAQ,IACN,MAAM,MAAM,KAAK,WAAW,GAAG,YAAY,MAAM,KAAK,YAAY,GACnE;AACD,SAAQ,KAAK;AACb,SAAQ,IAAI,cAAc;AAC1B,SAAQ,IAAI,MAAM,KAAK,QAAQ,aAAa,WAAW,GAAG,CAAC;AAC3D,KAAI,QAAQ,gBAAgB,KAC1B,SAAQ,IAAI,MAAM,KAAK,KAAK,iBAAiB,CAAC;AAEhD,KAAI,CAAC,OAAO,QACV,SAAQ,IAAI,MAAM,KAAK,sBAAsB,CAAC;AAEhD,SAAQ,IAAI,MAAM,KAAK,KAAK,cAAc,OAAO,WAAW,GAAG,CAAC;AAChE,SAAQ,KAAK;AACb,SAAQ,IACN,UAAU,MAAM,KAAK,cAAc,GAAG,qCACvC;AACD,SAAQ,IACN,MAAM,IACJ,+EACD,CACF;AACD,SAAQ,KAAK;;AAGf,SAAS,oBAAoB,aAAyC;AACpE,KAAI,CAAC,YAAa,QAAO;AACzB,KAAI,CAAC,uBAAuB,KAAK,YAAY,CAC3C,QAAO;;AAKX,SAAS,aAAa,YAA4B;AAChD,QAAO,KAAK,SAAS,QAAQ,KAAK,EAAE,WAAW,IAAI;;;;ACtMrD,MAAa,0BAA0B;AAEvC,MAAa,oBAAoB,CAC/B,wBACA,qBACD;AAkBD,MAAa,aAAsB,IAAI,QAAQ,MAAM,CAClD,YAAY,qDAAqD,CACjE,OACC,qBACA,wCACA,OAAO,wBAAwB,CAChC,CACA,OAAO,iBAAiB,uCAAuC,CAC/D,OAAO,iBAAiB,oBAAoB,cAAc,CAC1D,QAAQ,YAA8B;AACrC,QAAO,aAAa,YAAY;EAC9B,MAAM,aAAa,QAAQ,KAAK;AAGhC,wBAFgB,MAAM,wBAAwB,YAAY,QAAQ,CAEpC;AAC9B,QAAM,iBAAiB,YAAY,QAAQ;GAC3C;EACF;AAEJ,eAAsB,wBACpB,YACA,UAA4B,EAAE,EACI;CAClC,MAAM,qBAAqB,KAAK,QAAQ,WAAW;CACnD,MAAM,kBAAkB,KAAK,KAAK,oBAAoB,eAAe;AACrE,KAAI,CAAC,WAAW,gBAAgB,CAC9B,OAAM,IAAI,MACR,iFACD;CAIH,MAAM,cAAc,gBADA,MAAM,gBAAgB,gBAAgB,CACV,IAAI,KAAK,SAAS,WAAW;CAE7E,MAAM,iBAAiB,KAAK,KAAK,oBAAoB,iBAAiB;AACtE,KAAI,CAAC,WAAW,eAAe,CAC7B,OAAM,IAAI,MACR,mFACD;CAGH,MAAM,OAAO,UAAU,QAAQ,QAAQ,OAAA,KAA+B,CAAC;CACvE,MAAM,OAAO,oBAAoB,QAAQ,KAAK;CAC9C,MAAM,OAAO,cAAc,QAAQ,KAAK;AAExC,QAAO;EACL,YAAY;EACZ;EACA;EACA,UAAU,eAAe,MAAM,KAAK;EACpC,QAAQ;EACR;EACA,QAAQ;EACT;;AAGH,SAAgB,iBAAiB,UAA4B,EAAE,EAAY;CACzE,MAAM,OAAO,UAAU,QAAQ,QAAQ,OAAA,KAA+B,CAAC;CACvE,MAAM,OAAO,oBAAoB,QAAQ,KAAK;CAC9C,MAAM,OAAO,cAAc,QAAQ,KAAK;CACxC,MAAM,OAAO;EAAC;EAAU,OAAO,KAAK;EAAE;EAAU;EAAK;AAErD,KAAI,KACF,MAAK,KAAK,UAAU,KAAK;AAG3B,QAAO;;AAGT,SAAgB,sBAAsB,SAAwC;AAC5E,SAAQ,KAAK;AACb,SAAQ,IAAI,MAAM,KAAK,KAAK,mBAAmB,CAAC;AAChD,SAAQ,IAAI,MAAM,KAAK,WAAW,GAAG,MAAM,KAAK,QAAQ,SAAS,CAAC;AAClE,SAAQ,IAAI,MAAM,KAAK,WAAW,GAAG,MAAM,MAAM,QAAQ,OAAO,CAAC;AACjE,SAAQ,IAAI,MAAM,KAAK,WAAW,GAAG,MAAM,MAAM,QAAQ,KAAK,CAAC;AAC/D,SAAQ,IAAI,MAAM,KAAK,UAAU,CAAC;AAClC,MAAK,MAAM,SAAS,QAAQ,OAC1B,SAAQ,IAAI,MAAM,KAAK,OAAO,GAAG,MAAM,KAAK,MAAM,CAAC;AAErD,SAAQ,KAAK;;AAGf,eAAsB,iBACpB,YACA,UAA4B,EAAE,EACf;CACf,IAAI,cAAc,mBAAmB,WAAW;AAChD,KAAI,CAAC,aAAa;EAIhB,MAAM,iBAAiB,kBAAkB,WAAW;AACpD,UAAQ,IACN,MAAM,OACJ,uCAAuC,eAAe,WACvD,CACF;AACD,MAAI;AACF,SAAM,oBAAoB,WAAW;UAC/B;AAGR,gBAAc,mBAAmB,WAAW;;AAE9C,KAAI,CAAC,YACH,OAAM,IAAI,MACR,8CAA8C,kBAAkB,WAAW,CAAC,QAAQ,WAAW,eAChG;AAGH,OAAM,cAAc,aAAa,iBAAiB,QAAQ,EAAE,WAAW;;AAGzE,SAAS,mBAAmB,YAAwC;CAClE,MAAM,cAAc,KAAK,KACvB,YACA,gBACA,QACA,OACA,UACD;AACD,QAAO,WAAW,YAAY,GAAG,cAAc,KAAA;;AAGjD,eAAe,gBAAgB,iBAA2C;AACxE,KAAI;AACF,SAAO,KAAK,MAAM,MAAM,SAAS,iBAAiB,QAAQ,CAAC;UACpD,KAAK;EACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,QAAM,IAAI,MAAM,gCAAgC,UAAU;;;AAI9D,SAAS,gBAAgB,aAA0C;AACjE,KAAI,CAACC,WAAS,YAAY,CAAE,QAAO,KAAA;CACnC,MAAM,OAAO,YAAY;AACzB,KAAI,OAAO,SAAS,SAAU,QAAO,KAAA;CACrC,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;;AAGxC,SAAS,UAAU,OAAuB;CACxC,MAAM,OAAO,OAAO,MAAM;AAC1B,KAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,OAAO,MAChD,OAAM,IAAI,MAAM,+CAA+C;AAEjE,QAAO;;AAGT,SAAS,oBACP,MACoB;AACpB,KAAI,SAAS,KAAA,KAAa,SAAS,MAAO,QAAO,KAAA;AACjD,KAAI,SAAS,KAAM,QAAO;CAE1B,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAO,QAAQ,SAAS,IAAI,UAAU;;AAGxC,SAAS,cAAc,MAAkC;CACvD,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,WAAW,QAAQ,SAAS,IAAI,UAAU;;AAGnD,SAAS,eAAe,MAAc,MAAkC;AAEtE,QAAO,UADa,QAAQ,SAAS,YAAY,OAAO,YAC3B,GAAG;;AAGlC,SAAS,cACP,YACA,MACA,KACe;AACf,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,YAAY,GAAG,KAAK,EAAE;GAC3D;GACA,OAAO;GACP,OAAO,QAAQ,aAAa;GAC7B,CAAC;AAEF,QAAM,GAAG,SAAS,OAAO;AACzB,QAAM,GAAG,SAAS,MAAM,WAAW;AACjC,OAAI,SAAS,KAAK,WAAW,YAAY,WAAW,WAAW;AAC7D,aAAS;AACT;;AAGF,0BACE,IAAI,MACF,SACI,sCAAsC,OAAO,KAC7C,oCAAoC,QAAQ,UAAU,GAC3D,CACF;IACD;GACF;;AAGJ,SAASA,WAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;ACpO7E,SAAgB,4BAAuD;AACrE,QAAO,EAAE,QAAQ,wCAAwC,EAAE;;;;ACC7D,MAAM,oBAAoB;AAE1B,eAAsB,iBACpB,QAC6B;CAC7B,MAAM,WAAW,MAAM,aAAa,OAAO;AAE3C,KAAI,SAAS,WAAW,EACtB,OAAM,IAAI,MACR,yGACD;AAqBH,SAlBiB,MAAM,QAAQ;EAC7B,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS,SAAS,KAAK,aAAa;GAClC,OAAO,GAAG,QAAQ,KAAK,IAAI,QAAQ,KAAK;GACxC,OAAO,QAAQ;GAChB,EAAE;EACH,UAAU,OAAe,YACvB,QAAQ,QACN,QACI,QAAQ,QAAQ,WACd,OAAO,MAAM,aAAa,CAAC,SAAS,MAAM,aAAa,CAAC,CACzD,GACD,QACL;EACJ,CAAC,EAEc;;AAGlB,eAAsB,aACpB,QACmC;AACnC,KAAI;EACF,MAAM,gBAAgB,MAAM,OAAO,IAAa,iBAAiB,EAC/D,MAAM,GACP,CAAC;EACF,MAAM,aAAa,KAAK,IACtB,eAAe,cAAc,IAAI,GACjC,kBACD;EACD,MAAM,YAAY,CAAC,cAAc;AAEjC,OAAK,IAAI,OAAO,GAAG,QAAQ,YAAY,QAAQ,EAC7C,WAAU,KACR,MAAM,OAAO,IAAa,iBAAiB,EACzC,MACD,CAAC,CACH;AAGH,SAAO,UAAU,QAAQ,0BAA0B;UAC5C,KAAK;AACZ,MAAI,eAAe,IAAI,EAAE;AACvB,OAAI,IAAI,WAAW,OAAO,IAAI,WAAW,IACvC,OAAM,IAAI,MACR,mEACD;AAEH,SAAM,IAAI,MACR,6CAA6C,IAAI,OAAO,KAAK,IAAI,UAClE;;EAGH,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,QAAM,IAAI,MAAM,wCAAwC,UAAU;;;AAItE,SAAS,eAAe,UAAuC;AAC7D,KAAI,CAACC,WAAS,SAAS,CAAE,QAAO,KAAA;CAChC,MAAM,OAAO,SAAS;AACtB,KAAI,CAACA,WAAS,KAAK,CAAE,QAAO,KAAA;CAC5B,MAAM,aAAa,KAAK;AACxB,KAAI,CAACA,WAAS,WAAW,CAAE,QAAO,KAAA;CAClC,MAAM,aAAa,WAAW,kBAAkB,WAAW;AAC3D,KACE,OAAO,eAAe,YACtB,CAAC,OAAO,UAAU,WAAW,IAC7B,aAAa,EAEb;AAEF,QAAO;;AAGT,SAAS,0BAA0B,UAAoC;AAErE,QADmB,oBAAoB,SAAS,CAE7C,IAAI,iBAAiB,CACrB,QAAQ,YAAsC,YAAY,KAAA,EAAU;;AAGzE,SAAS,oBAAoB,UAAuC;AAClE,KAAI,MAAM,QAAQ,SAAS,CAAE,QAAO;AACpC,KAAI,CAACA,WAAS,SAAS,CAAE,QAAO,EAAE;CAElC,MAAM,iBAAiB,SAAS;AAChC,KAAI,MAAM,QAAQ,eAAe,CAAE,QAAO;CAE1C,MAAM,OAAO,SAAS;AACtB,KAAI,MAAM,QAAQ,KAAK,CAAE,QAAO;AAChC,KAAIA,WAAS,KAAK,IAAI,MAAM,QAAQ,KAAK,YAAY,CACnD,QAAO,KAAK;AAGd,QAAO,EAAE;;AAGX,SAAS,iBAAiB,OAA2C;AACnE,KAAI,CAACA,WAAS,MAAM,CAAE,QAAO,KAAA;CAE7B,MAAM,OAAO,WAAW,OAAO,OAAO,IAAI,WAAW,OAAO,KAAK;AACjE,KAAI,CAAC,KAAM,QAAO,KAAA;AAQlB,QAAO;EAAE;EAAM,MALb,WAAW,OAAO,OAAO,IACzB,WAAW,OAAO,QAAQ,IAC1B,WAAW,OAAO,OAAO,IACzB;EAEmB;;AAGvB,SAAS,WACP,QACA,KACoB;CACpB,MAAM,QAAQ,OAAO;AACrB,KAAI,OAAO,UAAU,SAAU,QAAO,KAAA;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,UAAU,UAAU,KAAA;;AAG7B,SAAS,eACP,OACgE;AAChE,QACE,iBAAiB,SACjB,YAAY,SACZ,OAAQ,MAAwC,WAAW;;AAI/D,SAASA,WAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;AC/I7E,MAAa,cAAuB,IAAI,QAAQ,OAAO,CACpD,YAAY,wDAAwD,CACpE,OAAO,oBAAoB,4CAA4C,CACvE,OAAO,OAAO,YAA+B;AAC5C,KAAI;EACF,MAAM,aAAa,QAAQ,KAAK;EAChC,MAAM,SAAS,MAAM,iBAAiB,WAAW;EAEjD,IAAI,UAAU,QAAQ,SAAS,MAAM,IAAI,KAAA;AACzC,MAAI,CAAC,SAAS;GACZ,MAAM,UAAU,IAAI,uBAAuB,CAAC,OAAO;AACnD,OAAI;IACF,MAAM,EAAE,WAAW,2BAA2B;AAC9C,YAAQ,MAAM;AACd,cAAU,MAAM,iBAAiB,OAAO;YACjC,KAAK;AACZ,YAAQ,KAAK,0BAA0B;AACvC,UAAM;;AAGR,OAAI,CAAC,SAAS;AACZ,YAAQ,IAAI,MAAM,IAAI,aAAa,CAAC;AACpC;;;EAIJ,MAAM,aAAa,kBAAkB,OAAO,QAAQ,EAAE,SAAS,CAAC;EAChE,MAAM,mBAAmB,oBAAoB,WAAW,WAAW,GAAG;AACtE,MAAI,iBAAkB,OAAM,IAAI,MAAM,iBAAiB;AAEvD,QAAM,kBAAkB,YAAY,WAAW;AAE/C,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,MAAM,yBAAyB,CAAC;AAClD,UAAQ,IACN,MAAM,KAAK,iBAAiB,GAC1B,MAAM,KACJ,KAAK,SAAS,YAAY,OAAO,KAAK,IAAA,yBACvC,CACJ;AACD,UAAQ,IACN,MAAM,KAAK,iBAAiB,GAAG,MAAM,MAAM,WAAW,QAAQ,CAC/D;AACD,UAAQ,IACN,MAAM,KAAK,iBAAiB,GAC1B,MAAM,MAAM,GAAG,WAAW,QAAQ,yBAAyB,CAC9D;AACD,UAAQ,KAAK;UACN,KAAK;AACZ,UAAQ,KAAK;AACb,UAAQ,MACN,MAAM,IAAI,SAAS,GACjB,OACC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,EACpD;AACD,UAAQ,KAAK;AACb,UAAQ,KAAK,EAAE;;EAEjB;;;ACrDJ,eAAsB,yBAAyB,SAGJ;AAIzC,QAAO,aAHU,MAAM,QAAQ,OAAO,IACpC,iBAAiB,mBAAmB,QAAQ,QAAQ,CAAC,0BACtD,CAC4B,CAAC,IAAI,wBAAwB;;AAG5D,eAAsB,uBAAuB,SAIR;AAKnC,QAAO,aAJU,MAAM,QAAQ,OAAO,IACpC,iBAAiB,mBAAmB,QAAQ,QAAQ,CAAC,gCACrD,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,KAAA,EAC5C,CAC4B,CAAC,IAAI,kBAAkB;;AAGtD,SAAgB,iBACd,UACQ;AACR,KAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAO,SACJ,KAAK,YAAY;EAChB,MAAM,WACJ,QAAQ,aAAa,QAAQ,cAAc;EAC7C,MAAM,UAAU,QAAQ,WAAW;EACnC,MAAM,SAAS,QAAQ,UAAU;EACjC,MAAM,UAAU,QAAQ,aAAa,QAAQ,aAAa;AAK1D,SAAO,GAAG,SAAS,GAAG,QAAQ,KAAK,OAAO,KAHxC,QAAQ,kBAAkB,KAAA,IACtB,sBACA,GAAG,QAAQ,cAAc,WAAW,QAAQ,kBAAkB,IAAI,KAAK,MACpB,KAAK;GAC9D,CACD,KAAK,KAAK;;AAGf,SAAgB,cAAc,MAAgD;AAC5E,KAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QAAO,KACJ,KAAK,UAAU;AAGd,SAAO,IAFW,MAAM,aAAa,eAEhB,IADP,MAAM,QAAQ,MAAM,MAAM,aAAa,GAAG,OACzB,GAAG,MAAM;GACxC,CACD,KAAK,KAAK;;AAGf,SAAS,wBAAwB,OAA6C;CAC5E,MAAM,SAAS,wBAAwB,MAAM;CAC7C,MAAM,YAAY,UAAU,QAAQ,YAAY;AAChD,QAAO;EACL,YAAY,gBAAgB,QAAQ,CAAC,eAAe,aAAa,CAAC;EAClE,WAAW,gBAAgB,QAAQ,CAAC,cAAc,YAAY,CAAC;EAC/D,SAAS,gBAAgB,QAAQ,CAAC,WAAW,OAAO,CAAC;EACrD,QAAQ,gBAAgB,QAAQ,CAAC,UAAU,QAAQ,CAAC;EACpD,WAAW,gBAAgB,QAAQ,CAAC,cAAc,YAAY,CAAC;EAC/D,WAAW,gBAAgB,QAAQ,CAAC,cAAc,YAAY,CAAC;EAC/D,GAAI,YAAY,EAAE,eAAe,UAAU,QAAQ,GAAG,EAAE;EACxD,KAAK;EACN;;AAGH,SAAS,kBAAkB,OAAuC;CAChE,MAAM,SAAS,wBAAwB,MAAM;AAC7C,QAAO;EACL,WAAW,gBAAgB,QAAQ;GACjC;GACA;GACA;GACD,CAAC;EACF,OAAO,gBAAgB,QAAQ,CAAC,SAAS,WAAW,CAAC;EACrD,SACE,gBAAgB,QAAQ;GAAC;GAAW;GAAS;GAAU;GAAQ,CAAC,IAChE,KAAK,UAAU,MAAM;EACvB,KAAK;EACN;;AAGH,SAAS,aAAa,OAA2B;AAC/C,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO;AACjC,KAAI,CAAC,SAAS,MAAM,CAAE,QAAO,EAAE;AAE/B,MAAK,MAAM,OAAO;EAChB;EACA;EACA;EACA;EACA;EACA;EACD,EAAW;EACV,MAAM,SAAS,MAAM;AACrB,MAAI,MAAM,QAAQ,OAAO,CAAE,QAAO;;AAGpC,QAAO,CAAC,MAAM;;AAGhB,SAAS,wBAAwB,OAAyC;AACxE,KAAI,CAAC,SAAS,MAAM,CAAE,QAAO,EAAE;AAC/B,MAAK,MAAM,OAAO;EAChB;EACA;EACA;EACA;EACA;EACD,EAAW;EACV,MAAM,SAAS,MAAM;AACrB,MAAI,SAAS,OAAO,CAAE,QAAO;;AAE/B,QAAO;;AAGT,SAAS,UACP,QACA,KACgC;CAChC,MAAM,QAAQ,OAAO;AACrB,QAAO,MAAM,QAAQ,MAAM,GAAG,QAAQ,KAAA;;AAGxC,SAAS,gBACP,QACA,MACoB;AACpB,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,OAAO;AACrB,MAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EAAG,QAAO;AACjE,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,CACrD,QAAO,OAAO,MAAM;;;AAK1B,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;ACrJ7E,MAAa,cAAuB,IAAI,QAAQ,OAAO,CACpD,YAAY,wDAAwD,CACpE,OAAO,oBAAoB,4CAA4C,CACvE,OAAO,oBAAoB,4CAA4C,KAAK,CAC5E,OAAO,UAAU,iCAAiC,CAClD,QAAQ,YAAgC;AACvC,QAAO,aAAa,YAAY;EAC9B,MAAM,UAAU,MAAMC,iBAAe,QAAQ,KAAK,EAAE,QAAQ,QAAQ;EACpE,MAAM,QAAQ,WAAW,QAAQ,MAAM;EACvC,MAAM,OAAO,MAAM,uBAAuB;GACxC,QAAQ,wCAAwC;GAChD;GACA;GACD,CAAC;AAEF,MAAI,QAAQ,SAAS,MAAM;AACzB,WAAQ,IACN,KAAK,UACH,KAAK,KAAK,UAAU,MAAM,IAAI,EAC9B,MACA,EACD,CACF;AACD;;AAGF,UAAQ,IAAI,MAAM,KAAK,KAAK,2BAA2B,UAAU,CAAC;AAClE,UAAQ,KAAK;AACb,UAAQ,IAAI,cAAc,KAAK,CAAC;GAChC;EACF;AAEJ,eAAeA,iBACb,YACA,UACiB;CACjB,MAAM,UACJ,UAAU,MAAM,KAAK,MAAM,iBAAiB,WAAW,EAAE,OAAO;AAClE,KAAI,SAAS,MAAM,EAAE;EACnB,MAAM,iBAAiB,QAAQ,MAAM;EACrC,MAAM,eAAe,oBAAoB,eAAe;AACxD,MAAI,aAAc,OAAM,IAAI,MAAM,aAAa;AAC/C,SAAO;;AAGT,OAAM,IAAI,MACR,wFACD;;AAGH,SAAS,WAAW,OAA+C;AACjE,KAAI,CAAC,MAAO,QAAO,KAAA;CACnB,MAAM,SAAS,OAAO,MAAM;AAC5B,KAAI,OAAO,UAAU,OAAO,IAAI,SAAS,KAAK,UAAU,IAAK,QAAO;AACpE,OAAM,IAAI,MAAM,gDAAgD;;;;ACpBlE,eAAsB,qBACpB,SACA,cACqC;AACrC,KAAI,cAAc;AAChB,QAAM,aAAa,mBAAmB;GACpC,YAAY,QAAQ;GACpB,QAAQ,QAAQ;GACjB,CAAC;EAEF,MAAM,SAAS,QAAQ,WAAW;AAClC,MAAI,OACF,QAAO;GAAE;GAAQ,UAAU;GAAO,QAAQ,QAAQ;GAAQ;AAG5D,QAAM,aAAa,oBAAoB;GACrC,QAAQ,QAAQ;GAChB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GACjB,CAAC;AACF,SAAO;GAAE;GAAQ,UAAU;GAAM,QAAQ,QAAQ;GAAQ;;CAG3D,MAAM,UAAU,MAAM,sBACpB,QAAQ,YACR,QAAQ,QACT;AAED,OAAM,6BAA6B,QAAQ,YAAY,QAAQ;AAC/D,KAAI,QAAQ,kBAAkB,KAC5B,OAAM,4BAA4B;EAChC,YAAY,QAAQ;EACpB,YAAY;EACb,CAAC;CAGJ,MAAM,SAAS,QAAQ,WAAW;AAClC,OAAM,2BACJ,QAAQ,kBAEN,8BAA8B;EAC5B,YAAY,QAAQ;EACpB,QAAQ,QAAQ;EAChB,YAAY;EACZ,aAAa;GAAE,MAAM;GAAW,MAAM;GAAS;EAC/C;EACA,GAAI,SAAS,EAAE,GAAG,EAAE,QAAQ,wCAAwC,EAAE;EACvE,CAAC,EACJ,QACD;AAED,QAAO;EACL;EACA,UAAU,CAAC;EACX,QAAQ,QAAQ;EAChB;EACD;;AAUH,MAAa,iBAA0B,IAAI,QAAQ,UAAU,CAC1D,YAAY,iCAAiC,CAC7C,OACC,uBACA,oCACA,uBACD,CACA,OAAO,oBAAoB,4CAA4C,CACvE,OAAO,aAAa,uCAAuC,CAC3D,OAAO,oBAAoB,6CAA6C,CACxE,QAAQ,YAAmC;AAC1C,QAAO,aAAa,YAAY;EAC9B,MAAM,aAAa,QAAQ,KAAK;EAChC,MAAM,SAAS,QAAQ,UAAA;EACvB,MAAM,UAAU,MAAM,sBAAsB,YAAY,QAAQ,QAAQ;EACxE,MAAM,SAAS,QAAQ,WAAW;AAElC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,KAAK,uBAAuB,CAAC;AACpD,UAAQ,KAAK;AACb,0BAAwB;AACxB,UAAQ,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,MAAM,QAAQ,CAAC;AAC3D,UAAQ,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,KAAK,OAAO,CAAC;AACzD,MAAI,OACF,SAAQ,IAAI,MAAM,OAAO,sCAAsC,CAAC;AAElE,UAAQ,KAAK;EAEb,MAAM,kBAAkB,IAAI,+BAA+B,CAAC,OAAO;AACnE,QAAM,6BAA6B,YAAY,QAAQ;AACvD,kBAAgB,QAAQ,2BAA2B;AAEnD,MAAI,QAAQ,kBAAkB,MAAM;GAClC,MAAM,mBAAmB,IAAI,+BAA+B,CAAC,OAAO;AAKpE,QAJkB,MAAM,4BAA4B;IAClD;IACA,YAAY;IACb,CAAC,EACY,IACZ,kBAAiB,QAAQ,2BAA2B;OAEpD,kBAAiB,KAAK,sCAAsC;;EAIhE,MAAM,iBAAiB,IACrB,SACI,qDACA,8CACL,CAAC,OAAO;EAET,MAAM,SAAS,MAAM,2BACnB,kBAEE,8BAA8B;GAC5B;GACA;GACA,YAAY;GACZ,aAAa;IAAE,MAAM;IAAW,MAAM;IAAS;GAC/C;GACA,GAAI,SACA,EAAE,GACF,EAAE,QAAQ,wCAAwC,EAAE;GACzD,CAAC,EACJ,QACD;AAED,iBAAe,QACb,SAAS,oCAAoC,2BAC9C;AAED,MAAI,QAAQ;AACV,WAAQ,IACN,MAAM,OAAO,uDAAuD,CACrE;AACD,WAAQ,KAAK;AACb,6BAA0B,OAAO;;AAGnC,4BAA0B;GACxB,OAAO,SAAS,2BAA2B;GAC3C,YAAY,WAAW;GACvB;GACA;GACD,CAAC;GACF;EACF;AAEJ,eAAsB,sBACpB,YACA,UACiB;CACjB,MAAM,UACJ,UAAU,MAAM,KAAK,MAAM,iBAAiB,WAAW,EAAE,OAAO;AAClE,KAAI,SAAS,MAAM,EAAE;EACnB,MAAM,iBAAiB,QAAQ,MAAM;EACrC,MAAM,eAAe,oBAAoB,eAAe;AACxD,MAAI,aAAc,OAAM,IAAI,MAAM,aAAa;AAC/C,SAAO;;AAGT,OAAM,IAAI,MACR,wFACD;;;;ACnMH,SAAS,IAAI,OAA+B;AAC1C,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EAAG,QAAO,MAAM,MAAM;AAC7E,QAAO;;AAGT,eAAsB,iBACpB,QACsB;CACtB,MAAM,MAAM,MAAM,OAAO,IAAgB,UAAU;CACnD,MAAM,WAAW,CAAC,IAAI,IAAI,WAAW,EAAE,IAAI,IAAI,UAAU,CAAC,CACvD,QAAQ,SAAyB,SAAS,KAAK,CAC/C,KAAK,IAAI,CACT,MAAM;CACT,MAAM,UACJ,IAAI,IAAI,UAAU,KACjB,OAAO,IAAI,OAAO,YAAY,OAAO,SAAS,IAAI,GAAG,GAClD,OAAO,IAAI,GAAG,GACd;AACN,QAAO;EACL,MACE,IAAI,IAAI,UAAU,KACjB,SAAS,SAAS,IAAI,WAAW,SAClC,IAAI,IAAI,MAAM;EAChB,UAAU;EACX;;;;;;;;;;;;;;ACSH,eAAsB,kBACpB,SACkC;CAClC,MAAM,EAAE,KAAK,WAAW;CACxB,MAAM,SAAS,QAAQ,UAAU;AAIjC,KAAI,CAAE,MAAM,gBAAgB,IAAI,CAC9B,OAAM,QAAQ,KAAK,OAAO;CAS5B,MAAM,OAAO,MAAM,wBAAwB;EACzC;EACA,SAAS,QAAQ;EAClB,CAAC;CAQF,IAAI,SAAS;AAEb,KADqB,MAAM,sBAAsB,KAAK,KAAK,WAAW,OAAO,EAC3D;AAChB,QAAM,SAAS,KAAK,KAAK,WAAW,OAAO;AAC3C,MAAI,MAAM,WAAW,IAAI,EAAE;GACzB,MAAM,EAAE,OAAO,WAAW,MAAM,0BAA0B,IAAI;AAC9D,OAAI,SAAS,KAAK,QAAQ,EACxB,QAAO;IAAE,MAAM;IAAY;IAAO;IAAQ;AAE5C,OAAI,SAAS,GAAG;IACd,MAAM,WAAW,MAAM,sBAAsB,IAAI;AACjD,QAAI,SAAU,OAAM,SAAS,KAAK,oCAAoC;AACtE,QAAI;AACF,WAAM,oBAAoB,IAAI;cACtB;AACR,SAAI,SAAU,OAAM,YAAY,IAAI;;AAEtC,aAAS;;QASX,UAAS,MAAM,kBAAkB,IAAI;;CAKzC,IAAI,YAAY;AAChB,KAAI,QAAQ,WAAW,SAAU,MAAM,sBAAsB,IAAI,EAAG;AAElE,QAAM,cAAc,KADJ,MAAM,mBAAmB,QAAQ,QAAQ,QAAQ,EAC/B,MAAM,sBAAsB,OAAO,CAAC;AACtE,cAAY;;AAGd,OAAM,QAAQ,KAAK,KAAK,WAAW,OAAO;AAE1C,QAAO;EAAE,MAAM;EAAU;EAAQ;EAAW;;AAG9C,MAAM,yBAAyB;AAE/B,SAAS,YAAoB;AAC3B,yBAAO,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,IAAI;;;;;;;AAQhE,eAAe,mBACb,QACA,MACiB;CACjB,MAAM,cAAc,QAAQ,GAAG,uBAAuB,KAAK,WAAW;AACtE,KAAI;EACF,MAAM,KAAK,MAAM,YAAY,iBAAiB,OAAO,EAAE,IAAM;AAG7D,SAAO,GAFY,GAAG,OAAO,GAAG,GAAG,KAAK,MAAM,KAEvB,cADN,GAAG,WAAW,KAAK,GAAG,SAAS,KAAK;SAE/C;AACN,SAAO;;;;AAKX,eAAe,sBACb,QACwC;AACxC,KAAI;EACF,MAAM,KAAK,MAAM,YAAY,iBAAiB,OAAO,EAAE,IAAM;AAC7D,MAAI,GAAG,KACL,QAAO;GAAE,MAAM,GAAG;GAAM,OAAO;GAAiB;SAE5C;;AAMV,SAAS,YAAe,SAAqB,IAAwB;AACnE,QAAO,QAAQ,KAAK,CAClB,SACA,IAAI,SAAgB,GAAG,WACrB,iBAAiB,uBAAO,IAAI,MAAM,mBAAmB,GAAG,IAAI,CAAC,EAAE,GAAG,CACnE,CACF,CAAC;;;;ACrJJ,MAAa,cAAuB,IAAI,QAAQ,OAAO,CACpD,YACC,2EACD,CACA,OACC,uBACA,oCACA,uBACD,CACA,OAAO,oBAAoB,4CAA4C,CACvE,OAAO,mBAAmB,iCAAiC,CAC3D,OACC,2BACA,oEACD,CACA,OACC,eACA,yDACD,CACA,OACC,kBACA,qDACD,CACA,OAAO,aAAa,sDAAsD,CAC1E,OAAO,oBAAoB,6CAA6C,CACxE,QAAQ,YACP,aAAa,YAAY;CACvB,MAAM,aAAa,QAAQ,KAAK;CAChC,MAAM,SAAS,QAAQ,UAAA;CACvB,MAAM,UAAU,MAAM,sBAAsB,YAAY,QAAQ,QAAQ;CACxE,MAAM,SAAS,QAAQ,UAAU;AAEjC,SAAQ,KAAK;AACb,SAAQ,IAAI,MAAM,KAAK,KAAK,oBAAoB,CAAC;AACjD,SAAQ,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,MAAM,QAAQ,CAAC;AAC3D,SAAQ,KAAK;CASb,MAAM,SAAS,wCAAwC;CACvD,MAAM,cAAc,IAAI,6BAA6B,CAAC,OAAO;AAC7D,KAAI;EACF,MAAM,SAAS,MAAM,kBAAkB;GACrC,KAAK;GACL;GACA;GACA;GACA,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;GACvD,GAAI,QAAQ,WAAW,QAAQ,EAAE,QAAQ,OAAO,GAAG,EAAE;GACtD,CAAC;AACF,MAAI,OAAO,SAAS,YAAY;AAC9B,eAAY,KACV,iCAAiC,OAAO,kBAClC,OAAO,MAAM,UAAU,OAAO,OAAO,WAC5C;AACD,SAAM,IAAI,MACR,6HAED;;EAEH,MAAM,QAAkB,EAAE;AAC1B,MAAI,OAAO,SAAS,EAClB,OAAM,KACJ,UAAU,OAAO,OAAO,SAAS,OAAO,WAAW,IAAI,KAAK,MAC7D;AAEH,QAAM,KAAK,OAAO,YAAY,uBAAuB,SAAS;AAC9D,cAAY,QAAQ,6BAA6B,MAAM,KAAK,KAAK,CAAC,GAAG;UAC9D,KAAK;AACZ,MAAI,qBAAqB,IAAI,CAC3B,aAAY,KACV,mEACD;WACQ,eAAe,YAAY,IAAI,aAAa,KAAK;AAC1D,eAAY,KAAK,IAAI,QAAQ;AAC7B,WAAQ,IACN,MAAM,OACJ,kEACD,CACF;SACI;AAGL,OAAI,YAAY,WAAY,aAAY,KAAK,kBAAkB;AAC/D,SAAM;;;AAIV,KAAI,QAAQ,gBAAgB,MAAM;AAChC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,4CAA4C,CAAC;AACnE;;CAIF,MAAM,SAAS,QAAQ,WAAW;CAClC,MAAM,iBAAiB,IACrB,SACI,mDACA,4CACL,CAAC,OAAO;AACT,KAAI;AACF,QAAM,qBAAqB;GACzB;GACA;GACA;GACA;GACA,eAAe,QAAQ,kBAAkB;GAC1C,CAAC;AACF,iBAAe,QACb,SACI,oCACA,2BACL;UACM,KAAK;AACZ,iBAAe,KAAK,iBAAiB;AACrC,QAAM;;AAGR,SAAQ,KAAK;AACb,SAAQ,IAAI,MAAM,MAAM,KAAK,QAAQ,CAAC;EACtC,CACH;;;ACxIH,MAAa,gBAAyB,IAAI,QAAQ,SAAS,CACxD,YAAY,qDAAqD,CACjE,OAAO,oBAAoB,4CAA4C,CACvE,OAAO,UAAU,oCAAoC,CACrD,QAAQ,YAAkC;AACzC,QAAO,aAAa,YAAY;EAC9B,MAAM,UAAU,MAAM,eAAe,QAAQ,KAAK,EAAE,QAAQ,QAAQ;EACpE,MAAM,WAAW,MAAM,yBAAyB;GAC9C,QAAQ,wCAAwC;GAChD;GACD,CAAC;AAEF,MAAI,QAAQ,SAAS,MAAM;AACzB,WAAQ,IACN,KAAK,UACH,SAAS,KAAK,YAAY,QAAQ,IAAI,EACtC,MACA,EACD,CACF;AACD;;AAGF,UAAQ,IAAI,MAAM,KAAK,KAAK,6BAA6B,UAAU,CAAC;AACpE,UAAQ,KAAK;AACb,UAAQ,IAAI,iBAAiB,SAAS,CAAC;GACvC;EACF;AAEJ,eAAe,eACb,YACA,UACiB;CACjB,MAAM,UACJ,UAAU,MAAM,KAAK,MAAM,iBAAiB,WAAW,EAAE,OAAO;AAClE,KAAI,SAAS,MAAM,EAAE;EACnB,MAAM,iBAAiB,QAAQ,MAAM;EACrC,MAAM,eAAe,oBAAoB,eAAe;AACxD,MAAI,aAAc,OAAM,IAAI,MAAM,aAAa;AAC/C,SAAO;;AAGT,OAAM,IAAI,MACR,wFACD;;;;AC/CH,MAAa,kBAA2B,IAAI,QAAQ,WAAW,CAC5D,YAAY,8CAA8C,CAC1D,OAAO,UAAU,2CAA2C,CAC5D,QAAQ,YAAmC;AAC1C,QAAO,aAAa,YAAY;EAC9B,MAAM,SAAS,MAAM,6BAA6B,QAAQ,KAAK,CAAC;AAEhE,MAAI,QAAQ,SAAS,MAAM;AACzB,WAAQ,IACN,KAAK,UACH;IACE,OAAO;IACP,QAAQ,OAAO;IACf,WAAW,OAAO,UAAU;IAC5B,SAAS,OAAO,UAAU;IAC1B,SAAS,OAAO,UAAU,QAAQ,KAAK,YAAY;KACjD,MAAM,OAAO;KACb,MAAM,OAAO;KACd,EAAE;IACJ,EACD,MACA,EACD,CACF;AACD;;AAGF,UAAQ,IAAI,MAAM,MAAM,wBAAwB,OAAO,CAAC,CAAC;GACzD;EACF;;;AC5BJ,MAAa,gBAAyB,IAAI,QAAQ,SAAS,CACxD,YACC,4FACD,CACA,WAAW,cAAc,CACzB,WAAW,aAAa,CACxB,WAAW,WAAW,CACtB,WAAW,YAAY,CACvB,WAAW,gBAAgB,CAC3B,WAAW,aAAa,CACxB,WAAW,eAAe,CAC1B,WAAW,YAAY,CACvB,WAAW,cAAc,CACzB,WAAW,YAAY;AAE1B,MAAM,SAAsB;CAC1B,MAAM;CACN,SAAS;CACT,SAAS,KAAoB;EAC3B,MAAM,wBAAwB,YAAY,IAAI,SAAS,SAAS;AAChE,MAAI,uBAAuB;AACzB,uBAAoB,uBAAuB,cAAc;AACzD,uBAAoB,uBAAuB,aAAa;AACxD,uBAAoB,uBAAuB,WAAW;AACtD,uBAAoB,uBAAuB,YAAY;AACvD,uBAAoB,uBAAuB,gBAAgB;AAC3D,uBAAoB,uBAAuB,aAAa;AACxD,uBAAoB,uBAAuB,eAAe;AAC1D,uBAAoB,uBAAuB,YAAY;AACvD,uBAAoB,uBAAuB,cAAc;AACzD,uBAAoB,uBAAuB,YAAY;AACvD;;AAGF,MAAI,QAAQ,WAAW,cAAc;;CAExC;AAyED,SAAS,oBAAoB,QAAiB,OAAsB;AAClE,KAAI,YAAY,QAAQ,MAAM,MAAM,CAAC,CAAE;AACvC,QAAO,WAAW,MAAM;;AAG1B,SAAS,YAAY,QAAiB,MAAmC;AACvE,QAAO,OAAO,UAAU,MAAM,YAAY,QAAQ,MAAM,KAAK,KAAK"}
1
+ {"version":3,"file":"index.mjs","names":["isNodeError","isRecord","isRecord","readPackageJson","isRecord","isRecord","isRecord","resolveDroplet"],"sources":["../src/utils/config.ts","../src/utils/validation.ts","../src/utils/source-package.ts","../src/utils/command.ts","../src/utils/package-manager.ts","../src/utils/package-scripts.ts","../src/commands/build.ts","../src/lib/git.ts","../src/utils/git-credential.ts","../src/utils/widget-marker.ts","../src/commands/clone.ts","../src/utils/template.ts","../src/utils/github-template.ts","../src/commands/create.ts","../src/commands/dev.ts","../src/utils/auth-client.ts","../src/utils/droplets.ts","../src/commands/link.ts","../src/utils/droplet-api.ts","../src/commands/logs.ts","../src/commands/publish.ts","../src/utils/me.ts","../src/lib/git-sync.ts","../src/commands/push.ts","../src/commands/status.ts","../src/commands/validate.ts","../src/index.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport const WIDGET_CONFIG_FILE = \"fluid.widget.config.ts\";\n\nexport interface FluidWidgetConfig {\n readonly droplet?: string;\n}\n\nexport interface LoadedWidgetConfig {\n readonly path: string;\n readonly config: Partial<FluidWidgetConfig>;\n}\n\nexport class WidgetConfigParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WidgetConfigParseError\";\n }\n}\n\nexport function resolveWidgetConfigPath(projectDir: string): string {\n return path.join(projectDir, WIDGET_CONFIG_FILE);\n}\n\nexport async function loadWidgetConfig(\n projectDir: string,\n): Promise<LoadedWidgetConfig> {\n const configPath = resolveWidgetConfigPath(projectDir);\n\n let source: string;\n try {\n source = await readFile(configPath, \"utf-8\");\n } catch (err) {\n if (isNodeError(err) && err.code === \"ENOENT\") {\n return { path: configPath, config: {} };\n }\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Unable to read ${WIDGET_CONFIG_FILE}: ${message}`);\n }\n\n return { path: configPath, config: parseWidgetConfigSource(source) };\n}\n\nexport async function writeWidgetConfig(\n projectDir: string,\n config: FluidWidgetConfig,\n): Promise<void> {\n await writeFile(\n resolveWidgetConfigPath(projectDir),\n formatWidgetConfig(config),\n \"utf-8\",\n );\n}\n\nexport function formatWidgetConfig(config: FluidWidgetConfig): string {\n const lines = [\n 'import type { FluidWidgetConfig } from \"@fluid-app/fluid-cli-widget\";',\n 'import { widgetPackage as sourceWidgetPackage } from \"./manifest\";',\n \"\",\n \"const config = {\",\n ];\n\n if (config.droplet) {\n lines.push(` droplet: ${JSON.stringify(config.droplet)},`);\n }\n\n lines.push(\n \"} satisfies FluidWidgetConfig;\",\n \"\",\n \"const widgetConfig: FluidWidgetConfig = config;\",\n \"const packageStableId = widgetConfig.droplet;\",\n \"\",\n \"export const widgetPackage = packageStableId\",\n \" ? {\",\n \" ...sourceWidgetPackage,\",\n \" packageStableId,\",\n \" packageId: `${sourceWidgetPackage.scope}.${packageStableId}` as const,\",\n \" }\",\n \" : sourceWidgetPackage;\",\n \"export const widgetPackages = [widgetPackage] as const;\",\n \"\",\n \"export default config;\",\n \"export const droplet = widgetConfig.droplet;\",\n \"\",\n );\n return lines.join(\"\\n\");\n}\n\nexport function parseWidgetConfigSource(\n source: string,\n): Partial<FluidWidgetConfig> {\n const objectSource = extractConfigObjectLiteral(source);\n const config = parseConfigObjectProperties(objectSource);\n\n return config;\n}\n\nexport function mergeWidgetConfig(\n current: Partial<FluidWidgetConfig>,\n updates: Partial<FluidWidgetConfig>,\n): FluidWidgetConfig {\n const droplet =\n normalizeOptionalString(updates.droplet) ??\n normalizeOptionalString(current.droplet);\n\n return droplet ? { droplet } : {};\n}\n\nexport function validateDropletUuid(dropletUuid: string): string | undefined {\n if (!dropletUuid) return \"Droplet UUID is required.\";\n if (dropletUuid.length > MAX_DROPLET_UUID_LENGTH) {\n return `Droplet UUID must be ${MAX_DROPLET_UUID_LENGTH} characters or fewer.`;\n }\n if (!URL_SAFE_IDENTIFIER_PATTERN.test(dropletUuid)) {\n return (\n \"Droplet UUID must be URL-safe text: letters, numbers, \" +\n \"'_', '~', and '-' only.\"\n );\n }\n return undefined;\n}\n\nfunction extractConfigObjectLiteral(source: string): string {\n const configStart = /\\bconst\\s+config\\s*=\\s*\\{/.exec(source);\n if (!configStart) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} must declare \\`const config = { ... } satisfies FluidWidgetConfig\\`.`,\n );\n }\n\n const openBraceIndex = source.indexOf(\"{\", configStart.index);\n const closeBraceIndex = findMatchingBrace(source, openBraceIndex);\n const suffix = stripComments(source.slice(closeBraceIndex + 1));\n if (!/^\\s*(?:as\\s+const\\s+)?satisfies\\s+FluidWidgetConfig\\s*;/.test(suffix)) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} config object must use \\`satisfies FluidWidgetConfig\\` or \\`as const satisfies FluidWidgetConfig\\`.`,\n );\n }\n\n return stripComments(source.slice(openBraceIndex + 1, closeBraceIndex));\n}\n\nfunction parseConfigObjectProperties(\n objectSource: string,\n): Partial<FluidWidgetConfig> {\n const config: { droplet?: string } = {};\n\n for (const member of splitTopLevelMembers(objectSource)) {\n const trimmedMember = member.trim();\n if (!trimmedMember) continue;\n\n const propertyMatch = /^(droplet)\\s*:\\s*([\\s\\S]+)$/.exec(trimmedMember);\n if (!propertyMatch) {\n const propertyName = /^([A-Za-z_$][\\w$]*)\\s*:/.exec(trimmedMember)?.[1];\n throw new WidgetConfigParseError(\n propertyName\n ? `${WIDGET_CONFIG_FILE} does not support config field ${propertyName}. Supported field is droplet.`\n : `${WIDGET_CONFIG_FILE} config fields must use optional droplet: \"...\" string literal.`,\n );\n }\n\n const propertyName = propertyMatch[1];\n if (propertyName !== \"droplet\") {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} config field could not be parsed.`,\n );\n }\n const valueSource = propertyMatch[2]?.trim() ?? \"\";\n const value = parseStringLiteralValue(valueSource, propertyName);\n if (!value.trim()) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} field ${propertyName} must be a non-empty string literal.`,\n );\n }\n\n if (config.droplet !== undefined) {\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} field droplet must only be declared once.`,\n );\n }\n config.droplet = value;\n }\n\n return config;\n}\n\nfunction parseStringLiteralValue(\n valueSource: string,\n propertyName: string,\n): string {\n if (valueSource.startsWith('\"') && valueSource.endsWith('\"')) {\n try {\n const parsed = JSON.parse(valueSource) as unknown;\n if (typeof parsed === \"string\") return parsed;\n } catch {\n // Fall through to the actionable error below.\n }\n }\n\n if (valueSource.startsWith(\"'\") && valueSource.endsWith(\"'\")) {\n return parseSingleQuotedStringLiteral(valueSource);\n }\n\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} field ${propertyName} must be a string literal (for example ${propertyName}: \"value\").`,\n );\n}\n\nfunction parseSingleQuotedStringLiteral(valueSource: string): string {\n let value = \"\";\n\n for (let index = 1; index < valueSource.length - 1; index += 1) {\n const char = valueSource[index];\n if (char !== \"\\\\\") {\n value += char;\n continue;\n }\n\n index += 1;\n const escaped = valueSource[index];\n switch (escaped) {\n case \"\\\\\":\n case \"'\":\n case '\"':\n value += escaped;\n break;\n case \"n\":\n value += \"\\n\";\n break;\n case \"r\":\n value += \"\\r\";\n break;\n case \"t\":\n value += \"\\t\";\n break;\n case \"b\":\n value += \"\\b\";\n break;\n case \"f\":\n value += \"\\f\";\n break;\n case \"v\":\n value += \"\\v\";\n break;\n default:\n value += escaped ?? \"\";\n break;\n }\n }\n\n return value;\n}\n\nfunction stripComments(source: string): string {\n let result = \"\";\n let stringQuote: '\"' | \"'\" | \"`\" | undefined;\n let escaped = false;\n let lineComment = false;\n let blockComment = false;\n\n for (let index = 0; index < source.length; index += 1) {\n const char = source[index];\n const nextChar = source[index + 1];\n\n if (lineComment) {\n if (char === \"\\n\" || char === \"\\r\") {\n lineComment = false;\n result += char;\n } else {\n result += \" \";\n }\n continue;\n }\n\n if (blockComment) {\n if (char === \"*\" && nextChar === \"/\") {\n blockComment = false;\n result += \" \";\n index += 1;\n } else if (char === \"\\n\" || char === \"\\r\") {\n result += char;\n } else {\n result += \" \";\n }\n continue;\n }\n\n if (stringQuote) {\n result += char;\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === stringQuote) {\n stringQuote = undefined;\n }\n continue;\n }\n\n if (char === \"/\" && nextChar === \"/\") {\n lineComment = true;\n result += \" \";\n index += 1;\n continue;\n }\n\n if (char === \"/\" && nextChar === \"*\") {\n blockComment = true;\n result += \" \";\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n stringQuote = char;\n }\n result += char;\n }\n\n return result;\n}\n\nfunction splitTopLevelMembers(objectSource: string): string[] {\n const members: string[] = [];\n let memberStart = 0;\n let stringQuote: '\"' | \"'\" | \"`\" | undefined;\n let escaped = false;\n let nestedDepth = 0;\n\n for (let index = 0; index < objectSource.length; index += 1) {\n const char = objectSource[index];\n\n if (stringQuote) {\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === stringQuote) {\n stringQuote = undefined;\n }\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n stringQuote = char;\n continue;\n }\n\n if (char === \"{\" || char === \"[\" || char === \"(\") {\n nestedDepth += 1;\n continue;\n }\n if (char === \"}\" || char === \"]\" || char === \")\") {\n nestedDepth -= 1;\n continue;\n }\n\n if (char === \",\" && nestedDepth === 0) {\n members.push(objectSource.slice(memberStart, index));\n memberStart = index + 1;\n }\n }\n\n members.push(objectSource.slice(memberStart));\n return members;\n}\n\nfunction findMatchingBrace(source: string, openBraceIndex: number): number {\n let depth = 0;\n let stringQuote: '\"' | \"'\" | \"`\" | undefined;\n let escaped = false;\n let lineComment = false;\n let blockComment = false;\n\n for (let index = openBraceIndex; index < source.length; index += 1) {\n const char = source[index];\n const nextChar = source[index + 1];\n\n if (lineComment) {\n if (char === \"\\n\" || char === \"\\r\") lineComment = false;\n continue;\n }\n\n if (blockComment) {\n if (char === \"*\" && nextChar === \"/\") {\n blockComment = false;\n index += 1;\n }\n continue;\n }\n\n if (stringQuote) {\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === stringQuote) {\n stringQuote = undefined;\n }\n continue;\n }\n\n if (char === \"/\" && nextChar === \"/\") {\n lineComment = true;\n index += 1;\n continue;\n }\n\n if (char === \"/\" && nextChar === \"*\") {\n blockComment = true;\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n stringQuote = char;\n continue;\n }\n\n if (char === \"{\") depth += 1;\n if (char === \"}\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n\n throw new WidgetConfigParseError(\n `${WIDGET_CONFIG_FILE} config object is missing a closing brace.`,\n );\n}\n\nfunction normalizeOptionalString(\n value: string | undefined,\n): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\ninterface NodeError extends Error {\n readonly code?: string;\n}\n\nfunction isNodeError(error: unknown): error is NodeError {\n return error instanceof Error && \"code\" in error;\n}\n\nconst MAX_DROPLET_UUID_LENGTH = 256;\nconst URL_SAFE_SEGMENT_SOURCE = \"[A-Za-z0-9][A-Za-z0-9_~-]*\";\nconst URL_SAFE_IDENTIFIER_PATTERN = new RegExp(`^${URL_SAFE_SEGMENT_SOURCE}$`);\n","export interface WidgetCliValidationError {\n readonly path?: string;\n readonly message: string;\n}\n\nexport function formatValidationErrors(\n errors: readonly WidgetCliValidationError[],\n): string {\n if (errors.length === 0) return \"Validation failed.\";\n\n return [\n \"Validation failed:\",\n ...errors.map((error) => {\n const location = error.path ? `${error.path}: ` : \"\";\n return ` - ${location}${error.message}`;\n }),\n ].join(\"\\n\");\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, rm, rmdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n loadSourceWidgetPackages,\n validateSingleSourceWidgetPackage,\n} from \"@fluid-app/fluid-cli-portal\";\nimport {\n WIDGET_CONFIG_FILE,\n loadWidgetConfig,\n validateDropletUuid,\n} from \"./config.js\";\nimport type {\n ValidatedWidgetPackageBuild,\n WidgetPackageValidationError,\n} from \"@fluid-app/fluid-cli-portal\";\nimport { formatValidationErrors } from \"./validation.js\";\n\nexport const DEFAULT_WIDGET_OUT_DIR = \".fluid/widget-dist\";\nexport const ROOT_WIDGET_CONFIG_FILE: string = WIDGET_CONFIG_FILE;\n\nconst SOURCE_CONFIG_CANDIDATES = [\n \"src/widgets.config.ts\",\n \"src/portal.config.ts\",\n \"portal.config.ts\",\n] as const;\n\nexport interface WidgetValidationResult {\n readonly projectDir: string;\n readonly sourceConfigPath?: string;\n readonly validated: ValidatedWidgetPackageBuild;\n}\n\nexport class WidgetValidationError extends Error {\n public readonly errors: readonly WidgetPackageValidationError[];\n\n constructor(errors: readonly WidgetPackageValidationError[]) {\n super(formatValidationErrors(errors));\n this.name = \"WidgetValidationError\";\n this.errors = errors;\n }\n}\n\nexport async function validateDropletWidgetProject(\n projectDir: string,\n packageKeyOverride?: string,\n): Promise<WidgetValidationResult> {\n const resolvedProjectDir = path.resolve(projectDir);\n const sourceConfig = resolveWidgetSourceConfig(resolvedProjectDir);\n if (!sourceConfig) {\n throw new WidgetValidationError([\n {\n code: \"NO_SOURCE_PACKAGE\",\n path: ROOT_WIDGET_CONFIG_FILE,\n message:\n `No widget package config found. Create ${ROOT_WIDGET_CONFIG_FILE} ` +\n \"or src/widgets.config.ts that exports defineWidgetPackage(...).\",\n },\n ]);\n }\n\n const configErrors = await validateRootWidgetConfig(\n resolvedProjectDir,\n packageKeyOverride,\n );\n if (configErrors.length > 0) {\n throw new WidgetValidationError(configErrors);\n }\n\n const sourcePackages = await withRootWidgetConfigBridge(\n resolvedProjectDir,\n async () => {\n const loadResult = await loadSourceWidgetPackages(resolvedProjectDir);\n if (!loadResult.success) {\n throw new WidgetValidationError([\n {\n code: \"INVALID_SOURCE_PACKAGE\",\n path: sourceConfig.relativePath,\n message: appendDetails(\n loadResult.error.message,\n loadResult.error.details,\n ),\n },\n ]);\n }\n return loadResult.value;\n },\n packageKeyOverride,\n );\n\n const validation = validateSingleSourceWidgetPackage(sourcePackages, {\n owner: \"droplet\",\n });\n const errors = [\n ...validation.errors,\n ...validateDropletMetadata(sourcePackages),\n ];\n\n if (!validation.success || !validation.value || errors.length > 0) {\n throw new WidgetValidationError(errors);\n }\n\n return {\n projectDir: resolvedProjectDir,\n sourceConfigPath: sourceConfig.relativePath,\n validated: validation.value,\n };\n}\n\nexport async function withRootWidgetConfigBridge<T>(\n projectDir: string,\n callback: () => Promise<T>,\n packageKeyOverride?: string,\n): Promise<T> {\n const rootConfigPath = path.join(projectDir, ROOT_WIDGET_CONFIG_FILE);\n if (!existsSync(rootConfigPath) || resolvePortalSourceConfig(projectDir)) {\n return callback();\n }\n\n const packageKey =\n packageKeyOverride?.trim() ||\n (await loadWidgetConfig(projectDir)).config.droplet;\n if (!packageKey) {\n throw new Error(\n \"fluid.widget.config.ts must set droplet before validating, building, or publishing.\",\n );\n }\n\n const srcDir = path.join(projectDir, \"src\");\n const bridgePath = path.join(srcDir, \"widgets.config.ts\");\n const srcDirExisted = existsSync(srcDir);\n await mkdir(srcDir, { recursive: true });\n try {\n await writeFile(\n bridgePath,\n createRootWidgetConfigBridgeSource(packageKey),\n {\n encoding: \"utf-8\",\n flag: \"wx\",\n },\n );\n } catch (err) {\n if (isNodeError(err) && err.code === \"EEXIST\") {\n throw new Error(\n `${path.relative(projectDir, bridgePath)} already exists. ` +\n \"Remove this stale Fluid widget CLI bridge file and try again.\",\n );\n }\n throw err;\n }\n\n try {\n return await callback();\n } finally {\n await rm(bridgePath, { force: true }).catch(() => {});\n if (!srcDirExisted) await rmdir(srcDir).catch(() => {});\n }\n}\n\nfunction createRootWidgetConfigBridgeSource(packageKey: string): string {\n return `import { widgetPackage as sourceWidgetPackage } from \"../manifest\";\n\nconst packageKey = ${JSON.stringify(packageKey)};\nconst packageId = sourceWidgetPackage.scope + \".\" + packageKey;\n\nexport const widgetPackage = {\n ...sourceWidgetPackage,\n packageStableId: packageKey,\n packageId,\n};\n\nexport const widgetPackages = [widgetPackage] as const;\nexport default widgetPackage;\n`;\n}\n\nexport function resolveWidgetSourceConfig(\n projectDir: string,\n): { readonly path: string; readonly relativePath: string } | undefined {\n const rootConfig = path.join(projectDir, ROOT_WIDGET_CONFIG_FILE);\n if (existsSync(rootConfig)) {\n return { path: rootConfig, relativePath: ROOT_WIDGET_CONFIG_FILE };\n }\n\n return resolvePortalSourceConfig(projectDir);\n}\n\nexport function formatValidationSuccess(\n result: WidgetValidationResult,\n): string {\n return [\n \"Widget package is valid.\",\n `Config: ${result.sourceConfigPath ?? \"unknown\"}`,\n `Package: ${result.validated.packageId}`,\n `Version: ${result.validated.version}`,\n `Widgets: ${result.validated.widgets.length}`,\n ].join(\"\\n\");\n}\n\nasync function validateRootWidgetConfig(\n projectDir: string,\n packageKeyOverride?: string,\n): Promise<WidgetPackageValidationError[]> {\n const configPath = path.join(projectDir, ROOT_WIDGET_CONFIG_FILE);\n if (!existsSync(configPath)) return [];\n\n try {\n const loaded = await loadWidgetConfig(projectDir);\n const droplet = packageKeyOverride ?? loaded.config.droplet ?? \"\";\n const packageKeyError = validateDropletUuid(droplet);\n if (!packageKeyError) return [];\n\n return [\n {\n code: \"INVALID_PACKAGE_KEY\",\n path: ROOT_WIDGET_CONFIG_FILE,\n message: packageKeyError,\n },\n ];\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return [\n {\n code: \"INVALID_SOURCE_PACKAGE\",\n path: ROOT_WIDGET_CONFIG_FILE,\n message,\n },\n ];\n }\n}\n\nfunction validateDropletMetadata(\n sourcePackages: readonly unknown[],\n): WidgetPackageValidationError[] {\n if (sourcePackages.length !== 1) return [];\n\n const sourcePackage = sourcePackages[0];\n if (!isRecord(sourcePackage)) return [];\n\n const errors: WidgetPackageValidationError[] = [];\n if (sourcePackage[\"packageType\"] !== \"droplet\") {\n errors.push({\n code: \"UNSUPPORTED_OWNER\",\n path: \"packageType\",\n message:\n 'Droplet widget packages must set packageType: \"droplet\" in package metadata.',\n });\n }\n\n if (!isNonEmptyString(sourcePackage[\"packageStableId\"])) {\n errors.push({\n code: \"INVALID_PACKAGE_KEY\",\n path: \"packageStableId\",\n message:\n \"Droplet widget packages must set packageStableId so published widget types remain stable across builds.\",\n });\n }\n\n const widgets = sourcePackage[\"widgets\"];\n if (Array.isArray(widgets)) {\n widgets.forEach((widget, index) => {\n if (!isRecord(widget)) return;\n validateJsonSerializable(\n widget[\"propertySchema\"],\n `widgets[${index}].propertySchema`,\n errors,\n );\n validateJsonSerializable(\n widget[\"defaultProps\"],\n `widgets[${index}].defaultProps`,\n errors,\n );\n });\n }\n\n return errors;\n}\n\nfunction resolvePortalSourceConfig(\n projectDir: string,\n): { readonly path: string; readonly relativePath: string } | undefined {\n for (const relativePath of SOURCE_CONFIG_CANDIDATES) {\n const candidate = path.join(projectDir, relativePath);\n if (existsSync(candidate)) return { path: candidate, relativePath };\n }\n\n return undefined;\n}\n\nfunction validateJsonSerializable(\n value: unknown,\n pathLabel: string,\n errors: WidgetPackageValidationError[],\n): void {\n if (value === undefined) return;\n\n try {\n assertJsonSerializable(value, pathLabel);\n } catch (err) {\n errors.push({\n code: \"INVALID_WIDGET_METADATA\",\n path: pathLabel,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n}\n\nfunction assertJsonSerializable(value: unknown, pathLabel: string): void {\n if (value === null) return;\n\n const valueType = typeof value;\n if (valueType === \"string\" || valueType === \"boolean\") return;\n if (valueType === \"number\") {\n if (Number.isFinite(value)) return;\n throw new Error(`${pathLabel} must not contain NaN or Infinity.`);\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n assertJsonSerializable(item, `${pathLabel}[${index}]`);\n });\n return;\n }\n if (isRecord(value)) {\n for (const [key, item] of Object.entries(value)) {\n if (item === undefined) {\n throw new Error(`${pathLabel}.${key} must not be undefined.`);\n }\n assertJsonSerializable(item, `${pathLabel}.${key}`);\n }\n return;\n }\n\n throw new Error(`${pathLabel} must contain only JSON-serializable values.`);\n}\n\nfunction appendDetails(message: string, details: string | undefined): string {\n return details ? `${message}\\n${details}` : message;\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\ninterface NodeError extends Error {\n readonly code?: string;\n}\n\nfunction isNodeError(error: unknown): error is NodeError {\n return error instanceof Error && \"code\" in error;\n}\n","import chalk from \"chalk\";\n\nexport async function runCliAction(action: () => Promise<void>): Promise<void> {\n try {\n await action();\n } catch (err) {\n console.error(chalk.red(\"Error:\") + \" \" + formatUnknownError(err));\n process.exit(1);\n }\n}\n\nexport function formatUnknownError(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport function getRunCommand(\n script: string,\n cwd: string = process.cwd(),\n): string {\n return `${detectPackageManager(cwd)} run ${script}`;\n}\n\nexport function getInstallCommand(cwd: string = process.cwd()): string {\n return `${detectPackageManager(cwd)} install`;\n}\n\nexport async function installDependencies(cwd: string): Promise<void> {\n const packageManager = detectPackageManager(cwd);\n await runPackageManager(packageManager, [\"install\"], cwd);\n}\n\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(path.join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(path.join(cwd, \"yarn.lock\"))) return \"yarn\";\n if (existsSync(path.join(cwd, \"bun.lockb\"))) return \"bun\";\n if (existsSync(path.join(cwd, \"package-lock.json\"))) return \"npm\";\n\n const invokingPackageManager = readInvokingPackageManager();\n if (invokingPackageManager) return invokingPackageManager;\n\n const declaredPackageManager = readDeclaredPackageManager(cwd);\n if (declaredPackageManager && isCommandAvailable(declaredPackageManager)) {\n return declaredPackageManager;\n }\n\n return findAvailablePackageManager() ?? \"pnpm\";\n}\n\nfunction runPackageManager(\n command: PackageManager,\n args: readonly string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, [...args], {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n child.once(\"error\", (error: Error) => {\n reject(error);\n });\n\n child.once(\"exit\", (code: number | null) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(\n new Error(\n `${command} ${args.join(\" \")} exited with code ${code ?? \"unknown\"}`,\n ),\n );\n });\n });\n}\n\nfunction readInvokingPackageManager(): PackageManager | undefined {\n const userAgent = process.env[\"npm_config_user_agent\"];\n if (!userAgent) return undefined;\n\n const name = userAgent.split(\"/\")[0];\n if (isPackageManager(name)) return name;\n return undefined;\n}\n\nfunction readDeclaredPackageManager(cwd: string): PackageManager | undefined {\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) return undefined;\n\n try {\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf-8\"),\n ) as unknown;\n if (!isRecord(packageJson)) return undefined;\n\n const packageManager = packageJson[\"packageManager\"];\n if (typeof packageManager !== \"string\") return undefined;\n\n const name = packageManager.split(\"@\")[0];\n if (isPackageManager(name)) return name;\n } catch {\n // Malformed package.json is reported by command paths that need to parse it.\n }\n\n return undefined;\n}\n\nfunction findAvailablePackageManager(): PackageManager | undefined {\n for (const packageManager of [\"pnpm\", \"yarn\", \"bun\", \"npm\"] as const) {\n if (isCommandAvailable(packageManager)) return packageManager;\n }\n return undefined;\n}\n\nfunction isCommandAvailable(command: PackageManager): boolean {\n const result = spawnSync(command, [\"--version\"], {\n shell: process.platform === \"win32\",\n stdio: \"ignore\",\n });\n return result.status === 0;\n}\n\nfunction isPackageManager(value: string | undefined): value is PackageManager {\n return (\n value === \"pnpm\" || value === \"yarn\" || value === \"bun\" || value === \"npm\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { detectPackageManager } from \"./package-manager.js\";\n\nexport interface PackageScriptRunResult {\n readonly ran: boolean;\n readonly command?: string;\n}\n\nexport async function runPackageScriptIfAvailable(options: {\n readonly projectDir: string;\n readonly scriptName: string;\n}): Promise<PackageScriptRunResult> {\n const packageJsonPath = path.join(options.projectDir, \"package.json\");\n if (!existsSync(packageJsonPath)) return { ran: false };\n\n const packageJson = await readPackageJson(packageJsonPath);\n if (!hasPackageScript(packageJson, options.scriptName)) return { ran: false };\n\n const packageManager = detectPackageManager(options.projectDir);\n const args = [\"run\", options.scriptName];\n await runCommand(packageManager, args, options.projectDir);\n\n return {\n ran: true,\n command: `${packageManager} ${args.join(\" \")}`,\n };\n}\n\nfunction runCommand(\n command: string,\n args: readonly string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n stdio: \"inherit\",\n env: process.env,\n shell: process.platform === \"win32\",\n });\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(\n new Error(\n signal\n ? `${command} ${args.join(\" \")} exited with signal ${signal}.`\n : `${command} ${args.join(\" \")} exited with code ${code ?? \"unknown\"}.`,\n ),\n );\n });\n });\n}\n\nasync function readPackageJson(packageJsonPath: string): Promise<unknown> {\n const source = await readFile(packageJsonPath, \"utf-8\");\n try {\n return JSON.parse(source) as unknown;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Unable to parse package.json: ${message}`);\n }\n}\n\nfunction hasPackageScript(value: unknown, scriptName: string): boolean {\n if (!isRecord(value)) return false;\n const scripts = value[\"scripts\"];\n if (!isRecord(scripts)) return false;\n return typeof scripts[scriptName] === \"string\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { Command } from \"commander\";\nimport {\n buildSharedWidgetPackage,\n validateWidgetPublishOutDir,\n} from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n DEFAULT_WIDGET_OUT_DIR,\n validateDropletWidgetProject,\n withRootWidgetConfigBridge,\n} from \"../utils/source-package.js\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { runPackageScriptIfAvailable } from \"../utils/package-scripts.js\";\n\nexport interface BuildWidgetOptions {\n readonly outDir?: string;\n readonly skipTypecheck?: boolean;\n}\n\nexport interface BuildWidgetPackageOptions {\n readonly projectDir: string;\n readonly outDir: string;\n readonly skipTypecheck?: boolean;\n}\n\nexport interface BuildWidgetPackageResult {\n readonly outDir: string;\n readonly packageId: string;\n readonly version: string;\n}\n\nexport async function buildWidgetPackage(\n options: BuildWidgetPackageOptions,\n): Promise<BuildWidgetPackageResult> {\n await validateDropletWidgetProject(options.projectDir);\n\n if (options.skipTypecheck !== true) {\n await runPackageScriptIfAvailable({\n projectDir: options.projectDir,\n scriptName: \"typecheck\",\n });\n }\n\n const outDir = validateWidgetPublishOutDir(\n options.projectDir,\n options.outDir,\n );\n const buildResult = await withRootWidgetConfigBridge(options.projectDir, () =>\n buildSharedWidgetPackage({\n projectDir: options.projectDir,\n publishDir: outDir,\n owner: \"droplet\",\n }),\n );\n\n if (!buildResult.success) {\n const details = buildResult.error.details\n ? `\\n${buildResult.error.details}`\n : \"\";\n throw new Error(`${buildResult.error.message}${details}`);\n }\n\n return {\n outDir: buildResult.value.publishDir,\n packageId: buildResult.value.packageId,\n version: buildResult.value.version,\n };\n}\n\nexport const buildCommand: Command = new Command(\"build\")\n .description(\"Validate and build the current droplet widget package\")\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_WIDGET_OUT_DIR,\n )\n .option(\"--skip-typecheck\", \"Skip package typecheck script when present\")\n .action((options: BuildWidgetOptions) => {\n return runCliAction(async () => {\n const outDir = options.outDir ?? DEFAULT_WIDGET_OUT_DIR;\n console.log(chalk.blue.bold(\"Building Fluid widget package\"));\n console.log();\n\n const spinner = ora(\n \"Validating and building widget artifacts...\",\n ).start();\n const result = await buildWidgetPackage({\n projectDir: process.cwd(),\n outDir,\n skipTypecheck: options.skipTypecheck,\n });\n spinner.succeed(\"Built widget runtime artifacts\");\n\n console.log();\n console.log(chalk.gray(\"Package: \") + chalk.white(result.packageId));\n console.log(chalk.gray(\"Version: \") + chalk.white(result.version));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n });\n });\n","/**\n * Git wrapper for the Fluid widget CLI — shells out to the system `git`\n * binary via execa. Mirrors the Mist CLI write path\n * (`packages/cli/mist/src/lib/git.ts`): we deliberately do NOT bundle git or\n * use a pure-JS implementation; users are expected to have git installed and\n * we surface a friendly, actionable error when they don't.\n *\n * Security: a token-bearing `remote_url` from POST .../git_credential must\n * never be logged, persisted, or exposed in the process table. The token is\n * stripped from the URL and handed to git through a GIT_ASKPASS script via env\n * vars (FLUID_GIT_USER / FLUID_GIT_PASS) — so it never appears in argv\n * (visible to `ps aux` / `/proc/<pid>/cmdline`) and is never written to\n * `.git/config`. `-c credential.helper=` stops git from caching it, and\n * `GIT_TERMINAL_PROMPT=0` makes auth fail fast instead of hanging on a prompt.\n */\n\nimport { chmodSync, existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { execa, type ExecaError } from \"execa\";\n\nexport class GitError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"GitError\";\n this.exitCode = exitCode;\n }\n}\n\n/**\n * execa throws ENOENT when the git binary itself is missing — the single most\n * common failure on non-developer machines. Translate it into an actionable\n * message (mirrors Mist Desktop's git-availability guidance) instead of a\n * bare \"git <verb> failed (exit 1)\". Returns null for every other failure so\n * call sites keep their specific messages.\n */\nexport function gitMissingError(err: unknown): GitError | null {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code !== \"ENOENT\") return null;\n return new GitError(\n \"Git isn't installed or isn't on your PATH. Install it and try again:\\n\" +\n \" macOS: xcode-select --install (or `brew install git`)\\n\" +\n \" Windows: https://git-scm.com/download/win\\n\" +\n \" Linux: use your package manager, e.g. `sudo apt-get install git`\\n\" +\n \"Downloads for all platforms: https://git-scm.com/downloads\",\n 127,\n );\n}\n\n/**\n * Split a token-bearing remote URL into the userless URL + creds. Keeps the\n * token off git's argv: we pass `cleanUrl` to git and feed `username` /\n * `password` back through GIT_ASKPASS env vars. If the URL has no embedded\n * credentials, returns empty strings — fine for public repos where git won't\n * invoke askpass.\n */\nfunction splitRemoteCredentials(remoteUrl: string): {\n cleanUrl: string;\n username: string;\n password: string;\n} {\n let u: URL;\n try {\n u = new URL(remoteUrl);\n } catch {\n // Not a URL (e.g. a local filesystem path used for dev/testing). Pass it\n // through untouched — there are no embedded credentials to strip.\n return { cleanUrl: remoteUrl, username: \"\", password: \"\" };\n }\n const username = decodeURIComponent(u.username);\n const password = decodeURIComponent(u.password);\n u.username = \"\";\n u.password = \"\";\n return { cleanUrl: u.toString(), username, password };\n}\n\n/**\n * Write a stub GIT_ASKPASS shell script to a per-process tmpdir and return its\n * path. The script contains no secret — it just echoes back whichever env var\n * (FLUID_GIT_USER / FLUID_GIT_PASS) matches git's prompt. Credentials only\n * live in the spawned git process's env for the duration of the call.\n *\n * One POSIX script for all platforms: Git for Windows runs GIT_ASKPASS through\n * its bundled sh, so a plain sh script works everywhere. Idempotent.\n */\nlet askpassPath: string | null = null;\nfunction ensureAskpassScript(): string {\n if (askpassPath && existsSync(askpassPath)) return askpassPath;\n const dir = path.join(os.tmpdir(), `fluid-widget-askpass-${process.pid}`);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n const p = path.join(dir, \"askpass.sh\");\n writeFileSync(\n p,\n `#!/bin/sh\\ncase \"$1\" in\\n Username*) printf '%s' \"$FLUID_GIT_USER\" ;;\\n *) printf '%s' \"$FLUID_GIT_PASS\" ;;\\nesac\\n`,\n { mode: 0o700 },\n );\n chmodSync(p, 0o700);\n askpassPath = p;\n return askpassPath;\n}\n\n/**\n * Build the spawn env + cleaned URL for a credentialed git invocation. The\n * returned `cleanUrl` has userinfo stripped (safe to pass as argv); the `env`\n * carries GIT_ASKPASS + FLUID_GIT_USER / FLUID_GIT_PASS and\n * GIT_TERMINAL_PROMPT=0.\n */\nfunction gitAuthSpawn(remoteUrl: string): {\n cleanUrl: string;\n env: NodeJS.ProcessEnv;\n} {\n const { cleanUrl, username, password } = splitRemoteCredentials(remoteUrl);\n return {\n cleanUrl,\n env: {\n ...process.env,\n GIT_ASKPASS: ensureAskpassScript(),\n GIT_TERMINAL_PROMPT: \"0\",\n FLUID_GIT_USER: username,\n FLUID_GIT_PASS: password,\n },\n };\n}\n\nfunction wrapGitError(err: unknown, verb: string): GitError {\n const missing = gitMissingError(err);\n if (missing) return missing;\n const e = err as ExecaError;\n return new GitError(\n `git ${verb} failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n}\n\n/** Confirm git is installed. Cheap call once at the start of a git command. */\nexport async function ensureGitAvailable(): Promise<void> {\n try {\n await execa(\"git\", [\"--version\"]);\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n throw new GitError(\n \"`git` is required but couldn't be run. Install it from https://git-scm.com/downloads.\",\n );\n }\n}\n\n/** Is `cwd` inside a git working tree? */\nexport async function isGitRepository(cwd: string): Promise<boolean> {\n try {\n const { stdout } = await execa(\n \"git\",\n [\"rev-parse\", \"--is-inside-work-tree\"],\n { cwd },\n );\n return stdout.trim() === \"true\";\n } catch {\n return false;\n }\n}\n\n/** `git init` (+ set the initial branch to `branch`). No-op if already a repo. */\nexport async function gitInit(cwd: string, branch = \"main\"): Promise<void> {\n try {\n await execa(\"git\", [\"init\", \"--initial-branch\", branch], { cwd });\n } catch (err) {\n // Older gits lack --initial-branch; fall back to a plain init.\n const missing = gitMissingError(err);\n if (missing) throw missing;\n try {\n await execa(\"git\", [\"init\"], { cwd });\n } catch (fallbackErr) {\n throw wrapGitError(fallbackErr, \"init\");\n }\n }\n}\n\n/**\n * `git clone <cleanUrl> <targetDir>`. The original remoteUrl carries a token;\n * gitAuthSpawn strips it from the URL and re-injects it via GIT_ASKPASS.\n */\nexport async function gitClone(\n remoteUrl: string,\n targetDir: string,\n options: {\n readonly depth?: number;\n readonly branch?: string;\n /**\n * Capture git's stderr instead of inheriting it. Used for best-effort\n * clones (e.g. the create template fetch) where the caller handles\n * failure and doesn't want git's raw error text on the console.\n */\n readonly silent?: boolean;\n } = {},\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n const args = [\"-c\", \"credential.helper=\", \"clone\", \"--quiet\"];\n if (options.depth != null) args.push(\"--depth\", String(options.depth));\n if (options.branch) args.push(\"--branch\", options.branch);\n args.push(cleanUrl, targetDir);\n try {\n await execa(\"git\", args, {\n env,\n stdio: options.silent ? \"pipe\" : [\"ignore\", \"inherit\", \"inherit\"],\n });\n } catch (err) {\n throw wrapGitError(err, \"clone\");\n }\n}\n\n/** `git push <remote> HEAD:<branch>` — credentials via GIT_ASKPASS, never argv. */\nexport async function gitPush(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\n \"-c\",\n \"credential.helper=\",\n \"-c\",\n \"http.https://github.com/.extraheader=\",\n \"push\",\n cleanUrl,\n `HEAD:${branch}`,\n ],\n { cwd, env, stdio: [\"ignore\", \"inherit\", \"inherit\"] },\n );\n } catch (err) {\n throw wrapGitError(err, \"push\");\n }\n}\n\n/**\n * Does `branch` exist on the remote? Uses `git ls-remote --heads`, which is\n * the reliable way to tell a genuinely-empty remote (freshly provisioned repo,\n * first push) apart from a connection/auth failure. Returns false only when the\n * remote answered but has no such branch; **throws** on any transport/auth\n * error so callers don't mistake a network blip for \"empty remote\" and skip\n * reconciliation.\n */\nexport async function gitRemoteBranchExists(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<boolean> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n const { stdout } = await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"ls-remote\", \"--heads\", cleanUrl, branch],\n { cwd, env },\n );\n return stdout.trim().length > 0;\n } catch (err) {\n throw wrapGitError(err, \"ls-remote\");\n }\n}\n\n/**\n * Fetch the given branch from the token-bearing remote, writing `FETCH_HEAD`.\n * Throws on failure — callers should first confirm the branch exists with\n * `gitRemoteBranchExists` so a genuinely-empty remote isn't treated as an error.\n */\nexport async function gitFetch(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"fetch\", \"--quiet\", cleanUrl, branch],\n { cwd, env },\n );\n } catch (err) {\n throw wrapGitError(err, \"fetch\");\n }\n}\n\n/**\n * Count commits in local HEAD vs `FETCH_HEAD` (after `gitFetch`). Returns\n * `{ahead, behind}`. `0/0` means \"in sync\" (or no FETCH_HEAD / no HEAD yet).\n */\nexport async function gitAheadBehindVsFetchHead(\n cwd: string,\n): Promise<{ ahead: number; behind: number }> {\n try {\n const { stdout } = await execa(\n \"git\",\n [\"rev-list\", \"--left-right\", \"--count\", \"HEAD...FETCH_HEAD\"],\n { cwd },\n );\n const [a, b] = stdout.trim().split(/\\s+/);\n const ahead = Number.parseInt(a ?? \"0\", 10);\n const behind = Number.parseInt(b ?? \"0\", 10);\n return {\n ahead: Number.isFinite(ahead) ? ahead : 0,\n behind: Number.isFinite(behind) ? behind : 0,\n };\n } catch {\n return { ahead: 0, behind: 0 };\n }\n}\n\n/** Does `cwd` have any commits yet? (false right after `git init`.) */\nexport async function hasCommits(cwd: string): Promise<boolean> {\n try {\n await execa(\"git\", [\"rev-parse\", \"--verify\", \"HEAD\"], { cwd });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Adopt `FETCH_HEAD` as the current (unborn) branch's base: point the branch\n * ref at it and load its tree into the index, leaving the working tree\n * untouched. The next auto-commit then records the local project tree as a\n * child of the remote history — local files win, remote-only files are\n * recorded as deletions — so the push fast-forwards instead of being\n * rejected for unrelated history. Only call this when `hasCommits` is false;\n * on a repo with local commits it would silently rewrite the branch ref.\n *\n * Returns the number of remote commits adopted.\n */\nexport async function gitAdoptFetchHead(cwd: string): Promise<number> {\n try {\n await execa(\"git\", [\"reset\", \"--mixed\", \"FETCH_HEAD\"], { cwd });\n const { stdout } = await execa(\n \"git\",\n [\"rev-list\", \"--count\", \"FETCH_HEAD\"],\n { cwd },\n );\n const count = Number.parseInt(stdout.trim(), 10);\n return Number.isFinite(count) ? count : 0;\n } catch (err) {\n throw wrapGitError(err, \"adopt remote history\");\n }\n}\n\n/** Fast-forward `HEAD` to `FETCH_HEAD`. Fails if not fast-forwardable. */\nexport async function gitMergeFastForward(cwd: string): Promise<void> {\n try {\n await execa(\"git\", [\"merge\", \"--ff-only\", \"FETCH_HEAD\"], { cwd });\n } catch (err) {\n throw wrapGitError(err, \"fast-forward merge\");\n }\n}\n\n/** Are there uncommitted changes (working tree or index) in this repo? */\nexport async function hasUncommittedChanges(cwd: string): Promise<boolean> {\n try {\n const { stdout } = await execa(\"git\", [\"status\", \"--porcelain\"], { cwd });\n return stdout.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/** Stash working-tree + untracked changes with a tagged message. */\nexport async function gitStash(cwd: string, message: string): Promise<void> {\n try {\n await execa(\n \"git\",\n [\"stash\", \"push\", \"--include-untracked\", \"--message\", message],\n { cwd },\n );\n } catch (err) {\n throw wrapGitError(err, \"stash push\");\n }\n}\n\n/** Pop the most recent stash. Throws on conflict so callers can surface it. */\nexport async function gitStashPop(cwd: string): Promise<void> {\n try {\n await execa(\"git\", [\"stash\", \"pop\"], { cwd });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n \"Couldn't restore your local changes after pulling — the edits collided \" +\n \"with a teammate's. Run `git stash list` and resolve manually.\",\n e.exitCode ?? 1,\n );\n }\n}\n\n/** Read the current HEAD sha, or null if there is no commit yet. */\nexport async function getHeadSha(cwd: string): Promise<string | null> {\n try {\n const { stdout } = await execa(\"git\", [\"rev-parse\", \"HEAD\"], { cwd });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\nexport interface GitCommitIdentity {\n readonly name: string;\n readonly email: string;\n}\n\nconst DEFAULT_COMMIT_IDENTITY: GitCommitIdentity = {\n name: \"Fluid CLI\",\n email: \"cli@fluid.app\",\n};\n\n/**\n * `git add -A && git commit -m <message>` in `cwd`.\n *\n * The widget \"push\" UX is \"ship my changes\" — the user shouldn't need to know\n * about staging or commit messages. This bundles working-tree edits into one\n * commit per push. If the repo has no configured user.name / user.email we\n * pass a synthetic identity so the commit isn't rejected. \"nothing to commit\"\n * is treated as a no-op rather than an error.\n */\nexport async function gitAutoCommit(\n cwd: string,\n message: string,\n identity: GitCommitIdentity = DEFAULT_COMMIT_IDENTITY,\n): Promise<void> {\n try {\n await execa(\"git\", [\"add\", \"-A\"], { cwd });\n } catch (err) {\n throw wrapGitError(err, \"add\");\n }\n\n let hasName = false;\n let hasEmail = false;\n try {\n const r = await execa(\"git\", [\"config\", \"user.name\"], { cwd });\n hasName = r.stdout.trim().length > 0;\n } catch {\n // exit 1 from `git config <key>` just means the key is unset.\n }\n try {\n const r = await execa(\"git\", [\"config\", \"user.email\"], { cwd });\n hasEmail = r.stdout.trim().length > 0;\n } catch {\n // ditto.\n }\n const identityArgs = [\n ...(hasName ? [] : [\"-c\", `user.name=${identity.name}`]),\n ...(hasEmail ? [] : [\"-c\", `user.email=${identity.email}`]),\n ];\n\n try {\n await execa(\"git\", [...identityArgs, \"commit\", \"-m\", message], {\n cwd,\n stdio: [\"ignore\", \"inherit\", \"inherit\"],\n });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n if (typeof e.stderr === \"string\" && /nothing to commit/i.test(e.stderr)) {\n return;\n }\n throw wrapGitError(err, \"commit\");\n }\n}\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\n\n/**\n * A short-lived (~1h) credentialed git remote URL minted by the backend. The\n * `remoteUrl` embeds an installation token and must never be logged,\n * persisted, or written to `.git/config` — hand it straight to the git helpers\n * in `../lib/git.js`, which strip the token off argv via GIT_ASKPASS.\n */\nexport interface WidgetGitCredential {\n readonly remoteUrl: string;\n readonly expiresAt: string | null;\n}\n\ninterface GitCredentialResponse {\n readonly git_credential?: {\n readonly remote_url?: unknown;\n readonly expires_at?: unknown;\n };\n}\n\nexport interface MintWidgetGitCredentialOptions {\n readonly client: FetchClient;\n /**\n * Droplet UUID that owns the widget package. When provided we mint against\n * the droplet-scoped endpoint; otherwise we mint against the company-owned\n * widget package endpoint.\n */\n readonly droplet?: string;\n}\n\n/**\n * Mint a git credential for a widget package.\n *\n * Backend (fluid-commerce PR #19162 — not deployed to prod yet):\n * - droplet-owned: POST /api/droplets/:uuid/widget_package/git_credential\n * - company-owned: POST /api/company/fluid_os/widget_package/git_credential\n * Both respond `{ git_credential: { remote_url, expires_at } }`.\n *\n * Throws the underlying `ApiError` (with `.status`) on failure so callers can\n * decide whether to degrade gracefully (see `isGitSyncUnavailable`).\n */\nexport async function mintWidgetGitCredential(\n options: MintWidgetGitCredentialOptions,\n): Promise<WidgetGitCredential> {\n const path = options.droplet\n ? `/api/droplets/${encodeURIComponent(options.droplet)}/widget_package/git_credential`\n : \"/api/company/fluid_os/widget_package/git_credential\";\n\n const response = await options.client.post<GitCredentialResponse>(path);\n const remoteUrl = response?.git_credential?.remote_url;\n if (typeof remoteUrl !== \"string\" || remoteUrl.length === 0) {\n throw new Error(\n \"The git credential response did not include a remote URL. \" +\n \"Update the Fluid CLI, or contact support if this persists.\",\n );\n }\n const expiresAtRaw = response.git_credential?.expires_at;\n return {\n remoteUrl,\n expiresAt: typeof expiresAtRaw === \"string\" ? expiresAtRaw : null,\n };\n}\n\n/**\n * Sanitize a package key the same way the backend does when naming the repo\n * (`GitSync::Provisioner`): GitHub's repo-name alphabet is `[A-Za-z0-9._-]`,\n * so every other character (including the `~` allowed in package keys) becomes\n * a hyphen. Lets us compare a requested key against the minted repo name.\n */\nexport function sanitizeWidgetPackageKey(key: string): string {\n return key.replace(/[^A-Za-z0-9._-]/g, \"-\");\n}\n\n/**\n * Extract the sanitized package key from a minted widget remote URL. The\n * backend names repos `widget-<sanitized package_key>-<widget_package id>`, so\n * `https://x-access-token:tok@github.com/org/widget-reviews-42.git` → `reviews`.\n * Returns null when the URL doesn't match that shape (never throws; the token\n * in the URL is never logged — only the pathname is read).\n */\nexport function widgetRepoKeyFromRemoteUrl(remoteUrl: string): string | null {\n try {\n const name = new URL(remoteUrl).pathname\n .split(\"/\")\n .pop()\n ?.replace(/\\.git$/, \"\");\n const match = name?.match(/^widget-(.+)-\\d+$/);\n return match?.[1] ?? null;\n } catch {\n return null;\n }\n}\n\n/** Best-effort read of an HTTP status off an unknown thrown error. */\nexport function getErrorStatus(err: unknown): number | undefined {\n if (err && typeof err === \"object\" && \"status\" in err) {\n const status = (err as { status?: unknown }).status;\n if (typeof status === \"number\") return status;\n }\n return undefined;\n}\n\n/**\n * Should a git-credential failure degrade to \"publish artifacts only\" rather\n * than abort? True when the endpoint isn't deployed (404) or the package's git\n * repo isn't provisioned/connected yet (409). Other statuses (auth, 5xx) are\n * genuine errors the caller may still choose to treat as best-effort.\n */\nexport function isGitSyncUnavailable(err: unknown): boolean {\n const status = getErrorStatus(err);\n return status === 404 || status === 409;\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * `.fluid-widget` marker file — written by `fluid widget clone` so future\n * commands (and Mist Desktop) can identify a checked-out widget package repo\n * and know which owner to mint git credentials against. Mirrors Mist's `.mist`\n * marker (which records slug / vendor_name).\n */\nexport const WIDGET_MARKER_FILE = \".fluid-widget\";\n\nexport interface WidgetMarker {\n readonly package_key: string;\n /** Droplet UUID when the package is droplet-owned; omitted for company-owned. */\n readonly droplet?: string;\n}\n\nexport function resolveWidgetMarkerPath(dir: string): string {\n return path.join(dir, WIDGET_MARKER_FILE);\n}\n\nexport function writeWidgetMarker(dir: string, marker: WidgetMarker): void {\n const payload: WidgetMarker = marker.droplet\n ? { package_key: marker.package_key, droplet: marker.droplet }\n : { package_key: marker.package_key };\n writeFileSync(\n resolveWidgetMarkerPath(dir),\n JSON.stringify(payload, null, 2) + \"\\n\",\n \"utf8\",\n );\n}\n\nexport function readWidgetMarker(dir: string): WidgetMarker | null {\n const filePath = resolveWidgetMarkerPath(dir);\n if (!existsSync(filePath)) return null;\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf8\")) as unknown;\n if (!parsed || typeof parsed !== \"object\") return null;\n const obj = parsed as Record<string, unknown>;\n const packageKey = obj[\"package_key\"];\n if (typeof packageKey !== \"string\" || packageKey.length === 0) return null;\n const droplet = obj[\"droplet\"];\n return {\n package_key: packageKey,\n ...(typeof droplet === \"string\" && droplet.length > 0 ? { droplet } : {}),\n };\n } catch {\n return null;\n }\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { ensureGitAvailable, gitClone } from \"../lib/git.js\";\nimport {\n isGitSyncUnavailable,\n mintWidgetGitCredential,\n sanitizeWidgetPackageKey,\n widgetRepoKeyFromRemoteUrl,\n} from \"../utils/git-credential.js\";\nimport { validateDropletUuid } from \"../utils/config.js\";\nimport { writeWidgetMarker } from \"../utils/widget-marker.js\";\nimport {\n getInstallCommand,\n installDependencies,\n} from \"../utils/package-manager.js\";\n\nexport interface CloneCommandOptions {\n readonly droplet?: string;\n readonly dir?: string;\n readonly skipInstall?: boolean;\n}\n\nexport const cloneCommand: Command = new Command(\"clone\")\n .description(\n \"Clone a widget package's git repository (mints a fresh token per call)\",\n )\n .argument(\"<package>\", \"Widget package key to clone\")\n .option(\n \"--droplet <uuid>\",\n \"Droplet UUID that owns the package (defaults to the company-owned package)\",\n )\n .option(\"--dir <dir>\", \"Target directory (defaults to ./<package>/)\")\n .option(\"--skip-install\", \"Skip dependency installation\")\n .action((packageKey: string, options: CloneCommandOptions) =>\n runCliAction(async () => {\n const trimmedPackage = packageKey.trim();\n if (!trimmedPackage) throw new Error(\"A widget package key is required.\");\n\n const droplet = options.droplet?.trim();\n if (droplet) {\n const dropletError = validateDropletUuid(droplet);\n if (dropletError) throw new Error(dropletError);\n }\n\n // Clone is a pure git operation — fail fast with an actionable message\n // when git isn't installed rather than partway through.\n await ensureGitAvailable();\n\n const targetDir = path.resolve(options.dir ?? trimmedPackage);\n if (existsSync(targetDir)) {\n throw new Error(\n `Directory ${targetDir} already exists. Pass --dir or remove it first.`,\n );\n }\n\n // The credential endpoints are scoped to an *owner*, not a package key:\n // a company (or droplet) has exactly one widget package, so the backend\n // resolves the repo from the authenticated company / the droplet uuid —\n // there is no package-key selector to send. `<package>` is therefore a\n // local label used for the target directory name and the `.fluid-widget`\n // marker, mirroring how `fluid mist clone` names by vendor_name.\n const client = createAuthenticatedWidgetPackageClient();\n const spinner = ora(\"Minting git credential…\").start();\n let remoteUrl: string;\n try {\n const cred = await mintWidgetGitCredential({\n client,\n ...(droplet ? { droplet } : {}),\n });\n remoteUrl = cred.remoteUrl;\n } catch (err) {\n spinner.fail(\"Couldn't mint a git credential\");\n if (isGitSyncUnavailable(err)) {\n throw new Error(\n \"Widget git sync isn't available for this package yet. \" +\n \"Publish the package first, or try again once git sync is enabled.\",\n );\n }\n throw err;\n }\n\n // The owner determines the repo, so guard against a requested key that\n // disagrees with what was actually minted — otherwise we'd clone one\n // repo but stamp the marker with a different package name, leaving future\n // push/publish acting on a checkout whose marker and source disagree.\n const mintedKey = widgetRepoKeyFromRemoteUrl(remoteUrl);\n if (!mintedKey) {\n // Fail closed: an unparseable repo name means we can't prove the\n // checkout matches the requested key, and a wrong marker would leave\n // future push/publish acting on the wrong package.\n spinner.fail(\"Couldn't verify the owner's widget repository\");\n throw new Error(\n \"The minted git repository URL did not match the expected widget \" +\n \"repository format, so the CLI cannot safely write a package \" +\n \"marker. Update the Fluid CLI, or contact support if this persists.\",\n );\n }\n if (mintedKey !== sanitizeWidgetPackageKey(trimmedPackage)) {\n spinner.fail(\"Requested package does not match the owner's repository\");\n throw new Error(\n `The ${droplet ? \"droplet\" : \"company\"}'s widget package is ` +\n `\"${mintedKey}\", not \"${trimmedPackage}\". Re-run with the correct ` +\n `package key (or --droplet), so the checkout and its marker agree.`,\n );\n }\n\n spinner.text = `Cloning into ${path.basename(targetDir)}/…`;\n try {\n // Token-bearing URL is passed inline only — never written to .git/config.\n await gitClone(remoteUrl, targetDir);\n } catch (err) {\n spinner.fail(\"git clone failed\");\n throw err;\n }\n\n // Drop a `.fluid-widget` marker so future commands (and Mist Desktop)\n // know the owner without re-parsing config.\n writeWidgetMarker(targetDir, {\n package_key: trimmedPackage,\n ...(droplet ? { droplet } : {}),\n });\n\n spinner.succeed(`Cloned into ${chalk.cyan(targetDir)}`);\n\n // A cloned checkout is unrunnable until dependencies land (`widget dev`\n // needs the project's own Vite) — install here like `create` does so\n // clone-then-run works without a manual step in between.\n const installCommand = getInstallCommand(targetDir);\n if (options.skipInstall !== true) {\n spinner.start(`Installing dependencies with ${installCommand}...`);\n try {\n await installDependencies(targetDir);\n spinner.succeed(\"Installed dependencies\");\n } catch {\n spinner.fail(\"Failed to install dependencies\");\n console.log();\n console.log(chalk.yellow(\"You can install dependencies manually:\"));\n console.log(chalk.cyan(` ${installCommand}`));\n }\n }\n\n console.log(\n chalk.dim(` cd ${path.relative(process.cwd(), targetDir) || \".\"}`),\n );\n if (options.skipInstall === true) {\n console.log(chalk.dim(` ${installCommand}`));\n }\n }),\n );\n","import { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { WidgetTemplateVariables } from \"../types.js\";\n\ndeclare const __FLUID_PORTAL_SDK_VERSION__: string | undefined;\ndeclare const __FLUID_CLI_CORE_VERSION__: string | undefined;\ndeclare const __FLUID_CLI_WIDGET_VERSION__: string | undefined;\n\nconst EMBEDDED_PORTAL_SDK_VERSION =\n typeof __FLUID_PORTAL_SDK_VERSION__ === \"string\"\n ? __FLUID_PORTAL_SDK_VERSION__\n : undefined;\nconst EMBEDDED_CLI_CORE_VERSION =\n typeof __FLUID_CLI_CORE_VERSION__ === \"string\"\n ? __FLUID_CLI_CORE_VERSION__\n : undefined;\nconst EMBEDDED_CLI_WIDGET_VERSION =\n typeof __FLUID_CLI_WIDGET_VERSION__ === \"string\"\n ? __FLUID_CLI_WIDGET_VERSION__\n : undefined;\n\nexport function getDefaultTemplatePath(): string {\n return path.join(findPackageRoot(), \"templates\", \"default\");\n}\n\nexport async function directoryExists(filePath: string): Promise<boolean> {\n try {\n const stats = await stat(filePath);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function copyWidgetTemplate(\n templatePath: string,\n targetPath: string,\n variables: WidgetTemplateVariables,\n): Promise<void> {\n const files = await getFiles(templatePath);\n\n for (const file of files) {\n const sourcePath = path.join(templatePath, file);\n const isTemplate = file.endsWith(\".template\");\n const outputFiles = getOutputFilenames(file);\n\n const content = await readFile(sourcePath, \"utf-8\");\n const processed = isTemplate ? renderTemplate(content, variables) : content;\n\n await writeOutputFiles(targetPath, outputFiles, processed);\n }\n\n for (const skillFile of await getSharedTemplateSkillFiles()) {\n await writeOutputFiles(\n targetPath,\n getOutputFilenames(skillFile.relativePath),\n skillFile.content,\n );\n }\n}\n\nexport async function getPortalSdkVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion(\n [\"portal\", \"sdk\"],\n EMBEDDED_PORTAL_SDK_VERSION,\n options,\n );\n}\n\nexport async function getPortalCoreVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion([\"portal\", \"core\"], undefined, options);\n}\n\nexport async function getCliVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion(\n [\"cli\", \"core\"],\n EMBEDDED_CLI_CORE_VERSION,\n options,\n );\n}\n\nexport async function getWidgetCliVersion(\n options: {\n readonly local?: boolean;\n readonly targetPath?: string;\n } = {},\n): Promise<string> {\n return getWorkspacePackageVersion(\n [\"cli\", \"widget\"],\n EMBEDDED_CLI_WIDGET_VERSION,\n options,\n );\n}\n\nasync function getWorkspacePackageVersion(\n packagePathSegments: readonly string[],\n embeddedVersion: string | undefined,\n options: { readonly local?: boolean; readonly targetPath?: string },\n): Promise<string> {\n try {\n const packageRoot = findPackageRoot();\n const packagesRoot = path.join(packageRoot, \"..\", \"..\");\n const targetPackageRoot = path.join(packagesRoot, ...packagePathSegments);\n\n if (options.local) {\n const linkPath = (\n options.targetPath\n ? path.relative(options.targetPath, targetPackageRoot)\n : targetPackageRoot\n ).replace(/\\\\/g, \"/\");\n return `link:${linkPath || \".\"}`;\n }\n\n if (embeddedVersion) return embeddedVersion;\n\n const packageJsonPath = path.join(targetPackageRoot, \"package.json\");\n const content = await readFile(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n if (typeof pkg.version !== \"string\") {\n throw new Error(`Missing version in ${packageJsonPath}`);\n }\n return pkg.version;\n } catch (error) {\n if (embeddedVersion) return embeddedVersion;\n throw new Error(\n `Could not resolve the exact template package version for ${packagePathSegments.join(\"/\")}`,\n { cause: error },\n );\n }\n}\n\nasync function getFiles(dir: string, baseDir = dir): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await getFiles(fullPath, baseDir)));\n } else {\n files.push(path.relative(baseDir, fullPath));\n }\n }\n\n return files;\n}\n\ninterface TemplateSkillFile {\n readonly relativePath: string;\n readonly content: string;\n}\n\nasync function getSharedTemplateSkillFiles(): Promise<TemplateSkillFile[]> {\n const packageRoot = findFluidCliPackageRoot();\n const skillsRoot = path.join(packageRoot, \"template-skills\");\n const files = await getFiles(skillsRoot);\n\n return Promise.all(\n files.map(async (file) => ({\n relativePath: path.join(\"skills\", file),\n content: await readFile(path.join(skillsRoot, file), \"utf-8\"),\n })),\n );\n}\n\nfunction findFluidCliPackageRoot(): string {\n const workspacePackageRoot = path.join(findPackageRoot(), \"..\", \"core\");\n if (existsSync(path.join(workspacePackageRoot, \"template-skills\"))) {\n return workspacePackageRoot;\n }\n\n let dir = path.dirname(\n fileURLToPath(import.meta.resolve(\"@fluid-app/fluid-cli\")),\n );\n while (!existsSync(path.join(dir, \"package.json\"))) {\n const parent = path.dirname(dir);\n if (parent === dir)\n throw new Error(\"Could not find Fluid CLI package root\");\n dir = parent;\n }\n return dir;\n}\n\nfunction renderTemplate(\n content: string,\n variables: WidgetTemplateVariables,\n): string {\n const withConditionals = content.replace(\n /{{\\s*#if\\s+([a-zA-Z0-9_]+)\\s*}}([\\s\\S]*?){{\\s*\\/if\\s*}}/g,\n (match, key, block) => {\n if (!isTemplateVariableKey(key)) return match;\n return variables[key] ? String(block) : \"\";\n },\n );\n\n return withConditionals.replace(\n /{{\\s*([a-zA-Z0-9_]+)\\s*}}/g,\n (match, key) => {\n if (isTemplateVariableKey(key)) return variables[key] ?? \"\";\n return match;\n },\n );\n}\n\nfunction isTemplateVariableKey(\n key: string,\n): key is keyof WidgetTemplateVariables {\n return [\n \"projectName\",\n \"widgetScope\",\n \"widgetPackageVersion\",\n \"sdkVersion\",\n \"localCoreVersion\",\n \"fluidCliVersion\",\n \"widgetCliVersion\",\n \"droplet\",\n ].includes(key);\n}\n\nasync function writeOutputFiles(\n targetPath: string,\n outputFiles: readonly string[],\n content: string,\n): Promise<void> {\n for (const outputFile of outputFiles) {\n const destinationPath = path.join(targetPath, outputFile);\n await mkdir(path.dirname(destinationPath), { recursive: true });\n await writeFile(destinationPath, content, \"utf-8\");\n }\n}\n\nfunction getOutputFilenames(filename: string): string[] {\n const outputFilename = getOutputFilename(filename);\n const normalized = outputFilename.replace(/\\\\/g, \"/\");\n\n if (normalized === \"AGENTS.md\") return [\"AGENTS.md\", \"CLAUDE.md\"];\n\n if (normalized.startsWith(\"skills/\")) {\n return [\n path.join(\".agents\", outputFilename),\n path.join(\".claude\", outputFilename),\n ];\n }\n\n return [outputFilename];\n}\n\nfunction getOutputFilename(filename: string): string {\n return filename.endsWith(\".template\")\n ? filename.slice(0, -\".template\".length)\n : filename;\n}\n\nfunction findPackageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (!existsSync(path.join(dir, \"package.json\"))) {\n const parent = path.dirname(dir);\n if (parent === dir)\n throw new Error(\"Could not find widget CLI package root\");\n dir = parent;\n }\n return dir;\n}\n","import { cp, mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { ensureGitAvailable, gitClone } from \"../lib/git.js\";\n\n/**\n * The canonical widget starter lives on GitHub so widget projects share the\n * same \"invisible git\" collaboration model Mist apps have. It is an explicit\n * opt-in for `fluid widget create`; the bundled template is the default.\n */\nexport const DEFAULT_WIDGET_TEMPLATE_REPO_URL =\n \"https://github.com/Fluid-WeCommerce/widget-template.git\";\n\n/**\n * The template repo to clone. Overridable via `FLUID_WIDGET_TEMPLATE_REPO`\n * (read at call time so tests can point at a local repo). Falls back to the\n * canonical GitHub template.\n */\nexport function widgetTemplateRepoUrl(): string {\n return (\n process.env[\"FLUID_WIDGET_TEMPLATE_REPO\"] ??\n DEFAULT_WIDGET_TEMPLATE_REPO_URL\n );\n}\n\n/**\n * The defaults baked into the GitHub template's rendered files. `create`\n * rewrites these to the user's chosen values after cloning. Keep in sync with\n * `scripts/render-template-repo.mts`.\n */\nexport const TEMPLATE_DEFAULTS = {\n projectName: \"my-widget\",\n widgetScope: \"droplet\",\n widgetPackageVersion: \"0.1.0\",\n} as const;\n\nexport interface GithubTemplateVariables {\n readonly projectName: string;\n readonly widgetScope: string;\n readonly widgetPackageVersion: string;\n}\n\n/**\n * Clone the GitHub widget template into `targetPath`, strip its git history,\n * and rewrite the baked defaults to the user's values. The repo holds a fully\n * rendered project (no `{{placeholders}}`), so we do targeted, deterministic\n * replacements of the known defaults rather than template interpolation.\n *\n * Returns true on success. Returns false (never throws) when the template\n * couldn't be fetched — git missing, offline, repo unavailable. The caller\n * reports that requested-template failure. The partially-cloned target is\n * cleaned up before returning false.\n */\nexport async function tryFetchGithubTemplate(\n targetPath: string,\n variables: GithubTemplateVariables,\n): Promise<boolean> {\n let tempDir: string | undefined;\n try {\n await ensureGitAvailable();\n tempDir = await mkdtemp(path.join(os.tmpdir(), \"fluid-widget-template-\"));\n const clonePath = path.join(tempDir, \"template\");\n await gitClone(widgetTemplateRepoUrl(), clonePath, {\n depth: 1,\n branch: \"main\",\n silent: true,\n });\n\n // Strip git history: generate-from-template semantics — the new project\n // gets its own (invisible) repo later via `fluid widget push`.\n await rm(path.join(clonePath, \".git\"), { recursive: true, force: true });\n\n await cp(clonePath, targetPath, { recursive: true });\n await applyTemplateRenames(targetPath, variables);\n return true;\n } catch {\n // Any failure → clean up and let the caller report the opt-in failure.\n await rm(targetPath, { recursive: true, force: true }).catch(() => {});\n return false;\n } finally {\n if (tempDir)\n await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/**\n * Rewrite the template's baked defaults (project name, scope, version) to the\n * user's chosen values across the small set of files that reference them.\n * Missing files are skipped — the template can evolve without breaking this.\n */\nasync function applyTemplateRenames(\n targetPath: string,\n variables: GithubTemplateVariables,\n): Promise<void> {\n const { projectName, widgetScope, widgetPackageVersion } = variables;\n\n await replaceInFile(path.join(targetPath, \"package.json\"), [\n [\n `\"name\": ${JSON.stringify(TEMPLATE_DEFAULTS.projectName)}`,\n `\"name\": ${JSON.stringify(projectName)}`,\n ],\n ]);\n\n await replaceInFile(path.join(targetPath, \"index.html\"), [\n [\n `<title>${TEMPLATE_DEFAULTS.projectName}</title>`,\n `<title>${projectName}</title>`,\n ],\n ]);\n\n await replaceInFile(path.join(targetPath, \"README.md\"), [\n [`# ${TEMPLATE_DEFAULTS.projectName}\\n`, `# ${projectName}\\n`],\n ]);\n\n await replaceInFile(path.join(targetPath, \"manifest.ts\"), [\n [\n `scope: ${JSON.stringify(TEMPLATE_DEFAULTS.widgetScope)},`,\n `scope: ${JSON.stringify(widgetScope)},`,\n ],\n [\n `version: ${JSON.stringify(TEMPLATE_DEFAULTS.widgetPackageVersion)},`,\n `version: ${JSON.stringify(widgetPackageVersion)},`,\n ],\n ]);\n}\n\n/**\n * Replace the first occurrence of each `[from, to]` pair in a file. No-op when\n * `from` isn't present (or `from === to`), so re-running is harmless and an\n * unchanged default (e.g. scope already \"droplet\") isn't a failure.\n */\nasync function replaceInFile(\n filePath: string,\n replacements: ReadonlyArray<readonly [string, string]>,\n): Promise<void> {\n if (!existsSync(filePath)) return;\n let content = await readFile(filePath, \"utf8\");\n let changed = false;\n for (const [from, to] of replacements) {\n if (from === to) continue;\n const index = content.indexOf(from);\n if (index === -1) continue;\n content = content.slice(0, index) + to + content.slice(index + from.length);\n changed = true;\n }\n if (changed) await writeFile(filePath, content, \"utf8\");\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport path from \"node:path\";\nimport type { WidgetCreateOptions } from \"../types.js\";\nimport {\n copyWidgetTemplate,\n directoryExists,\n getCliVersion,\n getDefaultTemplatePath,\n getPortalCoreVersion,\n getPortalSdkVersion,\n getWidgetCliVersion,\n} from \"../utils/template.js\";\nimport {\n getInstallCommand,\n getRunCommand,\n installDependencies,\n} from \"../utils/package-manager.js\";\nimport {\n mergeWidgetConfig,\n validateDropletUuid,\n writeWidgetConfig,\n} from \"../utils/config.js\";\nimport { tryFetchGithubTemplate } from \"../utils/github-template.js\";\n\nconst DEFAULT_WIDGET_PACKAGE_VERSION = \"0.1.0\";\nconst DEFAULT_WIDGET_SCOPE = \"droplet\";\n\nexport interface CreateWidgetProjectDependencies {\n readonly installDependencies: typeof installDependencies;\n readonly tryFetchGithubTemplate: typeof tryFetchGithubTemplate;\n}\n\nconst defaultCreateWidgetProjectDependencies = {\n installDependencies,\n tryFetchGithubTemplate,\n} satisfies CreateWidgetProjectDependencies;\n\nexport const createCommand: Command = new Command(\"create\")\n .description(\"Create a standalone Fluid widget project\")\n .argument(\"<project-name>\", \"Name of the widget project to create\")\n .option(\n \"--skip-install\",\n \"Create the scaffold only; skip dependency installation\",\n )\n .option(\n \"-o, --output-dir <dir>\",\n \"Directory to create the project in (defaults to cwd)\",\n )\n .option(\n \"--scope <scope>\",\n \"Widget package scope/namespace\",\n DEFAULT_WIDGET_SCOPE,\n )\n .option(\n \"--package-version <version>\",\n \"Initial widget package version\",\n DEFAULT_WIDGET_PACKAGE_VERSION,\n )\n .option(\n \"--local\",\n \"Use local monorepo packages via file: links (for development testing)\",\n )\n .option(\n \"--remote-template\",\n \"Use the GitHub starter template instead of the bundled template\",\n )\n .option(\"--droplet <uuid>\", \"Existing droplet UUID that owns the package\")\n .action(async (projectName: string, options: WidgetCreateOptions) => {\n try {\n await createWidgetProject(projectName, options);\n } catch (err) {\n console.log();\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n process.exit(1);\n }\n });\n\nexport async function createWidgetProject(\n projectName: string,\n options: WidgetCreateOptions,\n dependencies: CreateWidgetProjectDependencies = defaultCreateWidgetProjectDependencies,\n): Promise<void> {\n console.log();\n console.log(chalk.bold(\"Creating a new Fluid widget project\"));\n console.log();\n\n const projectNameError = validateProjectName(projectName);\n if (projectNameError) throw new Error(projectNameError);\n\n const droplet = options.droplet?.trim();\n if (droplet) {\n const dropletError = validateDropletUuid(droplet);\n if (dropletError) throw new Error(dropletError);\n }\n\n const outputDir = path.resolve(options.outputDir ?? process.cwd());\n const targetPath = path.join(outputDir, projectName);\n if (await directoryExists(targetPath)) {\n throw new Error(`Directory already exists: ${targetPath}`);\n }\n\n const templatePath = getDefaultTemplatePath();\n if (\n options.remoteTemplate !== true &&\n !(await directoryExists(templatePath))\n ) {\n throw new Error(\"Default widget template not found.\");\n }\n\n const config = mergeWidgetConfig({}, { droplet });\n const widgetScope = options.scope ?? DEFAULT_WIDGET_SCOPE;\n const localOptions = { local: options.local === true, targetPath };\n const variables = {\n projectName,\n droplet: config.droplet,\n widgetScope,\n widgetPackageVersion:\n options.packageVersion ?? DEFAULT_WIDGET_PACKAGE_VERSION,\n sdkVersion: await getPortalSdkVersion(localOptions),\n localCoreVersion: options.local\n ? await getPortalCoreVersion(localOptions)\n : undefined,\n fluidCliVersion: await getCliVersion(localOptions),\n widgetCliVersion: await getWidgetCliVersion(localOptions),\n };\n\n if (options.local === true && options.remoteTemplate === true) {\n throw new Error(\"--remote-template cannot be combined with --local\");\n }\n\n // The bundled template is the deterministic default. The mutable GitHub\n // mirror is available only through an explicit opt-in and never silently\n // replaces or falls back to a different schema.\n const useRemoteTemplate = options.remoteTemplate === true;\n\n let scaffolded = false;\n if (useRemoteTemplate) {\n const remoteSpinner = ora(\n \"Fetching widget template from GitHub...\",\n ).start();\n scaffolded = await dependencies.tryFetchGithubTemplate(targetPath, {\n projectName,\n widgetScope,\n widgetPackageVersion:\n options.packageVersion ?? DEFAULT_WIDGET_PACKAGE_VERSION,\n });\n if (scaffolded) {\n remoteSpinner.succeed(\"Fetched widget template from GitHub\");\n } else {\n remoteSpinner.fail(\"Failed to fetch the GitHub widget template\");\n throw new Error(\n \"Couldn't fetch the requested GitHub template. Remove --remote-template to use the bundled template.\",\n );\n }\n }\n\n const spinner = ora(\n scaffolded ? \"Finalizing widget project...\" : \"Copying widget template...\",\n ).start();\n try {\n if (!scaffolded) {\n await copyWidgetTemplate(templatePath, targetPath, variables);\n }\n await writeWidgetConfig(targetPath, config);\n spinner.succeed(\n scaffolded ? \"Prepared widget project\" : \"Copied widget template\",\n );\n } catch (err) {\n spinner.fail(\"Failed to create widget project\");\n throw err;\n }\n\n const installCommand = getInstallCommand(targetPath);\n if (options.skipInstall !== true) {\n spinner.start(`Installing dependencies with ${installCommand}...`);\n try {\n await dependencies.installDependencies(targetPath);\n spinner.succeed(\"Installed dependencies\");\n } catch (error) {\n spinner.fail(\"Failed to install dependencies\");\n console.log();\n console.log(chalk.yellow(`The scaffold was retained at ${targetPath}.`));\n console.log(chalk.yellow(\"Install dependencies manually to continue:\"));\n console.log(chalk.cyan(` cd ${formatCdPath(targetPath)}`));\n console.log(chalk.cyan(` ${installCommand}`));\n throw error;\n }\n }\n\n console.log();\n if (options.skipInstall === true) {\n console.log(\n chalk.yellow(\n \"Scaffold only: dependencies were not installed and must be installed before development.\",\n ),\n );\n console.log();\n }\n console.log(\n chalk.green.bold(\"Success!\") + ` Created ${chalk.cyan(projectName)}`,\n );\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.cyan(` cd ${formatCdPath(targetPath)}`));\n if (options.skipInstall === true) {\n console.log(chalk.cyan(` ${installCommand}`));\n }\n if (!config.droplet) {\n console.log(chalk.cyan(\" fluid widget link\"));\n }\n console.log(chalk.cyan(` ${getRunCommand(\"dev\", targetPath)}`));\n console.log();\n console.log(\n \"Edit \" + chalk.cyan(\"manifest.ts\") + \" to customize your widget package.\",\n );\n console.log(\n chalk.dim(\n \"This command only creates local project files; it does not create a droplet.\",\n ),\n );\n console.log();\n}\n\nfunction validateProjectName(projectName: string): string | undefined {\n if (!projectName) return \"Project name is required.\";\n if (!/^[a-z0-9][a-z0-9-]*$/.test(projectName)) {\n return \"Project name must contain only lowercase letters, numbers, and hyphens.\";\n }\n return undefined;\n}\n\nfunction formatCdPath(targetPath: string): string {\n return path.relative(process.cwd(), targetPath) || \".\";\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { runCliAction } from \"../utils/command.js\";\nimport {\n getInstallCommand,\n installDependencies,\n} from \"../utils/package-manager.js\";\n\nexport const DEFAULT_WIDGET_DEV_PORT = 5174;\n\nexport const WIDGET_DEV_ROUTES = [\n \"/__widget-packages__\",\n \"/__runtime-entry__\",\n] as const;\n\nexport interface WidgetDevOptions {\n readonly port?: string;\n readonly host?: boolean | string;\n readonly mode?: string;\n}\n\nexport interface WidgetDevProjectSummary {\n readonly projectDir: string;\n readonly packageName: string;\n readonly viteConfigPath: string;\n readonly localUrl: string;\n readonly target: string;\n readonly mode: string;\n readonly routes: readonly string[];\n}\n\nexport const devCommand: Command = new Command(\"dev\")\n .description(\"Start the local Fluid widget development endpoints\")\n .option(\n \"-p, --port <port>\",\n \"Port to run the widget dev server on\",\n String(DEFAULT_WIDGET_DEV_PORT),\n )\n .option(\"--host [host]\", \"Expose the dev server to the network\")\n .option(\"--mode <mode>\", \"Vite mode to run\", \"development\")\n .action((options: WidgetDevOptions) => {\n return runCliAction(async () => {\n const projectDir = process.cwd();\n const summary = await resolveWidgetDevProject(projectDir, options);\n\n printWidgetDevSummary(summary);\n await runViteDevServer(projectDir, options);\n });\n });\n\nexport async function resolveWidgetDevProject(\n projectDir: string,\n options: WidgetDevOptions = {},\n): Promise<WidgetDevProjectSummary> {\n const resolvedProjectDir = path.resolve(projectDir);\n const packageJsonPath = path.join(resolvedProjectDir, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n throw new Error(\n \"No package.json found. Run this command from a Fluid widget project directory.\",\n );\n }\n\n const packageJson = await readPackageJson(packageJsonPath);\n const packageName = readPackageName(packageJson) ?? path.basename(projectDir);\n\n const viteConfigPath = path.join(resolvedProjectDir, \"vite.config.ts\");\n if (!existsSync(viteConfigPath)) {\n throw new Error(\n \"No vite.config.ts found. Run this command from a Fluid widget project directory.\",\n );\n }\n\n const port = parsePort(options.port ?? String(DEFAULT_WIDGET_DEV_PORT));\n const host = normalizeHostOption(options.host);\n const mode = normalizeMode(options.mode);\n\n return {\n projectDir: resolvedProjectDir,\n packageName,\n viteConfigPath,\n localUrl: formatLocalUrl(port, host),\n target: packageName,\n mode,\n routes: WIDGET_DEV_ROUTES,\n };\n}\n\nexport function buildViteDevArgs(options: WidgetDevOptions = {}): string[] {\n const port = parsePort(options.port ?? String(DEFAULT_WIDGET_DEV_PORT));\n const host = normalizeHostOption(options.host);\n const mode = normalizeMode(options.mode);\n const args = [\"--port\", String(port), \"--mode\", mode];\n\n if (host) {\n args.push(\"--host\", host);\n }\n\n return args;\n}\n\nexport function printWidgetDevSummary(summary: WidgetDevProjectSummary): void {\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Dev\"));\n console.log(chalk.gray(\"Local: \") + chalk.cyan(summary.localUrl));\n console.log(chalk.gray(\"Target: \") + chalk.white(summary.target));\n console.log(chalk.gray(\"Mode: \") + chalk.white(summary.mode));\n console.log(chalk.gray(\"Routes:\"));\n for (const route of summary.routes) {\n console.log(chalk.gray(\" - \") + chalk.cyan(route));\n }\n console.log();\n}\n\nexport async function runViteDevServer(\n projectDir: string,\n options: WidgetDevOptions = {},\n): Promise<void> {\n let viteCliPath = resolveViteCliPath(projectDir);\n if (!viteCliPath) {\n // Cloned checkouts arrive without node_modules (`fluid widget clone` is a\n // pure git operation) and agent-scaffolded projects may skip the install\n // too. Install once here instead of bouncing the user to a manual step.\n const installCommand = getInstallCommand(projectDir);\n console.log(\n chalk.yellow(\n `Vite is not installed yet — running ${installCommand} first...`,\n ),\n );\n try {\n await installDependencies(projectDir);\n } catch {\n // Fall through to the resolution check below for the actionable error.\n }\n viteCliPath = resolveViteCliPath(projectDir);\n }\n if (!viteCliPath) {\n throw new Error(\n `Unable to find Vite in node_modules. Run \\`${getInstallCommand(projectDir)}\\` in ${projectDir}, then retry.`,\n );\n }\n\n await runNodeScript(viteCliPath, buildViteDevArgs(options), projectDir);\n}\n\nfunction resolveViteCliPath(projectDir: string): string | undefined {\n const viteCliPath = path.join(\n projectDir,\n \"node_modules\",\n \"vite\",\n \"bin\",\n \"vite.js\",\n );\n return existsSync(viteCliPath) ? viteCliPath : undefined;\n}\n\nasync function readPackageJson(packageJsonPath: string): Promise<unknown> {\n try {\n return JSON.parse(await readFile(packageJsonPath, \"utf-8\")) as unknown;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Unable to read package.json: ${message}`);\n }\n}\n\nfunction readPackageName(packageJson: unknown): string | undefined {\n if (!isRecord(packageJson)) return undefined;\n const name = packageJson[\"name\"];\n if (typeof name !== \"string\") return undefined;\n const trimmed = name.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction parsePort(value: string): number {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(\"Port must be an integer between 1 and 65535.\");\n }\n return port;\n}\n\nfunction normalizeHostOption(\n host: WidgetDevOptions[\"host\"],\n): string | undefined {\n if (host === undefined || host === false) return undefined;\n if (host === true) return \"0.0.0.0\";\n\n const trimmed = host.trim();\n return trimmed.length > 0 ? trimmed : \"0.0.0.0\";\n}\n\nfunction normalizeMode(mode: string | undefined): string {\n const trimmed = mode?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : \"development\";\n}\n\nfunction formatLocalUrl(port: number, host: string | undefined): string {\n const displayHost = host && host !== \"0.0.0.0\" ? host : \"localhost\";\n return `http://${displayHost}:${port}`;\n}\n\nfunction runNodeScript(\n scriptPath: string,\n args: readonly string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(process.execPath, [scriptPath, ...args], {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code, signal) => {\n if (code === 0 || signal === \"SIGINT\" || signal === \"SIGTERM\") {\n resolve();\n return;\n }\n\n reject(\n new Error(\n signal\n ? `Vite dev server exited with signal ${signal}.`\n : `Vite dev server exited with code ${code ?? \"unknown\"}.`,\n ),\n );\n });\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\n\nexport interface AuthenticatedClientResult {\n readonly client: FetchClient;\n}\n\nexport function createAuthenticatedClient(): AuthenticatedClientResult {\n return { client: createAuthenticatedWidgetPackageClient() };\n}\n","import prompts from \"prompts\";\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport type { Choice } from \"prompts\";\n\nexport interface DropletChoice {\n readonly uuid: string;\n readonly name: string;\n}\n\nconst MAX_DROPLET_PAGES = 100;\n\nexport async function promptForDroplet(\n client: FetchClient,\n): Promise<string | undefined> {\n const droplets = await listDroplets(client);\n\n if (droplets.length === 0) {\n throw new Error(\n \"No droplets were found for this account. Create a droplet in Fluid first, then run this command again.\",\n );\n }\n\n const response = await prompts({\n type: \"autocomplete\",\n name: \"droplet\",\n message: \"Select the droplet that owns this widget package\",\n choices: droplets.map((droplet) => ({\n title: `${droplet.name} (${droplet.uuid})`,\n value: droplet.uuid,\n })),\n suggest: (input: string, choices: Choice[]) =>\n Promise.resolve(\n input\n ? choices.filter((choice) =>\n choice.title.toLowerCase().includes(input.toLowerCase()),\n )\n : choices,\n ),\n });\n\n return response[\"droplet\"] as string | undefined;\n}\n\nexport async function listDroplets(\n client: FetchClient,\n): Promise<readonly DropletChoice[]> {\n try {\n const firstResponse = await client.get<unknown>(\"/api/droplets\", {\n page: 1,\n });\n const totalPages = Math.min(\n readTotalPages(firstResponse) ?? 1,\n MAX_DROPLET_PAGES,\n );\n const responses = [firstResponse];\n\n for (let page = 2; page <= totalPages; page += 1) {\n responses.push(\n await client.get<unknown>(\"/api/droplets\", {\n page,\n }),\n );\n }\n\n return responses.flatMap(normalizeDropletsResponse);\n } catch (err) {\n if (isApiLikeError(err)) {\n if (err.status === 401 || err.status === 403) {\n throw new Error(\n \"Your Fluid session has expired. Run `fluid login` and try again.\",\n );\n }\n throw new Error(\n `Could not fetch droplets from Fluid (HTTP ${err.status}). ${err.message}`,\n );\n }\n\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Could not fetch droplets from Fluid. ${message}`);\n }\n}\n\nfunction readTotalPages(response: unknown): number | undefined {\n if (!isRecord(response)) return undefined;\n const meta = response[\"meta\"];\n if (!isRecord(meta)) return undefined;\n const pagination = meta[\"pagination\"];\n if (!isRecord(pagination)) return undefined;\n const totalPages = pagination[\"total_pages\"] ?? pagination[\"totalPages\"];\n if (\n typeof totalPages !== \"number\" ||\n !Number.isInteger(totalPages) ||\n totalPages < 1\n ) {\n return undefined;\n }\n return totalPages;\n}\n\nfunction normalizeDropletsResponse(response: unknown): DropletChoice[] {\n const candidates = extractDropletArray(response);\n return candidates\n .map(normalizeDroplet)\n .filter((droplet): droplet is DropletChoice => droplet !== undefined);\n}\n\nfunction extractDropletArray(response: unknown): readonly unknown[] {\n if (Array.isArray(response)) return response;\n if (!isRecord(response)) return [];\n\n const directDroplets = response[\"droplets\"];\n if (Array.isArray(directDroplets)) return directDroplets;\n\n const data = response[\"data\"];\n if (Array.isArray(data)) return data;\n if (isRecord(data) && Array.isArray(data[\"droplets\"])) {\n return data[\"droplets\"];\n }\n\n return [];\n}\n\nfunction normalizeDroplet(value: unknown): DropletChoice | undefined {\n if (!isRecord(value)) return undefined;\n\n const uuid = readString(value, \"uuid\") ?? readString(value, \"id\");\n if (!uuid) return undefined;\n\n const name =\n readString(value, \"name\") ??\n readString(value, \"title\") ??\n readString(value, \"slug\") ??\n uuid;\n\n return { uuid, name };\n}\n\nfunction readString(\n record: Readonly<Record<string, unknown>>,\n key: string,\n): string | undefined {\n const value = record[key];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction isApiLikeError(\n error: unknown,\n): error is { readonly status: number; readonly message: string } {\n return (\n error instanceof Error &&\n \"status\" in error &&\n typeof (error as { readonly status?: unknown }).status === \"number\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import path from \"node:path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { WidgetLinkOptions } from \"../types.js\";\nimport { createAuthenticatedClient } from \"../utils/auth-client.js\";\nimport { promptForDroplet } from \"../utils/droplets.js\";\nimport {\n WIDGET_CONFIG_FILE,\n loadWidgetConfig,\n mergeWidgetConfig,\n validateDropletUuid,\n writeWidgetConfig,\n} from \"../utils/config.js\";\n\nexport const linkCommand: Command = new Command(\"link\")\n .description(\"Link this widget project to an existing Fluid droplet\")\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .action(async (options: WidgetLinkOptions) => {\n try {\n const projectDir = process.cwd();\n const loaded = await loadWidgetConfig(projectDir);\n\n let droplet = options.droplet?.trim() || undefined;\n if (!droplet) {\n const spinner = ora(\"Fetching droplets...\").start();\n try {\n const { client } = createAuthenticatedClient();\n spinner.stop();\n droplet = await promptForDroplet(client);\n } catch (err) {\n spinner.fail(\"Unable to load droplets\");\n throw err;\n }\n\n if (!droplet) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n }\n\n const nextConfig = mergeWidgetConfig(loaded.config, { droplet });\n const nextDropletError = validateDropletUuid(nextConfig.droplet ?? \"\");\n if (nextDropletError) throw new Error(nextDropletError);\n\n await writeWidgetConfig(projectDir, nextConfig);\n\n console.log();\n console.log(chalk.green(\"Linked widget project.\"));\n console.log(\n chalk.gray(\"Config: \") +\n chalk.cyan(\n path.relative(projectDir, loaded.path) || WIDGET_CONFIG_FILE,\n ),\n );\n console.log(\n chalk.gray(\"Droplet: \") + chalk.white(nextConfig.droplet),\n );\n console.log(\n chalk.gray(\"Package key: \") +\n chalk.white(`${nextConfig.droplet} (derived from droplet)`),\n );\n console.log();\n } catch (err) {\n console.log();\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n process.exit(1);\n }\n });\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\n\nexport interface DropletWidgetVersionSummary {\n readonly packageKey?: string;\n readonly packageId?: string;\n readonly version?: string;\n readonly status?: string;\n readonly createdAt?: string;\n readonly updatedAt?: string;\n readonly artifactCount?: number;\n readonly raw: unknown;\n}\n\nexport interface DropletWidgetLogEntry {\n readonly timestamp?: string;\n readonly level?: string;\n readonly message: string;\n readonly raw: unknown;\n}\n\nexport async function fetchDropletWidgetStatus(options: {\n readonly client: FetchClient;\n readonly droplet: string;\n}): Promise<DropletWidgetVersionSummary[]> {\n const response = await options.client.get<unknown>(\n `/api/droplets/${encodeURIComponent(options.droplet)}/widget_package_versions`,\n );\n return extractArray(response).map(normalizeVersionSummary);\n}\n\nexport async function fetchDropletWidgetLogs(options: {\n readonly client: FetchClient;\n readonly droplet: string;\n readonly limit?: number;\n}): Promise<DropletWidgetLogEntry[]> {\n const response = await options.client.get<unknown>(\n `/api/droplets/${encodeURIComponent(options.droplet)}/widget_package_versions/logs`,\n options.limit ? { limit: options.limit } : undefined,\n );\n return extractArray(response).map(normalizeLogEntry);\n}\n\nexport function formatStatusRows(\n versions: readonly DropletWidgetVersionSummary[],\n): string {\n if (versions.length === 0) return \"No widget package versions found.\";\n\n return versions\n .map((version) => {\n const identity =\n version.packageId ?? version.packageKey ?? \"unknown-package\";\n const release = version.version ?? \"unknown-version\";\n const status = version.status ?? \"unknown\";\n const updated = version.updatedAt ?? version.createdAt ?? \"unknown time\";\n const artifacts =\n version.artifactCount === undefined\n ? \"unknown artifacts\"\n : `${version.artifactCount} artifact${version.artifactCount === 1 ? \"\" : \"s\"}`;\n return `${identity}@${release} — ${status} — ${artifacts} — ${updated}`;\n })\n .join(\"\\n\");\n}\n\nexport function formatLogRows(logs: readonly DropletWidgetLogEntry[]): string {\n if (logs.length === 0) return \"No widget package logs found.\";\n\n return logs\n .map((entry) => {\n const timestamp = entry.timestamp ?? \"unknown time\";\n const level = entry.level ? entry.level.toUpperCase() : \"INFO\";\n return `[${timestamp}] ${level} ${entry.message}`;\n })\n .join(\"\\n\");\n}\n\nfunction normalizeVersionSummary(value: unknown): DropletWidgetVersionSummary {\n const record = unwrapKnownNestedRecord(value);\n const artifacts = readArray(record, \"artifacts\");\n return {\n packageKey: readFirstString(record, [\"package_key\", \"packageKey\"]),\n packageId: readFirstString(record, [\"package_id\", \"packageId\"]),\n version: readFirstString(record, [\"version\", \"name\"]),\n status: readFirstString(record, [\"status\", \"state\"]),\n createdAt: readFirstString(record, [\"created_at\", \"createdAt\"]),\n updatedAt: readFirstString(record, [\"updated_at\", \"updatedAt\"]),\n ...(artifacts ? { artifactCount: artifacts.length } : {}),\n raw: value,\n };\n}\n\nfunction normalizeLogEntry(value: unknown): DropletWidgetLogEntry {\n const record = unwrapKnownNestedRecord(value);\n return {\n timestamp: readFirstString(record, [\n \"timestamp\",\n \"created_at\",\n \"createdAt\",\n ]),\n level: readFirstString(record, [\"level\", \"severity\"]),\n message:\n readFirstString(record, [\"message\", \"event\", \"status\", \"state\"]) ??\n JSON.stringify(value),\n raw: value,\n };\n}\n\nfunction extractArray(value: unknown): unknown[] {\n if (Array.isArray(value)) return value;\n if (!isRecord(value)) return [];\n\n for (const key of [\n \"widget_package_versions\",\n \"widgetPackageVersions\",\n \"versions\",\n \"logs\",\n \"events\",\n \"data\",\n ] as const) {\n const nested = value[key];\n if (Array.isArray(nested)) return nested;\n }\n\n return [value];\n}\n\nfunction unwrapKnownNestedRecord(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) return {};\n for (const key of [\n \"widget_package_version\",\n \"widgetPackageVersion\",\n \"version\",\n \"log\",\n \"event\",\n ] as const) {\n const nested = value[key];\n if (isRecord(nested)) return nested;\n }\n return value;\n}\n\nfunction readArray(\n record: Record<string, unknown>,\n key: string,\n): readonly unknown[] | undefined {\n const value = record[key];\n return Array.isArray(value) ? value : undefined;\n}\n\nfunction readFirstString(\n record: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value;\n if (typeof value === \"number\" && Number.isFinite(value))\n return String(value);\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { Command } from \"commander\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport { loadWidgetConfig, validateDropletUuid } from \"../utils/config.js\";\nimport { fetchDropletWidgetLogs, formatLogRows } from \"../utils/droplet-api.js\";\nimport { runCliAction } from \"../utils/command.js\";\n\nexport interface LogsCommandOptions {\n readonly droplet?: string;\n readonly limit?: string;\n readonly json?: boolean;\n}\n\nexport const logsCommand: Command = new Command(\"logs\")\n .description(\"Show recent widget package publish logs for a Droplet\")\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--limit <number>\", \"Maximum number of log entries to request\", \"50\")\n .option(\"--json\", \"Print raw log response as JSON\")\n .action((options: LogsCommandOptions) => {\n return runCliAction(async () => {\n const droplet = await resolveDroplet(process.cwd(), options.droplet);\n const limit = parseLimit(options.limit);\n const logs = await fetchDropletWidgetLogs({\n client: createAuthenticatedWidgetPackageClient(),\n droplet,\n limit,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n logs.map((entry) => entry.raw),\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(chalk.blue.bold(`Widget logs for droplet ${droplet}`));\n console.log();\n console.log(formatLogRows(logs));\n });\n });\n\nasync function resolveDroplet(\n projectDir: string,\n override: string | undefined,\n): Promise<string> {\n const droplet =\n override?.trim() || (await loadWidgetConfig(projectDir)).config.droplet;\n if (droplet?.trim()) {\n const trimmedDroplet = droplet.trim();\n const dropletError = validateDropletUuid(trimmedDroplet);\n if (dropletError) throw new Error(dropletError);\n return trimmedDroplet;\n }\n\n throw new Error(\n \"Missing droplet UUID. Pass --droplet <uuid> or set droplet in fluid.widget.config.ts.\",\n );\n}\n\nfunction parseLimit(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number(value);\n if (Number.isInteger(parsed) && parsed > 0 && parsed <= 500) return parsed;\n throw new Error(\"--limit must be an integer between 1 and 500.\");\n}\n","import { Command } from \"commander\";\nimport {\n createAuthenticatedWidgetPackageClient,\n printDryRunSessionPayload,\n printRuntimeOnlyNotice,\n printWidgetPublishSummary,\n publishWidgetRuntimeArtifacts,\n} from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n DEFAULT_WIDGET_OUT_DIR,\n validateDropletWidgetProject,\n withRootWidgetConfigBridge,\n} from \"../utils/source-package.js\";\nimport { loadWidgetConfig, validateDropletUuid } from \"../utils/config.js\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { runPackageScriptIfAvailable } from \"../utils/package-scripts.js\";\n\nexport interface PublishWidgetPackageOptions {\n readonly projectDir: string;\n readonly outDir: string;\n readonly droplet?: string;\n readonly dryRun?: boolean;\n readonly skipTypecheck?: boolean;\n readonly client?: unknown;\n}\n\nexport interface PublishWidgetPackageResult {\n readonly dryRun: boolean;\n readonly uploaded: boolean;\n readonly outDir: string;\n readonly droplet?: string;\n}\n\nexport interface PublishWidgetPackageDependencies {\n readonly buildWidgetPackage: (options: {\n readonly projectDir: string;\n readonly outDir: string;\n }) => Promise<void>;\n readonly uploadWidgetPackage: (options: {\n readonly outDir: string;\n readonly droplet?: string;\n readonly client?: unknown;\n }) => Promise<void>;\n}\n\nexport async function publishWidgetPackage(\n options: PublishWidgetPackageOptions,\n dependencies?: PublishWidgetPackageDependencies,\n): Promise<PublishWidgetPackageResult> {\n if (dependencies) {\n await dependencies.buildWidgetPackage({\n projectDir: options.projectDir,\n outDir: options.outDir,\n });\n\n const dryRun = options.dryRun === true;\n if (dryRun) {\n return { dryRun, uploaded: false, outDir: options.outDir };\n }\n\n await dependencies.uploadWidgetPackage({\n outDir: options.outDir,\n droplet: options.droplet,\n client: options.client,\n });\n return { dryRun, uploaded: true, outDir: options.outDir };\n }\n\n const droplet = await resolvePublishDroplet(\n options.projectDir,\n options.droplet,\n );\n\n await validateDropletWidgetProject(options.projectDir, droplet);\n if (options.skipTypecheck !== true) {\n await runPackageScriptIfAvailable({\n projectDir: options.projectDir,\n scriptName: \"typecheck\",\n });\n }\n\n const dryRun = options.dryRun === true;\n await withRootWidgetConfigBridge(\n options.projectDir,\n () =>\n publishWidgetRuntimeArtifacts({\n projectDir: options.projectDir,\n outDir: options.outDir,\n buildOwner: \"droplet\",\n uploadOwner: { kind: \"droplet\", uuid: droplet },\n dryRun,\n ...(dryRun ? {} : { client: createAuthenticatedWidgetPackageClient() }),\n }),\n droplet,\n );\n\n return {\n dryRun,\n uploaded: !dryRun,\n outDir: options.outDir,\n droplet,\n };\n}\n\nexport interface PublishCommandOptions {\n readonly outDir?: string;\n readonly droplet?: string;\n readonly dryRun?: boolean;\n readonly skipTypecheck?: boolean;\n}\n\nexport const publishCommand: Command = new Command(\"publish\")\n .description(\"Publish a Fluid widget package\")\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_WIDGET_OUT_DIR,\n )\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--dry-run\", \"Build and validate without uploading\")\n .option(\"--skip-typecheck\", \"Skip package typecheck script when present\")\n .action((options: PublishCommandOptions) => {\n return runCliAction(async () => {\n const projectDir = process.cwd();\n const outDir = options.outDir ?? DEFAULT_WIDGET_OUT_DIR;\n const droplet = await resolvePublishDroplet(projectDir, options.droplet);\n const dryRun = options.dryRun === true;\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Publish\"));\n console.log();\n printRuntimeOnlyNotice();\n console.log(chalk.gray(\"Droplet: \") + chalk.white(droplet));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n if (dryRun) {\n console.log(chalk.yellow(\"Dry run: no upload will be created.\"));\n }\n console.log();\n\n const validateSpinner = ora(\"Validating widget package...\").start();\n await validateDropletWidgetProject(projectDir, droplet);\n validateSpinner.succeed(\"Validated widget package\");\n\n if (options.skipTypecheck !== true) {\n const typecheckSpinner = ora(\"Running package typecheck...\").start();\n const typecheck = await runPackageScriptIfAvailable({\n projectDir,\n scriptName: \"typecheck\",\n });\n if (typecheck.ran) {\n typecheckSpinner.succeed(\"Package typecheck passed\");\n } else {\n typecheckSpinner.info(\"No typecheck script found; skipping\");\n }\n }\n\n const publishSpinner = ora(\n dryRun\n ? \"Building and preparing dry-run upload payload...\"\n : \"Building and publishing widget artifacts...\",\n ).start();\n\n const result = await withRootWidgetConfigBridge(\n projectDir,\n () =>\n publishWidgetRuntimeArtifacts({\n projectDir,\n outDir,\n buildOwner: \"droplet\",\n uploadOwner: { kind: \"droplet\", uuid: droplet },\n dryRun,\n ...(dryRun\n ? {}\n : { client: createAuthenticatedWidgetPackageClient() }),\n }),\n droplet,\n );\n\n publishSpinner.succeed(\n dryRun ? \"Prepared dry-run upload payload\" : \"Published widget package\",\n );\n\n if (dryRun) {\n console.log(\n chalk.yellow(\"Dry run complete — upload session was not requested.\"),\n );\n console.log();\n printDryRunSessionPayload(result);\n }\n\n printWidgetPublishSummary({\n title: dryRun ? \"Widget publish dry run\" : \"Widget publish\",\n ownerLabel: `droplet ${droplet}`,\n outDir,\n result,\n });\n });\n });\n\nexport async function resolvePublishDroplet(\n projectDir: string,\n override: string | undefined,\n): Promise<string> {\n const droplet =\n override?.trim() || (await loadWidgetConfig(projectDir)).config.droplet;\n if (droplet?.trim()) {\n const trimmedDroplet = droplet.trim();\n const dropletError = validateDropletUuid(trimmedDroplet);\n if (dropletError) throw new Error(dropletError);\n return trimmedDroplet;\n }\n\n throw new Error(\n \"Missing droplet UUID. Pass --droplet <uuid> or set droplet in fluid.widget.config.ts.\",\n );\n}\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\n\n/**\n * `GET /api/me` — the authenticated user's identity, used to stamp auto-commit\n * messages with `<name>: <msg> (<public_id>)` so collaboration history traces\n * back to a real person. Best-effort: push still commits if this fails.\n */\nexport interface CurrentUser {\n readonly name: string | null;\n readonly publicId: string | null;\n}\n\ninterface MeResponse {\n readonly id?: unknown;\n readonly public_id?: unknown;\n readonly full_name?: unknown;\n readonly first_name?: unknown;\n readonly last_name?: unknown;\n readonly email?: unknown;\n}\n\nfunction str(value: unknown): string | null {\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n return null;\n}\n\nexport async function fetchCurrentUser(\n client: FetchClient,\n): Promise<CurrentUser> {\n const raw = await client.get<MeResponse>(\"/api/me\");\n const composed = [str(raw.first_name), str(raw.last_name)]\n .filter((part): part is string => part !== null)\n .join(\" \")\n .trim();\n const idValue =\n str(raw.public_id) ??\n (typeof raw.id === \"number\" && Number.isFinite(raw.id)\n ? String(raw.id)\n : null);\n return {\n name:\n str(raw.full_name) ??\n (composed.length > 0 ? composed : null) ??\n str(raw.email),\n publicId: idValue,\n };\n}\n","import type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport {\n gitAdoptFetchHead,\n gitAheadBehindVsFetchHead,\n gitAutoCommit,\n gitFetch,\n gitInit,\n gitMergeFastForward,\n gitPush,\n gitRemoteBranchExists,\n gitStash,\n gitStashPop,\n hasCommits,\n hasUncommittedChanges,\n isGitRepository,\n type GitCommitIdentity,\n} from \"./git.js\";\nimport { mintWidgetGitCredential } from \"../utils/git-credential.js\";\nimport { fetchCurrentUser } from \"../utils/me.js\";\n\nexport interface SyncWidgetGitRepoOptions {\n readonly cwd: string;\n readonly client: FetchClient;\n /** Droplet UUID that owns the package; omitted for company-owned packages. */\n readonly droplet?: string;\n readonly branch?: string;\n /** Base auto-commit message (before the author/public-id stamp). */\n readonly message?: string;\n /** Skip the auto-commit step and push existing commits only. */\n readonly commit?: boolean;\n}\n\nexport type SyncWidgetGitRepoResult =\n | {\n readonly kind: \"synced\";\n readonly pulled: number;\n readonly committed: boolean;\n }\n | {\n readonly kind: \"diverged\";\n readonly ahead: number;\n readonly behind: number;\n };\n\n/**\n * Sync a widget project's invisible git repo: mint a credential, reconcile\n * with origin (fast-forward pull when safe), auto-commit working-tree changes\n * with an author-stamped message, and push HEAD to the branch.\n *\n * Mirrors the Mist CLI write path (`packages/cli/mist/src/commands/push.ts`).\n * Throws on hard failures (mint error, diverged history is returned rather\n * than thrown so the caller can message it); the token-bearing remote URL is\n * only ever handed to the git helpers, never logged or persisted.\n */\nexport async function syncWidgetGitRepo(\n options: SyncWidgetGitRepoOptions,\n): Promise<SyncWidgetGitRepoResult> {\n const { cwd, client } = options;\n const branch = options.branch ?? \"main\";\n\n // Ensure a local repo exists — projects created via `fluid widget create`\n // have their git history stripped, so first push initializes one.\n if (!(await isGitRepository(cwd))) {\n await gitInit(cwd, branch);\n }\n\n // Mint one credential for the whole sync — tokens live ~1h, far beyond a\n // push. Minting again mid-flow would reintroduce a degrade window AFTER\n // the auto-commit: a 404/409 there reads as \"sync unavailable\" to the\n // caller, which would publish artifacts while the fresh commit stays\n // local. With a single mint, unavailability can only surface before any\n // local or remote mutation.\n const cred = await mintWidgetGitCredential({\n client,\n droplet: options.droplet,\n });\n\n // Reconcile against the remote before committing. `gitRemoteBranchExists`\n // and `gitFetch` both throw on transport/auth failure (propagated to the\n // caller as a hard error) so a network blip is never mistaken for an empty\n // remote — that would skip drift detection and let us push over a\n // collaborator's work. We only skip reconciliation when the branch\n // genuinely doesn't exist yet (freshly provisioned repo, first push).\n let pulled = 0;\n const branchExists = await gitRemoteBranchExists(cwd, cred.remoteUrl, branch);\n if (branchExists) {\n await gitFetch(cwd, cred.remoteUrl, branch);\n if (await hasCommits(cwd)) {\n const { ahead, behind } = await gitAheadBehindVsFetchHead(cwd);\n if (behind > 0 && ahead > 0) {\n return { kind: \"diverged\", ahead, behind };\n }\n if (behind > 0) {\n const wasDirty = await hasUncommittedChanges(cwd);\n if (wasDirty) await gitStash(cwd, \"fluid-widget-push: pre-pull stash\");\n try {\n await gitMergeFastForward(cwd);\n } finally {\n if (wasDirty) await gitStashPop(cwd); // throws on conflict\n }\n pulled = behind;\n }\n } else {\n // Brand-new local repo (`create` strips git history) but the remote\n // branch already has commits — the backend provisions repos with an\n // auto-init README (or starter-template) commit. Adopt that history\n // as the local base so the auto-commit below lands on top of it and\n // the push fast-forwards; a fresh root commit here would be rejected\n // as unrelated history.\n pulled = await gitAdoptFetchHead(cwd);\n }\n }\n\n // Auto-commit working-tree changes (unless --no-commit).\n let committed = false;\n if (options.commit !== false && (await hasUncommittedChanges(cwd))) {\n const message = await buildCommitMessage(client, options.message);\n await gitAutoCommit(cwd, message, await resolveCommitIdentity(client));\n committed = true;\n }\n\n await gitPush(cwd, cred.remoteUrl, branch);\n\n return { kind: \"synced\", pulled, committed };\n}\n\nconst DEFAULT_MESSAGE_PREFIX = \"Publish from Fluid widget CLI\";\n\nfunction timestamp(): string {\n return new Date().toISOString().slice(0, 19).replace(\"T\", \" \");\n}\n\n/**\n * Build the auto-commit message, stamped as `<name>: <msg> (<public_id>)` so\n * collaboration history traces back to a real person. Best-effort: a failed or\n * slow /api/me still yields a usable bare message.\n */\nasync function buildCommitMessage(\n client: FetchClient,\n base?: string,\n): Promise<string> {\n const baseMessage = base ?? `${DEFAULT_MESSAGE_PREFIX} · ${timestamp()}`;\n try {\n const me = await withTimeout(fetchCurrentUser(client), 5_000);\n const namePrefix = me.name ? `${me.name}: ` : \"\";\n const idSuffix = me.publicId ? ` (${me.publicId})` : \"\";\n return `${namePrefix}${baseMessage}${idSuffix}`;\n } catch {\n return baseMessage;\n }\n}\n\n/** Prefer the Fluid user for the git author when the repo has no identity. */\nasync function resolveCommitIdentity(\n client: FetchClient,\n): Promise<GitCommitIdentity | undefined> {\n try {\n const me = await withTimeout(fetchCurrentUser(client), 5_000);\n if (me.name) {\n return { name: me.name, email: \"cli@fluid.app\" };\n }\n } catch {\n // Fall through to the git.ts default identity.\n }\n return undefined;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms),\n ),\n ]);\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport { DEFAULT_WIDGET_OUT_DIR } from \"../utils/source-package.js\";\nimport { runCliAction } from \"../utils/command.js\";\nimport { syncWidgetGitRepo } from \"../lib/git-sync.js\";\nimport { GitError } from \"../lib/git.js\";\nimport { isGitSyncUnavailable } from \"../utils/git-credential.js\";\nimport { publishWidgetPackage, resolvePublishDroplet } from \"./publish.js\";\n\nexport interface PushCommandOptions {\n readonly outDir?: string;\n readonly droplet?: string;\n readonly dryRun?: boolean;\n readonly skipTypecheck?: boolean;\n readonly branch?: string;\n readonly message?: string;\n /** Set false by `--no-commit`: push existing commits without auto-committing. */\n readonly commit?: boolean;\n /** Sync the git repo but skip the build + publish pipeline. */\n readonly skipPublish?: boolean;\n}\n\nexport const pushCommand: Command = new Command(\"push\")\n .description(\n \"Sync the widget's git repository (commit + push), then build and publish\",\n )\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_WIDGET_OUT_DIR,\n )\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--branch <name>\", \"Branch to push (default: main)\")\n .option(\n \"-m, --message <message>\",\n \"Commit message for the auto-commit (default: timestamped Publish)\",\n )\n .option(\n \"--no-commit\",\n \"Skip the auto-commit step (push existing commits only)\",\n )\n .option(\n \"--skip-publish\",\n \"Sync the git repository only; skip build + publish\",\n )\n .option(\"--dry-run\", \"Build and validate without uploading (publish step)\")\n .option(\"--skip-typecheck\", \"Skip package typecheck script when present\")\n .action((options: PushCommandOptions) =>\n runCliAction(async () => {\n const projectDir = process.cwd();\n const outDir = options.outDir ?? DEFAULT_WIDGET_OUT_DIR;\n const droplet = await resolvePublishDroplet(projectDir, options.droplet);\n const branch = options.branch ?? \"main\";\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Push\"));\n console.log(chalk.gray(\"Droplet: \") + chalk.white(droplet));\n console.log();\n\n // --- Git sync phase -------------------------------------------------\n // Degrade to publish-only ONLY when git sync isn't in play: the backend\n // endpoint isn't deployed yet (404/409) or git isn't installed. Every\n // other failure — diverged history, stash-pop conflict, auth failure\n // after a local commit, rejected push — aborts BEFORE publish, so we\n // never leave artifacts published while the source repo is unsynced or\n // the local checkout is in a broken git state.\n const client = createAuthenticatedWidgetPackageClient();\n const syncSpinner = ora(\"Syncing widget repository…\").start();\n try {\n const result = await syncWidgetGitRepo({\n cwd: projectDir,\n client,\n droplet,\n branch,\n ...(options.message ? { message: options.message } : {}),\n ...(options.commit === false ? { commit: false } : {}),\n });\n if (result.kind === \"diverged\") {\n syncSpinner.fail(\n `Your local history and origin/${branch} have diverged ` +\n `(${result.ahead} ahead, ${result.behind} behind).`,\n );\n throw new Error(\n \"Resolve in a terminal with `git pull --rebase`, fix any conflicts, \" +\n \"then re-run `fluid widget push`. Nothing was published.\",\n );\n }\n const parts: string[] = [];\n if (result.pulled > 0) {\n parts.push(\n `pulled ${result.pulled} commit${result.pulled === 1 ? \"\" : \"s\"}`,\n );\n }\n parts.push(result.committed ? \"committed + pushed\" : \"pushed\");\n syncSpinner.succeed(`Synced widget repository (${parts.join(\", \")})`);\n } catch (err) {\n if (isGitSyncUnavailable(err)) {\n syncSpinner.info(\n \"Widget git sync isn't available yet — publishing artifacts only.\",\n );\n } else if (err instanceof GitError && err.exitCode === 127) {\n syncSpinner.warn(err.message);\n console.log(\n chalk.yellow(\n \"Skipping git sync (git unavailable); publishing artifacts only.\",\n ),\n );\n } else {\n // Hard failure — stop before publishing so source and artifacts\n // don't drift out of sync.\n if (syncSpinner.isSpinning) syncSpinner.fail(\"Git sync failed\");\n throw err;\n }\n }\n\n if (options.skipPublish === true) {\n console.log();\n console.log(chalk.dim(\"Skipped build + publish (--skip-publish).\"));\n return;\n }\n\n // --- Publish phase ---------------------------------------------------\n const dryRun = options.dryRun === true;\n const publishSpinner = ora(\n dryRun\n ? \"Building and preparing dry-run upload payload…\"\n : \"Building and publishing widget artifacts…\",\n ).start();\n try {\n await publishWidgetPackage({\n projectDir,\n outDir,\n droplet,\n dryRun,\n skipTypecheck: options.skipTypecheck === true,\n });\n publishSpinner.succeed(\n dryRun\n ? \"Prepared dry-run upload payload\"\n : \"Published widget package\",\n );\n } catch (err) {\n publishSpinner.fail(\"Publish failed\");\n throw err;\n }\n\n console.log();\n console.log(chalk.green.bold(\"Done.\"));\n }),\n );\n","import { Command } from \"commander\";\nimport { createAuthenticatedWidgetPackageClient } from \"@fluid-app/fluid-cli-portal\";\nimport chalk from \"chalk\";\nimport { loadWidgetConfig, validateDropletUuid } from \"../utils/config.js\";\nimport {\n fetchDropletWidgetStatus,\n formatStatusRows,\n} from \"../utils/droplet-api.js\";\nimport { runCliAction } from \"../utils/command.js\";\n\nexport interface StatusCommandOptions {\n readonly droplet?: string;\n readonly json?: boolean;\n}\n\nexport const statusCommand: Command = new Command(\"status\")\n .description(\"Show published widget package status for a Droplet\")\n .option(\"--droplet <uuid>\", \"Droplet UUID that owns the widget package\")\n .option(\"--json\", \"Print raw status response as JSON\")\n .action((options: StatusCommandOptions) => {\n return runCliAction(async () => {\n const droplet = await resolveDroplet(process.cwd(), options.droplet);\n const versions = await fetchDropletWidgetStatus({\n client: createAuthenticatedWidgetPackageClient(),\n droplet,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n versions.map((version) => version.raw),\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(chalk.blue.bold(`Widget status for droplet ${droplet}`));\n console.log();\n console.log(formatStatusRows(versions));\n });\n });\n\nasync function resolveDroplet(\n projectDir: string,\n override: string | undefined,\n): Promise<string> {\n const droplet =\n override?.trim() || (await loadWidgetConfig(projectDir)).config.droplet;\n if (droplet?.trim()) {\n const trimmedDroplet = droplet.trim();\n const dropletError = validateDropletUuid(trimmedDroplet);\n if (dropletError) throw new Error(dropletError);\n return trimmedDroplet;\n }\n\n throw new Error(\n \"Missing droplet UUID. Pass --droplet <uuid> or set droplet in fluid.widget.config.ts.\",\n );\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport {\n formatValidationSuccess,\n validateDropletWidgetProject,\n} from \"../utils/source-package.js\";\nimport { runCliAction } from \"../utils/command.js\";\n\nexport interface ValidateWidgetOptions {\n readonly json?: boolean;\n}\n\nexport const validateCommand: Command = new Command(\"validate\")\n .description(\"Validate the current droplet widget package\")\n .option(\"--json\", \"Print machine-readable validation output\")\n .action((options: ValidateWidgetOptions) => {\n return runCliAction(async () => {\n const result = await validateDropletWidgetProject(process.cwd());\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n valid: true,\n config: result.sourceConfigPath,\n packageId: result.validated.packageId,\n version: result.validated.version,\n widgets: result.validated.widgets.map((widget) => ({\n name: widget.name,\n type: widget.type,\n })),\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(chalk.green(formatValidationSuccess(result)));\n });\n });\n","import { Command } from \"commander\";\nimport type { FluidPlugin, PluginContext } from \"@fluid-app/fluid-cli\";\nimport { buildCommand } from \"./commands/build.js\";\nimport { cloneCommand } from \"./commands/clone.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { linkCommand } from \"./commands/link.js\";\nimport { logsCommand } from \"./commands/logs.js\";\nimport { publishCommand } from \"./commands/publish.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { validateCommand } from \"./commands/validate.js\";\n\nexport const widgetCommand: Command = new Command(\"widget\")\n .description(\n \"Create, preview, link, validate, build, publish, push, and clone standalone Fluid widgets\",\n )\n .addCommand(createCommand)\n .addCommand(cloneCommand)\n .addCommand(devCommand)\n .addCommand(linkCommand)\n .addCommand(validateCommand)\n .addCommand(buildCommand)\n .addCommand(publishCommand)\n .addCommand(pushCommand)\n .addCommand(statusCommand)\n .addCommand(logsCommand);\n\nconst plugin: FluidPlugin = {\n name: \"@fluid-app/fluid-cli-widget\",\n version: \"0.1.0\",\n register(ctx: PluginContext) {\n const existingWidgetCommand = findCommand(ctx.program, \"widget\");\n if (existingWidgetCommand) {\n addCommandIfMissing(existingWidgetCommand, createCommand);\n addCommandIfMissing(existingWidgetCommand, cloneCommand);\n addCommandIfMissing(existingWidgetCommand, devCommand);\n addCommandIfMissing(existingWidgetCommand, linkCommand);\n addCommandIfMissing(existingWidgetCommand, validateCommand);\n addCommandIfMissing(existingWidgetCommand, buildCommand);\n addCommandIfMissing(existingWidgetCommand, publishCommand);\n addCommandIfMissing(existingWidgetCommand, pushCommand);\n addCommandIfMissing(existingWidgetCommand, statusCommand);\n addCommandIfMissing(existingWidgetCommand, logsCommand);\n return;\n }\n\n ctx.program.addCommand(widgetCommand);\n },\n};\n\nexport default plugin;\n\nexport type {\n WidgetCommandOptions,\n WidgetCreateOptions,\n WidgetLinkOptions,\n WidgetTemplateVariables,\n} from \"./types.js\";\nexport { buildCommand, buildWidgetPackage } from \"./commands/build.js\";\nexport type {\n BuildWidgetOptions,\n BuildWidgetPackageOptions,\n BuildWidgetPackageResult,\n} from \"./commands/build.js\";\nexport { cloneCommand } from \"./commands/clone.js\";\nexport type { CloneCommandOptions } from \"./commands/clone.js\";\nexport {\n createCommand,\n createWidgetProject,\n type CreateWidgetProjectDependencies,\n} from \"./commands/create.js\";\nexport { pushCommand } from \"./commands/push.js\";\nexport type { PushCommandOptions } from \"./commands/push.js\";\nexport {\n DEFAULT_WIDGET_DEV_PORT,\n WIDGET_DEV_ROUTES,\n buildViteDevArgs,\n devCommand,\n printWidgetDevSummary,\n resolveWidgetDevProject,\n runViteDevServer,\n} from \"./commands/dev.js\";\nexport type {\n WidgetDevOptions,\n WidgetDevProjectSummary,\n} from \"./commands/dev.js\";\nexport { linkCommand } from \"./commands/link.js\";\nexport { logsCommand } from \"./commands/logs.js\";\nexport type { LogsCommandOptions } from \"./commands/logs.js\";\nexport { publishCommand, publishWidgetPackage } from \"./commands/publish.js\";\nexport type {\n PublishCommandOptions,\n PublishWidgetPackageDependencies,\n PublishWidgetPackageOptions,\n PublishWidgetPackageResult,\n} from \"./commands/publish.js\";\nexport { statusCommand } from \"./commands/status.js\";\nexport type { StatusCommandOptions } from \"./commands/status.js\";\nexport { validateCommand } from \"./commands/validate.js\";\nexport type { ValidateWidgetOptions } from \"./commands/validate.js\";\nexport {\n WIDGET_CONFIG_FILE,\n formatWidgetConfig,\n loadWidgetConfig,\n mergeWidgetConfig,\n parseWidgetConfigSource,\n resolveWidgetConfigPath,\n validateDropletUuid,\n writeWidgetConfig,\n type FluidWidgetConfig,\n type LoadedWidgetConfig,\n} from \"./utils/config.js\";\nexport {\n DEFAULT_WIDGET_OUT_DIR,\n ROOT_WIDGET_CONFIG_FILE,\n WidgetValidationError,\n formatValidationSuccess,\n resolveWidgetSourceConfig,\n validateDropletWidgetProject,\n withRootWidgetConfigBridge,\n type WidgetValidationResult,\n} from \"./utils/source-package.js\";\nexport { formatValidationErrors } from \"./utils/validation.js\";\nexport type { WidgetCliValidationError } from \"./utils/validation.js\";\n\nfunction addCommandIfMissing(parent: Command, child: Command): void {\n if (findCommand(parent, child.name())) return;\n parent.addCommand(child);\n}\n\nfunction findCommand(parent: Command, name: string): Command | undefined {\n return parent.commands?.find((command) => command.name() === name);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-app/fluid-cli-widget",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "Fluid CLI plugin for standalone widget package workflows",
5
5
  "files": [
6
6
  "dist",
@@ -31,7 +31,7 @@
31
31
  "ora": "^8.0.0",
32
32
  "prompts": "^2.4.2",
33
33
  "@fluid-app/fluid-cli": "0.1.14",
34
- "@fluid-app/fluid-cli-portal": "0.1.49"
34
+ "@fluid-app/fluid-cli-portal": "0.1.51"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "24.10.12",
@@ -34,7 +34,7 @@
34
34
  "engines": {
35
35
  "node": ">=24.0.0"
36
36
  },
37
- "packageManager": "pnpm@10.4.1",
37
+ "packageManager": "pnpm@10.22.0",
38
38
  "pnpm": {
39
39
  "onlyBuiltDependencies": ["esbuild"]
40
40
  }