@curenorway/kode-cli 1.9.0 → 1.10.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 +154 -67
- package/dist/{chunk-HKPZVOMY.js → chunk-CUZJE4JZ.js} +326 -40
- package/dist/cli.js +171 -108
- package/dist/index.d.ts +40 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -15,41 +15,101 @@ import {
|
|
|
15
15
|
readPageContext,
|
|
16
16
|
statusCommand,
|
|
17
17
|
watchCommand
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-CUZJE4JZ.js";
|
|
19
19
|
|
|
20
20
|
// src/cli.ts
|
|
21
21
|
import { Command } from "commander";
|
|
22
|
-
import
|
|
22
|
+
import chalk6 from "chalk";
|
|
23
23
|
import { createRequire } from "module";
|
|
24
24
|
|
|
25
|
-
// src/commands/
|
|
25
|
+
// src/commands/rollback.ts
|
|
26
26
|
import chalk from "chalk";
|
|
27
|
+
import ora from "ora";
|
|
28
|
+
async function rollbackCommand(environment = "staging") {
|
|
29
|
+
const projectRoot = findProjectRoot();
|
|
30
|
+
if (!projectRoot) {
|
|
31
|
+
console.log(chalk.red("\u274C Not in a Cure Kode project."));
|
|
32
|
+
console.log(chalk.dim(' Run "kode init" first.'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const config = getProjectConfig(projectRoot);
|
|
36
|
+
if (!config) {
|
|
37
|
+
console.log(chalk.red("\u274C Could not read project configuration."));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!["staging", "production"].includes(environment)) {
|
|
41
|
+
console.log(chalk.red(`\u274C Invalid environment: ${environment}`));
|
|
42
|
+
console.log(chalk.dim(' Use "staging" or "production"'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const client = createApiClient(config);
|
|
46
|
+
const spinner = ora(`Ruller tilbake ${environment}...`).start();
|
|
47
|
+
try {
|
|
48
|
+
if (environment === "production") {
|
|
49
|
+
const status = await client.getDeploymentStatus(config.siteId);
|
|
50
|
+
if (!status.productionEnabled) {
|
|
51
|
+
spinner.fail("Produksjon er ikke aktivert");
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(chalk.yellow("\u26A0\uFE0F Produksjon er deaktivert for dette prosjektet."));
|
|
54
|
+
console.log(chalk.dim(" Kan ikke rulle tilbake n\xE5r produksjon er deaktivert."));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const result = await client.rollback(config.siteId, environment);
|
|
59
|
+
spinner.succeed(`Tilbakerulling fullf\xF8rt (${result.duration_ms}ms)`);
|
|
60
|
+
console.log();
|
|
61
|
+
console.log(chalk.dim("Tilbakerulling detaljer:"));
|
|
62
|
+
console.log(chalk.dim(` Fra: ${result.rolledBackFrom.version}`));
|
|
63
|
+
console.log(chalk.dim(` Til: ${result.rolledBackTo.version}`));
|
|
64
|
+
console.log();
|
|
65
|
+
console.log(chalk.bold("CDN URL:"));
|
|
66
|
+
console.log(chalk.cyan(` ${result.cdn_url}`));
|
|
67
|
+
console.log();
|
|
68
|
+
console.log(chalk.green(`\u2705 ${environment.charAt(0).toUpperCase() + environment.slice(1)} er n\xE5 tilbake til forrige versjon!`));
|
|
69
|
+
} catch (error) {
|
|
70
|
+
spinner.fail("Tilbakerulling feilet");
|
|
71
|
+
if (error.statusCode === 404) {
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(chalk.yellow("\u26A0\uFE0F Ingen tidligere versjon \xE5 rulle tilbake til."));
|
|
74
|
+
console.log(chalk.dim(" Det m\xE5 v\xE6re minst 2 deployments for \xE5 kunne rulle tilbake."));
|
|
75
|
+
} else if (error.statusCode === 409) {
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk.yellow("\u26A0\uFE0F En annen deployment kj\xF8rer."));
|
|
78
|
+
console.log(chalk.dim(" Vent til den er ferdig og pr\xF8v igjen."));
|
|
79
|
+
} else {
|
|
80
|
+
console.error(chalk.red("\nError:"), error.message || error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/commands/pages.ts
|
|
86
|
+
import chalk2 from "chalk";
|
|
27
87
|
async function pagesCommand(options) {
|
|
28
88
|
const projectRoot = findProjectRoot();
|
|
29
89
|
if (!projectRoot) {
|
|
30
|
-
console.log(
|
|
31
|
-
console.log(
|
|
90
|
+
console.log(chalk2.red("Error: Not in a Cure Kode project."));
|
|
91
|
+
console.log(chalk2.dim('Run "kode init" first.'));
|
|
32
92
|
return;
|
|
33
93
|
}
|
|
34
94
|
const config = getProjectConfig(projectRoot);
|
|
35
95
|
if (!config) {
|
|
36
|
-
console.log(
|
|
96
|
+
console.log(chalk2.red("Error: Invalid project configuration."));
|
|
37
97
|
return;
|
|
38
98
|
}
|
|
39
99
|
if (options.delete && options.page) {
|
|
40
100
|
const deleted = deletePageContext(projectRoot, options.page);
|
|
41
101
|
if (deleted) {
|
|
42
|
-
console.log(
|
|
102
|
+
console.log(chalk2.green(`Deleted: ${options.page}`));
|
|
43
103
|
} else {
|
|
44
|
-
console.log(
|
|
104
|
+
console.log(chalk2.red(`Not found: ${options.page}`));
|
|
45
105
|
}
|
|
46
106
|
return;
|
|
47
107
|
}
|
|
48
108
|
if (options.page) {
|
|
49
109
|
const context = readPageContext(projectRoot, options.page);
|
|
50
110
|
if (!context) {
|
|
51
|
-
console.log(
|
|
52
|
-
console.log(
|
|
111
|
+
console.log(chalk2.red(`Page not found: ${options.page}`));
|
|
112
|
+
console.log(chalk2.dim('Use "kode pages" to list cached pages'));
|
|
53
113
|
return;
|
|
54
114
|
}
|
|
55
115
|
if (options.json) {
|
|
@@ -61,80 +121,80 @@ async function pagesCommand(options) {
|
|
|
61
121
|
}
|
|
62
122
|
const pages = listCachedPages(projectRoot);
|
|
63
123
|
if (pages.length === 0) {
|
|
64
|
-
console.log(
|
|
65
|
-
console.log(
|
|
124
|
+
console.log(chalk2.yellow("No cached pages."));
|
|
125
|
+
console.log(chalk2.dim('Use "kode html <url> --save" to cache page structures.'));
|
|
66
126
|
return;
|
|
67
127
|
}
|
|
68
128
|
if (options.json) {
|
|
69
129
|
console.log(JSON.stringify(pages, null, 2));
|
|
70
130
|
return;
|
|
71
131
|
}
|
|
72
|
-
console.log(
|
|
132
|
+
console.log(chalk2.bold(`Cached Pages (${pages.length})`));
|
|
73
133
|
console.log();
|
|
74
134
|
for (const page of pages) {
|
|
75
135
|
const path = new URL(page.url).pathname;
|
|
76
136
|
const date = new Date(page.extractedAt).toLocaleDateString();
|
|
77
137
|
const badges = [];
|
|
78
138
|
if (page.sectionCount > 0) badges.push(`${page.sectionCount} sections`);
|
|
79
|
-
if (page.cmsCollectionCount > 0) badges.push(
|
|
80
|
-
console.log(` ${
|
|
139
|
+
if (page.cmsCollectionCount > 0) badges.push(chalk2.cyan(`${page.cmsCollectionCount} CMS`));
|
|
140
|
+
console.log(` ${chalk2.bold(path)} ${chalk2.dim(`[${page.slug}]`)}`);
|
|
81
141
|
if (page.title) {
|
|
82
|
-
console.log(
|
|
142
|
+
console.log(chalk2.dim(` "${page.title}"`));
|
|
83
143
|
}
|
|
84
|
-
console.log(
|
|
144
|
+
console.log(chalk2.dim(` ${badges.join(", ")} \u2022 ${date}`));
|
|
85
145
|
console.log();
|
|
86
146
|
}
|
|
87
|
-
console.log(
|
|
88
|
-
console.log(
|
|
147
|
+
console.log(chalk2.dim(`Use "kode pages <slug>" to see details`));
|
|
148
|
+
console.log(chalk2.dim(`Use "kode html <url> --save --force" to refresh`));
|
|
89
149
|
}
|
|
90
150
|
function printPageDetails(context) {
|
|
91
|
-
console.log(
|
|
92
|
-
console.log(
|
|
93
|
-
console.log(
|
|
151
|
+
console.log(chalk2.bold(context.title || context.url));
|
|
152
|
+
console.log(chalk2.dim(context.url));
|
|
153
|
+
console.log(chalk2.dim(`Extracted: ${context.extractedAt}`));
|
|
94
154
|
console.log();
|
|
95
155
|
if (context.sections.length > 0) {
|
|
96
|
-
console.log(
|
|
156
|
+
console.log(chalk2.bold("Sections"));
|
|
97
157
|
for (const section of context.sections) {
|
|
98
158
|
const name = section.heading || section.id || section.className?.split(" ")[0] || "section";
|
|
99
159
|
const badges = [];
|
|
100
|
-
if (section.hasCms) badges.push(
|
|
101
|
-
if (section.hasForm) badges.push(
|
|
160
|
+
if (section.hasCms) badges.push(chalk2.cyan("CMS"));
|
|
161
|
+
if (section.hasForm) badges.push(chalk2.yellow("Form"));
|
|
102
162
|
const badgeStr = badges.length > 0 ? ` [${badges.join(", ")}]` : "";
|
|
103
163
|
console.log(` \u2022 ${name}${badgeStr}`);
|
|
104
164
|
if (section.textSample) {
|
|
105
|
-
console.log(
|
|
165
|
+
console.log(chalk2.dim(` "${section.textSample.slice(0, 80)}..."`));
|
|
106
166
|
}
|
|
107
167
|
}
|
|
108
168
|
console.log();
|
|
109
169
|
}
|
|
110
170
|
if (context.headings.length > 0) {
|
|
111
|
-
console.log(
|
|
171
|
+
console.log(chalk2.bold("Headings"));
|
|
112
172
|
for (const h of context.headings.slice(0, 10)) {
|
|
113
173
|
const level = "H" + h.level;
|
|
114
|
-
console.log(` ${
|
|
174
|
+
console.log(` ${chalk2.dim(level)} ${h.text}`);
|
|
115
175
|
}
|
|
116
176
|
if (context.headings.length > 10) {
|
|
117
|
-
console.log(
|
|
177
|
+
console.log(chalk2.dim(` ... and ${context.headings.length - 10} more`));
|
|
118
178
|
}
|
|
119
179
|
console.log();
|
|
120
180
|
}
|
|
121
181
|
if (context.ctas.length > 0) {
|
|
122
|
-
console.log(
|
|
182
|
+
console.log(chalk2.bold("CTAs"));
|
|
123
183
|
for (const cta of context.ctas) {
|
|
124
|
-
const href = cta.href ?
|
|
184
|
+
const href = cta.href ? chalk2.dim(` \u2192 ${cta.href}`) : "";
|
|
125
185
|
console.log(` \u2022 "${cta.text}"${href}`);
|
|
126
|
-
console.log(
|
|
186
|
+
console.log(chalk2.dim(` in ${cta.location}`));
|
|
127
187
|
}
|
|
128
188
|
console.log();
|
|
129
189
|
}
|
|
130
190
|
if (context.forms.length > 0) {
|
|
131
|
-
console.log(
|
|
191
|
+
console.log(chalk2.bold("Forms"));
|
|
132
192
|
for (const form of context.forms) {
|
|
133
|
-
console.log(` ${
|
|
193
|
+
console.log(` ${chalk2.bold(form.name || "form")}`);
|
|
134
194
|
for (const field of form.fields) {
|
|
135
|
-
const required = field.required ?
|
|
195
|
+
const required = field.required ? chalk2.red("*") : "";
|
|
136
196
|
const label = field.label || field.type;
|
|
137
|
-
console.log(` \u2022 ${label}${required} ${
|
|
197
|
+
console.log(` \u2022 ${label}${required} ${chalk2.dim(`(${field.type})`)}`);
|
|
138
198
|
}
|
|
139
199
|
if (form.submitText) {
|
|
140
200
|
console.log(` \u2192 Submit: "${form.submitText}"`);
|
|
@@ -143,31 +203,31 @@ function printPageDetails(context) {
|
|
|
143
203
|
console.log();
|
|
144
204
|
}
|
|
145
205
|
if (context.cmsPatterns.length > 0) {
|
|
146
|
-
console.log(
|
|
206
|
+
console.log(chalk2.bold("CMS Collections"));
|
|
147
207
|
for (const cms of context.cmsPatterns) {
|
|
148
|
-
console.log(` ${
|
|
208
|
+
console.log(` ${chalk2.bold(cms.containerClass)}: ${chalk2.cyan(`${cms.itemCount} items`)}`);
|
|
149
209
|
if (cms.templateFields.length > 0) {
|
|
150
|
-
console.log(
|
|
210
|
+
console.log(chalk2.dim(` Template fields: ${cms.templateFields.join(", ")}`));
|
|
151
211
|
}
|
|
152
212
|
}
|
|
153
213
|
console.log();
|
|
154
214
|
}
|
|
155
215
|
if (context.navigation.length > 0) {
|
|
156
|
-
console.log(
|
|
216
|
+
console.log(chalk2.bold("Navigation"));
|
|
157
217
|
for (const nav of context.navigation) {
|
|
158
|
-
console.log(` ${
|
|
218
|
+
console.log(` ${chalk2.bold(nav.type)}:`);
|
|
159
219
|
for (const item of nav.items.slice(0, 8)) {
|
|
160
|
-
const href = item.href ?
|
|
220
|
+
const href = item.href ? chalk2.dim(` \u2192 ${item.href}`) : "";
|
|
161
221
|
console.log(` \u2022 ${item.text}${href}`);
|
|
162
222
|
}
|
|
163
223
|
if (nav.items.length > 8) {
|
|
164
|
-
console.log(
|
|
224
|
+
console.log(chalk2.dim(` ... and ${nav.items.length - 8} more`));
|
|
165
225
|
}
|
|
166
226
|
}
|
|
167
227
|
console.log();
|
|
168
228
|
}
|
|
169
229
|
if (context.notes && context.notes.length > 0) {
|
|
170
|
-
console.log(
|
|
230
|
+
console.log(chalk2.bold("Notes"));
|
|
171
231
|
for (const note of context.notes) {
|
|
172
232
|
console.log(` \u2022 ${note}`);
|
|
173
233
|
}
|
|
@@ -176,40 +236,40 @@ function printPageDetails(context) {
|
|
|
176
236
|
}
|
|
177
237
|
|
|
178
238
|
// src/commands/set.ts
|
|
179
|
-
import
|
|
180
|
-
import
|
|
239
|
+
import chalk3 from "chalk";
|
|
240
|
+
import ora2 from "ora";
|
|
181
241
|
async function setCommand(script, options) {
|
|
182
242
|
const projectRoot = findProjectRoot();
|
|
183
243
|
if (!projectRoot) {
|
|
184
|
-
console.log(
|
|
185
|
-
console.log(
|
|
244
|
+
console.log(chalk3.red("\u274C Not in a Cure Kode project."));
|
|
245
|
+
console.log(chalk3.dim(' Run "kode init" first.'));
|
|
186
246
|
return;
|
|
187
247
|
}
|
|
188
248
|
const config = getProjectConfig(projectRoot);
|
|
189
249
|
if (!config) {
|
|
190
|
-
console.log(
|
|
250
|
+
console.log(chalk3.red("\u274C Could not read project configuration."));
|
|
191
251
|
return;
|
|
192
252
|
}
|
|
193
253
|
if (!options.scope && options.autoLoad === void 0) {
|
|
194
|
-
console.log(
|
|
195
|
-
console.log(
|
|
254
|
+
console.log(chalk3.yellow("\u26A0\uFE0F No changes specified."));
|
|
255
|
+
console.log(chalk3.dim(" Use --scope or --auto-load/--no-auto-load"));
|
|
196
256
|
console.log();
|
|
197
|
-
console.log(
|
|
198
|
-
console.log(
|
|
199
|
-
console.log(
|
|
200
|
-
console.log(
|
|
257
|
+
console.log(chalk3.dim("Examples:"));
|
|
258
|
+
console.log(chalk3.dim(" kode set my-script --scope page-specific"));
|
|
259
|
+
console.log(chalk3.dim(" kode set my-script --scope global --auto-load"));
|
|
260
|
+
console.log(chalk3.dim(" kode set my-script --no-auto-load"));
|
|
201
261
|
return;
|
|
202
262
|
}
|
|
203
|
-
const spinner =
|
|
263
|
+
const spinner = ora2(`Updating ${script}...`).start();
|
|
204
264
|
try {
|
|
205
265
|
const client = createApiClient(config);
|
|
206
266
|
const scripts = await client.listScripts(config.siteId);
|
|
207
267
|
const targetScript = scripts.find((s) => s.slug === script || s.name === script);
|
|
208
268
|
if (!targetScript) {
|
|
209
269
|
spinner.fail(`Script "${script}" not found`);
|
|
210
|
-
console.log(
|
|
270
|
+
console.log(chalk3.dim("\nAvailable scripts:"));
|
|
211
271
|
scripts.forEach((s) => {
|
|
212
|
-
console.log(
|
|
272
|
+
console.log(chalk3.dim(` - ${s.slug}`));
|
|
213
273
|
});
|
|
214
274
|
return;
|
|
215
275
|
}
|
|
@@ -229,80 +289,80 @@ async function setCommand(script, options) {
|
|
|
229
289
|
}
|
|
230
290
|
updates.changeSummary = `Updated settings: ${changes.join(", ")}`;
|
|
231
291
|
const updated = await client.updateScript(targetScript.id, updates);
|
|
232
|
-
spinner.succeed(
|
|
292
|
+
spinner.succeed(chalk3.green(`Updated ${script}`));
|
|
233
293
|
console.log();
|
|
234
294
|
for (const change of changes) {
|
|
235
|
-
console.log(
|
|
295
|
+
console.log(chalk3.dim(` ${change}`));
|
|
236
296
|
}
|
|
237
297
|
console.log();
|
|
238
298
|
if (options.scope === "page-specific") {
|
|
239
|
-
console.log(
|
|
240
|
-
console.log(
|
|
241
|
-
console.log(
|
|
299
|
+
console.log(chalk3.yellow("\u26A0\uFE0F Page-specific scripts need page assignments to load."));
|
|
300
|
+
console.log(chalk3.dim(" Use app.cure.no \u2192 Kode to assign pages, or use MCP:"));
|
|
301
|
+
console.log(chalk3.dim(" kode_assign_script_to_page(scriptSlug, pageSlug)"));
|
|
242
302
|
console.log();
|
|
243
303
|
}
|
|
244
|
-
console.log(
|
|
304
|
+
console.log(chalk3.dim('Run "kode deploy" to make changes live.'));
|
|
245
305
|
} catch (error) {
|
|
246
306
|
spinner.fail("Failed to update script");
|
|
247
|
-
console.error(
|
|
307
|
+
console.error(chalk3.red("\nError:"), error);
|
|
248
308
|
}
|
|
249
309
|
}
|
|
250
310
|
|
|
251
311
|
// src/commands/production.ts
|
|
252
|
-
import
|
|
253
|
-
import
|
|
312
|
+
import chalk4 from "chalk";
|
|
313
|
+
import ora3 from "ora";
|
|
254
314
|
async function productionCommand(action, options) {
|
|
255
315
|
if (!["enable", "disable", "status"].includes(action)) {
|
|
256
|
-
console.log(
|
|
257
|
-
console.log(
|
|
258
|
-
console.log(
|
|
259
|
-
console.log(
|
|
316
|
+
console.log(chalk4.red("\u274C Invalid action. Use: enable, disable, or status"));
|
|
317
|
+
console.log(chalk4.dim(" kode production enable [--domain <domain>]"));
|
|
318
|
+
console.log(chalk4.dim(" kode production disable"));
|
|
319
|
+
console.log(chalk4.dim(" kode production status"));
|
|
260
320
|
return;
|
|
261
321
|
}
|
|
262
322
|
const projectRoot = findProjectRoot();
|
|
263
323
|
if (!projectRoot) {
|
|
264
|
-
console.log(
|
|
265
|
-
console.log(
|
|
324
|
+
console.log(chalk4.red("\u274C Not in a Cure Kode project."));
|
|
325
|
+
console.log(chalk4.dim(' Run "kode init" first.'));
|
|
266
326
|
return;
|
|
267
327
|
}
|
|
268
328
|
const config = getProjectConfig(projectRoot);
|
|
269
329
|
if (!config) {
|
|
270
|
-
console.log(
|
|
330
|
+
console.log(chalk4.red("\u274C Could not read project configuration."));
|
|
271
331
|
return;
|
|
272
332
|
}
|
|
273
333
|
const client = createApiClient(config);
|
|
274
334
|
if (action === "status") {
|
|
275
|
-
const spinner2 =
|
|
335
|
+
const spinner2 = ora3("Fetching production status...").start();
|
|
276
336
|
try {
|
|
277
337
|
const status = await client.getDeploymentStatus(config.siteId);
|
|
278
338
|
spinner2.stop();
|
|
279
339
|
console.log();
|
|
280
|
-
console.log(
|
|
340
|
+
console.log(chalk4.bold("Production Status"));
|
|
281
341
|
console.log();
|
|
282
342
|
if (status.productionEnabled) {
|
|
283
|
-
console.log(
|
|
343
|
+
console.log(chalk4.green(" \u25CF Produksjon er aktivert"));
|
|
284
344
|
if (status.productionDomain) {
|
|
285
|
-
console.log(
|
|
345
|
+
console.log(chalk4.dim(` Domain: ${status.productionDomain}`));
|
|
286
346
|
}
|
|
287
347
|
if (status.production.lastSuccessful) {
|
|
288
348
|
console.log(
|
|
289
|
-
|
|
349
|
+
chalk4.dim(
|
|
290
350
|
` Siste deploy: v${status.production.lastSuccessful.version}`
|
|
291
351
|
)
|
|
292
352
|
);
|
|
293
353
|
}
|
|
294
354
|
} else {
|
|
295
|
-
console.log(
|
|
296
|
-
console.log(
|
|
355
|
+
console.log(chalk4.gray(" \u25CB Produksjon er deaktivert"));
|
|
356
|
+
console.log(chalk4.dim(" Kun staging er aktiv"));
|
|
297
357
|
}
|
|
298
358
|
console.log();
|
|
299
359
|
} catch (error) {
|
|
300
360
|
spinner2.fail("Failed to fetch status");
|
|
301
|
-
console.error(
|
|
361
|
+
console.error(chalk4.red("\nError:"), error.message || error);
|
|
302
362
|
}
|
|
303
363
|
return;
|
|
304
364
|
}
|
|
305
|
-
const spinner =
|
|
365
|
+
const spinner = ora3(
|
|
306
366
|
action === "enable" ? "Aktiverer produksjon..." : "Deaktiverer produksjon..."
|
|
307
367
|
).start();
|
|
308
368
|
try {
|
|
@@ -314,49 +374,49 @@ async function productionCommand(action, options) {
|
|
|
314
374
|
spinner.stop();
|
|
315
375
|
console.log();
|
|
316
376
|
if (action === "enable") {
|
|
317
|
-
console.log(
|
|
377
|
+
console.log(chalk4.green("\u2713 Produksjon er n\xE5 aktivert"));
|
|
318
378
|
if (result.productionDomain) {
|
|
319
|
-
console.log(
|
|
379
|
+
console.log(chalk4.dim(` Domain: ${result.productionDomain}`));
|
|
320
380
|
}
|
|
321
381
|
console.log();
|
|
322
|
-
console.log(
|
|
323
|
-
console.log(
|
|
324
|
-
console.log(
|
|
382
|
+
console.log(chalk4.dim(" Neste steg:"));
|
|
383
|
+
console.log(chalk4.dim(" 1. Deploy til staging: kode deploy"));
|
|
384
|
+
console.log(chalk4.dim(" 2. Promoter til produksjon: kode deploy --promote"));
|
|
325
385
|
} else {
|
|
326
|
-
console.log(
|
|
327
|
-
console.log(
|
|
386
|
+
console.log(chalk4.yellow("\u2713 Produksjon er n\xE5 deaktivert"));
|
|
387
|
+
console.log(chalk4.dim(" Kun staging-milj\xF8et er aktivt."));
|
|
328
388
|
console.log(
|
|
329
|
-
|
|
389
|
+
chalk4.dim(" Produksjonsdomenet vil f\xE5 en tom script-respons.")
|
|
330
390
|
);
|
|
331
391
|
}
|
|
332
392
|
console.log();
|
|
333
393
|
} catch (error) {
|
|
334
394
|
spinner.fail(action === "enable" ? "Kunne ikke aktivere produksjon" : "Kunne ikke deaktivere produksjon");
|
|
335
|
-
console.error(
|
|
395
|
+
console.error(chalk4.red("\nError:"), error.message || error);
|
|
336
396
|
}
|
|
337
397
|
}
|
|
338
398
|
|
|
339
399
|
// src/commands/update-claude-md.ts
|
|
340
|
-
import
|
|
400
|
+
import chalk5 from "chalk";
|
|
341
401
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
342
402
|
import { join } from "path";
|
|
343
403
|
async function updateClaudeMdCommand() {
|
|
344
404
|
const projectRoot = findProjectRoot();
|
|
345
405
|
if (!projectRoot) {
|
|
346
|
-
console.log(
|
|
347
|
-
console.log(
|
|
406
|
+
console.log(chalk5.red("\u274C Not in a Cure Kode project."));
|
|
407
|
+
console.log(chalk5.dim(' Run "kode init" first.'));
|
|
348
408
|
return;
|
|
349
409
|
}
|
|
350
410
|
const config = getProjectConfig(projectRoot);
|
|
351
411
|
if (!config) {
|
|
352
|
-
console.log(
|
|
412
|
+
console.log(chalk5.red("\u274C Could not read project configuration."));
|
|
353
413
|
return;
|
|
354
414
|
}
|
|
355
415
|
const claudeMdPath = join(projectRoot, "CLAUDE.md");
|
|
356
416
|
const newKodeSection = generateClaudeMdMinimal(config.siteName, config.siteSlug);
|
|
357
417
|
if (!existsSync(claudeMdPath)) {
|
|
358
418
|
writeFileSync(claudeMdPath, newKodeSection);
|
|
359
|
-
console.log(
|
|
419
|
+
console.log(chalk5.green("\u2705 Created CLAUDE.md with Cure Kode section"));
|
|
360
420
|
return;
|
|
361
421
|
}
|
|
362
422
|
let content = readFileSync(claudeMdPath, "utf-8");
|
|
@@ -375,18 +435,18 @@ async function updateClaudeMdCommand() {
|
|
|
375
435
|
content = newKodeSection + "---\n\n" + content;
|
|
376
436
|
writeFileSync(claudeMdPath, content);
|
|
377
437
|
if (removedCount > 1) {
|
|
378
|
-
console.log(
|
|
438
|
+
console.log(chalk5.green(`\u2705 Cleaned up ${removedCount} duplicate Kode sections and added fresh one`));
|
|
379
439
|
} else if (removedCount === 1) {
|
|
380
|
-
console.log(
|
|
440
|
+
console.log(chalk5.green("\u2705 Updated Cure Kode section in CLAUDE.md"));
|
|
381
441
|
} else {
|
|
382
|
-
console.log(
|
|
442
|
+
console.log(chalk5.green("\u2705 Added Cure Kode section to CLAUDE.md"));
|
|
383
443
|
}
|
|
384
444
|
console.log();
|
|
385
|
-
console.log(
|
|
386
|
-
console.log(
|
|
387
|
-
console.log(
|
|
388
|
-
console.log(
|
|
389
|
-
console.log(
|
|
445
|
+
console.log(chalk5.dim("The Cure Kode section now includes:"));
|
|
446
|
+
console.log(chalk5.dim(" \u2022 What is Cure Kode (internal tool explanation)"));
|
|
447
|
+
console.log(chalk5.dim(" \u2022 CDN URL with script tag for Webflow"));
|
|
448
|
+
console.log(chalk5.dim(" \u2022 Workflow steps"));
|
|
449
|
+
console.log(chalk5.dim(" \u2022 Command reference"));
|
|
390
450
|
}
|
|
391
451
|
|
|
392
452
|
// src/cli.ts
|
|
@@ -406,9 +466,12 @@ program.command("push").description("Upload local scripts to Cure").argument("[s
|
|
|
406
466
|
program.command("watch").description("Watch for changes and auto-push").option("-d, --deploy", "Auto-deploy after each push").action((options) => {
|
|
407
467
|
watchCommand(options);
|
|
408
468
|
});
|
|
409
|
-
program.command("deploy [environment]").description("Deploy to staging or production").option("-p, --promote", "Promote staging to production").action((environment, options) => {
|
|
469
|
+
program.command("deploy [environment]").description("Deploy to staging or production").option("-p, --promote", "Promote staging to production").option("-f, --force", "Force release stale deploy lock before deploying").action((environment, options) => {
|
|
410
470
|
deployCommand(environment, options);
|
|
411
471
|
});
|
|
472
|
+
program.command("rollback [environment]").description("Rollback to previous deployment").action((environment = "staging") => {
|
|
473
|
+
rollbackCommand(environment);
|
|
474
|
+
});
|
|
412
475
|
program.command("html <url>").description("Fetch and analyze HTML from a URL").option("-j, --json", "Output as JSON").option("--scripts", "Show only scripts").option("--styles", "Show only styles").option("-s, --save", "Save page structure to context").option("-f, --force", "Force refresh when using --save").action((url, options) => {
|
|
413
476
|
htmlCommand(url, options);
|
|
414
477
|
});
|
|
@@ -432,7 +495,7 @@ program.command("update-claude-md").alias("ucm").description("Add or update Cure
|
|
|
432
495
|
});
|
|
433
496
|
program.showHelpAfterError();
|
|
434
497
|
console.log();
|
|
435
|
-
console.log(
|
|
436
|
-
console.log(
|
|
498
|
+
console.log(chalk6.bold(" Cure Kode CLI"));
|
|
499
|
+
console.log(chalk6.dim(" Manage JS/CSS for Webflow sites"));
|
|
437
500
|
console.log();
|
|
438
501
|
program.parse();
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,9 @@ declare function getScriptsDir(projectRoot: string, projectConfig?: ProjectConfi
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Cure Kode API Client
|
|
44
|
+
*
|
|
45
|
+
* All requests automatically retry on network/transient errors
|
|
46
|
+
* with exponential backoff (500ms → 1s → 2s).
|
|
44
47
|
*/
|
|
45
48
|
interface CdnSite {
|
|
46
49
|
id: string;
|
|
@@ -158,12 +161,42 @@ declare class KodeApiClient {
|
|
|
158
161
|
};
|
|
159
162
|
canPromote: boolean;
|
|
160
163
|
}>;
|
|
164
|
+
rollback(siteId: string, environment?: 'staging' | 'production'): Promise<{
|
|
165
|
+
id: string;
|
|
166
|
+
status: 'rolled_back';
|
|
167
|
+
environment: 'staging' | 'production';
|
|
168
|
+
rolledBackFrom: {
|
|
169
|
+
version: string;
|
|
170
|
+
deploymentId: string;
|
|
171
|
+
};
|
|
172
|
+
rolledBackTo: {
|
|
173
|
+
version: string;
|
|
174
|
+
deploymentId: string;
|
|
175
|
+
};
|
|
176
|
+
cdn_url: string;
|
|
177
|
+
duration_ms: number;
|
|
178
|
+
}>;
|
|
161
179
|
setProductionEnabled(siteId: string, enabled: boolean, productionDomain?: string): Promise<{
|
|
162
180
|
success: boolean;
|
|
163
181
|
productionEnabled: boolean;
|
|
164
182
|
productionDomain: string | null;
|
|
165
183
|
}>;
|
|
166
184
|
fetchHtml(url: string): Promise<ParsedHtmlResult>;
|
|
185
|
+
getLockStatus(siteId: string): Promise<{
|
|
186
|
+
isLocked: boolean;
|
|
187
|
+
isStale: boolean;
|
|
188
|
+
lockHolder: string | null;
|
|
189
|
+
acquiredAt: string | null;
|
|
190
|
+
}>;
|
|
191
|
+
forceReleaseLock(siteId: string): Promise<{
|
|
192
|
+
success: boolean;
|
|
193
|
+
message: string;
|
|
194
|
+
wasLocked: boolean;
|
|
195
|
+
wasStale?: boolean;
|
|
196
|
+
previousLockHolder?: string;
|
|
197
|
+
acquiredAt?: string;
|
|
198
|
+
duration_ms?: number;
|
|
199
|
+
}>;
|
|
167
200
|
}
|
|
168
201
|
/**
|
|
169
202
|
* Create API client from project config
|
|
@@ -203,6 +236,11 @@ declare function pushCommand(options: {
|
|
|
203
236
|
|
|
204
237
|
/**
|
|
205
238
|
* Watch for local changes and auto-push
|
|
239
|
+
*
|
|
240
|
+
* Features:
|
|
241
|
+
* - Error tracking with retry queue
|
|
242
|
+
* - Status summary on error/success
|
|
243
|
+
* - Automatic retry after 30 seconds
|
|
206
244
|
*/
|
|
207
245
|
declare function watchCommand(options: {
|
|
208
246
|
deploy?: boolean;
|
|
@@ -214,9 +252,11 @@ declare function watchCommand(options: {
|
|
|
214
252
|
* Workflow:
|
|
215
253
|
* - `kode deploy` or `kode deploy staging` → deploys to staging
|
|
216
254
|
* - `kode deploy production` or `kode deploy --promote` → promotes staging to production
|
|
255
|
+
* - `kode deploy --force` → force release stale lock before deploying
|
|
217
256
|
*/
|
|
218
257
|
declare function deployCommand(environment?: 'staging' | 'production', options?: {
|
|
219
258
|
promote?: boolean;
|
|
259
|
+
force?: boolean;
|
|
220
260
|
}): Promise<void>;
|
|
221
261
|
|
|
222
262
|
/**
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@curenorway/kode-cli",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "CLI
|
|
3
|
+
"version": "1.10.0",
|
|
4
|
+
"description": "CLI for Cure Kode CDN - manage, deploy, and sync JS/CSS scripts for Webflow sites with AI agent support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cure-kode": "./dist/cli.js",
|