@kittl/cli 0.0.1 → 0.0.2

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.
@@ -0,0 +1,699 @@
1
+ import {
2
+ createExtensionDraftVersion
3
+ } from "../../chunk-GJPVFQRF.js";
4
+ import {
5
+ formatHttpClientError,
6
+ internalConfigExists,
7
+ internalConfigPath,
8
+ isSystemError,
9
+ writeInternalConfig
10
+ } from "../../chunk-XU2ZHSRY.js";
11
+ import {
12
+ useTerminalWidth
13
+ } from "../../chunk-EKU4DKQK.js";
14
+ import {
15
+ colors,
16
+ layoutStyles,
17
+ spacing,
18
+ textStyles
19
+ } from "../../chunk-3BPIJLS7.js";
20
+ import {
21
+ BaseCommand,
22
+ CLI_CONFIG,
23
+ isSubmitKey
24
+ } from "../../chunk-TK44DTSK.js";
25
+
26
+ // src/commands/app/init.ts
27
+ import { join as join2 } from "node:path";
28
+
29
+ // src/core/scaffolder.ts
30
+ import { access, mkdir, writeFile } from "node:fs/promises";
31
+ import { join } from "node:path";
32
+
33
+ // src/core/templates.ts
34
+ var DEFAULT_TERMS_URL = "https://example.com/terms";
35
+ var DEFAULT_PRIVACY_URL = "https://example.com/privacy";
36
+ var DEFAULT_MAIN_APP_PANEL_PATH = "index.html";
37
+ function packageNameFromExtensionName(name) {
38
+ const slug = name.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
39
+ return slug.length > 0 ? slug : "kittl-extension";
40
+ }
41
+ function initialExtensionManifest(displayName) {
42
+ const value = displayName.trim() || "Unnamed extension";
43
+ return {
44
+ displayName: value,
45
+ icon: "icon.svg",
46
+ tagline: `${value} for Kittl.`,
47
+ installPage: {
48
+ description: `Install ${value} to use this extension in Kittl.`,
49
+ coverImage: "icon.svg",
50
+ termsAndConditionsLink: DEFAULT_TERMS_URL,
51
+ privacyPolicyLink: DEFAULT_PRIVACY_URL
52
+ },
53
+ config: {
54
+ // New projects start without privileged scopes and can opt into them later.
55
+ scopes: ["design:state:read", "design:state:write"],
56
+ embed: {
57
+ mainAppPanel: {
58
+ path: DEFAULT_MAIN_APP_PANEL_PATH
59
+ }
60
+ }
61
+ }
62
+ };
63
+ }
64
+ function manifestTemplate(displayName) {
65
+ return `${JSON.stringify(
66
+ initialExtensionManifest(displayName),
67
+ null,
68
+ // replacer: none - default serialization
69
+ 2
70
+ // space: 2-space indent + line breaks
71
+ )}
72
+ `;
73
+ }
74
+ function packageJsonTemplate(displayName) {
75
+ return `${JSON.stringify(
76
+ {
77
+ name: packageNameFromExtensionName(displayName),
78
+ private: true,
79
+ version: "0.0.0",
80
+ type: "module",
81
+ scripts: {
82
+ dev: "vite",
83
+ build: "vite build",
84
+ preview: "vite preview"
85
+ },
86
+ dependencies: {
87
+ "@kittl/sdk": "^0.0.1"
88
+ },
89
+ devDependencies: {
90
+ vite: "^5.0.0"
91
+ }
92
+ },
93
+ null,
94
+ // replacer: none, default serialization
95
+ 2
96
+ // space: 2-space indent + line breaks
97
+ )}
98
+ `;
99
+ }
100
+ function viteConfigTemplate() {
101
+ return `import { defineConfig } from 'vite';
102
+
103
+ export default defineConfig({
104
+ server: {
105
+ port: ${CLI_CONFIG.scaffoldViteDevPort},
106
+ },
107
+ publicDir: 'public',
108
+ build: {
109
+ outDir: 'dist',
110
+ },
111
+ });
112
+ `;
113
+ }
114
+ function indexHtmlTemplate(displayName) {
115
+ return `<!DOCTYPE html>
116
+ <html lang="en">
117
+ <head>
118
+ <meta charset="UTF-8" />
119
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
120
+ <title>${displayName}</title>
121
+ </head>
122
+ <body>
123
+ <div id="app">
124
+ <h1>Hello Kittl!</h1>
125
+ <p>Welcome to your new extension: ${displayName}</p>
126
+ <button id="doSomething">Do some magic!</button>
127
+ </div>
128
+ <script type="module" src="/src/index.ts"></script>
129
+ </body>
130
+ </html>
131
+ `;
132
+ }
133
+ function indexTypescriptTemplate(displayName) {
134
+ return `import { kittl } from '@kittl/sdk';
135
+
136
+ document.getElementById('doSomething')?.addEventListener('click', async () => {
137
+ await kittl.design.text.addText({
138
+ text: 'Hello ${displayName} from Kittl SDK!',
139
+ position: {
140
+ relative: {
141
+ to: 'viewport',
142
+ location: 'center',
143
+ },
144
+ },
145
+ size: {
146
+ height: 100,
147
+ width: 400,
148
+ },
149
+ });
150
+ });
151
+ `;
152
+ }
153
+ var ICON_SVG_TEMPLATE = '<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 1024 1024"><rect width="1024" height="1024" rx="225" fill="#DEFE00"/><path fill="#080B10" transform="translate(581,235)" d="M0 0 C-7.93 26.81 -15.97 53.57 -24.12 80.31 C-24.35 81.04 -24.57 81.76 -24.79 82.5 C-25.92 86.19 -27.04 89.88 -28.17 93.57 C-28.5 94.67 -28.5 94.67 -28.85 95.8 C-29.3 97.29 -29.76 98.78 -30.21 100.27 C-35.39 117.26 -40.54 134.25 -45.69 151.25 C-46.09 152.58 -46.49 153.92 -46.9 155.25 C-47.68 157.83 -48.46 160.4 -49.24 162.98 C-50 165.48 -50.75 167.98 -51.51 170.48 C-53.37 176.6 -55.22 182.72 -57.06 188.84 C-57.99 191.91 -58.92 194.99 -59.84 198.06 C-60.29 199.54 -60.74 201.02 -61.18 202.51 C-61.8 204.56 -62.42 206.61 -63.04 208.67 C-63.4 209.84 -63.75 211.02 -64.12 212.23 C-65 215 -65 215 -66 217 C-31.32 207.79 -0.81 191.01 25.38 166.43 C27.48 164.48 29.6 162.63 31.81 160.81 C34.85 158.23 37.44 155.4 40.01 152.35 C41.45 150.66 42.91 148.99 44.39 147.34 C73.97 114.11 93.03 70.13 98 26 C113.47 23.05 128.96 20.3 144.5 17.74 C155.19 15.98 165.86 14.18 176.54 12.36 C178.95 11.95 181.37 11.54 183.79 11.13 C184.59 10.99 185.4 10.85 186.23 10.71 C187.86 10.44 189.49 10.16 191.13 9.88 C195.22 9.18 199.31 8.49 203.41 7.79 C207.32 7.12 211.22 6.45 215.13 5.79 C216.6 5.54 218.06 5.29 219.52 5.04 C221.55 4.69 223.57 4.35 225.6 4.01 C226.74 3.81 227.89 3.62 229.07 3.42 C232 3 232 3 236 3 C236.16 11.12 235.76 19 234.75 27.06 C234.62 28.15 234.48 29.23 234.34 30.35 C226.13 93.59 192.52 153.61 144 195 C143.05 195.84 142.11 196.67 141.13 197.53 C115.92 219.57 86.53 236.49 56 250 C55.6 259.92 56.83 269.35 58.31 279.13 C58.55 280.7 58.78 282.28 59.01 283.86 C59.57 287.61 60.14 291.36 60.71 295.11 C61.08 297.53 61.43 299.95 61.79 302.37 C64.96 323.35 70.45 343.85 77 364 C77.44 365.35 77.87 366.69 78.31 368.04 C87.9 397.66 98.51 426.64 111.58 454.91 C112.79 457.54 113.99 460.18 115.18 462.82 C120.11 473.66 125.8 484.06 131.59 494.45 C132.83 496.69 134.06 498.93 135.28 501.18 C144 517.14 153.68 532.57 165 546.81 C165.51 547.45 166.02 548.1 166.55 548.76 C167 549.32 167.45 549.87 167.92 550.45 C169 552 169 552 170 555 C169.42 555.28 168.83 555.56 168.23 555.85 C154.35 562.49 140.48 569.18 126.63 575.9 C115.75 581.18 104.87 586.45 93.98 591.7 C86.76 595.18 79.56 598.67 72.36 602.17 C66.13 605.19 59.89 608.21 53.66 611.23 C51.35 612.34 49.05 613.46 46.75 614.58 C44.04 615.89 41.33 617.2 38.63 618.5 C37.87 618.87 37.12 619.24 36.34 619.61 C33.37 621.03 31.33 622 28 622 C7.88 582.22 -1.64 541.14 -9.53 497.6 C-9.84 495.9 -10.14 494.21 -10.45 492.52 C-11.93 484.45 -13.35 476.42 -14.12 468.25 C-14.61 462.97 -14.61 462.97 -15.48 457.76 C-16.15 454.21 -16.43 450.66 -16.72 447.07 C-16.78 446.31 -16.84 445.56 -16.91 444.78 C-17.11 442.37 -17.3 439.97 -17.5 437.56 C-17.7 435.16 -17.89 432.76 -18.09 430.36 C-18.21 428.87 -18.34 427.38 -18.45 425.89 C-18.7 422.94 -18.99 420.04 -19.49 417.13 C-19.98 414.12 -20.26 411.19 -20.46 408.15 C-20.54 407.02 -20.62 405.88 -20.7 404.71 C-20.78 403.49 -20.86 402.26 -20.94 401 C-21.06 399.08 -21.06 399.08 -21.19 397.11 C-21.47 392.93 -21.74 388.75 -22 384.56 C-22.05 383.85 -22.09 383.14 -22.14 382.4 C-24.41 346.58 -25.21 310.89 -25 275 C-26.05 275.24 -27.1 275.48 -28.19 275.73 C-47.22 279.84 -66.64 281.24 -86 283 C-94.42 309.89 -102.59 336.84 -110.71 363.82 C-112.14 368.58 -113.57 373.34 -115 378.09 C-115.36 379.3 -115.36 379.3 -115.73 380.52 C-122.46 402.89 -129.26 425.23 -136.06 447.57 C-137.03 450.75 -137.99 453.93 -138.96 457.11 C-139.6 459.21 -140.24 461.32 -140.88 463.42 C-145.3 477.93 -149.64 492.47 -154 507 C-195.58 507 -237.16 507 -280 507 C-278.24 499.96 -276.51 493.16 -274.25 486.31 C-271.9 479.06 -269.79 471.77 -267.77 464.42 C-264.19 451.54 -260.37 438.73 -256.5 425.94 C-255.24 421.76 -253.98 417.58 -252.72 413.4 C-252.41 412.37 -252.1 411.35 -251.78 410.29 C-249.63 403.13 -247.52 395.96 -245.44 388.79 C-242.47 378.56 -239.41 368.37 -236.32 358.19 C-230.85 340.22 -230.85 340.22 -225.56 322.19 C-222.19 310.48 -218.62 298.84 -215.06 287.19 C-210.72 272.95 -206.4 258.7 -202.19 244.42 C-200.36 238.2 -198.51 231.98 -196.65 225.77 C-196.35 224.76 -196.05 223.75 -195.74 222.71 C-195.12 220.63 -194.5 218.55 -193.88 216.47 C-188.13 197.22 -188.13 197.22 -182.5 177.94 C-178.85 165.29 -174.97 152.72 -171.13 140.13 C-164.93 119.8 -158.75 99.46 -153 79 C-188.09 81.55 -226.46 97.99 -253 121 C-253.83 121.71 -254.66 122.42 -255.51 123.14 C-274.69 139.92 -289.02 161.6 -291.21 187.46 C-293.11 216.05 -280.75 245.26 -264.87 268.69 C-264.26 269.78 -263.64 270.87 -263 272 C-264.07 275.31 -265.83 276.91 -268.61 278.89 C-269.36 279.43 -270.1 279.96 -270.86 280.52 C-271.67 281.09 -272.48 281.66 -273.31 282.25 C-275.05 283.51 -276.79 284.76 -278.53 286.02 C-279.43 286.68 -280.33 287.33 -281.27 288 C-285.68 291.23 -290.03 294.55 -294.37 297.88 C-295.25 298.54 -296.12 299.21 -297.01 299.89 C-299.68 301.93 -302.34 303.96 -305 306 C-316.83 315.06 -328.7 324.04 -340.71 332.85 C-346.17 336.86 -351.59 340.92 -357 345 C-361.44 343.43 -363.83 339.89 -366.62 336.31 C-367.42 335.31 -367.42 335.31 -368.22 334.28 C-401.71 291.18 -419.04 237.97 -413.54 183.33 C-412.98 179.14 -412.11 175.08 -411 171 C-410.81 170.29 -410.62 169.57 -410.43 168.84 C-405.86 152.16 -397.84 136.47 -387 123 C-386.27 122.07 -385.54 121.14 -384.79 120.18 C-377.09 110.54 -368.68 102.62 -359 95 C-358.12 94.29 -357.24 93.58 -356.33 92.85 C-316.02 61.35 -264.24 45.67 -214.89 35.25 C-214.08 35.08 -213.27 34.91 -212.43 34.73 C-192.67 30.58 -172.78 27.22 -152.85 23.93 C-147.76 23.09 -142.68 22.24 -137.59 21.39 C-129.1 19.97 -120.6 18.56 -112.1 17.15 C-102.3 15.53 -92.51 13.9 -82.71 12.26 C-73.2 10.67 -63.69 9.09 -54.19 7.51 C-50.17 6.84 -46.15 6.17 -42.13 5.5 C-37.42 4.71 -32.71 3.93 -28 3.15 C-26.28 2.87 -24.56 2.58 -22.83 2.29 C-20.48 1.9 -18.12 1.51 -15.77 1.12 C-14.76 0.95 -14.76 0.95 -13.72 0.77 C-9.08 0.03 -4.68 -0.09 0 0 Z"/></svg>';
154
+
155
+ // src/core/scaffolder.ts
156
+ async function fileExists(filePath) {
157
+ try {
158
+ await access(filePath);
159
+ return true;
160
+ } catch (e) {
161
+ if (isSystemError(e, "ENOENT")) {
162
+ return false;
163
+ }
164
+ throw e;
165
+ }
166
+ }
167
+ async function scaffoldExtension(cwd, displayName) {
168
+ const manifestPath = join(cwd, CLI_CONFIG.manifestFileName);
169
+ const packageJsonPath = join(cwd, "package.json");
170
+ if (await fileExists(packageJsonPath)) {
171
+ if (await fileExists(manifestPath)) {
172
+ return {
173
+ written: [],
174
+ skipped: [],
175
+ existingPackageJson: true
176
+ };
177
+ }
178
+ await writeFile(manifestPath, manifestTemplate(displayName), "utf8");
179
+ return {
180
+ written: [CLI_CONFIG.manifestFileName],
181
+ skipped: [],
182
+ existingPackageJson: true,
183
+ createdManifestOnly: true
184
+ };
185
+ }
186
+ const files = [
187
+ {
188
+ rel: CLI_CONFIG.manifestFileName,
189
+ path: manifestPath,
190
+ content: manifestTemplate(displayName)
191
+ },
192
+ {
193
+ rel: "package.json",
194
+ path: packageJsonPath,
195
+ content: packageJsonTemplate(displayName)
196
+ },
197
+ {
198
+ rel: "vite.config.ts",
199
+ path: join(cwd, "vite.config.ts"),
200
+ content: viteConfigTemplate()
201
+ },
202
+ {
203
+ rel: "index.html",
204
+ path: join(cwd, "index.html"),
205
+ content: indexHtmlTemplate(displayName)
206
+ },
207
+ {
208
+ rel: join("public", "icon.svg"),
209
+ path: join(cwd, "public", "icon.svg"),
210
+ content: ICON_SVG_TEMPLATE
211
+ },
212
+ {
213
+ rel: join("src", "index.ts"),
214
+ path: join(cwd, "src", "index.ts"),
215
+ content: indexTypescriptTemplate(displayName)
216
+ }
217
+ ];
218
+ await mkdir(join(cwd, "public"), { recursive: true });
219
+ await mkdir(join(cwd, "src"), { recursive: true });
220
+ const written = [];
221
+ const skipped = [];
222
+ for (const f of files) {
223
+ if (await fileExists(f.path)) {
224
+ skipped.push(f.rel);
225
+ continue;
226
+ }
227
+ await writeFile(f.path, f.content, "utf8");
228
+ written.push(f.rel);
229
+ }
230
+ return { written, skipped };
231
+ }
232
+
233
+ // src/services/developer-organizations.service.ts
234
+ import { z } from "zod";
235
+ var developerOrganizationSchema = z.object({
236
+ id: z.string(),
237
+ name: z.string(),
238
+ createdAt: z.string().optional(),
239
+ updatedAt: z.string().optional()
240
+ });
241
+ var listResponseSchema = z.object({
242
+ success: z.literal(true),
243
+ result: z.object({
244
+ developerOrganizations: z.array(developerOrganizationSchema)
245
+ })
246
+ });
247
+ var createOrgResponseSchema = z.object({
248
+ success: z.literal(true),
249
+ result: z.object({
250
+ developerOrganizationId: z.string()
251
+ })
252
+ });
253
+ var createExtensionResponseSchema = z.object({
254
+ success: z.literal(true),
255
+ result: z.object({
256
+ extensionId: z.string()
257
+ })
258
+ });
259
+ async function listDeveloperOrganizations(client) {
260
+ const { data } = await client.get("/developer-organizations");
261
+ const parsed = listResponseSchema.parse(data);
262
+ return parsed.result.developerOrganizations;
263
+ }
264
+ async function createDeveloperOrganization(client, name) {
265
+ const { data } = await client.post("/developer-organizations", {
266
+ name
267
+ });
268
+ const parsed = createOrgResponseSchema.parse(data);
269
+ return parsed.result.developerOrganizationId;
270
+ }
271
+ async function createExtensionInDeveloperOrganization(client, developerOrganizationId, body) {
272
+ const path = `/developer-organizations/${developerOrganizationId}/extensions`;
273
+ const { data } = await client.post(path, body);
274
+ const parsed = createExtensionResponseSchema.parse(data);
275
+ return parsed.result.extensionId;
276
+ }
277
+
278
+ // src/ui/views/app-init/AppInitWizardView.tsx
279
+ import { Box as Box3, Text as Text3 } from "ink";
280
+ import { useCallback as useCallback3, useState as useState3 } from "react";
281
+
282
+ // src/ui/views/app-init/AppsInitOrgPickerView.tsx
283
+ import { Box, Text, useInput } from "ink";
284
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
285
+ import { jsx, jsxs } from "react/jsx-runtime";
286
+ var CREATE_NEW_LABEL = "Create new organization";
287
+ function AppsInitOrgPickerView({
288
+ organizations,
289
+ onDone
290
+ }) {
291
+ const width = useTerminalWidth();
292
+ const [index, setIndex] = useState(0);
293
+ const indexRef = useRef(index);
294
+ const organizationsRef = useRef(organizations);
295
+ const onDoneRef = useRef(onDone);
296
+ indexRef.current = index;
297
+ organizationsRef.current = organizations;
298
+ onDoneRef.current = onDone;
299
+ useEffect(() => {
300
+ const maxIndex = organizations.length;
301
+ setIndex((i) => i > maxIndex ? maxIndex : i);
302
+ }, [organizations]);
303
+ const labels = useMemo(
304
+ () => [...organizations.map((o) => o.name), CREATE_NEW_LABEL],
305
+ [organizations]
306
+ );
307
+ const handleInput = useCallback((_input, key) => {
308
+ if (key.escape) {
309
+ onDoneRef.current({ kind: "cancelled" });
310
+ return;
311
+ }
312
+ if (isSubmitKey(key)) {
313
+ const idx = indexRef.current;
314
+ const orgs = organizationsRef.current;
315
+ if (idx === orgs.length) {
316
+ onDoneRef.current({ kind: "create_new" });
317
+ return;
318
+ }
319
+ const org = orgs[idx];
320
+ onDoneRef.current({
321
+ kind: "selected",
322
+ developerOrganizationId: org.id,
323
+ name: org.name
324
+ });
325
+ return;
326
+ }
327
+ if (key.upArrow) {
328
+ setIndex((i) => {
329
+ const rc = organizationsRef.current.length + 1;
330
+ const next = i <= 0 ? rc - 1 : i - 1;
331
+ indexRef.current = next;
332
+ return next;
333
+ });
334
+ return;
335
+ }
336
+ if (key.downArrow) {
337
+ setIndex((i) => {
338
+ const rc = organizationsRef.current.length + 1;
339
+ const next = i >= rc - 1 ? 0 : i + 1;
340
+ indexRef.current = next;
341
+ return next;
342
+ });
343
+ }
344
+ }, []);
345
+ useInput(handleInput);
346
+ const empty = organizations.length === 0;
347
+ return /* @__PURE__ */ jsxs(
348
+ Box,
349
+ {
350
+ ...layoutStyles.viewColumn,
351
+ width: width > 0 ? width : "100%",
352
+ minWidth: 0,
353
+ children: [
354
+ /* @__PURE__ */ jsx(Text, { ...textStyles.title, children: "Select developer organization" }),
355
+ /* @__PURE__ */ jsx(Text, { ...textStyles.muted, children: "\u2191\u2193 move \xB7 Enter confirm \xB7 Esc cancel" }),
356
+ /* @__PURE__ */ jsxs(Box, { ...layoutStyles.section, flexDirection: "column", children: [
357
+ empty ? /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { ...textStyles.muted, children: "No organizations found. Let's make one!" }) }) : null,
358
+ labels.map((label, i) => {
359
+ const isSelected = i === index;
360
+ return /* @__PURE__ */ jsxs(
361
+ Text,
362
+ {
363
+ bold: isSelected,
364
+ color: isSelected ? colors.accent : void 0,
365
+ children: [
366
+ isSelected ? "\u203A " : " ",
367
+ label
368
+ ]
369
+ },
370
+ `${label}-${i}`
371
+ );
372
+ })
373
+ ] })
374
+ ]
375
+ }
376
+ );
377
+ }
378
+
379
+ // src/ui/views/app-init/TextInputView.tsx
380
+ import { Box as Box2, Text as Text2, useInput as useInput2 } from "ink";
381
+ import TextInput from "ink-text-input";
382
+ import { useCallback as useCallback2, useState as useState2 } from "react";
383
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
384
+ function TextInputView({
385
+ label,
386
+ placeholder,
387
+ requireNonEmpty = true,
388
+ onDone
389
+ }) {
390
+ const width = useTerminalWidth();
391
+ const [value, setValue] = useState2("");
392
+ const [error, setError] = useState2(null);
393
+ const finish = useCallback2(
394
+ (result) => {
395
+ onDone(result);
396
+ },
397
+ [onDone]
398
+ );
399
+ useInput2((_input, key) => {
400
+ if (key.escape) {
401
+ finish({ kind: "cancelled" });
402
+ }
403
+ });
404
+ const handleSubmit = useCallback2(
405
+ (submitted) => {
406
+ const trimmed = submitted.trim();
407
+ if (requireNonEmpty && trimmed.length === 0) {
408
+ setError("Cannot be empty.");
409
+ return;
410
+ }
411
+ setError(null);
412
+ finish({ kind: "submit", value: trimmed });
413
+ },
414
+ [finish, requireNonEmpty]
415
+ );
416
+ return /* @__PURE__ */ jsxs2(
417
+ Box2,
418
+ {
419
+ ...layoutStyles.viewColumn,
420
+ width: width > 0 ? width : "100%",
421
+ minWidth: 0,
422
+ children: [
423
+ /* @__PURE__ */ jsx2(Text2, { ...textStyles.title, children: label }),
424
+ /* @__PURE__ */ jsx2(Box2, { ...layoutStyles.section, flexDirection: "row", flexWrap: "wrap", children: /* @__PURE__ */ jsx2(
425
+ TextInput,
426
+ {
427
+ value,
428
+ onChange: (v) => {
429
+ setValue(v);
430
+ if (error) {
431
+ setError(null);
432
+ }
433
+ },
434
+ onSubmit: handleSubmit,
435
+ placeholder: placeholder ?? ""
436
+ }
437
+ ) }),
438
+ error ? /* @__PURE__ */ jsx2(Text2, { ...textStyles.error, children: error }) : /* @__PURE__ */ jsx2(Text2, { ...textStyles.muted, children: "Enter confirm \xB7 Esc cancel" })
439
+ ]
440
+ }
441
+ );
442
+ }
443
+
444
+ // src/ui/views/app-init/AppInitWizardView.tsx
445
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
446
+ function AppInitStepShell({
447
+ width,
448
+ apiError,
449
+ isLoading,
450
+ loadingText,
451
+ children
452
+ }) {
453
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", width, minWidth: 0, children: [
454
+ apiError ? /* @__PURE__ */ jsx3(Box3, { marginLeft: spacing.sm, marginBottom: spacing.sm, children: /* @__PURE__ */ jsx3(Text3, { ...textStyles.error, children: apiError }) }) : null,
455
+ isLoading ? /* @__PURE__ */ jsx3(Box3, { ...layoutStyles.viewColumn, children: /* @__PURE__ */ jsxs3(Text3, { ...textStyles.muted, children: [
456
+ loadingText,
457
+ "\u2026"
458
+ ] }) }) : children
459
+ ] });
460
+ }
461
+ function AppInitWizardView({
462
+ organizations,
463
+ client,
464
+ onDone
465
+ }) {
466
+ const width = useTerminalWidth();
467
+ const w = width > 0 ? width : "100%";
468
+ const [step, setStep] = useState3("pick");
469
+ const [draft, setDraft] = useState3({});
470
+ const [apiError, setApiError] = useState3(null);
471
+ const [isLoading, setIsLoading] = useState3(false);
472
+ const runTask = useCallback3(async (task) => {
473
+ setApiError(null);
474
+ setIsLoading(true);
475
+ try {
476
+ await task();
477
+ } catch (e) {
478
+ setApiError(formatHttpClientError(e));
479
+ } finally {
480
+ setIsLoading(false);
481
+ }
482
+ }, []);
483
+ const handlePick = useCallback3(
484
+ (r) => {
485
+ if (r.kind === "cancelled") {
486
+ onDone({ kind: "cancelled" });
487
+ return;
488
+ }
489
+ setApiError(null);
490
+ if (r.kind === "selected") {
491
+ setDraft({
492
+ developerOrganizationId: r.developerOrganizationId,
493
+ developerOrganizationName: r.name,
494
+ isNewDeveloperOrganizationCreated: false
495
+ });
496
+ setStep("ext_name");
497
+ return;
498
+ }
499
+ setDraft({});
500
+ setStep("org_name");
501
+ },
502
+ [onDone]
503
+ );
504
+ const handleOrgName = useCallback3(
505
+ (r) => {
506
+ if (r.kind === "cancelled") {
507
+ onDone({ kind: "cancelled" });
508
+ return;
509
+ }
510
+ void runTask(async () => {
511
+ const developerOrganizationId = await createDeveloperOrganization(
512
+ client,
513
+ r.value
514
+ );
515
+ setDraft({
516
+ developerOrganizationId,
517
+ developerOrganizationName: r.value,
518
+ isNewDeveloperOrganizationCreated: true
519
+ });
520
+ setStep("ext_name");
521
+ });
522
+ },
523
+ [client, onDone, runTask]
524
+ );
525
+ const handleExtName = useCallback3(
526
+ (r) => {
527
+ if (r.kind === "cancelled") {
528
+ onDone({ kind: "cancelled" });
529
+ return;
530
+ }
531
+ const orgId = draft.developerOrganizationId;
532
+ const orgName = draft.developerOrganizationName;
533
+ if (!orgId || !orgName) {
534
+ return;
535
+ }
536
+ const isNewDeveloperOrganizationCreated = Boolean(
537
+ draft.isNewDeveloperOrganizationCreated
538
+ );
539
+ void runTask(async () => {
540
+ const extensionId = await createExtensionInDeveloperOrganization(
541
+ client,
542
+ orgId,
543
+ { name: r.value }
544
+ );
545
+ onDone({
546
+ kind: "success",
547
+ data: {
548
+ developerOrganizationId: orgId,
549
+ developerOrganizationName: orgName,
550
+ extensionId,
551
+ extensionName: r.value,
552
+ isNewDeveloperOrganizationCreated
553
+ }
554
+ });
555
+ });
556
+ },
557
+ [client, draft, onDone, runTask]
558
+ );
559
+ switch (step) {
560
+ case "pick":
561
+ return /* @__PURE__ */ jsx3(
562
+ AppsInitOrgPickerView,
563
+ {
564
+ organizations,
565
+ onDone: handlePick
566
+ }
567
+ );
568
+ case "org_name":
569
+ return /* @__PURE__ */ jsx3(
570
+ AppInitStepShell,
571
+ {
572
+ width: w,
573
+ apiError,
574
+ isLoading,
575
+ loadingText: "Creating organization",
576
+ children: /* @__PURE__ */ jsx3(
577
+ TextInputView,
578
+ {
579
+ label: "New organization name:",
580
+ placeholder: "e.g. Functor Fountain Org",
581
+ onDone: handleOrgName
582
+ },
583
+ "wizard-org-name"
584
+ )
585
+ }
586
+ );
587
+ case "ext_name":
588
+ return /* @__PURE__ */ jsx3(
589
+ AppInitStepShell,
590
+ {
591
+ width: w,
592
+ apiError,
593
+ isLoading,
594
+ loadingText: "Creating extension",
595
+ children: /* @__PURE__ */ jsx3(
596
+ TextInputView,
597
+ {
598
+ label: "Extension name:",
599
+ placeholder: "e.g. WASM-powered toaster",
600
+ onDone: handleExtName
601
+ },
602
+ "wizard-ext-name"
603
+ )
604
+ }
605
+ );
606
+ }
607
+ }
608
+
609
+ // src/commands/app/init.ts
610
+ var AppInit = class _AppInit extends BaseCommand {
611
+ static description = "Initialize a Kittl app in this directory";
612
+ async run() {
613
+ await this.parse(_AppInit);
614
+ await this.ensureAuthenticated();
615
+ const cwd = process.cwd();
616
+ if (await internalConfigExists(cwd)) {
617
+ this.error(
618
+ `Kittl config already exists at ${internalConfigPath(cwd)}. Remove it or run from another directory.`,
619
+ { exit: 2 }
620
+ );
621
+ }
622
+ const client = this.getKittlApiClient();
623
+ let organizations;
624
+ try {
625
+ organizations = await listDeveloperOrganizations(client);
626
+ } catch (e) {
627
+ this.error(formatHttpClientError(e), { exit: 2 });
628
+ }
629
+ const wizardResult = await this.renderView(AppInitWizardView, {
630
+ organizations,
631
+ client
632
+ });
633
+ if (wizardResult.kind === "cancelled") {
634
+ this.exit(130);
635
+ }
636
+ const { data } = wizardResult;
637
+ const path = await writeInternalConfig(cwd, {
638
+ developerOrganizationId: data.developerOrganizationId,
639
+ extensionId: data.extensionId
640
+ });
641
+ let starterScaffoldWritten = false;
642
+ try {
643
+ const { skipped, existingPackageJson, createdManifestOnly } = await scaffoldExtension(cwd, data.extensionName);
644
+ starterScaffoldWritten = !existingPackageJson;
645
+ if (existingPackageJson) {
646
+ if (createdManifestOnly) {
647
+ this.log(
648
+ `package.json found; created ${CLI_CONFIG.manifestFileName} only (starter scaffold skipped).`
649
+ );
650
+ } else {
651
+ this.log(
652
+ "package.json found; skipped starter scaffold (manifest already present)."
653
+ );
654
+ }
655
+ } else if (skipped.length > 0) {
656
+ this.log(
657
+ `Skipped starter files (already present): ${skipped.join(", ")}`
658
+ );
659
+ }
660
+ } catch (e) {
661
+ this.error(e instanceof Error ? e.message : String(e), { exit: 2 });
662
+ }
663
+ try {
664
+ await createExtensionDraftVersion(
665
+ client,
666
+ data.extensionId,
667
+ join2(cwd, CLI_CONFIG.manifestFileName)
668
+ );
669
+ } catch (e) {
670
+ this.error(formatHttpClientError(e), { exit: 2 });
671
+ }
672
+ if (data.isNewDeveloperOrganizationCreated) {
673
+ this.log(`Created organization: "${data.developerOrganizationName}".`);
674
+ } else {
675
+ this.log(`Developer organization: "${data.developerOrganizationName}".`);
676
+ }
677
+ this.log(`Created app: "${data.extensionName}".`);
678
+ this.debug(`Generated config file at ${path}`);
679
+ this.log("");
680
+ this.log(`Success! Extension "${data.extensionName}" is ready.`);
681
+ this.log("Next steps:");
682
+ let step = 1;
683
+ if (starterScaffoldWritten) {
684
+ this.log(` ${step++}. npm install`);
685
+ this.log(` ${step++}. npm run dev`);
686
+ this.log(
687
+ ` \u2192 http://localhost:${String(CLI_CONFIG.scaffoldViteDevPort)} (see vite.config.ts)`
688
+ );
689
+ }
690
+ this.log(
691
+ ` ${step++}. Edit ${CLI_CONFIG.manifestFileName} as needed, then run 'kittl app update'`
692
+ );
693
+ this.log(` ${step++}. When you have a build, run 'kittl app upload'`);
694
+ }
695
+ };
696
+ export {
697
+ AppInit as default
698
+ };
699
+ //# sourceMappingURL=init.js.map