@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.
- package/LICENSE +201 -0
- package/README.md +15 -105
- package/dist/chunk-3BPIJLS7.js +51 -0
- package/dist/chunk-3BPIJLS7.js.map +1 -0
- package/dist/{chunk-4ISWSLZ5.js → chunk-637YZAKM.js} +3 -3
- package/dist/chunk-637YZAKM.js.map +1 -0
- package/dist/chunk-EKU4DKQK.js +20 -0
- package/dist/chunk-EKU4DKQK.js.map +1 -0
- package/dist/chunk-GJPVFQRF.js +98 -0
- package/dist/chunk-GJPVFQRF.js.map +1 -0
- package/dist/{chunk-JGD3QFQS.js → chunk-TK44DTSK.js} +280 -70
- package/dist/chunk-TK44DTSK.js.map +1 -0
- package/dist/chunk-XU2ZHSRY.js +143 -0
- package/dist/chunk-XU2ZHSRY.js.map +1 -0
- package/dist/commands/app/init.js +699 -0
- package/dist/commands/app/init.js.map +1 -0
- package/dist/commands/app/release.js +125 -0
- package/dist/commands/app/release.js.map +1 -0
- package/dist/commands/app/update.js +45 -0
- package/dist/commands/app/update.js.map +1 -0
- package/dist/commands/app/upload.js +419 -5
- package/dist/commands/app/upload.js.map +1 -1
- package/dist/commands/auth/login.js +13 -68
- package/dist/commands/auth/login.js.map +1 -1
- package/dist/commands/auth/logout.js +1 -1
- package/dist/commands/auth/logout.js.map +1 -1
- package/dist/commands/auth/whoami.js +2 -2
- package/dist/commands/whoami.js +2 -2
- package/package.json +4 -1
- package/dist/chunk-4ISWSLZ5.js.map +0 -1
- package/dist/chunk-JGD3QFQS.js.map +0 -1
- package/dist/commands/app/create.js +0 -16
- package/dist/commands/app/create.js.map +0 -1
|
@@ -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
|