@kittl/cli 0.0.1 → 0.0.3

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,726 @@
1
+ import {
2
+ createExtensionDraftVersion
3
+ } from "../../chunk-SUQB7HN4.js";
4
+ import {
5
+ formatHttpClientError,
6
+ internalConfigExists,
7
+ internalConfigPath,
8
+ isSystemError,
9
+ writeInternalConfig
10
+ } from "../../chunk-2OOJ3TW4.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
+ ensureDirectory,
24
+ getFileNameFromPath,
25
+ isSubmitKey
26
+ } from "../../chunk-YUKLWJFM.js";
27
+
28
+ // src/commands/app/init.ts
29
+ import { join as join2, relative, resolve } from "node:path";
30
+ import { Args } from "@oclif/core";
31
+
32
+ // src/core/scaffolder.ts
33
+ import { access, mkdir, writeFile } from "node:fs/promises";
34
+ import { join } from "node:path";
35
+
36
+ // src/core/templates.ts
37
+ var DEFAULT_TERMS_URL = "https://example.com/terms";
38
+ var DEFAULT_PRIVACY_URL = "https://example.com/privacy";
39
+ var DEFAULT_MAIN_APP_PANEL_PATH = "index.html";
40
+ var EXTENSION_MANIFEST_JSON_SCHEMA_URL = "https://api.kittl.com/extensions/manifest/schema.json";
41
+ function packageNameFromExtensionName(name) {
42
+ const slug = name.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
43
+ return slug.length > 0 ? slug : "kittl-extension";
44
+ }
45
+ function initialExtensionManifest(displayName) {
46
+ const value = displayName.trim() || "Unnamed extension";
47
+ return {
48
+ $schema: EXTENSION_MANIFEST_JSON_SCHEMA_URL,
49
+ displayName: value,
50
+ icon: "icon.svg",
51
+ tagline: `${value} for Kittl.`,
52
+ installPage: {
53
+ description: `Install ${value} to use this extension in Kittl.`,
54
+ coverImage: "icon.svg",
55
+ termsAndConditionsLink: DEFAULT_TERMS_URL,
56
+ privacyPolicyLink: DEFAULT_PRIVACY_URL
57
+ },
58
+ config: {
59
+ // New projects start without privileged scopes and can opt into them later.
60
+ scopes: ["design:state:read", "design:state:write"],
61
+ embed: {
62
+ mainAppPanel: {
63
+ path: DEFAULT_MAIN_APP_PANEL_PATH
64
+ }
65
+ }
66
+ }
67
+ };
68
+ }
69
+ function manifestTemplate(displayName) {
70
+ return `${JSON.stringify(
71
+ initialExtensionManifest(displayName),
72
+ null,
73
+ // replacer: none - default serialization
74
+ 2
75
+ // space: 2-space indent + line breaks
76
+ )}
77
+ `;
78
+ }
79
+ function packageJsonTemplate(displayName) {
80
+ return `${JSON.stringify(
81
+ {
82
+ name: packageNameFromExtensionName(displayName),
83
+ private: true,
84
+ version: "0.0.0",
85
+ type: "module",
86
+ scripts: {
87
+ dev: "vite",
88
+ build: "vite build",
89
+ preview: "vite preview"
90
+ },
91
+ dependencies: {
92
+ "@kittl/sdk": "^0.0.1"
93
+ },
94
+ devDependencies: {
95
+ vite: "^5.0.0"
96
+ }
97
+ },
98
+ null,
99
+ // replacer: none, default serialization
100
+ 2
101
+ // space: 2-space indent + line breaks
102
+ )}
103
+ `;
104
+ }
105
+ function viteConfigTemplate() {
106
+ return `import { defineConfig } from 'vite';
107
+
108
+ export default defineConfig({
109
+ server: {
110
+ port: ${CLI_CONFIG.scaffoldViteDevPort},
111
+ },
112
+ publicDir: 'public',
113
+ build: {
114
+ outDir: 'dist',
115
+ },
116
+ });
117
+ `;
118
+ }
119
+ function indexHtmlTemplate(displayName) {
120
+ return `<!DOCTYPE html>
121
+ <html lang="en">
122
+ <head>
123
+ <meta charset="UTF-8" />
124
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
125
+ <title>${displayName}</title>
126
+ </head>
127
+ <body>
128
+ <div id="app">
129
+ <h1>Hello Kittl!</h1>
130
+ <p>Welcome to your new extension: ${displayName}</p>
131
+ <button id="doSomething" type="button">Do some magic!</button>
132
+ </div>
133
+ <script type="module" src="/src/index.ts"></script>
134
+ </body>
135
+ </html>
136
+ `;
137
+ }
138
+ function indexTypescriptTemplate(displayName) {
139
+ return `import { kittl } from '@kittl/sdk';
140
+
141
+ document.getElementById('doSomething')?.addEventListener('click', async () => {
142
+ await kittl.design.text.addText({
143
+ text: 'Hello ${displayName} from Kittl SDK!',
144
+ position: {
145
+ relative: {
146
+ to: 'viewport',
147
+ location: 'center',
148
+ },
149
+ },
150
+ size: {
151
+ height: 100,
152
+ width: 400,
153
+ },
154
+ });
155
+ });
156
+ `;
157
+ }
158
+ 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>';
159
+
160
+ // src/core/scaffolder.ts
161
+ async function fileExists(filePath) {
162
+ try {
163
+ await access(filePath);
164
+ return true;
165
+ } catch (e) {
166
+ if (isSystemError(e, "ENOENT")) {
167
+ return false;
168
+ }
169
+ throw e;
170
+ }
171
+ }
172
+ async function scaffoldExtension(cwd, displayName) {
173
+ const manifestPath = join(cwd, CLI_CONFIG.manifestFileName);
174
+ const packageJsonPath = join(cwd, "package.json");
175
+ if (await fileExists(packageJsonPath)) {
176
+ if (await fileExists(manifestPath)) {
177
+ return {
178
+ written: [],
179
+ skipped: [],
180
+ existingPackageJson: true
181
+ };
182
+ }
183
+ await writeFile(manifestPath, manifestTemplate(displayName), "utf8");
184
+ return {
185
+ written: [CLI_CONFIG.manifestFileName],
186
+ skipped: [],
187
+ existingPackageJson: true,
188
+ createdManifestOnly: true
189
+ };
190
+ }
191
+ const files = [
192
+ {
193
+ rel: CLI_CONFIG.manifestFileName,
194
+ path: manifestPath,
195
+ content: manifestTemplate(displayName)
196
+ },
197
+ {
198
+ rel: "package.json",
199
+ path: packageJsonPath,
200
+ content: packageJsonTemplate(displayName)
201
+ },
202
+ {
203
+ rel: "vite.config.ts",
204
+ path: join(cwd, "vite.config.ts"),
205
+ content: viteConfigTemplate()
206
+ },
207
+ {
208
+ rel: "index.html",
209
+ path: join(cwd, "index.html"),
210
+ content: indexHtmlTemplate(displayName)
211
+ },
212
+ {
213
+ rel: join("public", "icon.svg"),
214
+ path: join(cwd, "public", "icon.svg"),
215
+ content: ICON_SVG_TEMPLATE
216
+ },
217
+ {
218
+ rel: join("src", "index.ts"),
219
+ path: join(cwd, "src", "index.ts"),
220
+ content: indexTypescriptTemplate(displayName)
221
+ }
222
+ ];
223
+ await mkdir(join(cwd, "public"), { recursive: true });
224
+ await mkdir(join(cwd, "src"), { recursive: true });
225
+ const written = [];
226
+ const skipped = [];
227
+ for (const f of files) {
228
+ if (await fileExists(f.path)) {
229
+ skipped.push(f.rel);
230
+ continue;
231
+ }
232
+ await writeFile(f.path, f.content, "utf8");
233
+ written.push(f.rel);
234
+ }
235
+ return { written, skipped };
236
+ }
237
+
238
+ // src/services/developer-organizations.service.ts
239
+ import { z } from "zod";
240
+ var developerOrganizationSchema = z.object({
241
+ id: z.string(),
242
+ name: z.string(),
243
+ createdAt: z.string().optional(),
244
+ updatedAt: z.string().optional()
245
+ });
246
+ var listResponseSchema = z.object({
247
+ success: z.literal(true),
248
+ result: z.object({
249
+ developerOrganizations: z.array(developerOrganizationSchema)
250
+ })
251
+ });
252
+ var createOrgResponseSchema = z.object({
253
+ success: z.literal(true),
254
+ result: z.object({
255
+ developerOrganizationId: z.string()
256
+ })
257
+ });
258
+ var createExtensionResponseSchema = z.object({
259
+ success: z.literal(true),
260
+ result: z.object({
261
+ extensionId: z.string()
262
+ })
263
+ });
264
+ async function listDeveloperOrganizations(client) {
265
+ const { data } = await client.get("/developer-organizations");
266
+ const parsed = listResponseSchema.parse(data);
267
+ return parsed.result.developerOrganizations;
268
+ }
269
+ async function createDeveloperOrganization(client, name) {
270
+ const { data } = await client.post("/developer-organizations", {
271
+ name
272
+ });
273
+ const parsed = createOrgResponseSchema.parse(data);
274
+ return parsed.result.developerOrganizationId;
275
+ }
276
+ async function createExtensionInDeveloperOrganization(client, developerOrganizationId, body) {
277
+ const path = `/developer-organizations/${developerOrganizationId}/extensions`;
278
+ const { data } = await client.post(path, body);
279
+ const parsed = createExtensionResponseSchema.parse(data);
280
+ return parsed.result.extensionId;
281
+ }
282
+
283
+ // src/ui/views/app-init/AppInitWizardView.tsx
284
+ import { Box as Box3, Text as Text3 } from "ink";
285
+ import { useCallback as useCallback3, useState as useState3 } from "react";
286
+
287
+ // src/ui/views/app-init/AppsInitOrgPickerView.tsx
288
+ import { Box, Text, useInput } from "ink";
289
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
290
+ import { jsx, jsxs } from "react/jsx-runtime";
291
+ var CREATE_NEW_LABEL = "Create new organization";
292
+ function AppsInitOrgPickerView({
293
+ organizations,
294
+ onDone
295
+ }) {
296
+ const width = useTerminalWidth();
297
+ const [index, setIndex] = useState(0);
298
+ const indexRef = useRef(index);
299
+ const organizationsRef = useRef(organizations);
300
+ const onDoneRef = useRef(onDone);
301
+ indexRef.current = index;
302
+ organizationsRef.current = organizations;
303
+ onDoneRef.current = onDone;
304
+ useEffect(() => {
305
+ const maxIndex = organizations.length;
306
+ setIndex((i) => i > maxIndex ? maxIndex : i);
307
+ }, [organizations]);
308
+ const labels = useMemo(
309
+ () => [...organizations.map((o) => o.name), CREATE_NEW_LABEL],
310
+ [organizations]
311
+ );
312
+ const handleInput = useCallback((_input, key) => {
313
+ if (key.escape) {
314
+ onDoneRef.current({ kind: "cancelled" });
315
+ return;
316
+ }
317
+ if (isSubmitKey(key)) {
318
+ const idx = indexRef.current;
319
+ const orgs = organizationsRef.current;
320
+ if (idx === orgs.length) {
321
+ onDoneRef.current({ kind: "create_new" });
322
+ return;
323
+ }
324
+ const org = orgs[idx];
325
+ onDoneRef.current({
326
+ kind: "selected",
327
+ developerOrganizationId: org.id,
328
+ name: org.name
329
+ });
330
+ return;
331
+ }
332
+ if (key.upArrow) {
333
+ setIndex((i) => {
334
+ const rc = organizationsRef.current.length + 1;
335
+ const next = i <= 0 ? rc - 1 : i - 1;
336
+ indexRef.current = next;
337
+ return next;
338
+ });
339
+ return;
340
+ }
341
+ if (key.downArrow) {
342
+ setIndex((i) => {
343
+ const rc = organizationsRef.current.length + 1;
344
+ const next = i >= rc - 1 ? 0 : i + 1;
345
+ indexRef.current = next;
346
+ return next;
347
+ });
348
+ }
349
+ }, []);
350
+ useInput(handleInput);
351
+ const empty = organizations.length === 0;
352
+ return /* @__PURE__ */ jsxs(
353
+ Box,
354
+ {
355
+ ...layoutStyles.viewColumn,
356
+ width: width > 0 ? width : "100%",
357
+ minWidth: 0,
358
+ children: [
359
+ /* @__PURE__ */ jsx(Text, { ...textStyles.title, children: "Select developer organization" }),
360
+ /* @__PURE__ */ jsx(Text, { ...textStyles.muted, children: "\u2191\u2193 move \xB7 Enter confirm \xB7 Esc cancel" }),
361
+ /* @__PURE__ */ jsxs(Box, { ...layoutStyles.section, flexDirection: "column", children: [
362
+ empty ? /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { ...textStyles.muted, children: "No organizations found. Let's make one!" }) }) : null,
363
+ labels.map((label, i) => {
364
+ const isSelected = i === index;
365
+ return /* @__PURE__ */ jsxs(
366
+ Text,
367
+ {
368
+ bold: isSelected,
369
+ color: isSelected ? colors.accent : void 0,
370
+ children: [
371
+ isSelected ? "\u203A " : " ",
372
+ label
373
+ ]
374
+ },
375
+ `${label}-${i}`
376
+ );
377
+ })
378
+ ] })
379
+ ]
380
+ }
381
+ );
382
+ }
383
+
384
+ // src/ui/views/app-init/TextInputView.tsx
385
+ import { Box as Box2, Text as Text2, useInput as useInput2 } from "ink";
386
+ import TextInput from "ink-text-input";
387
+ import { useCallback as useCallback2, useState as useState2 } from "react";
388
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
389
+ function TextInputView({
390
+ label,
391
+ placeholder,
392
+ initialValue,
393
+ requireNonEmpty = true,
394
+ onDone
395
+ }) {
396
+ const width = useTerminalWidth();
397
+ const [value, setValue] = useState2(() => initialValue?.trim() ?? "");
398
+ const [error, setError] = useState2(null);
399
+ const finish = useCallback2(
400
+ (result) => {
401
+ onDone(result);
402
+ },
403
+ [onDone]
404
+ );
405
+ useInput2((_input, key) => {
406
+ if (key.escape) {
407
+ finish({ kind: "cancelled" });
408
+ }
409
+ });
410
+ const handleSubmit = useCallback2(
411
+ (submitted) => {
412
+ const trimmed = submitted.trim();
413
+ if (requireNonEmpty && trimmed.length === 0) {
414
+ setError("Cannot be empty.");
415
+ return;
416
+ }
417
+ setError(null);
418
+ finish({ kind: "submit", value: trimmed });
419
+ },
420
+ [finish, requireNonEmpty]
421
+ );
422
+ return /* @__PURE__ */ jsxs2(
423
+ Box2,
424
+ {
425
+ ...layoutStyles.viewColumn,
426
+ width: width > 0 ? width : "100%",
427
+ minWidth: 0,
428
+ children: [
429
+ /* @__PURE__ */ jsx2(Text2, { ...textStyles.title, children: label }),
430
+ /* @__PURE__ */ jsx2(Box2, { ...layoutStyles.section, flexDirection: "row", flexWrap: "wrap", children: /* @__PURE__ */ jsx2(
431
+ TextInput,
432
+ {
433
+ value,
434
+ onChange: (v) => {
435
+ setValue(v);
436
+ if (error) {
437
+ setError(null);
438
+ }
439
+ },
440
+ onSubmit: handleSubmit,
441
+ placeholder: placeholder ?? ""
442
+ }
443
+ ) }),
444
+ error ? /* @__PURE__ */ jsx2(Text2, { ...textStyles.error, children: error }) : /* @__PURE__ */ jsx2(Text2, { ...textStyles.muted, children: "Enter confirm \xB7 Esc cancel" })
445
+ ]
446
+ }
447
+ );
448
+ }
449
+
450
+ // src/ui/views/app-init/AppInitWizardView.tsx
451
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
452
+ function AppInitStepShell({
453
+ width,
454
+ apiError,
455
+ isLoading,
456
+ loadingText,
457
+ children
458
+ }) {
459
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", width, minWidth: 0, children: [
460
+ apiError ? /* @__PURE__ */ jsx3(Box3, { marginLeft: spacing.sm, marginBottom: spacing.sm, children: /* @__PURE__ */ jsx3(Text3, { ...textStyles.error, children: apiError }) }) : null,
461
+ isLoading ? /* @__PURE__ */ jsx3(Box3, { ...layoutStyles.viewColumn, children: /* @__PURE__ */ jsxs3(Text3, { ...textStyles.muted, children: [
462
+ loadingText,
463
+ "\u2026"
464
+ ] }) }) : children
465
+ ] });
466
+ }
467
+ function AppInitWizardView({
468
+ organizations,
469
+ client,
470
+ extensionNameSuggestion,
471
+ onDone
472
+ }) {
473
+ const width = useTerminalWidth();
474
+ const w = width > 0 ? width : "100%";
475
+ const [step, setStep] = useState3("pick");
476
+ const [draft, setDraft] = useState3({});
477
+ const [apiError, setApiError] = useState3(null);
478
+ const [isLoading, setIsLoading] = useState3(false);
479
+ const runTask = useCallback3(async (task) => {
480
+ setApiError(null);
481
+ setIsLoading(true);
482
+ try {
483
+ await task();
484
+ } catch (e) {
485
+ setApiError(formatHttpClientError(e));
486
+ } finally {
487
+ setIsLoading(false);
488
+ }
489
+ }, []);
490
+ const handlePick = useCallback3(
491
+ (r) => {
492
+ if (r.kind === "cancelled") {
493
+ onDone({ kind: "cancelled" });
494
+ return;
495
+ }
496
+ setApiError(null);
497
+ if (r.kind === "selected") {
498
+ setDraft({
499
+ developerOrganizationId: r.developerOrganizationId,
500
+ developerOrganizationName: r.name,
501
+ isNewDeveloperOrganizationCreated: false
502
+ });
503
+ setStep("ext_name");
504
+ return;
505
+ }
506
+ setDraft({});
507
+ setStep("org_name");
508
+ },
509
+ [onDone]
510
+ );
511
+ const handleOrgName = useCallback3(
512
+ (r) => {
513
+ if (r.kind === "cancelled") {
514
+ onDone({ kind: "cancelled" });
515
+ return;
516
+ }
517
+ void runTask(async () => {
518
+ const developerOrganizationId = await createDeveloperOrganization(
519
+ client,
520
+ r.value
521
+ );
522
+ setDraft({
523
+ developerOrganizationId,
524
+ developerOrganizationName: r.value,
525
+ isNewDeveloperOrganizationCreated: true
526
+ });
527
+ setStep("ext_name");
528
+ });
529
+ },
530
+ [client, onDone, runTask]
531
+ );
532
+ const handleExtName = useCallback3(
533
+ (r) => {
534
+ if (r.kind === "cancelled") {
535
+ onDone({ kind: "cancelled" });
536
+ return;
537
+ }
538
+ const orgId = draft.developerOrganizationId;
539
+ const orgName = draft.developerOrganizationName;
540
+ if (!orgId || !orgName) {
541
+ return;
542
+ }
543
+ const isNewDeveloperOrganizationCreated = Boolean(
544
+ draft.isNewDeveloperOrganizationCreated
545
+ );
546
+ void runTask(async () => {
547
+ const extensionId = await createExtensionInDeveloperOrganization(
548
+ client,
549
+ orgId,
550
+ { name: r.value }
551
+ );
552
+ onDone({
553
+ kind: "success",
554
+ data: {
555
+ developerOrganizationId: orgId,
556
+ developerOrganizationName: orgName,
557
+ extensionId,
558
+ extensionName: r.value,
559
+ isNewDeveloperOrganizationCreated
560
+ }
561
+ });
562
+ });
563
+ },
564
+ [client, draft, onDone, runTask]
565
+ );
566
+ switch (step) {
567
+ case "pick":
568
+ return /* @__PURE__ */ jsx3(
569
+ AppsInitOrgPickerView,
570
+ {
571
+ organizations,
572
+ onDone: handlePick
573
+ }
574
+ );
575
+ case "org_name":
576
+ return /* @__PURE__ */ jsx3(
577
+ AppInitStepShell,
578
+ {
579
+ width: w,
580
+ apiError,
581
+ isLoading,
582
+ loadingText: "Creating organization",
583
+ children: /* @__PURE__ */ jsx3(
584
+ TextInputView,
585
+ {
586
+ label: "New organization name:",
587
+ placeholder: "e.g. Functor Fountain Org",
588
+ onDone: handleOrgName
589
+ },
590
+ "wizard-org-name"
591
+ )
592
+ }
593
+ );
594
+ case "ext_name":
595
+ return /* @__PURE__ */ jsx3(
596
+ AppInitStepShell,
597
+ {
598
+ width: w,
599
+ apiError,
600
+ isLoading,
601
+ loadingText: "Creating extension",
602
+ children: /* @__PURE__ */ jsx3(
603
+ TextInputView,
604
+ {
605
+ label: "Extension name:",
606
+ placeholder: "e.g. WASM-powered toaster",
607
+ initialValue: extensionNameSuggestion,
608
+ onDone: handleExtName
609
+ },
610
+ "wizard-ext-name"
611
+ )
612
+ }
613
+ );
614
+ }
615
+ }
616
+
617
+ // src/commands/app/init.ts
618
+ var AppInit = class _AppInit extends BaseCommand {
619
+ static description = "Initialize a Kittl app in the current directory or a new folder";
620
+ static args = {
621
+ path: Args.string({
622
+ description: "Directory for the app (created if it does not exist)",
623
+ default: ".",
624
+ required: false
625
+ })
626
+ };
627
+ async run() {
628
+ const { args } = await this.parse(_AppInit);
629
+ await this.ensureAuthenticated();
630
+ const targetDir = resolve(process.cwd(), args.path);
631
+ try {
632
+ await ensureDirectory(targetDir);
633
+ } catch (e) {
634
+ this.error(e instanceof Error ? e.message : String(e), { exit: 2 });
635
+ }
636
+ if (await internalConfigExists(targetDir)) {
637
+ this.error(
638
+ `Kittl config already exists at ${internalConfigPath(targetDir)}. Remove it or choose a different directory.`,
639
+ { exit: 2 }
640
+ );
641
+ }
642
+ const client = this.getKittlApiClient();
643
+ let organizations;
644
+ try {
645
+ organizations = await listDeveloperOrganizations(client);
646
+ } catch (e) {
647
+ this.error(formatHttpClientError(e), { exit: 2 });
648
+ }
649
+ const extensionNameSuggestion = args.path === "." ? void 0 : getFileNameFromPath(targetDir);
650
+ const wizardResult = await this.renderView(AppInitWizardView, {
651
+ organizations,
652
+ client,
653
+ extensionNameSuggestion
654
+ });
655
+ if (wizardResult.kind === "cancelled") {
656
+ this.exit(130);
657
+ }
658
+ const { data } = wizardResult;
659
+ const configFilePath = await writeInternalConfig(targetDir, {
660
+ developerOrganizationId: data.developerOrganizationId,
661
+ extensionId: data.extensionId
662
+ });
663
+ let starterScaffoldWritten = false;
664
+ try {
665
+ const { skipped, existingPackageJson, createdManifestOnly } = await scaffoldExtension(targetDir, data.extensionName);
666
+ starterScaffoldWritten = !existingPackageJson;
667
+ if (existingPackageJson) {
668
+ if (createdManifestOnly) {
669
+ this.log(
670
+ `package.json found; created ${CLI_CONFIG.manifestFileName} only (starter scaffold skipped).`
671
+ );
672
+ } else {
673
+ this.log(
674
+ "package.json found; skipped starter scaffold (manifest already present)."
675
+ );
676
+ }
677
+ } else if (skipped.length > 0) {
678
+ this.log(
679
+ `Skipped starter files (already present): ${skipped.join(", ")}`
680
+ );
681
+ }
682
+ } catch (e) {
683
+ this.error(e instanceof Error ? e.message : String(e), { exit: 2 });
684
+ }
685
+ try {
686
+ await createExtensionDraftVersion(
687
+ client,
688
+ data.extensionId,
689
+ join2(targetDir, CLI_CONFIG.manifestFileName)
690
+ );
691
+ } catch (e) {
692
+ this.error(formatHttpClientError(e), { exit: 2 });
693
+ }
694
+ if (data.isNewDeveloperOrganizationCreated) {
695
+ this.log(`Created organization: "${data.developerOrganizationName}".`);
696
+ } else {
697
+ this.log(`Developer organization: "${data.developerOrganizationName}".`);
698
+ }
699
+ this.log(`Created app: "${data.extensionName}".`);
700
+ this.debug(`Generated config file at ${configFilePath}`);
701
+ this.log("");
702
+ this.log(`Success! Extension "${data.extensionName}" is ready.`);
703
+ this.log("Next steps:");
704
+ let step = 1;
705
+ const isCurrentDir = resolve(process.cwd()) === targetDir;
706
+ const displayPath = relative(process.cwd(), targetDir);
707
+ if (!isCurrentDir) {
708
+ this.log(` ${step++}. cd ${JSON.stringify(displayPath)}`);
709
+ }
710
+ if (starterScaffoldWritten) {
711
+ this.log(` ${step++}. npm install`);
712
+ this.log(` ${step++}. npm run dev`);
713
+ this.log(
714
+ ` \u2192 http://localhost:${String(CLI_CONFIG.scaffoldViteDevPort)} (see vite.config.ts)`
715
+ );
716
+ }
717
+ this.log(
718
+ ` ${step++}. Edit ${CLI_CONFIG.manifestFileName} as needed, then run 'kittl app update'`
719
+ );
720
+ this.log(` ${step++}. When you have a build, run 'kittl app upload'`);
721
+ }
722
+ };
723
+ export {
724
+ AppInit as default
725
+ };
726
+ //# sourceMappingURL=init.js.map