@curenorway/kode-cli 1.18.0 → 2.0.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.
- package/README.md +10 -1
- package/dist/{chunk-MSXS4ARI.js → chunk-6RYN72CO.js} +727 -1172
- package/dist/chunk-GO6KLUXM.js +500 -0
- package/dist/chunk-MUW33LPZ.js +265 -0
- package/dist/chunk-R4KWWTS4.js +75 -0
- package/dist/chunk-TLLGB46I.js +418 -0
- package/dist/cli.js +345 -38
- package/dist/index.d.ts +73 -0
- package/dist/index.js +16 -12
- package/dist/pkg-DOXTOICF.js +18 -0
- package/dist/pull-G7GR67GG.js +7 -0
- package/dist/types-PZ7GFJEK.js +9 -0
- package/package.json +2 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// src/commands/pkg.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, writeFileSync, rmSync } from "fs";
|
|
4
|
+
import { join, relative, dirname, extname } from "path";
|
|
5
|
+
function getConfig() {
|
|
6
|
+
const configPath = join(process.cwd(), ".cure-kode", "config.json");
|
|
7
|
+
if (!existsSync(configPath)) return null;
|
|
8
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
9
|
+
return {
|
|
10
|
+
siteId: config.siteId,
|
|
11
|
+
apiKey: config.apiKey,
|
|
12
|
+
apiUrl: config.apiUrl || "https://app.cure.no",
|
|
13
|
+
scriptsDir: join(process.cwd(), ".cure-kode-scripts")
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function apiRequest(config, path, options = {}) {
|
|
17
|
+
const url = `${config.apiUrl}${path}`;
|
|
18
|
+
const response = await fetch(url, {
|
|
19
|
+
...options,
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"X-API-Key": config.apiKey,
|
|
23
|
+
...options.headers || {}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const err = await response.json().catch(() => ({ error: response.statusText }));
|
|
28
|
+
throw new Error(err.error || `HTTP ${response.status}`);
|
|
29
|
+
}
|
|
30
|
+
return response.json();
|
|
31
|
+
}
|
|
32
|
+
async function pkgAddCommand(name) {
|
|
33
|
+
const config = getConfig();
|
|
34
|
+
if (!config) return console.log(chalk.red("Not in a Kode project. Run kode init first."));
|
|
35
|
+
try {
|
|
36
|
+
console.log(chalk.dim(`Fetching @kode/${name}...`));
|
|
37
|
+
const pkg = await apiRequest(config, `/api/cdn/packages/${name}`);
|
|
38
|
+
if (!pkg.files?.length) {
|
|
39
|
+
return console.log(chalk.red(`Package "${name}" has no files.`));
|
|
40
|
+
}
|
|
41
|
+
const pkgDir = join(config.scriptsDir, "packages", "@kode", pkg.slug);
|
|
42
|
+
mkdirSync(pkgDir, { recursive: true });
|
|
43
|
+
for (const file of pkg.files) {
|
|
44
|
+
const filePath = join(pkgDir, file.path);
|
|
45
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
46
|
+
writeFileSync(filePath, file.content, "utf-8");
|
|
47
|
+
}
|
|
48
|
+
writeFileSync(join(pkgDir, "kode.json"), JSON.stringify({
|
|
49
|
+
name: pkg.name,
|
|
50
|
+
slug: pkg.slug,
|
|
51
|
+
version: pkg.version,
|
|
52
|
+
description: pkg.description,
|
|
53
|
+
entryPoint: pkg.entry_point,
|
|
54
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
55
|
+
}, null, 2) + "\n");
|
|
56
|
+
console.log(chalk.green(`\u2714 Installed @kode/${pkg.slug} v${pkg.version}`));
|
|
57
|
+
console.log(chalk.dim(` ${pkg.files.length} file(s) \u2192 .cure-kode-scripts/packages/@kode/${pkg.slug}/`));
|
|
58
|
+
console.log(chalk.dim(` Import: import { ... } from '@kode/${pkg.slug}'`));
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function pkgRemoveCommand(name) {
|
|
64
|
+
const config = getConfig();
|
|
65
|
+
if (!config) return console.log(chalk.red("Not in a Kode project. Run kode init first."));
|
|
66
|
+
const pkgDir = join(config.scriptsDir, "packages", "@kode", name);
|
|
67
|
+
if (!existsSync(pkgDir)) {
|
|
68
|
+
return console.log(chalk.red(`Package "@kode/${name}" is not installed.`));
|
|
69
|
+
}
|
|
70
|
+
rmSync(pkgDir, { recursive: true, force: true });
|
|
71
|
+
console.log(chalk.green(`\u2714 Removed @kode/${name}`));
|
|
72
|
+
}
|
|
73
|
+
async function pkgPublishCommand(options) {
|
|
74
|
+
const config = getConfig();
|
|
75
|
+
if (!config) return console.log(chalk.red("Not in a Kode project. Run kode init first."));
|
|
76
|
+
if (!options.path) return console.log(chalk.red("Usage: kode pkg publish --path <path> --slug <slug>"));
|
|
77
|
+
if (!options.slug) return console.log(chalk.red("Usage: kode pkg publish --path <path> --slug <slug>"));
|
|
78
|
+
const sourcePath = join(config.scriptsDir, options.path);
|
|
79
|
+
if (!existsSync(sourcePath)) {
|
|
80
|
+
return console.log(chalk.red(`Path not found: ${options.path}`));
|
|
81
|
+
}
|
|
82
|
+
const files = [];
|
|
83
|
+
const stat = statSync(sourcePath);
|
|
84
|
+
if (stat.isFile()) {
|
|
85
|
+
const ext = extname(sourcePath);
|
|
86
|
+
files.push({ path: `index${ext}`, content: readFileSync(sourcePath, "utf-8") });
|
|
87
|
+
} else {
|
|
88
|
+
collectFiles(sourcePath, sourcePath, files);
|
|
89
|
+
}
|
|
90
|
+
if (files.length === 0) {
|
|
91
|
+
return console.log(chalk.red("No files found."));
|
|
92
|
+
}
|
|
93
|
+
const entryNames = ["index.ts", "index.tsx", "index.jsx", "index.js"];
|
|
94
|
+
const entryPoint = files.find((f) => entryNames.includes(f.path))?.path || files[0].path;
|
|
95
|
+
const displayName = options.slug.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
96
|
+
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : void 0;
|
|
97
|
+
try {
|
|
98
|
+
console.log(chalk.dim(`Publishing ${files.length} file(s) as @kode/${options.slug}...`));
|
|
99
|
+
const result = await apiRequest(config, "/api/cdn/packages", {
|
|
100
|
+
method: "POST",
|
|
101
|
+
body: JSON.stringify({
|
|
102
|
+
name: displayName,
|
|
103
|
+
slug: options.slug,
|
|
104
|
+
description: options.description,
|
|
105
|
+
entryPoint,
|
|
106
|
+
files,
|
|
107
|
+
tags
|
|
108
|
+
})
|
|
109
|
+
});
|
|
110
|
+
const verb = result.created ? "Published" : "Updated";
|
|
111
|
+
console.log(chalk.green(`\u2714 ${verb} @kode/${result.slug} v${result.version}`));
|
|
112
|
+
console.log(chalk.dim(` ${files.length} file(s), entry: ${entryPoint}`));
|
|
113
|
+
console.log(chalk.dim(` Install: kode pkg add ${result.slug}`));
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function pkgListCommand() {
|
|
119
|
+
const config = getConfig();
|
|
120
|
+
if (!config) return console.log(chalk.red("Not in a Kode project. Run kode init first."));
|
|
121
|
+
try {
|
|
122
|
+
const packages = await apiRequest(config, "/api/cdn/packages");
|
|
123
|
+
const installedDir = join(config.scriptsDir, "packages", "@kode");
|
|
124
|
+
const installed = existsSync(installedDir) ? readdirSync(installedDir) : [];
|
|
125
|
+
if (packages.length === 0) {
|
|
126
|
+
return console.log(chalk.dim("No packages in registry."));
|
|
127
|
+
}
|
|
128
|
+
console.log(chalk.bold(`\u{1F4E6} Packages (${packages.length}):
|
|
129
|
+
`));
|
|
130
|
+
for (const pkg of packages) {
|
|
131
|
+
const isInstalled = installed.includes(pkg.slug);
|
|
132
|
+
const status = isInstalled ? chalk.green(" \u2714") : "";
|
|
133
|
+
const tags = pkg.tags?.length ? chalk.dim(` [${pkg.tags.join(", ")}]`) : "";
|
|
134
|
+
console.log(` ${chalk.cyan(pkg.slug)} v${pkg.version}${status} \u2014 ${pkg.description || chalk.dim("No description")}${tags}`);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function pkgInfoCommand(name) {
|
|
141
|
+
const config = getConfig();
|
|
142
|
+
if (!config) return console.log(chalk.red("Not in a Kode project. Run kode init first."));
|
|
143
|
+
try {
|
|
144
|
+
const pkg = await apiRequest(config, `/api/cdn/packages/${name}`);
|
|
145
|
+
const installedDir = join(config.scriptsDir, "packages", "@kode", pkg.slug);
|
|
146
|
+
const isInstalled = existsSync(installedDir);
|
|
147
|
+
console.log(chalk.bold(`
|
|
148
|
+
\u{1F4E6} @kode/${pkg.slug} v${pkg.version}`));
|
|
149
|
+
console.log(` Name: ${pkg.name}`);
|
|
150
|
+
if (pkg.description) console.log(` Description: ${pkg.description}`);
|
|
151
|
+
console.log(` Entry: ${pkg.entry_point}`);
|
|
152
|
+
if (pkg.tags?.length) console.log(` Tags: ${pkg.tags.join(", ")}`);
|
|
153
|
+
console.log(` Installs: ${pkg.install_count}`);
|
|
154
|
+
console.log(` Status: ${isInstalled ? chalk.green("Installed") : chalk.dim("Not installed")}`);
|
|
155
|
+
if (pkg.files?.length) {
|
|
156
|
+
console.log(` Files:`);
|
|
157
|
+
for (const f of pkg.files) {
|
|
158
|
+
console.log(chalk.dim(` ${f.path}`));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (err) {
|
|
162
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function pkgUpdateCommand(name) {
|
|
166
|
+
const config = getConfig();
|
|
167
|
+
if (!config) return console.log(chalk.red("Not in a Kode project. Run kode init first."));
|
|
168
|
+
const pkgDir = join(config.scriptsDir, "packages", "@kode", name);
|
|
169
|
+
if (!existsSync(pkgDir)) {
|
|
170
|
+
return console.log(chalk.red(`Package "@kode/${name}" is not installed.`));
|
|
171
|
+
}
|
|
172
|
+
let currentVersion = 0;
|
|
173
|
+
const manifestPath = join(pkgDir, "kode.json");
|
|
174
|
+
if (existsSync(manifestPath)) {
|
|
175
|
+
try {
|
|
176
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
177
|
+
currentVersion = manifest.version || 0;
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const pkg = await apiRequest(config, `/api/cdn/packages/${name}`);
|
|
183
|
+
if (pkg.version <= currentVersion) {
|
|
184
|
+
return console.log(chalk.dim(`@kode/${name} is already up to date (v${currentVersion}).`));
|
|
185
|
+
}
|
|
186
|
+
await pkgAddCommand(name);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function collectFiles(baseDir, currentDir, files) {
|
|
192
|
+
for (const entry of readdirSync(currentDir, { withFileTypes: true })) {
|
|
193
|
+
const fullPath = join(currentDir, entry.name);
|
|
194
|
+
if (entry.isDirectory()) {
|
|
195
|
+
if (!["node_modules", ".git", "dist"].includes(entry.name)) {
|
|
196
|
+
collectFiles(baseDir, fullPath, files);
|
|
197
|
+
}
|
|
198
|
+
} else if (entry.isFile()) {
|
|
199
|
+
files.push({ path: relative(baseDir, fullPath), content: readFileSync(fullPath, "utf-8") });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function restorePackages() {
|
|
204
|
+
const config = getConfig();
|
|
205
|
+
if (!config) return;
|
|
206
|
+
const scriptsDir = config.scriptsDir;
|
|
207
|
+
if (!existsSync(scriptsDir)) return;
|
|
208
|
+
const importRegex = /from\s+['"]@kode\/([^'"\/]+)['"]/g;
|
|
209
|
+
const neededPackages = /* @__PURE__ */ new Set();
|
|
210
|
+
for (const entry of readdirSync(scriptsDir, { withFileTypes: true })) {
|
|
211
|
+
if (!entry.isFile()) continue;
|
|
212
|
+
if (![".ts", ".tsx", ".js", ".jsx"].includes(extname(entry.name))) continue;
|
|
213
|
+
const content = readFileSync(join(scriptsDir, entry.name), "utf-8");
|
|
214
|
+
let match;
|
|
215
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
216
|
+
neededPackages.add(match[1]);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (neededPackages.size === 0) return;
|
|
220
|
+
const packagesDir = join(scriptsDir, "packages", "@kode");
|
|
221
|
+
const installed = existsSync(packagesDir) ? readdirSync(packagesDir) : [];
|
|
222
|
+
const builtin = ["webflow"];
|
|
223
|
+
const missing = [...neededPackages].filter(
|
|
224
|
+
(pkg) => !builtin.includes(pkg) && !installed.includes(pkg)
|
|
225
|
+
);
|
|
226
|
+
if (missing.length === 0) return;
|
|
227
|
+
const spinner = (await import("ora")).default(`Gjenoppretter ${missing.length} pakke(r)...`).start();
|
|
228
|
+
let restored = 0;
|
|
229
|
+
for (const slug of missing) {
|
|
230
|
+
try {
|
|
231
|
+
const pkg = await apiRequest(config, `/api/cdn/packages/${slug}`);
|
|
232
|
+
if (!pkg?.files) continue;
|
|
233
|
+
const pkgDir = join(packagesDir, slug);
|
|
234
|
+
mkdirSync(pkgDir, { recursive: true });
|
|
235
|
+
for (const file of pkg.files) {
|
|
236
|
+
const filePath = join(pkgDir, file.path);
|
|
237
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
238
|
+
writeFileSync(filePath, file.content, "utf-8");
|
|
239
|
+
}
|
|
240
|
+
writeFileSync(join(pkgDir, "kode.json"), JSON.stringify({
|
|
241
|
+
name: pkg.name || slug,
|
|
242
|
+
version: String(pkg.version || "1"),
|
|
243
|
+
description: pkg.description || "",
|
|
244
|
+
entryPoint: pkg.entry_point || "index.ts"
|
|
245
|
+
}, null, 2), "utf-8");
|
|
246
|
+
restored++;
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (restored > 0) {
|
|
251
|
+
spinner.succeed(`${restored} pakke(r) gjenopprettet: ${missing.filter((_, i) => i < restored).map((s) => `@kode/${s}`).join(", ")}`);
|
|
252
|
+
} else {
|
|
253
|
+
spinner.info("Ingen pakker \xE5 gjenopprette");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export {
|
|
258
|
+
pkgAddCommand,
|
|
259
|
+
pkgRemoveCommand,
|
|
260
|
+
pkgPublishCommand,
|
|
261
|
+
pkgListCommand,
|
|
262
|
+
pkgInfoCommand,
|
|
263
|
+
pkgUpdateCommand,
|
|
264
|
+
restorePackages
|
|
265
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApiClient,
|
|
3
|
+
findProjectRoot,
|
|
4
|
+
getProjectConfig,
|
|
5
|
+
getScriptsDir
|
|
6
|
+
} from "./chunk-TLLGB46I.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/types.ts
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
import { writeFileSync, mkdirSync, existsSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
async function generateCmsTypes(options) {
|
|
14
|
+
const silent = options?.silent ?? false;
|
|
15
|
+
const spinner = silent ? null : ora("Henter CMS-typer fra Webflow...").start();
|
|
16
|
+
try {
|
|
17
|
+
const projectRoot = findProjectRoot();
|
|
18
|
+
if (!projectRoot) {
|
|
19
|
+
spinner?.fail("Ikke i et Kode-prosjekt");
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const config = getProjectConfig(projectRoot);
|
|
23
|
+
if (!config) {
|
|
24
|
+
spinner?.fail("Kunne ikke lese prosjektkonfigurasjon");
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const api = createApiClient(config);
|
|
28
|
+
let result;
|
|
29
|
+
try {
|
|
30
|
+
result = await api.getCmsTypes(config.siteId);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
if (err.message?.includes("Webflow credentials not configured")) {
|
|
33
|
+
spinner?.info("Webflow ikke konfigurert \u2014 hopper over CMS-typer");
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
if (!result.collections || result.collections.length === 0) {
|
|
39
|
+
spinner?.info("Ingen CMS-samlinger funnet");
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const scriptsDir = getScriptsDir(projectRoot, config);
|
|
43
|
+
const typesDir = join(scriptsDir, "types");
|
|
44
|
+
if (!existsSync(typesDir)) {
|
|
45
|
+
mkdirSync(typesDir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
writeFileSync(join(typesDir, "cms.d.ts"), result.typescript, "utf-8");
|
|
48
|
+
if (!silent) {
|
|
49
|
+
spinner?.succeed(
|
|
50
|
+
`CMS-typer generert: ${result.collections.length} samlinger \u2192 ${chalk.cyan("types/cms.d.ts")}`
|
|
51
|
+
);
|
|
52
|
+
for (const col of result.collections) {
|
|
53
|
+
console.log(
|
|
54
|
+
` ${chalk.dim("\u2022")} ${col.displayName} ${chalk.dim(`(${col.fieldCount} felt)`)}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
spinner?.stop();
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
} catch (err) {
|
|
62
|
+
if (!silent) {
|
|
63
|
+
spinner?.fail(`Kunne ikke generere CMS-typer: ${err.message}`);
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function typesCommand() {
|
|
69
|
+
await generateCmsTypes({ silent: false });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
generateCmsTypes,
|
|
74
|
+
typesCommand
|
|
75
|
+
};
|