@hitslop/shots 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/SKILL.md +536 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +113 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/auth.d.ts +7 -0
  7. package/dist/commands/auth.d.ts.map +1 -0
  8. package/dist/commands/auth.js +106 -0
  9. package/dist/commands/auth.js.map +1 -0
  10. package/dist/commands/crop.d.ts +5 -0
  11. package/dist/commands/crop.d.ts.map +1 -0
  12. package/dist/commands/crop.js +32 -0
  13. package/dist/commands/crop.js.map +1 -0
  14. package/dist/commands/default.d.ts +2 -0
  15. package/dist/commands/default.d.ts.map +1 -0
  16. package/dist/commands/default.js +142 -0
  17. package/dist/commands/default.js.map +1 -0
  18. package/dist/commands/feedback.d.ts +2 -0
  19. package/dist/commands/feedback.d.ts.map +1 -0
  20. package/dist/commands/feedback.js +6 -0
  21. package/dist/commands/feedback.js.map +1 -0
  22. package/dist/commands/generate.d.ts +3 -0
  23. package/dist/commands/generate.d.ts.map +1 -0
  24. package/dist/commands/generate.js +5 -0
  25. package/dist/commands/generate.js.map +1 -0
  26. package/dist/commands/init.d.ts +2 -0
  27. package/dist/commands/init.d.ts.map +1 -0
  28. package/dist/commands/init.js +5 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/install.d.ts +2 -0
  31. package/dist/commands/install.d.ts.map +1 -0
  32. package/dist/commands/install.js +13 -0
  33. package/dist/commands/install.js.map +1 -0
  34. package/dist/commands/scrape.d.ts +5 -0
  35. package/dist/commands/scrape.d.ts.map +1 -0
  36. package/dist/commands/scrape.js +5 -0
  37. package/dist/commands/scrape.js.map +1 -0
  38. package/dist/commands/studio.d.ts +7 -0
  39. package/dist/commands/studio.d.ts.map +1 -0
  40. package/dist/commands/studio.js +351 -0
  41. package/dist/commands/studio.js.map +1 -0
  42. package/dist/commands/styles.d.ts +2 -0
  43. package/dist/commands/styles.d.ts.map +1 -0
  44. package/dist/commands/styles.js +25 -0
  45. package/dist/commands/styles.js.map +1 -0
  46. package/dist/commands/view.d.ts +2 -0
  47. package/dist/commands/view.d.ts.map +1 -0
  48. package/dist/commands/view.js +25 -0
  49. package/dist/commands/view.js.map +1 -0
  50. package/dist/core/crop-pipeline.d.ts +28 -0
  51. package/dist/core/crop-pipeline.d.ts.map +1 -0
  52. package/dist/core/crop-pipeline.js +82 -0
  53. package/dist/core/crop-pipeline.js.map +1 -0
  54. package/dist/core/generate.d.ts +20 -0
  55. package/dist/core/generate.d.ts.map +1 -0
  56. package/dist/core/generate.js +388 -0
  57. package/dist/core/generate.js.map +1 -0
  58. package/dist/core/init.d.ts +3 -0
  59. package/dist/core/init.d.ts.map +1 -0
  60. package/dist/core/init.js +77 -0
  61. package/dist/core/init.js.map +1 -0
  62. package/dist/core/mock-generator.d.ts +5 -0
  63. package/dist/core/mock-generator.d.ts.map +1 -0
  64. package/dist/core/mock-generator.js +42 -0
  65. package/dist/core/mock-generator.js.map +1 -0
  66. package/dist/core/prompt-builder.d.ts +15 -0
  67. package/dist/core/prompt-builder.d.ts.map +1 -0
  68. package/dist/core/prompt-builder.js +195 -0
  69. package/dist/core/prompt-builder.js.map +1 -0
  70. package/dist/core/providers/fal.d.ts +3 -0
  71. package/dist/core/providers/fal.d.ts.map +1 -0
  72. package/dist/core/providers/fal.js +53 -0
  73. package/dist/core/providers/fal.js.map +1 -0
  74. package/dist/core/providers/index.d.ts +3 -0
  75. package/dist/core/providers/index.d.ts.map +1 -0
  76. package/dist/core/providers/index.js +2 -0
  77. package/dist/core/providers/index.js.map +1 -0
  78. package/dist/core/providers/managed.d.ts +3 -0
  79. package/dist/core/providers/managed.d.ts.map +1 -0
  80. package/dist/core/providers/managed.js +132 -0
  81. package/dist/core/providers/managed.js.map +1 -0
  82. package/dist/core/providers/openai.d.ts +3 -0
  83. package/dist/core/providers/openai.d.ts.map +1 -0
  84. package/dist/core/providers/openai.js +40 -0
  85. package/dist/core/providers/openai.js.map +1 -0
  86. package/dist/core/providers/replicate.d.ts +3 -0
  87. package/dist/core/providers/replicate.d.ts.map +1 -0
  88. package/dist/core/providers/replicate.js +87 -0
  89. package/dist/core/providers/replicate.js.map +1 -0
  90. package/dist/core/providers/resolve.d.ts +3 -0
  91. package/dist/core/providers/resolve.d.ts.map +1 -0
  92. package/dist/core/providers/resolve.js +41 -0
  93. package/dist/core/providers/resolve.js.map +1 -0
  94. package/dist/core/providers/types.d.ts +29 -0
  95. package/dist/core/providers/types.d.ts.map +1 -0
  96. package/dist/core/providers/types.js +2 -0
  97. package/dist/core/providers/types.js.map +1 -0
  98. package/dist/core/scraper.d.ts +22 -0
  99. package/dist/core/scraper.d.ts.map +1 -0
  100. package/dist/core/scraper.js +138 -0
  101. package/dist/core/scraper.js.map +1 -0
  102. package/dist/core/walkthrough.d.ts +10 -0
  103. package/dist/core/walkthrough.d.ts.map +1 -0
  104. package/dist/core/walkthrough.js +116 -0
  105. package/dist/core/walkthrough.js.map +1 -0
  106. package/dist/schema/config.d.ts +45 -0
  107. package/dist/schema/config.d.ts.map +1 -0
  108. package/dist/schema/config.js +36 -0
  109. package/dist/schema/config.js.map +1 -0
  110. package/dist/schema/manifest.d.ts +43 -0
  111. package/dist/schema/manifest.d.ts.map +1 -0
  112. package/dist/schema/manifest.js +5 -0
  113. package/dist/schema/manifest.js.map +1 -0
  114. package/dist/schema/style-meta.d.ts +8 -0
  115. package/dist/schema/style-meta.d.ts.map +1 -0
  116. package/dist/schema/style-meta.js +2 -0
  117. package/dist/schema/style-meta.js.map +1 -0
  118. package/dist/styles/installer.d.ts +2 -0
  119. package/dist/styles/installer.d.ts.map +1 -0
  120. package/dist/styles/installer.js +43 -0
  121. package/dist/styles/installer.js.map +1 -0
  122. package/dist/styles/registry.d.ts +20 -0
  123. package/dist/styles/registry.d.ts.map +1 -0
  124. package/dist/styles/registry.js +96 -0
  125. package/dist/styles/registry.js.map +1 -0
  126. package/dist/util/auth-store.d.ts +12 -0
  127. package/dist/util/auth-store.d.ts.map +1 -0
  128. package/dist/util/auth-store.js +46 -0
  129. package/dist/util/auth-store.js.map +1 -0
  130. package/dist/util/id.d.ts +2 -0
  131. package/dist/util/id.d.ts.map +1 -0
  132. package/dist/util/id.js +14 -0
  133. package/dist/util/id.js.map +1 -0
  134. package/dist/util/json.d.ts +3 -0
  135. package/dist/util/json.d.ts.map +1 -0
  136. package/dist/util/json.js +9 -0
  137. package/dist/util/json.js.map +1 -0
  138. package/dist/util/open.d.ts +2 -0
  139. package/dist/util/open.d.ts.map +1 -0
  140. package/dist/util/open.js +21 -0
  141. package/dist/util/open.js.map +1 -0
  142. package/dist/util/paths.d.ts +9 -0
  143. package/dist/util/paths.d.ts.map +1 -0
  144. package/dist/util/paths.js +21 -0
  145. package/dist/util/paths.js.map +1 -0
  146. package/package.json +37 -0
  147. package/studio/assets/index-BgiuT_Mv.css +1 -0
  148. package/studio/assets/index-DnN633_x.js +9 -0
  149. package/studio/index.html +13 -0
  150. package/styles/clean-premium/meta.json +7 -0
  151. package/styles/clean-premium/prompt.md +16 -0
@@ -0,0 +1,41 @@
1
+ import { createOpenAIProvider } from "./openai.js";
2
+ import { createFalProvider } from "./fal.js";
3
+ import { createReplicateProvider } from "./replicate.js";
4
+ import { createManagedProvider } from "./managed.js";
5
+ const PROVIDER_FACTORIES = {
6
+ openai: createOpenAIProvider,
7
+ fal: createFalProvider,
8
+ replicate: createReplicateProvider,
9
+ managed: createManagedProvider,
10
+ };
11
+ const AUTO_DETECT_ORDER = [
12
+ { key: "OPENAI_API_KEY", provider: "openai" },
13
+ { key: "FAL_KEY", provider: "fal" },
14
+ { key: "REPLICATE_API_TOKEN", provider: "replicate" },
15
+ ];
16
+ export function resolveProvider(explicit) {
17
+ if (explicit) {
18
+ const name = explicit;
19
+ const factory = PROVIDER_FACTORIES[name];
20
+ if (!factory) {
21
+ throw new Error(`Unknown provider "${explicit}". Valid options: ${Object.keys(PROVIDER_FACTORIES).join(", ")}`);
22
+ }
23
+ return factory();
24
+ }
25
+ // Auto-detect based on available env vars
26
+ for (const { key, provider } of AUTO_DETECT_ORDER) {
27
+ if (process.env[key]) {
28
+ console.log(`Auto-detected provider: ${provider} (${key} is set)`);
29
+ return PROVIDER_FACTORIES[provider]();
30
+ }
31
+ }
32
+ throw new Error([
33
+ "No API key found. Set one of the following environment variables:",
34
+ " OPENAI_API_KEY — OpenAI (direct, exact dimensions)",
35
+ " FAL_KEY — fal.ai (proxy, exact dimensions, often cheaper)",
36
+ " REPLICATE_API_TOKEN — Replicate (proxy, aspect ratio presets)",
37
+ "",
38
+ "Or use --mock for testing without an API key.",
39
+ ].join("\n"));
40
+ }
41
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/core/providers/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,kBAAkB,GAA8C;IACpE,MAAM,EAAE,oBAAoB;IAC5B,GAAG,EAAE,iBAAiB;IACtB,SAAS,EAAE,uBAAuB;IAClC,OAAO,EAAE,qBAAqB;CAC/B,CAAC;AAEF,MAAM,iBAAiB,GAAmD;IACxE,EAAE,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,EAAE;IAC7C,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE;IACnC,EAAE,GAAG,EAAE,qBAAqB,EAAE,QAAQ,EAAE,WAAW,EAAE;CACtD,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,QAAwB,CAAC;QACtC,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,qBAAqB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/F,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,0CAA0C;IAC1C,KAAK,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,iBAAiB,EAAE,CAAC;QAClD,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,2BAA2B,QAAQ,KAAK,GAAG,UAAU,CAAC,CAAC;YACnE,OAAO,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb;QACE,mEAAmE;QACnE,yDAAyD;QACzD,uEAAuE;QACvE,iEAAiE;QACjE,EAAE;QACF,+CAA+C;KAChD,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ export type ProviderName = "openai" | "fal" | "replicate" | "managed";
2
+ export type ManagedBackendProvider = "openai" | "fal";
3
+ export interface ReferenceImage {
4
+ buffer: Buffer;
5
+ filename: string;
6
+ mimeType: string;
7
+ }
8
+ export interface GenerateInput {
9
+ prompt: string;
10
+ references: ReferenceImage[];
11
+ quality: "high" | "medium" | "low";
12
+ width: number;
13
+ height: number;
14
+ panelCount?: number;
15
+ platform?: "iphone" | "ipad" | "android";
16
+ managedProvider?: ManagedBackendProvider;
17
+ n: 1;
18
+ }
19
+ export interface GenerateOutput {
20
+ imageBuffer: Buffer;
21
+ actualWidth: number;
22
+ actualHeight: number;
23
+ provider: ProviderName;
24
+ }
25
+ export interface ImageProvider {
26
+ readonly name: ProviderName;
27
+ generate(input: GenerateInput): Promise<GenerateOutput>;
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/providers/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,KAAK,GAAG,WAAW,GAAG,SAAS,CAAC;AACtE,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,CAAC,EAAE,CAAC,CAAC;CACN;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACzD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ export declare function parseAppStoreId(url: string): number;
2
+ interface ScrapedApp {
3
+ title: string;
4
+ description: string;
5
+ icon: string;
6
+ genres: string[];
7
+ genreIds: string[];
8
+ developer: string;
9
+ version: string;
10
+ releaseNotes: string;
11
+ score: number;
12
+ reviews: number;
13
+ screenshots: string[];
14
+ url: string;
15
+ }
16
+ export declare function scrapeAppStore(url: string, country?: string): Promise<ScrapedApp>;
17
+ export declare function scrapeAndUpdateConfig(url: string, options?: {
18
+ downloadScreenshots?: boolean;
19
+ country?: string;
20
+ }): Promise<void>;
21
+ export {};
22
+ //# sourceMappingURL=scraper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scraper.d.ts","sourceRoot":"","sources":["../../src/core/scraper.ts"],"names":[],"mappings":"AAwBA,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAInD;AAED,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAID,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,SAAO,GACb,OAAO,CAAC,UAAU,CAAC,CA0CrB;AAyBD,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAChE,OAAO,CAAC,IAAI,CAAC,CAgFf"}
@@ -0,0 +1,138 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readJson, writeJson } from "../util/json.js";
4
+ import { shotsDir } from "../util/paths.js";
5
+ const ITUNES_LOOKUP = "https://itunes.apple.com/lookup";
6
+ export function parseAppStoreId(url) {
7
+ const match = url.match(/\/id(\d+)/);
8
+ if (!match)
9
+ throw new Error("Invalid App Store URL — expected /id{number}");
10
+ return parseInt(match[1], 10);
11
+ }
12
+ const SHOTS_API_URL = process.env.SHOTS_API_URL || "http://localhost:3000";
13
+ export async function scrapeAppStore(url, country = "us") {
14
+ const id = parseAppStoreId(url);
15
+ const app = await fetchiTunesLookup(id, country);
16
+ const result = {
17
+ title: app.trackName ?? "",
18
+ description: app.description ?? "",
19
+ icon: app.artworkUrl512 ?? "",
20
+ genres: app.genres ?? [],
21
+ genreIds: app.genreIds ?? [],
22
+ developer: app.artistName ?? "",
23
+ version: app.version ?? "",
24
+ releaseNotes: app.releaseNotes ?? "",
25
+ score: app.averageUserRating ?? 0,
26
+ reviews: app.userRatingCount ?? 0,
27
+ screenshots: app.screenshotUrls ?? [],
28
+ url: app.trackViewUrl ?? url,
29
+ };
30
+ // Fallback: if iTunes API returned no screenshots, try the web server endpoint.
31
+ if (result.screenshots.length === 0) {
32
+ try {
33
+ const apiUrl = `${SHOTS_API_URL}/api/screenshots/${id}?country=${country}`;
34
+ const fallbackRes = await fetch(apiUrl);
35
+ if (fallbackRes.ok) {
36
+ const fallbackData = (await fallbackRes.json());
37
+ if (fallbackData.screenshots?.length > 0) {
38
+ result.screenshots = fallbackData.screenshots;
39
+ console.log(`Fetched ${fallbackData.screenshots.length} screenshots from web server (iTunes API had none)`);
40
+ }
41
+ }
42
+ }
43
+ catch {
44
+ // Backend unreachable — continue with empty screenshots
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+ async function fetchiTunesLookup(appId, country = "us") {
50
+ const params = new URLSearchParams({
51
+ id: String(appId),
52
+ country,
53
+ entity: "software",
54
+ });
55
+ const res = await fetch(`${ITUNES_LOOKUP}?${params}`);
56
+ if (!res.ok) {
57
+ throw new Error(`iTunes API returned HTTP ${res.status}`);
58
+ }
59
+ const data = (await res.json());
60
+ if (!data.results?.length) {
61
+ throw new Error(`App ${appId} not found in iTunes (country: ${country})`);
62
+ }
63
+ return data.results[0];
64
+ }
65
+ export async function scrapeAndUpdateConfig(url, options = {}) {
66
+ const dir = shotsDir();
67
+ const configPath = path.join(dir, "config.json");
68
+ let config;
69
+ try {
70
+ config = await readJson(configPath);
71
+ }
72
+ catch {
73
+ console.error("Error: .shots/config.json not found. Run `npx -y @hitslop/shots@latest init` to initialize first.");
74
+ process.exit(1);
75
+ }
76
+ console.log(`Scraping App Store data for: ${url}\n`);
77
+ const app = await scrapeAppStore(url, options.country);
78
+ // Update config with scraped data
79
+ config.appName = app.title;
80
+ config.appStoreUrl = app.url;
81
+ config.aso = {
82
+ title: app.title.slice(0, 30),
83
+ subtitle: "",
84
+ description: app.description.slice(0, 4000),
85
+ keywords: "",
86
+ genres: app.genres,
87
+ developer: app.developer,
88
+ version: app.version,
89
+ releaseNotes: app.releaseNotes,
90
+ };
91
+ config.ratings = {
92
+ score: Math.round(app.score * 10) / 10,
93
+ reviewCount: app.reviews,
94
+ };
95
+ config.scrapedAssets = {
96
+ iconUrl: app.icon,
97
+ screenshotUrls: app.screenshots,
98
+ scrapedAt: new Date().toISOString(),
99
+ };
100
+ await writeJson(configPath, config);
101
+ // Print summary
102
+ console.log(`App: ${app.title}`);
103
+ console.log(`Developer: ${app.developer}`);
104
+ console.log(`Version: ${app.version}`);
105
+ console.log(`Rating: ${config.ratings.score}/5 (${app.reviews.toLocaleString()} reviews)`);
106
+ console.log(`Genres: ${app.genres.join(", ")}`);
107
+ console.log(`Screenshots: ${app.screenshots.length} found`);
108
+ console.log("");
109
+ console.log("ASO field char counts:");
110
+ console.log(` Title: ${config.aso.title.length}/30`);
111
+ console.log(` Description: ${config.aso.description.length}/4000`);
112
+ console.log("");
113
+ // Download screenshots if requested
114
+ if (options.downloadScreenshots && app.screenshots.length > 0) {
115
+ const screenshotDir = path.join(dir, "app-screenshots");
116
+ await fs.mkdir(screenshotDir, { recursive: true });
117
+ console.log("Downloading screenshots...");
118
+ for (let i = 0; i < app.screenshots.length; i++) {
119
+ const screenshotUrl = app.screenshots[i];
120
+ try {
121
+ const response = await fetch(screenshotUrl);
122
+ if (!response.ok)
123
+ throw new Error(`HTTP ${response.status}`);
124
+ const buffer = Buffer.from(await response.arrayBuffer());
125
+ const ext = path.extname(new URL(screenshotUrl).pathname) || ".png";
126
+ const filename = `app-screenshot-${i + 1}${ext}`;
127
+ await fs.writeFile(path.join(screenshotDir, filename), buffer);
128
+ console.log(` Downloaded: ${filename}`);
129
+ }
130
+ catch (err) {
131
+ console.warn(` Failed to download screenshot ${i + 1}: ${err}`);
132
+ }
133
+ }
134
+ console.log("");
135
+ }
136
+ console.log("Config updated: .shots/config.json");
137
+ }
138
+ //# sourceMappingURL=scraper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scraper.js","sourceRoot":"","sources":["../../src/core/scraper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Config } from "../schema/config.js";
2
+ export interface WalkthroughResult {
3
+ config: Partial<Config>;
4
+ downloadScreenshots: boolean;
5
+ screenshotCount: number;
6
+ featuresToHighlight: string;
7
+ aestheticGuidance: string;
8
+ }
9
+ export declare function runWalkthrough(): Promise<WalkthroughResult>;
10
+ //# sourceMappingURL=walkthrough.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walkthrough.d.ts","sourceRoot":"","sources":["../../src/core/walkthrough.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAUD,wBAAsB,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAmIjE"}
@@ -0,0 +1,116 @@
1
+ import readline from "node:readline/promises";
2
+ import { stdin, stdout } from "node:process";
3
+ import chalk from "chalk";
4
+ import { scrapeAppStore } from "./scraper.js";
5
+ async function ask(rl, question) {
6
+ const answer = await rl.question(chalk.cyan(question) + " ");
7
+ return answer.trim();
8
+ }
9
+ export async function runWalkthrough() {
10
+ const rl = readline.createInterface({ input: stdin, output: stdout });
11
+ try {
12
+ console.log(chalk.bold("\nWelcome to Shots!\n"));
13
+ console.log(chalk.dim("Let's set up your project.\n"));
14
+ // 0. Ensure OPENAI_API_KEY is available (needed for image generation)
15
+ if (!process.env.OPENAI_API_KEY) {
16
+ console.log(chalk.yellow(" OPENAI_API_KEY not found in environment."));
17
+ console.log(chalk.dim(" This key is needed to generate screenshots with OpenAI GPT Image."));
18
+ console.log(chalk.dim(" Get one at https://platform.openai.com/api-keys\n"));
19
+ const key = await ask(rl, "OPENAI_API_KEY (or Enter to skip):");
20
+ if (key) {
21
+ process.env.OPENAI_API_KEY = key;
22
+ console.log(chalk.green(" Key set for this session.\n"));
23
+ }
24
+ else {
25
+ console.log(chalk.dim(" Skipped — you can still use --mock for testing.\n"));
26
+ }
27
+ }
28
+ // 1. App name (required)
29
+ let appName = "";
30
+ while (!appName) {
31
+ appName = await ask(rl, "App name:");
32
+ if (!appName) {
33
+ console.log(chalk.yellow(" App name is required."));
34
+ }
35
+ }
36
+ // 2. App Store URL (optional)
37
+ const appStoreUrl = await ask(rl, "App Store URL (leave blank to skip):");
38
+ const config = { appName };
39
+ let downloadScreenshots = false;
40
+ if (appStoreUrl) {
41
+ // Scrape App Store data
42
+ console.log(chalk.dim("\nScraping App Store data...\n"));
43
+ try {
44
+ const app = await scrapeAppStore(appStoreUrl);
45
+ config.appName = app.title || appName;
46
+ config.appStoreUrl = app.url;
47
+ config.aso = {
48
+ title: app.title.slice(0, 30),
49
+ subtitle: "",
50
+ description: app.description.slice(0, 4000),
51
+ keywords: "",
52
+ genres: app.genres,
53
+ developer: app.developer,
54
+ version: app.version,
55
+ releaseNotes: app.releaseNotes,
56
+ };
57
+ config.ratings = {
58
+ score: Math.round(app.score * 10) / 10,
59
+ reviewCount: app.reviews,
60
+ };
61
+ config.scrapedAssets = {
62
+ iconUrl: app.icon,
63
+ screenshotUrls: app.screenshots,
64
+ scrapedAt: new Date().toISOString(),
65
+ };
66
+ console.log(` ${chalk.bold(app.title)} by ${app.developer}`);
67
+ console.log(` ${config.ratings.score}/5 (${app.reviews.toLocaleString()} reviews)`);
68
+ console.log(` ${app.screenshots.length} screenshots found`);
69
+ if (app.screenshots.length > 0) {
70
+ downloadScreenshots = true;
71
+ }
72
+ }
73
+ catch (err) {
74
+ console.log(chalk.yellow(` Could not scrape: ${err.message}`));
75
+ console.log(chalk.dim(" You can run `npx -y @hitslop/shots@latest scrape <url>` later.\n"));
76
+ config.appStoreUrl = appStoreUrl;
77
+ }
78
+ }
79
+ // Always ask positioning questions (optional — press Enter to skip)
80
+ const positioning = await ask(rl, "What makes your app different? (optional)");
81
+ const targetAudience = await ask(rl, "Who is your app for? (optional)");
82
+ if (positioning)
83
+ config.positioning = positioning;
84
+ if (targetAudience)
85
+ config.targetAudience = targetAudience;
86
+ // Screenshot count
87
+ const countRaw = await ask(rl, "How many screenshots? (1-10, default 3):");
88
+ let screenshotCount = 3;
89
+ if (countRaw) {
90
+ const parsed = parseInt(countRaw, 10);
91
+ if (parsed >= 1 && parsed <= 10) {
92
+ screenshotCount = parsed;
93
+ }
94
+ else {
95
+ console.log(chalk.yellow(" Invalid number — using default (3)."));
96
+ }
97
+ }
98
+ // Features to highlight
99
+ const featuresToHighlight = await ask(rl, "What features or screens should we highlight? (optional)");
100
+ // Aesthetic guidance
101
+ const aestheticGuidance = await ask(rl, "Any visual style or aesthetic guidance? (optional)");
102
+ if (aestheticGuidance)
103
+ config.visualTone = aestheticGuidance;
104
+ return {
105
+ config,
106
+ downloadScreenshots,
107
+ screenshotCount,
108
+ featuresToHighlight,
109
+ aestheticGuidance,
110
+ };
111
+ }
112
+ finally {
113
+ rl.close();
114
+ }
115
+ }
116
+ //# sourceMappingURL=walkthrough.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walkthrough.js","sourceRoot":"","sources":["../../src/core/walkthrough.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export interface Benefit {
2
+ headline: string;
3
+ subtitle: string;
4
+ approach: "moment" | "outcome" | "pain";
5
+ panelType: string;
6
+ feature: string;
7
+ arcPosition: "hero" | "differentiator" | "core" | "trust" | "closer";
8
+ }
9
+ export interface Config {
10
+ appName: string;
11
+ appStoreUrl: string;
12
+ devices?: Array<"iphone" | "ipad" | "android">;
13
+ positioning: string;
14
+ targetAudience: string;
15
+ visualTone: string;
16
+ brandColors: {
17
+ primary: string;
18
+ secondary: string;
19
+ accent: string;
20
+ text: string;
21
+ };
22
+ aso: {
23
+ title: string;
24
+ subtitle: string;
25
+ description: string;
26
+ keywords: string;
27
+ genres: string[];
28
+ developer: string;
29
+ version: string;
30
+ releaseNotes: string;
31
+ };
32
+ ratings: {
33
+ score: number;
34
+ reviewCount: number;
35
+ };
36
+ scrapedAssets: {
37
+ iconUrl: string;
38
+ screenshotUrls: string[];
39
+ scrapedAt: string;
40
+ };
41
+ activeStyle: string;
42
+ benefits: Benefit[];
43
+ }
44
+ export declare const DEFAULT_CONFIG: Config;
45
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/schema/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;CACtE;AAED,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,GAAG,EAAE;QACH,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,aAAa,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,MAkC5B,CAAC"}
@@ -0,0 +1,36 @@
1
+ export const DEFAULT_CONFIG = {
2
+ appName: "My App",
3
+ appStoreUrl: "",
4
+ devices: ["iphone"],
5
+ positioning: "",
6
+ targetAudience: "",
7
+ visualTone: "clean, modern, premium",
8
+ brandColors: {
9
+ primary: "#1a1a2e",
10
+ secondary: "#16213e",
11
+ accent: "#0f969c",
12
+ text: "#f5f5f5",
13
+ },
14
+ aso: {
15
+ title: "",
16
+ subtitle: "",
17
+ description: "",
18
+ keywords: "",
19
+ genres: [],
20
+ developer: "",
21
+ version: "",
22
+ releaseNotes: "",
23
+ },
24
+ ratings: {
25
+ score: 0,
26
+ reviewCount: 0,
27
+ },
28
+ scrapedAssets: {
29
+ iconUrl: "",
30
+ screenshotUrls: [],
31
+ scrapedAt: "",
32
+ },
33
+ activeStyle: "",
34
+ benefits: [],
35
+ };
36
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/schema/config.ts"],"names":[],"mappings":"AA6CA,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,OAAO,EAAE,QAAQ;IACjB,WAAW,EAAE,EAAE;IACf,OAAO,EAAE,CAAC,QAAQ,CAAC;IACnB,WAAW,EAAE,EAAE;IACf,cAAc,EAAE,EAAE;IAClB,UAAU,EAAE,wBAAwB;IACpC,WAAW,EAAE;QACX,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,SAAS;KAChB;IACD,GAAG,EAAE;QACH,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,EAAE;KACjB;IACD,OAAO,EAAE;QACP,KAAK,EAAE,CAAC;QACR,WAAW,EAAE,CAAC;KACf;IACD,aAAa,EAAE;QACb,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,EAAE;QAClB,SAAS,EAAE,EAAE;KACd;IACD,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,EAAE;CACb,CAAC"}
@@ -0,0 +1,43 @@
1
+ export interface FeedbackEntry {
2
+ from: "user" | "agent";
3
+ text: string;
4
+ at: string;
5
+ }
6
+ export interface ShotDimensions {
7
+ platform?: "iphone" | "ipad" | "android";
8
+ compositeWidth: number;
9
+ compositeHeight: number;
10
+ targetWidth: number;
11
+ targetHeight: number;
12
+ }
13
+ export interface Shot {
14
+ id: string;
15
+ compositeFile: string;
16
+ screenshotFiles: string[];
17
+ prompt: string;
18
+ userPrompt?: string;
19
+ runDir?: string;
20
+ promptFile?: string;
21
+ referencesFile?: string;
22
+ feedbackFile?: string;
23
+ metadataFile?: string;
24
+ model: string;
25
+ quality: string;
26
+ referenceImages: string[];
27
+ feedback: FeedbackEntry[];
28
+ parentId: string | null;
29
+ provider?: string;
30
+ managedProvider?: "openai" | "fal";
31
+ mode?: string;
32
+ styleName?: string;
33
+ setName?: string;
34
+ panelCount?: number;
35
+ dimensions?: ShotDimensions;
36
+ createdAt: string;
37
+ }
38
+ export interface Manifest {
39
+ version: number;
40
+ shots: Shot[];
41
+ }
42
+ export declare const DEFAULT_MANIFEST: Manifest;
43
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/schema/manifest.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,eAAO,MAAM,gBAAgB,EAAE,QAG9B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export const DEFAULT_MANIFEST = {
2
+ version: 2,
3
+ shots: [],
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/schema/manifest.ts"],"names":[],"mappings":"AA6CA,MAAM,CAAC,MAAM,gBAAgB,GAAa;IACxC,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,EAAE;CACV,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface StyleMeta {
2
+ name: string;
3
+ displayName: string;
4
+ description: string;
5
+ visualTone: string;
6
+ panelTypes: string[];
7
+ }
8
+ //# sourceMappingURL=style-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-meta.d.ts","sourceRoot":"","sources":["../../src/schema/style-meta.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=style-meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-meta.js","sourceRoot":"","sources":["../../src/schema/style-meta.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function installStyle(styleName: string): Promise<void>;
2
+ //# sourceMappingURL=installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/styles/installer.ts"],"names":[],"mappings":"AAoBA,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BnE"}
@@ -0,0 +1,43 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readJson, writeJson } from "../util/json.js";
4
+ import { shotsDir, bundledStylesPath } from "../util/paths.js";
5
+ async function copyDir(src, dest) {
6
+ await fs.mkdir(dest, { recursive: true });
7
+ const entries = await fs.readdir(src, { withFileTypes: true });
8
+ for (const entry of entries) {
9
+ const srcPath = path.join(src, entry.name);
10
+ const destPath = path.join(dest, entry.name);
11
+ if (entry.isDirectory()) {
12
+ await copyDir(srcPath, destPath);
13
+ }
14
+ else {
15
+ await fs.copyFile(srcPath, destPath);
16
+ }
17
+ }
18
+ }
19
+ export async function installStyle(styleName) {
20
+ const dir = shotsDir();
21
+ const bundledDir = path.join(bundledStylesPath(), styleName);
22
+ const destDir = path.join(dir, "styles", styleName);
23
+ // Verify bundled style exists
24
+ try {
25
+ await fs.access(bundledDir);
26
+ }
27
+ catch {
28
+ throw new Error(`Style "${styleName}" not found in bundled styles. Run \`npx -y @hitslop/shots@latest styles\` to see available styles.`);
29
+ }
30
+ // Copy to .shots/styles/
31
+ await copyDir(bundledDir, destDir);
32
+ // Update activeStyle in config
33
+ const configPath = path.join(dir, "config.json");
34
+ try {
35
+ const config = await readJson(configPath);
36
+ config.activeStyle = styleName;
37
+ await writeJson(configPath, config);
38
+ }
39
+ catch {
40
+ // Config doesn't exist yet — that's okay
41
+ }
42
+ }
43
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/styles/installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE/D,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB;IAClD,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAEpD,8BAA8B;IAC9B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,UAAU,SAAS,qGAAqG,CACzH,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,MAAM,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAEnC,+BAA+B;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAS,UAAU,CAAC,CAAC;QAClD,MAAM,CAAC,WAAW,GAAG,SAAS,CAAC;QAC/B,MAAM,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;IAC3C,CAAC;AACH,CAAC"}