@curenorway/kode-cli 1.17.1 → 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.
@@ -1,67 +1,25 @@
1
- // src/config.ts
2
- import Conf from "conf";
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4
- import { join, dirname } from "path";
5
- var globalConfig = new Conf({
6
- projectName: "cure-kode",
7
- defaults: {
8
- apiUrl: "https://app.cure.no"
9
- }
10
- });
11
- var PROJECT_CONFIG_DIR = ".cure-kode";
12
- var PROJECT_CONFIG_FILE = "config.json";
13
- var DEFAULT_SCRIPTS_DIR = ".cure-kode-scripts";
14
- function findProjectRoot(startDir = process.cwd()) {
15
- let currentDir = startDir;
16
- while (currentDir !== dirname(currentDir)) {
17
- const configPath = join(currentDir, PROJECT_CONFIG_DIR, PROJECT_CONFIG_FILE);
18
- if (existsSync(configPath)) {
19
- return currentDir;
20
- }
21
- currentDir = dirname(currentDir);
22
- }
23
- return null;
24
- }
25
- function getProjectConfig(projectRoot) {
26
- const root = projectRoot || findProjectRoot();
27
- if (!root) return null;
28
- const configPath = join(root, PROJECT_CONFIG_DIR, PROJECT_CONFIG_FILE);
29
- if (!existsSync(configPath)) return null;
30
- try {
31
- const content = readFileSync(configPath, "utf-8");
32
- return JSON.parse(content);
33
- } catch {
34
- return null;
35
- }
36
- }
37
- function saveProjectConfig(config, projectRoot = process.cwd()) {
38
- const configDir = join(projectRoot, PROJECT_CONFIG_DIR);
39
- const configPath = join(configDir, PROJECT_CONFIG_FILE);
40
- if (!existsSync(configDir)) {
41
- mkdirSync(configDir, { recursive: true });
42
- }
43
- writeFileSync(configPath, JSON.stringify(config, null, 2));
44
- }
45
- function getApiUrl(projectConfig) {
46
- return projectConfig?.apiUrl || globalConfig.get("apiUrl");
47
- }
48
- function getApiKey(projectConfig) {
49
- return projectConfig?.apiKey || globalConfig.get("defaultApiKey") || null;
50
- }
51
- function setGlobalConfig(key, value) {
52
- globalConfig.set(key, value);
53
- }
54
- function getScriptsDir(projectRoot, projectConfig) {
55
- return join(projectRoot, projectConfig?.scriptsDir || DEFAULT_SCRIPTS_DIR);
56
- }
1
+ import {
2
+ pagesToInfoFormat,
3
+ scriptsToDocsFormat,
4
+ updateClaudeMd,
5
+ updateKodeDocs
6
+ } from "./chunk-GO6KLUXM.js";
7
+ import {
8
+ DEFAULT_SCRIPTS_DIR,
9
+ createApiClient,
10
+ findProjectRoot,
11
+ getProjectConfig,
12
+ getScriptsDir,
13
+ saveProjectConfig
14
+ } from "./chunk-TLLGB46I.js";
57
15
 
58
16
  // src/lib/context.ts
59
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
60
- import { join as join2 } from "path";
17
+ import { existsSync, readFileSync, writeFileSync } from "fs";
18
+ import { join } from "path";
61
19
  var CONTEXT_FILE = "context.md";
62
- var PROJECT_CONFIG_DIR2 = ".cure-kode";
20
+ var PROJECT_CONFIG_DIR = ".cure-kode";
63
21
  function getContextPath(projectRoot) {
64
- return join2(projectRoot, PROJECT_CONFIG_DIR2, CONTEXT_FILE);
22
+ return join(projectRoot, PROJECT_CONFIG_DIR, CONTEXT_FILE);
65
23
  }
66
24
  function parseContext(content) {
67
25
  const context = {
@@ -270,11 +228,11 @@ function serializeContext(context) {
270
228
  }
271
229
  function readContext(projectRoot) {
272
230
  const contextPath = getContextPath(projectRoot);
273
- if (!existsSync2(contextPath)) {
231
+ if (!existsSync(contextPath)) {
274
232
  return null;
275
233
  }
276
234
  try {
277
- const content = readFileSync2(contextPath, "utf-8");
235
+ const content = readFileSync(contextPath, "utf-8");
278
236
  return parseContext(content);
279
237
  } catch {
280
238
  return null;
@@ -283,7 +241,7 @@ function readContext(projectRoot) {
283
241
  function writeContext(projectRoot, context) {
284
242
  const contextPath = getContextPath(projectRoot);
285
243
  const content = serializeContext(context);
286
- writeFileSync2(contextPath, content, "utf-8");
244
+ writeFileSync(contextPath, content, "utf-8");
287
245
  }
288
246
  function appendNote(projectRoot, note, agent = "CLI") {
289
247
  const context = readContext(projectRoot);
@@ -1201,267 +1159,47 @@ Option C: Full rollback
1201
1159
  }
1202
1160
 
1203
1161
  // src/version.ts
1204
- var CLI_VERSION = "1.17.1";
1162
+ var CLI_VERSION = "1.19.0";
1205
1163
 
1206
1164
  // src/commands/init.ts
1207
1165
  import chalk from "chalk";
1208
1166
  import ora from "ora";
1209
1167
  import enquirer from "enquirer";
1210
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5, readFileSync as readFileSync5 } from "fs";
1211
- import { join as join5 } from "path";
1212
-
1213
- // src/lib/claude-md.ts
1214
- import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1168
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync3 } from "fs";
1215
1169
  import { join as join3 } from "path";
1216
- var KODE_REFERENCE = `## Cure Kode
1217
-
1218
- This project uses **Cure Kode** for JS/CSS delivery. **Before modifying scripts:**
1219
-
1220
- 1. Run \`kode pull\` to get latest from server
1221
- 2. Make your changes in \`.cure-kode-scripts/\`
1222
- 3. Run \`kode push\` to upload, then \`kode deploy\` to publish
1223
-
1224
- Full documentation: [.cure-kode/KODE.md](.cure-kode/KODE.md)
1225
-
1226
- ---
1227
-
1228
- `;
1229
- function hasKodeReference(content) {
1230
- return content.includes(".cure-kode/KODE.md") || content.includes("cure-kode/KODE.md") || content.includes("KODE.md");
1231
- }
1232
- function generateKodeMd(siteName, siteSlug, scripts, pages, options) {
1233
- const productionEnabled = options?.productionEnabled ?? false;
1234
- let md = `# Cure Kode: ${siteName}
1235
-
1236
- This project uses **Cure Kode** CDN for JavaScript/CSS delivery to Webflow.
1237
-
1238
- > **This file is auto-generated.** Do not edit manually - changes will be overwritten by \`kode pull\`, \`kode push\`, and \`kode sync\`.
1239
-
1240
- **Produksjon:** ${productionEnabled ? "\u2713 Aktivert \u2014 deploy til staging og produksjon" : "\u25CB Deaktivert \u2014 kun staging. Ikke hent fra produksjons-URL."}
1241
-
1242
- ---
1243
-
1244
- `;
1245
- md += `## CDN URL
1246
-
1247
- Add this to Webflow \u2192 Project Settings \u2192 Custom Code \u2192 Head:
1248
-
1249
- \`\`\`html
1250
- <script src="https://app.cure.no/api/cdn/${siteSlug}/init.js"></script>
1251
- \`\`\`
1252
-
1253
- ---
1254
-
1255
- `;
1256
- md += `## Scripts
1257
-
1258
- `;
1259
- if (scripts.length > 0) {
1260
- md += `| Script | Type | Scope | Auto | Purpose |
1261
- |--------|------|-------|------|---------|
1262
- `;
1263
- for (const script of scripts) {
1264
- const type = script.type === "javascript" ? "JS" : "CSS";
1265
- const scope = script.scope === "global" ? "Global" : "Page";
1266
- const auto = script.autoLoad ? "\u26A1" : "\u25CB";
1267
- const purpose = script.purpose || script.description || "\u2014";
1268
- const truncated = purpose.length > 50 ? purpose.slice(0, 47) + "..." : purpose;
1269
- md += `| \`${script.slug}\` | ${type} | ${scope} | ${auto} | ${truncated} |
1270
- `;
1271
- }
1272
- md += `
1273
- > \u26A1 = auto-loads on every page, \u25CB = manual load via \`CK.loadScript('slug')\`
1274
-
1275
- `;
1276
- } else {
1277
- md += `No scripts yet. Create one with \`kode push\`.
1278
-
1279
- `;
1280
- }
1281
- if (pages.length > 0) {
1282
- md += `---
1283
-
1284
- ## Pages
1285
-
1286
- Page-specific scripts only load when URL matches these patterns:
1287
-
1288
- `;
1289
- for (const page of pages) {
1290
- md += `- **${page.name}** (\`${page.slug}\`) \u2192 \`${page.patterns.join("`, `")}\`
1291
- `;
1292
- }
1293
- md += `
1294
- `;
1295
- }
1296
- const pageSpecificScripts = scripts.filter(
1297
- (s) => s.scope === "page-specific" && s.pageAssignments && s.pageAssignments.length > 0
1298
- );
1299
- if (pageSpecificScripts.length > 0) {
1300
- md += `---
1301
-
1302
- ## Script \u2192 Page Assignments
1303
-
1304
- | Script | Pages |
1305
- |--------|-------|
1306
- `;
1307
- for (const script of pageSpecificScripts) {
1308
- const pageList = script.pageAssignments.map((pa) => {
1309
- const page = pages.find((p) => p.slug === pa.pageSlug);
1310
- const patterns = page ? ` (\`${page.patterns.join("`, `")}\`)` : "";
1311
- return `\`${pa.pageSlug}\`${patterns}`;
1312
- }).join(", ");
1313
- md += `| \`${script.slug}\` | ${pageList} |
1314
- `;
1315
- }
1316
- md += `
1317
- `;
1318
- }
1319
- md += `---
1320
-
1321
- ## Workflow
1322
-
1323
- **Before making changes:**
1324
- \`\`\`bash
1325
- kode pull # Get latest scripts from server
1326
- \`\`\`
1327
-
1328
- **After making changes:**
1329
- \`\`\`bash
1330
- kode push # Upload your changes
1331
- kode deploy # Deploy to staging
1332
- kode deploy --promote # When ready, promote to production
1333
- \`\`\`
1334
-
1335
- **Periodically:**
1336
- \`\`\`bash
1337
- kode doctor # Check for issues and CLI updates
1338
- \`\`\`
1339
-
1340
- ---
1341
-
1342
- ## CLI Commands
1343
-
1344
- | Command | Description |
1345
- |---------|-------------|
1346
- | \`kode status\` | Show sync status and staleness warnings |
1347
- | \`kode pull\` | Download scripts from server |
1348
- | \`kode push\` | Upload local changes |
1349
- | \`kode sync\` | Bidirectional sync with conflict detection |
1350
- | \`kode diff <script>\` | Compare local vs remote versions |
1351
- | \`kode deploy\` | Deploy to staging |
1352
- | \`kode deploy --dry-run\` | Preview deployment without executing |
1353
- | \`kode deploy --promote\` | Promote staging to production |
1354
- | \`kode doctor\` | Check config, API, sync state, and CLI version |
1355
- | \`kode pages\` | List CDN pages |
1356
- | \`kode pages create <name> -p /path\` | Create a page with URL patterns |
1357
- | \`kode pages assign <page> <script>\` | Assign script to page |
1358
-
1359
- ## MCP Tools
1360
-
1361
- AI agents can use these tools directly:
1362
-
1363
- - \`kode_list_scripts\` - List all scripts
1364
- - \`kode_push\` - Upload local files
1365
- - \`kode_deploy\` / \`kode_promote\` - Deploy to staging/production
1366
- - \`kode_create_page\` - Create CDN page with URL patterns
1367
- - \`kode_assign_script_to_page\` - Assign script to page
1368
-
1369
- ## File Structure
1370
-
1371
- \`\`\`
1372
- .cure-kode/
1373
- \u251C\u2500\u2500 config.json # Site configuration (contains API key - gitignored)
1374
- \u251C\u2500\u2500 scripts.json # Sync state for conflict detection
1375
- \u251C\u2500\u2500 context.md # Dynamic context for AI agents
1376
- \u2514\u2500\u2500 KODE.md # This file - auto-generated docs
1377
-
1378
- .cure-kode-scripts/ # Your script files
1379
- \u251C\u2500\u2500 main.js
1380
- \u251C\u2500\u2500 form-handler.js
1381
- \u2514\u2500\u2500 ...
1382
-
1383
- .claude/skills/ # Claude Code skills
1384
- \u251C\u2500\u2500 deploy/ # /deploy \u2014 push and deploy workflow
1385
- \u2514\u2500\u2500 webflow-patterns/ # Auto-loaded Webflow DOM reference
1386
- \`\`\`
1387
- `;
1388
- return md;
1389
- }
1390
- function ensureClaudeMdReference(projectRoot) {
1391
- const claudeMdPath = join3(projectRoot, "CLAUDE.md");
1392
- if (!existsSync3(claudeMdPath)) {
1393
- writeFileSync3(claudeMdPath, KODE_REFERENCE);
1394
- return { created: true, updated: false, skipped: false };
1395
- }
1396
- const content = readFileSync3(claudeMdPath, "utf-8");
1397
- if (hasKodeReference(content)) {
1398
- return { created: false, updated: false, skipped: true };
1399
- }
1400
- const newContent = KODE_REFERENCE + content;
1401
- writeFileSync3(claudeMdPath, newContent);
1402
- return { created: false, updated: true, skipped: false };
1403
- }
1404
- function updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options) {
1405
- const kodeMdPath = join3(projectRoot, ".cure-kode", "KODE.md");
1406
- const existed = existsSync3(kodeMdPath);
1407
- const content = generateKodeMd(siteName, siteSlug, scripts, pages, options);
1408
- writeFileSync3(kodeMdPath, content);
1409
- return { created: !existed, updated: existed };
1410
- }
1411
- function updateKodeDocs(projectRoot, siteName, siteSlug, scripts, pages, options) {
1412
- const kodeMd = updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options);
1413
- const claudeMd = ensureClaudeMdReference(projectRoot);
1414
- return { kodeMd, claudeMd };
1415
- }
1416
- function scriptsToDocsFormat(scripts, pages) {
1417
- return scripts.map((s) => {
1418
- const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
1419
- const page = pages?.find((pg) => pg.id === p.page_id);
1420
- return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
1421
- }).filter((p) => p !== null);
1422
- return {
1423
- slug: s.slug,
1424
- name: s.name,
1425
- type: s.type,
1426
- scope: s.scope,
1427
- autoLoad: s.auto_load,
1428
- purpose: s.metadata?.purpose || s.description,
1429
- pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0
1430
- };
1431
- });
1432
- }
1433
- function pagesToInfoFormat(pages) {
1434
- return pages.filter((p) => p.is_active).map((p) => ({
1435
- name: p.name,
1436
- slug: p.slug,
1437
- patterns: p.url_patterns
1438
- }));
1439
- }
1440
- var updateClaudeMd = updateKodeDocs;
1441
1170
 
1442
1171
  // src/lib/skills.ts
1443
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
1444
- import { join as join4 } from "path";
1172
+ import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
1173
+ import { join as join2 } from "path";
1445
1174
  function generateSkills(projectRoot, siteSlug) {
1446
- const skillsDir = join4(projectRoot, ".claude", "skills");
1175
+ const skillsDir = join2(projectRoot, ".claude", "skills");
1447
1176
  const created = [];
1448
1177
  const skipped = [];
1449
- const deployDir = join4(skillsDir, "deploy");
1450
- const deployPath = join4(deployDir, "SKILL.md");
1451
- if (!existsSync4(deployPath)) {
1452
- mkdirSync2(deployDir, { recursive: true });
1453
- writeFileSync4(deployPath, generateDeploySkill(siteSlug));
1178
+ const deployDir = join2(skillsDir, "deploy");
1179
+ const deployPath = join2(deployDir, "SKILL.md");
1180
+ if (!existsSync2(deployPath)) {
1181
+ mkdirSync(deployDir, { recursive: true });
1182
+ writeFileSync2(deployPath, generateDeploySkill(siteSlug));
1454
1183
  created.push("deploy");
1455
1184
  } else {
1456
1185
  skipped.push("deploy");
1457
1186
  }
1458
- const webflowDir = join4(skillsDir, "webflow-patterns");
1459
- const webflowSkillPath = join4(webflowDir, "SKILL.md");
1460
- const webflowRefPath = join4(webflowDir, "reference.md");
1461
- if (!existsSync4(webflowSkillPath)) {
1462
- mkdirSync2(webflowDir, { recursive: true });
1463
- writeFileSync4(webflowSkillPath, WEBFLOW_SKILL);
1464
- writeFileSync4(webflowRefPath, WEBFLOW_REFERENCE);
1187
+ const libraryDir = join2(skillsDir, "library");
1188
+ const libraryPath = join2(libraryDir, "SKILL.md");
1189
+ if (!existsSync2(libraryPath)) {
1190
+ mkdirSync(libraryDir, { recursive: true });
1191
+ writeFileSync2(libraryPath, LIBRARY_SKILL);
1192
+ created.push("library");
1193
+ } else {
1194
+ skipped.push("library");
1195
+ }
1196
+ const webflowDir = join2(skillsDir, "webflow-patterns");
1197
+ const webflowSkillPath = join2(webflowDir, "SKILL.md");
1198
+ const webflowRefPath = join2(webflowDir, "reference.md");
1199
+ if (!existsSync2(webflowSkillPath)) {
1200
+ mkdirSync(webflowDir, { recursive: true });
1201
+ writeFileSync2(webflowSkillPath, WEBFLOW_SKILL);
1202
+ writeFileSync2(webflowRefPath, WEBFLOW_REFERENCE);
1465
1203
  created.push("webflow-patterns");
1466
1204
  } else {
1467
1205
  skipped.push("webflow-patterns");
@@ -1565,6 +1303,85 @@ See [reference.md](reference.md) for:
1565
1303
  - Animation and interaction scripting
1566
1304
  - Cure Kode script loading and execution order
1567
1305
  `;
1306
+ var LIBRARY_SKILL = `---
1307
+ name: library
1308
+ description: Check the Cure Kode global library before writing common patterns from scratch. Contains reusable GSAP animations, form handlers, scroll effects, and utilities organized in folders.
1309
+ user-invocable: false
1310
+ ---
1311
+
1312
+ # Cure Kode Library (Bibliotek)
1313
+
1314
+ Before writing common JavaScript/CSS patterns, check if the global library already has a reusable snippet.
1315
+
1316
+ ## Workflow
1317
+
1318
+ ### 1. Browse available snippets
1319
+
1320
+ \`\`\`
1321
+ kode library list # Flat list grouped by category
1322
+ kode library --tree # Folder tree view
1323
+ \`\`\`
1324
+
1325
+ Or search for a specific pattern:
1326
+
1327
+ \`\`\`
1328
+ kode library search "scroll"
1329
+ \`\`\`
1330
+
1331
+ Via MCP: use \`kode_library_list\` (with category/folder filter) or \`kode_library_get\`.
1332
+
1333
+ ### 2. Copy and adapt
1334
+
1335
+ **Direct copy** (for utilities that don't need changes):
1336
+ \`\`\`
1337
+ kode library add debounce-throttle
1338
+ kode push
1339
+ \`\`\`
1340
+
1341
+ **Copy-and-adapt** (for patterns that need project-specific selectors):
1342
+ 1. Read the snippet: \`kode library search gsap\`
1343
+ 2. Copy it: \`kode library add gsap-scroll-reveal\`
1344
+ 3. Edit the local file \u2014 update CSS selectors, classes, timing
1345
+ 4. Push: \`kode push\`
1346
+
1347
+ ### 3. Contribute back
1348
+
1349
+ If you improve a library snippet or create a reusable pattern:
1350
+ \`\`\`
1351
+ kode library push my-improved-script.js
1352
+ kode library push my-script.js --folder animations # Push to folder
1353
+ \`\`\`
1354
+
1355
+ Update an existing library snippet from a local file:
1356
+ \`\`\`
1357
+ kode library update gsap-scroll-reveal
1358
+ \`\`\`
1359
+
1360
+ ### 4. Manage folders and trash
1361
+
1362
+ \`\`\`
1363
+ kode library folders # List all folders
1364
+ kode library folders --create "Forms" # Create folder
1365
+ kode library trash # List trashed snippets
1366
+ kode library trash --restore <id> # Restore from trash
1367
+ \`\`\`
1368
+
1369
+ ## Categories
1370
+
1371
+ | Category | Content |
1372
+ |----------|---------|
1373
+ | \`animations\` | GSAP scroll reveals, smooth scrolling, parallax, counters |
1374
+ | \`forms\` | Form validation, multi-step forms, Webflow form intercept |
1375
+ | \`utilities\` | Debounce/throttle, viewport detection, cookie helpers |
1376
+ | \`tracking\` | Event tracking, scroll depth, click maps |
1377
+ | \`integrations\` | Third-party widget loaders, API connectors |
1378
+
1379
+ ## Local reference files
1380
+
1381
+ Library snippets are downloaded to \`.cure-kode-scripts/library/\` during \`kode library pull\`.
1382
+ These are **reference only** \u2014 they are never deployed. Only files in the root of \`.cure-kode-scripts/\` are pushed.
1383
+ Files are organized by folder name (or category as fallback).
1384
+ `;
1568
1385
  var WEBFLOW_REFERENCE = `# Webflow Patterns \u2014 Detailed Reference
1569
1386
 
1570
1387
  ## CMS Collection Lists
@@ -1897,26 +1714,154 @@ async function initCommand(options) {
1897
1714
  apiKey,
1898
1715
  scriptsDir: DEFAULT_SCRIPTS_DIR,
1899
1716
  environment: "staging",
1717
+ ...options.dev && { apiUrl: "http://localhost:3000" },
1900
1718
  ...projectCtx?.project && { projectId: projectCtx.project.id }
1901
1719
  };
1902
1720
  spinner.start("Oppretter prosjektstruktur...");
1903
1721
  saveProjectConfig(config, cwd);
1904
- const scriptsPath = join5(cwd, DEFAULT_SCRIPTS_DIR);
1905
- if (!existsSync5(scriptsPath)) {
1906
- mkdirSync3(scriptsPath, { recursive: true });
1722
+ const scriptsPath = join3(cwd, DEFAULT_SCRIPTS_DIR);
1723
+ if (!existsSync3(scriptsPath)) {
1724
+ mkdirSync2(scriptsPath, { recursive: true });
1907
1725
  }
1908
- const gitignorePath = join5(cwd, ".cure-kode", ".gitignore");
1726
+ const gitignorePath = join3(cwd, ".cure-kode", ".gitignore");
1909
1727
  const gitignoreContent = `# Hold config.json privat - inneholder API-n\xF8kkel
1910
1728
  config.json
1911
1729
  `;
1912
- writeFileSync5(gitignorePath, gitignoreContent);
1730
+ writeFileSync3(gitignorePath, gitignoreContent);
1731
+ const tsconfigPath = join3(cwd, "tsconfig.json");
1732
+ if (!existsSync3(tsconfigPath)) {
1733
+ writeFileSync3(tsconfigPath, JSON.stringify({
1734
+ compilerOptions: {
1735
+ target: "ES2020",
1736
+ module: "ESNext",
1737
+ moduleResolution: "bundler",
1738
+ jsx: "react-jsx",
1739
+ strict: true,
1740
+ noEmit: true,
1741
+ skipLibCheck: true,
1742
+ baseUrl: ".",
1743
+ paths: {
1744
+ "@kode/*": [".cure-kode-scripts/packages/@kode/*"]
1745
+ }
1746
+ },
1747
+ include: [".cure-kode-scripts/**/*"]
1748
+ }, null, 2) + "\n");
1749
+ }
1750
+ const packageJsonPath = join3(cwd, "package.json");
1751
+ if (!existsSync3(packageJsonPath)) {
1752
+ writeFileSync3(packageJsonPath, JSON.stringify({
1753
+ private: true,
1754
+ name: `kode-${site.slug}`,
1755
+ description: `Cure Kode scripts for ${site.name}`,
1756
+ devDependencies: {
1757
+ "@types/react": "^18.0.0",
1758
+ "@types/react-dom": "^18.0.0",
1759
+ "typescript": "^5.0.0"
1760
+ }
1761
+ }, null, 2) + "\n");
1762
+ }
1913
1763
  spinner.succeed("Prosjektstruktur opprettet");
1764
+ spinner.start("Installerer TypeScript-typer...");
1765
+ try {
1766
+ const { execSync } = await import("child_process");
1767
+ execSync("npm install", { cwd, stdio: "ignore", timeout: 3e4 });
1768
+ spinner.succeed("TypeScript-typer installert");
1769
+ } catch {
1770
+ spinner.warn('Kunne ikke installere TypeScript-typer automatisk. Kj\xF8r "npm install" manuelt.');
1771
+ }
1772
+ const webflowPkgDir = join3(scriptsPath, "packages", "@kode", "webflow");
1773
+ if (!existsSync3(webflowPkgDir)) {
1774
+ mkdirSync2(webflowPkgDir, { recursive: true });
1775
+ const siteSlug = config.siteSlug || "";
1776
+ writeFileSync3(join3(webflowPkgDir, "index.ts"), `/**
1777
+ * @kode/webflow \u2014 Runtime CMS helper for Webflow sites
1778
+ * Auto-generated by Cure Kode. Do not edit.
1779
+ */
1780
+
1781
+ import type { CmsCollections } from '../../../types/cms'
1782
+
1783
+ type CollectionSlug = keyof CmsCollections
1784
+
1785
+ interface CmsQueryOptions {
1786
+ limit?: number
1787
+ offset?: number
1788
+ }
1789
+
1790
+ const SITE_SLUG = '${siteSlug}'
1791
+
1792
+ function getApiBase(): string {
1793
+ if (typeof window === 'undefined') return 'https://app.cure.no'
1794
+ // Detect from the init.js script tag URL
1795
+ const scripts = document.querySelectorAll('script[src*="cure-kode"], script[src*="/api/cdn/"]')
1796
+ for (const s of scripts) {
1797
+ const src = (s as HTMLScriptElement).src
1798
+ if (src.includes('/api/cdn/')) {
1799
+ const url = new URL(src)
1800
+ return url.origin
1801
+ }
1802
+ }
1803
+ return 'https://app.cure.no'
1804
+ }
1805
+
1806
+ const API_BASE = getApiBase()
1807
+
1808
+ /**
1809
+ * Fetch all items from a CMS collection with full type safety
1810
+ *
1811
+ * @example
1812
+ * import { getCmsItems } from '@kode/webflow'
1813
+ * const ideas = await getCmsItems('ide')
1814
+ * ideas.forEach(idea => console.log(idea.name, idea.description))
1815
+ */
1816
+ export async function getCmsItems<K extends CollectionSlug>(
1817
+ collection: K,
1818
+ options?: CmsQueryOptions
1819
+ ): Promise<CmsCollections[K][]> {
1820
+ const params = new URLSearchParams({ collection })
1821
+ if (options?.limit) params.set('limit', String(options.limit))
1822
+ if (options?.offset) params.set('offset', String(options.offset))
1823
+
1824
+ const res = await fetch(\`\${API_BASE}/api/cdn/\${SITE_SLUG}/cms?\${params}\`)
1825
+
1826
+ if (!res.ok) throw new Error(\`[Kode] CMS fetch failed: \${res.status}\`)
1827
+ const data = await res.json()
1828
+ return data.items as CmsCollections[K][]
1829
+ }
1830
+
1831
+ /**
1832
+ * Fetch a single CMS item by ID or slug
1833
+ *
1834
+ * @example
1835
+ * import { getCmsItem } from '@kode/webflow'
1836
+ * const idea = await getCmsItem('ide', 'my-great-idea')
1837
+ */
1838
+ export async function getCmsItem<K extends CollectionSlug>(
1839
+ collection: K,
1840
+ itemId: string
1841
+ ): Promise<CmsCollections[K] | null> {
1842
+ const params = new URLSearchParams({ collection, itemId })
1843
+
1844
+ const res = await fetch(\`\${API_BASE}/api/cdn/\${SITE_SLUG}/cms?\${params}\`)
1845
+
1846
+ if (res.status === 404) return null
1847
+ if (!res.ok) throw new Error(\`[Kode] CMS fetch failed: \${res.status}\`)
1848
+ return res.json() as Promise<CmsCollections[K]>
1849
+ }
1850
+ `, "utf-8");
1851
+ writeFileSync3(join3(webflowPkgDir, "kode.json"), JSON.stringify({
1852
+ name: "webflow",
1853
+ version: "1.0.0",
1854
+ description: "Runtime CMS helper for Webflow sites",
1855
+ entryPoint: "index.ts",
1856
+ builtin: true
1857
+ }, null, 2), "utf-8");
1858
+ }
1914
1859
  spinner.start("Konfigurerer MCP-servere...");
1915
- const mcpConfigPath = join5(cwd, ".mcp.json");
1860
+ const mcpConfigPath = join3(cwd, ".mcp.json");
1916
1861
  let mcpConfig = {};
1917
- if (existsSync5(mcpConfigPath)) {
1862
+ if (existsSync3(mcpConfigPath)) {
1918
1863
  try {
1919
- mcpConfig = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
1864
+ mcpConfig = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
1920
1865
  } catch {
1921
1866
  }
1922
1867
  }
@@ -1965,7 +1910,7 @@ config.json
1965
1910
  mcpConfig.mcpServers[server.name] = serverConfig;
1966
1911
  }
1967
1912
  }
1968
- writeFileSync5(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
1913
+ writeFileSync3(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
1969
1914
  spinner.succeed("MCP-servere konfigurert");
1970
1915
  if (secretWarnings.length > 0) {
1971
1916
  console.log();
@@ -2017,8 +1962,46 @@ config.json
2017
1962
  production_domain: site.production_domain
2018
1963
  };
2019
1964
  const contextMdContent = generateInitialContext(config, scripts, siteInfo);
2020
- writeFileSync5(join5(cwd, ".cure-kode", "context.md"), contextMdContent);
1965
+ writeFileSync3(join3(cwd, ".cure-kode", "context.md"), contextMdContent);
2021
1966
  spinner.succeed("AI-dokumentasjon generert");
1967
+ spinner.start("Laster ned bibliotek-referanser...");
1968
+ try {
1969
+ const libResponse = await fetch("https://app.cure.no/api/cdn/library", {
1970
+ headers: { "X-API-Key": apiKey }
1971
+ });
1972
+ if (libResponse.ok) {
1973
+ const libSnippets = await libResponse.json();
1974
+ if (libSnippets.length > 0) {
1975
+ const { existsSync: exists, mkdirSync: mkDir, writeFileSync: writeFile } = await import("fs");
1976
+ const { join: joinPath } = await import("path");
1977
+ const libDir = joinPath(scriptsPath, "library");
1978
+ let downloaded = 0;
1979
+ for (const s of libSnippets) {
1980
+ const catDir = joinPath(libDir, s.category || "other");
1981
+ if (!exists(catDir)) mkDir(catDir, { recursive: true });
1982
+ const ext = s.type === "javascript" ? "js" : "css";
1983
+ try {
1984
+ const snippetRes = await fetch(`https://app.cure.no/api/cdn/library/${s.slug}`, {
1985
+ headers: { "X-API-Key": apiKey }
1986
+ });
1987
+ if (snippetRes.ok) {
1988
+ const full = await snippetRes.json();
1989
+ writeFile(joinPath(catDir, `${s.slug}.${ext}`), full.code);
1990
+ downloaded++;
1991
+ }
1992
+ } catch {
1993
+ }
1994
+ }
1995
+ spinner.succeed(`${downloaded} bibliotek-referanser lastet ned`);
1996
+ } else {
1997
+ spinner.succeed("Biblioteket er tomt");
1998
+ }
1999
+ } else {
2000
+ spinner.succeed("Bibliotek ikke tilgjengelig");
2001
+ }
2002
+ } catch {
2003
+ spinner.succeed("Bibliotek hoppet over");
2004
+ }
2022
2005
  spinner.start("Genererer Claude Code skills...");
2023
2006
  const skillsResult = generateSkills(cwd, config.siteSlug);
2024
2007
  if (skillsResult.created.length > 0) {
@@ -2026,6 +2009,23 @@ config.json
2026
2009
  } else {
2027
2010
  spinner.succeed("Claude Code skills finnes allerede");
2028
2011
  }
2012
+ try {
2013
+ const { pullCommand } = await import("./pull-G7GR67GG.js");
2014
+ console.log();
2015
+ await pullCommand({});
2016
+ } catch {
2017
+ }
2018
+ try {
2019
+ const { generateCmsTypes } = await import("./types-PZ7GFJEK.js");
2020
+ await generateCmsTypes({ silent: false });
2021
+ } catch {
2022
+ }
2023
+ try {
2024
+ const { restorePackages } = await import("./pkg-DOXTOICF.js");
2025
+ await restorePackages();
2026
+ } catch (err) {
2027
+ console.log(chalk.dim(` Pakke-gjenoppretting hoppet over: ${err?.message || "ukjent feil"}`));
2028
+ }
2029
2029
  console.log();
2030
2030
  console.log(chalk.green(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
2031
2031
  console.log(chalk.green(" \u2551") + chalk.bold.green(" \u2705 Cure Kode er klar! ") + chalk.green("\u2551"));
@@ -2041,9 +2041,12 @@ config.json
2041
2041
  console.log(chalk.dim(" \u251C\u2500\u2500 CLAUDE.md ") + chalk.dim("(uendret - har allerede referanse)"));
2042
2042
  }
2043
2043
  console.log(chalk.dim(" \u251C\u2500\u2500 .mcp.json ") + chalk.green("(MCP-servere)"));
2044
+ console.log(chalk.dim(" \u251C\u2500\u2500 package.json ") + chalk.green("(TypeScript/React-typer)"));
2045
+ console.log(chalk.dim(" \u251C\u2500\u2500 tsconfig.json ") + chalk.green("(TypeScript-konfigurasjon)"));
2044
2046
  console.log(chalk.dim(" \u251C\u2500\u2500 .claude/skills/ ") + chalk.green("(Claude Code skills)"));
2045
2047
  console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 deploy/ (/deploy \u2014 push og deploy)"));
2046
- console.log(chalk.dim(" \u2502 \u2514\u2500\u2500 webflow-patterns/ (Webflow DOM-referanse)"));
2048
+ console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 webflow-patterns/ (Webflow DOM-referanse)"));
2049
+ console.log(chalk.dim(" \u2502 \u2514\u2500\u2500 library/ (Bibliotek-referanse)"));
2047
2050
  console.log(chalk.dim(" \u251C\u2500\u2500 .cure-kode/"));
2048
2051
  console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 config.json (konfigurasjon)"));
2049
2052
  console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 KODE.md ") + chalk.green("(Kode-dokumentasjon)"));
@@ -2073,9 +2076,8 @@ config.json
2073
2076
  }
2074
2077
  console.log(chalk.bold(" Neste steg:"));
2075
2078
  console.log();
2076
- console.log(chalk.cyan(" 1. kode pull ") + chalk.dim("Last ned eksisterende skript"));
2077
- console.log(chalk.cyan(" 2.") + chalk.dim(" Start din AI-agent (Claude Code, Cursor, etc.)"));
2078
- console.log(chalk.cyan(" 3.") + chalk.dim(" Godkjenn MCP-servere n\xE5r agenten starter"));
2079
+ console.log(chalk.cyan(" 1.") + chalk.dim(" Start din AI-agent (Claude Code, Cursor, etc.)"));
2080
+ console.log(chalk.cyan(" 2.") + chalk.dim(" Godkjenn MCP-servere n\xE5r agenten starter"));
2079
2081
  console.log();
2080
2082
  console.log(chalk.bold(" MCP-verkt\xF8y tilgjengelig:"));
2081
2083
  console.log();
@@ -2097,470 +2099,70 @@ config.json
2097
2099
  }
2098
2100
  }
2099
2101
 
2100
- // src/lib/retry.ts
2101
- function isRetryableError(error) {
2102
- if (error instanceof TypeError && error.message.includes("fetch")) {
2103
- return true;
2104
- }
2105
- const err = error;
2106
- const statusCode = err.statusCode || err.status;
2107
- if (statusCode && statusCode >= 400 && statusCode < 500) {
2108
- return false;
2109
- }
2110
- if (statusCode && statusCode >= 500) {
2111
- return true;
2112
- }
2113
- if (err.code === "ECONNRESET" || err.code === "ETIMEDOUT" || err.code === "ENOTFOUND") {
2114
- return true;
2115
- }
2116
- if (error instanceof Error) {
2117
- const message = error.message.toLowerCase();
2118
- if (message.includes("network") || message.includes("timeout") || message.includes("connection") || message.includes("socket")) {
2119
- return true;
2120
- }
2121
- }
2122
- return false;
2123
- }
2124
- function calculateDelay(attempt, baseDelayMs, maxDelayMs, backoffMultiplier, jitter) {
2125
- const exponentialDelay = baseDelayMs * Math.pow(backoffMultiplier, attempt - 1);
2126
- const cappedDelay = Math.min(exponentialDelay, maxDelayMs);
2127
- if (!jitter) {
2128
- return cappedDelay;
2129
- }
2130
- const jitterRange = cappedDelay * 0.25;
2131
- const jitterOffset = (Math.random() - 0.5) * 2 * jitterRange;
2132
- return Math.max(0, Math.round(cappedDelay + jitterOffset));
2133
- }
2134
- function sleep(ms) {
2135
- return new Promise((resolve) => setTimeout(resolve, ms));
2136
- }
2137
- async function withRetry(fn, options = {}) {
2138
- const {
2139
- maxAttempts = 3,
2140
- baseDelayMs = 500,
2141
- maxDelayMs = 5e3,
2142
- backoffMultiplier = 2,
2143
- jitter = true,
2144
- isRetryable = isRetryableError,
2145
- onRetry
2146
- } = options;
2147
- let lastError;
2148
- let totalDelayMs = 0;
2149
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2150
- try {
2151
- return await fn();
2152
- } catch (error) {
2153
- lastError = error instanceof Error ? error : new Error(String(error));
2154
- if (attempt >= maxAttempts || !isRetryable(error)) {
2155
- throw lastError;
2156
- }
2157
- const delayMs = calculateDelay(
2158
- attempt,
2159
- baseDelayMs,
2160
- maxDelayMs,
2161
- backoffMultiplier,
2162
- jitter
2163
- );
2164
- totalDelayMs += delayMs;
2165
- if (onRetry) {
2166
- onRetry(attempt, error, delayMs);
2167
- }
2168
- await sleep(delayMs);
2169
- }
2170
- }
2171
- throw lastError || new Error("Retry failed");
2172
- }
2173
-
2174
- // src/api.ts
2175
- var KodeApiError = class extends Error {
2176
- constructor(message, statusCode, response) {
2177
- super(message);
2178
- this.statusCode = statusCode;
2179
- this.response = response;
2180
- this.name = "KodeApiError";
2181
- }
2182
- };
2183
- var KodeApiClient = class {
2184
- baseUrl;
2185
- apiKey;
2186
- constructor(config) {
2187
- this.baseUrl = getApiUrl(config);
2188
- const apiKey = getApiKey(config);
2189
- if (!apiKey) {
2190
- throw new Error('API key is required. Run "kode init" first.');
2191
- }
2192
- this.apiKey = apiKey;
2193
- }
2194
- async request(endpoint, options = {}) {
2195
- const url = `${this.baseUrl}${endpoint}`;
2196
- return withRetry(
2197
- async () => {
2198
- const response = await fetch(url, {
2199
- ...options,
2200
- headers: {
2201
- "Content-Type": "application/json",
2202
- "X-API-Key": this.apiKey,
2203
- ...options.headers
2204
- }
2205
- });
2206
- const data = await response.json();
2207
- if (!response.ok) {
2208
- throw new KodeApiError(
2209
- data.error || `Request failed with status ${response.status}`,
2210
- response.status,
2211
- data
2212
- );
2213
- }
2214
- return data;
2215
- },
2216
- {
2217
- maxAttempts: 3,
2218
- baseDelayMs: 500,
2219
- // Custom retry check: retry on network errors and 5xx, but not 4xx
2220
- isRetryable: (error) => {
2221
- if (error instanceof KodeApiError) {
2222
- return error.statusCode >= 500;
2223
- }
2224
- return isRetryableError(error);
2225
- }
2226
- }
2227
- );
2228
- }
2229
- // Sites
2230
- async getSite(siteId) {
2231
- return this.request(`/api/cdn/sites/${siteId}`);
2232
- }
2233
- async listSites() {
2234
- return this.request("/api/cdn/sites");
2235
- }
2236
- // Scripts
2237
- async listScripts(siteId) {
2238
- return this.request(`/api/cdn/sites/${siteId}/scripts`);
2239
- }
2240
- async getScript(scriptId) {
2241
- return this.request(`/api/cdn/scripts/${scriptId}`);
2242
- }
2243
- async createScript(siteId, data) {
2244
- return this.request(`/api/cdn/sites/${siteId}/scripts`, {
2245
- method: "POST",
2246
- body: JSON.stringify(data)
2247
- });
2248
- }
2249
- async updateScript(scriptId, data) {
2250
- return this.request(`/api/cdn/scripts/${scriptId}`, {
2251
- method: "PUT",
2252
- body: JSON.stringify(data)
2253
- });
2254
- }
2255
- async deleteScript(scriptId) {
2256
- await this.request(`/api/cdn/scripts/${scriptId}`, {
2257
- method: "DELETE"
2258
- });
2259
- }
2260
- // Upload (alternative endpoint that works with API keys)
2261
- async uploadScript(data) {
2262
- return this.request("/api/cdn/upload", {
2263
- method: "POST",
2264
- body: JSON.stringify({
2265
- ...data,
2266
- apiKey: this.apiKey
2267
- })
2268
- });
2269
- }
2270
- // Pages
2271
- async listPages(siteId) {
2272
- return this.request(`/api/cdn/sites/${siteId}/pages`);
2273
- }
2274
- async getPage(pageId) {
2275
- return this.request(`/api/cdn/pages/${pageId}`);
2276
- }
2277
- async createPage(siteId, data) {
2278
- return this.request(`/api/cdn/sites/${siteId}/pages`, {
2279
- method: "POST",
2280
- body: JSON.stringify(data)
2281
- });
2282
- }
2283
- async updatePage(pageId, data) {
2284
- return this.request(`/api/cdn/pages/${pageId}`, {
2285
- method: "PATCH",
2286
- body: JSON.stringify(data)
2287
- });
2288
- }
2289
- async deletePage(pageId) {
2290
- return this.request(`/api/cdn/pages/${pageId}`, {
2291
- method: "DELETE"
2292
- });
2293
- }
2294
- async assignScriptToPage(pageId, scriptId, loadOrderOverride) {
2295
- return this.request(`/api/cdn/pages/${pageId}/scripts`, {
2296
- method: "POST",
2297
- body: JSON.stringify({ scriptId, loadOrderOverride })
2298
- });
2299
- }
2300
- async removeScriptFromPage(pageId, scriptId) {
2301
- return this.request(`/api/cdn/pages/${pageId}/scripts/${scriptId}`, {
2302
- method: "DELETE"
2303
- });
2304
- }
2305
- async getPageScripts(pageId) {
2306
- return this.request(`/api/cdn/pages/${pageId}/scripts`);
2307
- }
2308
- // Deployments
2309
- async deploy(siteId, environment = "staging") {
2310
- return this.request("/api/cdn/deploy", {
2311
- method: "POST",
2312
- body: JSON.stringify({
2313
- siteId,
2314
- environment,
2315
- apiKey: this.apiKey
2316
- })
2317
- });
2318
- }
2319
- async promoteToProduction(siteId, stagingDeploymentId) {
2320
- return this.request("/api/cdn/deploy/promote", {
2321
- method: "POST",
2322
- body: JSON.stringify({
2323
- siteId,
2324
- stagingDeploymentId,
2325
- apiKey: this.apiKey
2326
- })
2327
- });
2328
- }
2329
- async getDeploymentStatus(siteId) {
2330
- return this.request(`/api/cdn/sites/${siteId}/deployments/status`);
2331
- }
2332
- async rollback(siteId, environment = "staging") {
2333
- return this.request("/api/cdn/deploy/rollback", {
2334
- method: "POST",
2335
- body: JSON.stringify({
2336
- siteId,
2337
- environment
2338
- })
2339
- });
2340
- }
2341
- // Production enabled toggle (v2.3)
2342
- async setProductionEnabled(siteId, enabled, productionDomain) {
2343
- return this.request(`/api/cdn/sites/${siteId}/production`, {
2344
- method: "POST",
2345
- body: JSON.stringify({
2346
- enabled,
2347
- productionDomain
2348
- })
2349
- });
2350
- }
2351
- // HTML Fetch
2352
- async fetchHtml(url) {
2353
- return this.request("/api/cdn/fetch-html", {
2354
- method: "POST",
2355
- body: JSON.stringify({ url })
2356
- });
2357
- }
2358
- // Lock management
2359
- async getLockStatus(siteId) {
2360
- return this.request(`/api/cdn/deploy/lock?siteId=${siteId}`);
2361
- }
2362
- async forceReleaseLock(siteId) {
2363
- return this.request("/api/cdn/deploy/lock", {
2364
- method: "DELETE",
2365
- body: JSON.stringify({ siteId })
2366
- });
2367
- }
2368
- // Webflow Custom Code injection
2369
- async getWebflowCustomCodeStatus(siteId) {
2370
- return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`);
2371
- }
2372
- async injectWebflowCustomCode(siteId, location = "header") {
2373
- return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`, {
2374
- method: "POST",
2375
- body: JSON.stringify({ location })
2376
- });
2377
- }
2378
- async removeWebflowCustomCode(siteId) {
2379
- return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`, {
2380
- method: "DELETE"
2381
- });
2382
- }
2383
- };
2384
- function createApiClient(config) {
2385
- return new KodeApiClient(config);
2386
- }
2387
-
2388
- // src/commands/pull.ts
2102
+ // src/commands/push.ts
2389
2103
  import chalk2 from "chalk";
2390
2104
  import ora2 from "ora";
2391
- import { writeFileSync as writeFileSync6, readFileSync as readFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
2392
- import { join as join6 } from "path";
2105
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync4, readdirSync, statSync } from "fs";
2106
+ import { join as join4, basename, extname } from "path";
2393
2107
  import { createHash } from "crypto";
2394
- function hashContent(content) {
2395
- return createHash("sha256").update(content).digest("hex").substring(0, 16);
2396
- }
2397
- async function pullCommand(options) {
2398
- const projectRoot = findProjectRoot();
2399
- if (!projectRoot) {
2400
- console.log(chalk2.red("Feil: Ikke i et Cure Kode-prosjekt."));
2401
- console.log(chalk2.dim('Kj\xF8r "kode init" f\xF8rst.'));
2402
- return;
2403
- }
2404
- const config = getProjectConfig(projectRoot);
2405
- if (!config) {
2406
- console.log(chalk2.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
2407
- return;
2408
- }
2409
- const spinner = ora2("Henter skript...").start();
2108
+ import * as esbuild from "esbuild";
2109
+ var BUNDLEABLE_EXTENSIONS = [".ts", ".tsx", ".jsx"];
2110
+ async function bundleFile(filePath, scriptsDir) {
2410
2111
  try {
2411
- const client = createApiClient(config);
2412
- const scripts = await client.listScripts(config.siteId);
2413
- if (scripts.length === 0) {
2414
- spinner.info("Ingen skript funnet p\xE5 server.");
2415
- console.log(chalk2.dim('\nOpprett skript i Cure App eller bruk "kode push" for \xE5 laste opp.'));
2416
- return;
2417
- }
2418
- spinner.succeed(`Fant ${scripts.length} skript`);
2419
- const scriptsDir = getScriptsDir(projectRoot, config);
2420
- if (!existsSync6(scriptsDir)) {
2421
- mkdirSync4(scriptsDir, { recursive: true });
2422
- }
2423
- const metadataPath = join6(projectRoot, ".cure-kode", "scripts.json");
2424
- let existingMetadata = [];
2425
- if (existsSync6(metadataPath)) {
2426
- try {
2427
- existingMetadata = JSON.parse(readFileSync6(metadataPath, "utf-8"));
2428
- } catch {
2429
- }
2430
- }
2431
- const scriptsToPull = options.script ? scripts.filter((s) => s.slug === options.script || s.name === options.script) : scripts;
2432
- if (options.script && scriptsToPull.length === 0) {
2433
- console.log(chalk2.yellow(`
2434
- Fant ikke skript "${options.script}".`));
2435
- console.log(chalk2.dim("Tilgjengelige skript:"));
2436
- scripts.forEach((s) => {
2437
- console.log(chalk2.dim(` - ${s.slug} (${s.name})`));
2438
- });
2439
- return;
2440
- }
2441
- console.log();
2442
- let pulled = 0;
2443
- let skipped = 0;
2444
- let updated = 0;
2445
- for (const script of scriptsToPull) {
2446
- const ext = script.type === "javascript" ? "js" : "css";
2447
- const fileName = `${script.slug}.${ext}`;
2448
- const filePath = join6(scriptsDir, fileName);
2449
- const existingMeta = existingMetadata.find((m) => m.slug === script.slug);
2450
- const lastPulledVersion = existingMeta?.lastPulledVersion || 0;
2451
- if (existsSync6(filePath) && !options.force) {
2452
- const localContent = readFileSync6(filePath, "utf-8");
2453
- const localHash = hashContent(localContent);
2454
- const hasLocalChanges = existingMeta && localHash !== existingMeta.contentHash;
2455
- if (hasLocalChanges) {
2456
- if (script.current_version > lastPulledVersion) {
2457
- console.log(
2458
- chalk2.yellow(` \u26A0 ${fileName}`) + chalk2.dim(` (lokal v${lastPulledVersion} \u2192 server v${script.current_version}, konflikt)`)
2459
- );
2460
- console.log(chalk2.dim(` Bruk --force for \xE5 overskrive lokale endringer`));
2461
- } else {
2462
- console.log(
2463
- chalk2.yellow(` \u26A0 ${fileName}`) + chalk2.dim(" (lokale endringer, bruk --force)")
2464
- );
2112
+ const aliases = {};
2113
+ const pkgDir = join4(scriptsDir, "packages", "@kode");
2114
+ if (existsSync4(pkgDir)) {
2115
+ for (const name of readdirSync(pkgDir)) {
2116
+ const pkgPath = join4(pkgDir, name);
2117
+ if (!statSync(pkgPath).isDirectory()) continue;
2118
+ for (const entry of ["index.ts", "index.tsx", "index.jsx", "index.js"]) {
2119
+ const entryPath = join4(pkgPath, entry);
2120
+ if (existsSync4(entryPath)) {
2121
+ aliases[`@kode/${name}`] = entryPath;
2122
+ break;
2465
2123
  }
2466
- skipped++;
2467
- continue;
2468
- }
2469
- if (script.content === localContent) {
2470
- console.log(chalk2.dim(` \u25CB ${fileName} (ingen endringer)`));
2471
- skipped++;
2472
- continue;
2473
2124
  }
2474
2125
  }
2475
- writeFileSync6(filePath, script.content);
2476
- const scopeTag = script.scope === "global" ? chalk2.blue("[G]") : chalk2.magenta("[P]");
2477
- const loadTag = script.auto_load ? chalk2.green("\u26A1") : chalk2.dim("\u25CB");
2478
- if (lastPulledVersion > 0 && script.current_version > lastPulledVersion) {
2479
- console.log(
2480
- chalk2.green(` \u2713 ${fileName}`) + chalk2.dim(` v${lastPulledVersion} \u2192 v${script.current_version}`) + ` ${scopeTag} ${loadTag}`
2481
- );
2482
- updated++;
2483
- } else {
2484
- console.log(
2485
- chalk2.green(` \u2713 ${fileName}`) + chalk2.dim(` v${script.current_version}`) + ` ${scopeTag} ${loadTag}`
2486
- );
2487
- pulled++;
2488
- }
2489
- }
2490
- console.log();
2491
- if (pulled > 0) {
2492
- console.log(chalk2.green(`Hentet ${pulled} skript til ${config.scriptsDir}/`));
2493
- }
2494
- if (updated > 0) {
2495
- console.log(chalk2.cyan(`Oppdatert ${updated} skript med nye versjoner`));
2496
- }
2497
- if (skipped > 0) {
2498
- console.log(chalk2.dim(`Hoppet over ${skipped} skript`));
2499
2126
  }
2500
- let pages = [];
2501
- try {
2502
- pages = await client.listPages(config.siteId);
2503
- } catch {
2504
- }
2505
- const now = (/* @__PURE__ */ new Date()).toISOString();
2506
- const metadata = scripts.map((s) => {
2507
- const filePath = join6(scriptsDir, `${s.slug}.${s.type === "javascript" ? "js" : "css"}`);
2508
- const localContent = existsSync6(filePath) ? readFileSync6(filePath, "utf-8") : s.content;
2509
- const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
2510
- const page = pages.find((pg) => pg.id === p.page_id);
2511
- return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
2512
- }).filter((p) => p !== null);
2513
- return {
2514
- id: s.id,
2515
- slug: s.slug,
2516
- name: s.name,
2517
- type: s.type,
2518
- scope: s.scope,
2519
- autoLoad: s.auto_load,
2520
- version: s.current_version,
2521
- loadOrder: s.load_order,
2522
- pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
2523
- lastPulledVersion: s.current_version,
2524
- lastPulledAt: now,
2525
- contentHash: hashContent(localContent)
2526
- };
2127
+ const result = await esbuild.build({
2128
+ entryPoints: [filePath],
2129
+ bundle: true,
2130
+ format: "iife",
2131
+ platform: "browser",
2132
+ target: ["es2020"],
2133
+ minify: true,
2134
+ write: false,
2135
+ external: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"],
2136
+ jsx: "automatic",
2137
+ jsxImportSource: "react",
2138
+ absWorkingDir: scriptsDir,
2139
+ resolveExtensions: [".tsx", ".ts", ".jsx", ".js", ".css"],
2140
+ alias: aliases,
2141
+ // Shim require() for external React in browser IIFE context
2142
+ banner: {
2143
+ js: `var require=function(m){var g={"react":window.React,"react-dom":window.ReactDOM,"react-dom/client":window.ReactDOM,"react/jsx-runtime":window.React,"react/jsx-dev-runtime":window.React};if(g[m])return g[m];throw new Error("Cannot find module '"+m+"'")};`
2144
+ },
2145
+ logLevel: "silent"
2527
2146
  });
2528
- writeFileSync6(metadataPath, JSON.stringify(metadata, null, 2));
2529
- try {
2530
- const result = updateClaudeMd(
2531
- projectRoot,
2532
- config.siteName,
2533
- config.siteSlug,
2534
- scriptsToDocsFormat(scripts, pages),
2535
- pagesToInfoFormat(pages)
2536
- );
2537
- if (result.kodeMd.created) {
2538
- console.log(chalk2.green("Opprettet .cure-kode/KODE.md"));
2539
- } else if (result.kodeMd.updated) {
2540
- console.log(chalk2.dim("Oppdatert .cure-kode/KODE.md"));
2541
- }
2542
- if (result.claudeMd.created) {
2543
- console.log(chalk2.green("Opprettet CLAUDE.md med referanse"));
2544
- } else if (result.claudeMd.updated) {
2545
- console.log(chalk2.dim("La til Kode-referanse i CLAUDE.md"));
2546
- }
2547
- } catch {
2548
- }
2549
- console.log(chalk2.dim("\n[G]=Global [P]=Sidespesifikk \u26A1=Auto-last \u25CB=Manuell"));
2550
- } catch (error) {
2551
- spinner.fail("Kunne ikke hente skript");
2552
- console.error(chalk2.red("\nFeil:"), error);
2147
+ const code = result.outputFiles?.[0]?.text || "";
2148
+ const source = readFileSync4(filePath, "utf-8");
2149
+ const usesReact = /from\s+['"]react['"]/.test(source) || /from\s+['"]react-dom/.test(source) || /import\s+React/.test(source) || /require\s*\(\s*['"]react/.test(source) || /React\.createElement/.test(source);
2150
+ return { code, usesReact };
2151
+ } catch (err) {
2152
+ if (err && typeof err === "object" && "errors" in err) {
2153
+ const buildErr = err;
2154
+ const msg = buildErr.errors.map((e) => {
2155
+ let text = e.text;
2156
+ if (e.location) text = `${e.location.file}:${e.location.line}: ${text}`;
2157
+ return text;
2158
+ }).join("\n");
2159
+ return { code: "", usesReact: false, error: msg };
2160
+ }
2161
+ return { code: "", usesReact: false, error: err instanceof Error ? err.message : String(err) };
2553
2162
  }
2554
2163
  }
2555
-
2556
- // src/commands/push.ts
2557
- import chalk3 from "chalk";
2558
- import ora3 from "ora";
2559
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, existsSync as existsSync7, readdirSync } from "fs";
2560
- import { join as join7, basename, extname } from "path";
2561
- import { createHash as createHash2 } from "crypto";
2562
- function hashContent2(content) {
2563
- return createHash2("sha256").update(content).digest("hex").substring(0, 16);
2164
+ function hashContent(content) {
2165
+ return createHash("sha256").update(content).digest("hex").substring(0, 16);
2564
2166
  }
2565
2167
  function formatTimeDiff(date) {
2566
2168
  const diff = Date.now() - new Date(date).getTime();
@@ -2575,50 +2177,67 @@ function formatTimeDiff(date) {
2575
2177
  async function pushCommand(options) {
2576
2178
  const projectRoot = findProjectRoot();
2577
2179
  if (!projectRoot) {
2578
- console.log(chalk3.red("Feil: Ikke i et Cure Kode-prosjekt."));
2579
- console.log(chalk3.dim('Kj\xF8r "kode init" f\xF8rst.'));
2180
+ console.log(chalk2.red("Feil: Ikke i et Cure Kode-prosjekt."));
2181
+ console.log(chalk2.dim('Kj\xF8r "kode init" f\xF8rst.'));
2580
2182
  return;
2581
2183
  }
2582
2184
  const config = getProjectConfig(projectRoot);
2583
2185
  if (!config) {
2584
- console.log(chalk3.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
2186
+ console.log(chalk2.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
2585
2187
  return;
2586
2188
  }
2587
2189
  const scriptsDir = getScriptsDir(projectRoot, config);
2588
- if (!existsSync7(scriptsDir)) {
2589
- console.log(chalk3.yellow("Skriptmappen finnes ikke."));
2590
- console.log(chalk3.dim(`Forventet: ${scriptsDir}`));
2591
- console.log(chalk3.dim('Kj\xF8r "kode pull" f\xF8rst eller opprett skript manuelt.'));
2190
+ if (!existsSync4(scriptsDir)) {
2191
+ console.log(chalk2.yellow("Skriptmappen finnes ikke."));
2192
+ console.log(chalk2.dim(`Forventet: ${scriptsDir}`));
2193
+ console.log(chalk2.dim('Kj\xF8r "kode pull" f\xF8rst eller opprett skript manuelt.'));
2592
2194
  return;
2593
2195
  }
2594
- const metadataPath = join7(projectRoot, ".cure-kode", "scripts.json");
2196
+ const metadataPath = join4(projectRoot, ".cure-kode", "scripts.json");
2595
2197
  let metadata = [];
2596
- if (existsSync7(metadataPath)) {
2198
+ if (existsSync4(metadataPath)) {
2597
2199
  try {
2598
- metadata = JSON.parse(readFileSync7(metadataPath, "utf-8"));
2200
+ metadata = JSON.parse(readFileSync4(metadataPath, "utf-8"));
2599
2201
  } catch {
2600
2202
  }
2601
2203
  }
2204
+ const SUPPORTED_EXTENSIONS = [".js", ".css", ".ts", ".tsx", ".jsx"];
2602
2205
  const files = readdirSync(scriptsDir).filter(
2603
- (f) => f.endsWith(".js") || f.endsWith(".css")
2206
+ (f) => SUPPORTED_EXTENSIONS.some((ext) => f.endsWith(ext))
2604
2207
  );
2605
2208
  if (files.length === 0) {
2606
- console.log(chalk3.yellow("Ingen skriptfiler funnet."));
2607
- console.log(chalk3.dim(`Legg til .js eller .css filer i ${scriptsDir}/`));
2209
+ console.log(chalk2.yellow("Ingen skriptfiler funnet."));
2210
+ console.log(chalk2.dim(`Legg til .js, .ts, .tsx, .jsx eller .css filer i ${scriptsDir}/`));
2608
2211
  return;
2609
2212
  }
2213
+ const slugMap = /* @__PURE__ */ new Map();
2214
+ for (const f of files) {
2215
+ const slug = basename(f, extname(f));
2216
+ const existing = slugMap.get(slug) || [];
2217
+ existing.push(f);
2218
+ slugMap.set(slug, existing);
2219
+ }
2220
+ const collisions = [...slugMap.entries()].filter(([, fs]) => fs.length > 1);
2221
+ if (collisions.length > 0) {
2222
+ console.log();
2223
+ for (const [slug, collidingFiles] of collisions) {
2224
+ console.log(chalk2.yellow(` \u26A0\uFE0F Slug-kollisjon: "${slug}" brukes av: ${collidingFiles.join(", ")}`));
2225
+ console.log(chalk2.dim(` CDN kan bare ha \xE9n script per slug. Gi nytt navn til en av filene.`));
2226
+ }
2227
+ console.log();
2228
+ }
2610
2229
  const filesToPush = options.script ? files.filter(
2611
- (f) => basename(f, extname(f)) === options.script || f === options.script || f === `${options.script}.js` || f === `${options.script}.css`
2230
+ (f) => basename(f, extname(f)) === options.script || basename(f, extname(f)) === basename(options.script, extname(options.script)) || f === options.script
2612
2231
  ) : files;
2613
2232
  if (options.script && filesToPush.length === 0) {
2614
- console.log(chalk3.yellow(`Fant ikke skript "${options.script}" lokalt.`));
2615
- console.log(chalk3.dim("Tilgjengelige lokale skript:"));
2233
+ console.log(chalk2.yellow(`Fant ikke skript "${options.script}" lokalt.`));
2234
+ console.log(chalk2.dim("Tilgjengelige lokale skript:"));
2616
2235
  files.forEach((f) => {
2617
- console.log(chalk3.dim(` - ${f}`));
2236
+ console.log(chalk2.dim(` - ${f}`));
2618
2237
  });
2619
2238
  return;
2620
2239
  }
2621
- const spinner = ora3("Laster opp skript...").start();
2240
+ const spinner = ora2("Laster opp skript...").start();
2622
2241
  try {
2623
2242
  const client = createApiClient(config);
2624
2243
  const remoteScripts = await client.listScripts(config.siteId);
@@ -2630,46 +2249,74 @@ async function pushCommand(options) {
2630
2249
  console.log();
2631
2250
  let emptyScriptCount = 0;
2632
2251
  for (const file of filesToPush) {
2633
- const filePath = join7(scriptsDir, file);
2634
- const content = readFileSync7(filePath, "utf-8");
2252
+ const filePath = join4(scriptsDir, file);
2253
+ const sourceContent = readFileSync4(filePath, "utf-8");
2254
+ let content = sourceContent;
2635
2255
  const slug = basename(file, extname(file));
2636
- const type = extname(file) === ".js" ? "javascript" : "css";
2637
- if (content.trim().length === 0) {
2638
- console.log(chalk3.yellow(` \u26A0 ${file}`) + chalk3.dim(" (tom fil)"));
2639
- emptyScriptCount++;
2640
- }
2256
+ const type = extname(file) === ".css" ? "css" : "javascript";
2257
+ const needsBundle = BUNDLEABLE_EXTENSIONS.includes(extname(file));
2641
2258
  const remoteScript = remoteScripts.find((s) => s.slug === slug);
2642
- const localMeta = metadata.find((m) => m.slug === slug);
2643
- if (remoteScript) {
2259
+ const localMeta = metadata.find((m) => m.localFileName === file) || metadata.find((m) => m.slug === slug);
2260
+ const sourceHash = hashContent(sourceContent);
2261
+ const localSourceUnchanged = localMeta?.contentHash === sourceHash;
2262
+ if (remoteScript && localSourceUnchanged && !options.all) {
2263
+ console.log(chalk2.dim(` \u25CB ${file}`) + chalk2.dim(" ingen endringer"));
2264
+ skipped++;
2265
+ continue;
2266
+ }
2267
+ if (remoteScript && !options.force) {
2644
2268
  const lastPulledVersion = localMeta?.lastPulledVersion || 0;
2645
- if (remoteScript.current_version > lastPulledVersion && !options.force) {
2269
+ if (remoteScript.current_version > lastPulledVersion) {
2646
2270
  console.log();
2647
- console.log(chalk3.yellow(` \u26A0\uFE0F Advarsel: Server har nyere versjon!`));
2648
- console.log(chalk3.dim(` ${file}:`));
2649
- console.log(chalk3.dim(` Lokal: v${lastPulledVersion} (fra ${localMeta?.lastPulledAt ? formatTimeDiff(localMeta.lastPulledAt) : "ukjent"})`));
2650
- console.log(chalk3.dim(` Server: v${remoteScript.current_version}`));
2651
- console.log();
2652
- console.log(chalk3.dim(` Bruk --force for \xE5 overskrive, eller kj\xF8r "kode pull" f\xF8rst.`));
2271
+ console.log(chalk2.yellow(` \u26A0 ${file}: Server har nyere versjon`));
2272
+ console.log(chalk2.dim(` Lokal: v${lastPulledVersion} (fra ${localMeta?.lastPulledAt ? formatTimeDiff(localMeta.lastPulledAt) : "ukjent"})`));
2273
+ console.log(chalk2.dim(` Server: v${remoteScript.current_version}`));
2274
+ console.log(chalk2.dim(` Bruk --force for \xE5 overskrive, eller kj\xF8r "kode pull" f\xF8rst.`));
2653
2275
  console.log();
2654
2276
  conflicts++;
2655
2277
  continue;
2656
2278
  }
2657
- if (remoteScript.content === content && !options.all) {
2658
- console.log(chalk3.dim(` \u25CB ${file} (ingen endringer)`));
2659
- skipped++;
2279
+ }
2280
+ let usesReact = false;
2281
+ let bundleSize = 0;
2282
+ if (needsBundle) {
2283
+ const buildSpinner = ora2(chalk2.dim(` \u2699 ${file}`)).start();
2284
+ const result = await bundleFile(filePath, scriptsDir);
2285
+ if (result.error) {
2286
+ buildSpinner.fail(chalk2.red(` \u2717 ${file}`) + chalk2.dim(` bygging feilet: ${result.error}`));
2660
2287
  continue;
2661
2288
  }
2662
- const updateSpinner = ora3(`Oppdaterer ${file}...`).start();
2289
+ content = result.code;
2290
+ usesReact = result.usesReact;
2291
+ bundleSize = content.length;
2292
+ buildSpinner.stop();
2293
+ }
2294
+ if (content.trim().length === 0) {
2295
+ console.log(chalk2.yellow(` \u26A0 ${file}`) + chalk2.dim(" tom fil"));
2296
+ emptyScriptCount++;
2297
+ }
2298
+ const bundleInfo = needsBundle ? chalk2.dim(` ${bundleSize} bytes`) : "";
2299
+ const reactInfo = usesReact ? chalk2.magenta(" react") : "";
2300
+ const suffix = bundleInfo + reactInfo;
2301
+ if (remoteScript) {
2302
+ const sourceExt = needsBundle ? extname(file).slice(1) : void 0;
2303
+ const updateSpinner = ora2(chalk2.dim(` \u2191 ${file}`)).start();
2663
2304
  await client.updateScript(remoteScript.id, {
2664
2305
  content,
2665
- changeSummary: options.message || `Oppdatert via CLI`
2306
+ changeSummary: options.message || `Oppdatert via CLI`,
2307
+ ...needsBundle ? {
2308
+ metadata: { ...remoteScript.metadata || {}, usesReact },
2309
+ sourceContent,
2310
+ sourceType: sourceExt
2311
+ } : {}
2666
2312
  });
2667
2313
  updateSpinner.succeed(
2668
- chalk3.green(` \u2713 ${file}`) + chalk3.dim(` \u2192 v${remoteScript.current_version + 1}`)
2314
+ chalk2.green(` \u2713 ${file}`) + chalk2.dim(` v${remoteScript.current_version + 1}`) + suffix
2669
2315
  );
2670
2316
  pushed++;
2671
2317
  } else {
2672
- const createSpinner = ora3(`Oppretter ${file}...`).start();
2318
+ const sourceExt = needsBundle ? extname(file).slice(1) : void 0;
2319
+ const createSpinner = ora2(chalk2.dim(` + ${file}`)).start();
2673
2320
  const scriptScope = localMeta?.scope || "global";
2674
2321
  const newScript = await client.createScript(config.siteId, {
2675
2322
  name: slug.charAt(0).toUpperCase() + slug.slice(1).replace(/-/g, " "),
@@ -2677,33 +2324,37 @@ async function pushCommand(options) {
2677
2324
  type,
2678
2325
  scope: scriptScope,
2679
2326
  autoLoad: options.autoLoad,
2680
- content
2327
+ content,
2328
+ ...needsBundle ? {
2329
+ sourceContent,
2330
+ sourceType: sourceExt
2331
+ } : {}
2681
2332
  });
2682
- const autoLoadInfo = newScript.auto_load ? chalk3.green("auto-last") : chalk3.dim("manuell");
2333
+ const autoLoadInfo = newScript.auto_load ? chalk2.dim("auto") : chalk2.dim("manuell");
2683
2334
  createSpinner.succeed(
2684
- chalk3.green(` \u2713 ${file}`) + chalk3.cyan(" (ny)") + ` [${autoLoadInfo}]`
2335
+ chalk2.green(` \u2713 ${file}`) + chalk2.cyan(" ny") + chalk2.dim(` [${autoLoadInfo}]`) + suffix
2685
2336
  );
2686
2337
  created++;
2687
2338
  }
2688
2339
  }
2689
2340
  console.log();
2690
2341
  if (pushed > 0) {
2691
- console.log(chalk3.green(`Oppdatert ${pushed} skript`));
2342
+ console.log(chalk2.green(`Oppdatert ${pushed} skript`));
2692
2343
  }
2693
2344
  if (created > 0) {
2694
- console.log(chalk3.cyan(`Opprettet ${created} nye skript`));
2345
+ console.log(chalk2.cyan(`Opprettet ${created} nye skript`));
2695
2346
  }
2696
2347
  if (skipped > 0) {
2697
- console.log(chalk3.dim(`Hoppet over ${skipped} uendrede skript`));
2348
+ console.log(chalk2.dim(`Hoppet over ${skipped} uendrede skript`));
2698
2349
  }
2699
2350
  if (conflicts > 0) {
2700
- console.log(chalk3.yellow(`
2351
+ console.log(chalk2.yellow(`
2701
2352
  ${conflicts} skript med konflikter (bruk --force for \xE5 overskrive)`));
2702
2353
  }
2703
2354
  if (emptyScriptCount > 0) {
2704
- console.log(chalk3.yellow(`
2355
+ console.log(chalk2.yellow(`
2705
2356
  ${emptyScriptCount} tomme skript lastet opp`));
2706
- console.log(chalk3.dim("Tomme skript har ingen effekt ved deploy."));
2357
+ console.log(chalk2.dim("Tomme skript har ingen effekt ved deploy."));
2707
2358
  }
2708
2359
  let pages = [];
2709
2360
  try {
@@ -2713,9 +2364,17 @@ ${emptyScriptCount} tomme skript lastet opp`));
2713
2364
  const updatedScripts = await client.listScripts(config.siteId);
2714
2365
  const now = (/* @__PURE__ */ new Date()).toISOString();
2715
2366
  const updatedMetadata = updatedScripts.map((s) => {
2716
- const ext = s.type === "javascript" ? "js" : "css";
2717
- const filePath = join7(scriptsDir, `${s.slug}.${ext}`);
2718
- const localContent = existsSync7(filePath) ? readFileSync7(filePath, "utf-8") : s.content;
2367
+ const possibleExts = s.type === "css" ? [".css"] : [".js", ".ts", ".tsx", ".jsx"];
2368
+ let localFilePath = "";
2369
+ let localContent = s.content;
2370
+ for (const ext of possibleExts) {
2371
+ const candidate = join4(scriptsDir, `${s.slug}${ext}`);
2372
+ if (existsSync4(candidate)) {
2373
+ localFilePath = candidate;
2374
+ localContent = readFileSync4(candidate, "utf-8");
2375
+ break;
2376
+ }
2377
+ }
2719
2378
  const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
2720
2379
  const page = pages.find((pg) => pg.id === p.page_id);
2721
2380
  return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
@@ -2732,10 +2391,11 @@ ${emptyScriptCount} tomme skript lastet opp`));
2732
2391
  pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
2733
2392
  lastPulledVersion: s.current_version,
2734
2393
  lastPulledAt: now,
2735
- contentHash: hashContent2(localContent)
2394
+ contentHash: hashContent(localContent),
2395
+ localFileName: localFilePath ? basename(localFilePath) : void 0
2736
2396
  };
2737
2397
  });
2738
- writeFileSync7(metadataPath, JSON.stringify(updatedMetadata, null, 2));
2398
+ writeFileSync4(metadataPath, JSON.stringify(updatedMetadata, null, 2));
2739
2399
  try {
2740
2400
  const result = updateClaudeMd(
2741
2401
  projectRoot,
@@ -2745,69 +2405,117 @@ ${emptyScriptCount} tomme skript lastet opp`));
2745
2405
  pagesToInfoFormat(pages)
2746
2406
  );
2747
2407
  if (result.kodeMd.created) {
2748
- console.log(chalk3.green("Opprettet .cure-kode/KODE.md"));
2408
+ console.log(chalk2.green("Opprettet .cure-kode/KODE.md"));
2749
2409
  } else if (result.kodeMd.updated) {
2750
- console.log(chalk3.dim("Oppdatert .cure-kode/KODE.md"));
2410
+ console.log(chalk2.dim("Oppdatert .cure-kode/KODE.md"));
2751
2411
  }
2752
2412
  if (result.claudeMd.created) {
2753
- console.log(chalk3.green("Opprettet CLAUDE.md med referanse"));
2413
+ console.log(chalk2.green("Opprettet CLAUDE.md med referanse"));
2754
2414
  } else if (result.claudeMd.updated) {
2755
- console.log(chalk3.dim("La til Kode-referanse i CLAUDE.md"));
2415
+ console.log(chalk2.dim("La til Kode-referanse i CLAUDE.md"));
2416
+ }
2417
+ } catch {
2418
+ }
2419
+ try {
2420
+ let scanDir2 = function(dir, relativeTo) {
2421
+ if (!existsSync4(dir)) return;
2422
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
2423
+ if (entry.isDirectory()) {
2424
+ if (!EXCLUDED_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
2425
+ scanDir2(join4(dir, entry.name), relativeTo);
2426
+ }
2427
+ } else if (entry.isFile() && SUPPORTED_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
2428
+ const fullPath = join4(dir, entry.name);
2429
+ const relPath = fullPath.slice(relativeTo.length + 1);
2430
+ const fileContent = readFileSync4(fullPath, "utf-8");
2431
+ moduleFiles.push({
2432
+ path: relPath,
2433
+ content: fileContent,
2434
+ contentHash: hashContent(fileContent)
2435
+ });
2436
+ }
2437
+ }
2438
+ };
2439
+ var scanDir = scanDir2;
2440
+ const EXCLUDED_DIRS = ["packages", "node_modules", ".git", "dist", "build", "types"];
2441
+ const moduleFiles = [];
2442
+ for (const entry of readdirSync(scriptsDir, { withFileTypes: true })) {
2443
+ if (entry.isDirectory() && !EXCLUDED_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
2444
+ scanDir2(join4(scriptsDir, entry.name), scriptsDir);
2445
+ }
2446
+ }
2447
+ if (moduleFiles.length > 0) {
2448
+ let remoteFiles = [];
2449
+ try {
2450
+ remoteFiles = await client.getProjectFiles(config.siteId);
2451
+ } catch {
2452
+ }
2453
+ const hasChanges = moduleFiles.length !== remoteFiles.length || moduleFiles.some((f) => {
2454
+ const remote = remoteFiles.find((r) => r.path === f.path);
2455
+ return !remote || remote.contentHash !== f.contentHash;
2456
+ });
2457
+ if (hasChanges) {
2458
+ await client.updateProjectFiles(config.siteId, moduleFiles);
2459
+ console.log(chalk2.green(`Synkronisert ${moduleFiles.length} prosjektfil(er)`));
2460
+ for (const f of moduleFiles) {
2461
+ console.log(chalk2.dim(` + ${f.path}`));
2462
+ }
2463
+ }
2756
2464
  }
2757
2465
  } catch {
2758
2466
  }
2759
2467
  } catch (error) {
2760
2468
  spinner.fail("Kunne ikke laste opp skript");
2761
- console.error(chalk3.red("\nFeil:"), error);
2469
+ console.error(chalk2.red("\nFeil:"), error);
2762
2470
  }
2763
2471
  }
2764
2472
 
2765
2473
  // src/commands/watch.ts
2766
- import chalk4 from "chalk";
2474
+ import chalk3 from "chalk";
2767
2475
  import chokidar from "chokidar";
2768
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
2769
- import { join as join8, basename as basename2, extname as extname2 } from "path";
2476
+ import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
2477
+ import { join as join5, basename as basename2, extname as extname2 } from "path";
2770
2478
  async function watchCommand(options) {
2771
2479
  const projectRoot = findProjectRoot();
2772
2480
  if (!projectRoot) {
2773
- console.log(chalk4.red("\u274C Not in a Cure Kode project."));
2774
- console.log(chalk4.dim(' Run "kode init" first.'));
2481
+ console.log(chalk3.red("\u274C Not in a Cure Kode project."));
2482
+ console.log(chalk3.dim(' Run "kode init" first.'));
2775
2483
  return;
2776
2484
  }
2777
2485
  const config = getProjectConfig(projectRoot);
2778
2486
  if (!config) {
2779
- console.log(chalk4.red("\u274C Could not read project configuration."));
2487
+ console.log(chalk3.red("\u274C Could not read project configuration."));
2780
2488
  return;
2781
2489
  }
2782
2490
  const scriptsDir = getScriptsDir(projectRoot, config);
2783
- if (!existsSync8(scriptsDir)) {
2784
- console.log(chalk4.yellow("\u26A0\uFE0F Scripts directory not found."));
2785
- console.log(chalk4.dim(` Expected: ${scriptsDir}`));
2786
- console.log(chalk4.dim(' Run "kode pull" first.'));
2491
+ if (!existsSync5(scriptsDir)) {
2492
+ console.log(chalk3.yellow("\u26A0\uFE0F Scripts directory not found."));
2493
+ console.log(chalk3.dim(` Expected: ${scriptsDir}`));
2494
+ console.log(chalk3.dim(' Run "kode pull" first.'));
2787
2495
  return;
2788
2496
  }
2789
- console.log(chalk4.bold("\n\u{1F440} Watching for changes...\n"));
2790
- console.log(chalk4.dim(` Directory: ${scriptsDir}`));
2791
- console.log(chalk4.dim(` Site: ${config.siteName} (${config.siteSlug})`));
2792
- console.log(chalk4.dim(` Environment: ${config.environment || "staging"}`));
2497
+ console.log(chalk3.bold("\n\u{1F440} Watching for changes...\n"));
2498
+ console.log(chalk3.dim(` Directory: ${scriptsDir}`));
2499
+ console.log(chalk3.dim(` Site: ${config.siteName} (${config.siteSlug})`));
2500
+ console.log(chalk3.dim(` Environment: ${config.environment || "staging"}`));
2793
2501
  if (options.deploy) {
2794
- console.log(chalk4.cyan(` Auto-deploy: enabled`));
2502
+ console.log(chalk3.cyan(` Auto-deploy: enabled`));
2795
2503
  }
2796
2504
  console.log();
2797
- console.log(chalk4.dim("Press Ctrl+C to stop.\n"));
2505
+ console.log(chalk3.dim("Press Ctrl+C to stop.\n"));
2798
2506
  const client = createApiClient(config);
2799
- const metadataPath = join8(projectRoot, ".cure-kode", "scripts.json");
2507
+ const metadataPath = join5(projectRoot, ".cure-kode", "scripts.json");
2800
2508
  let metadata = [];
2801
- if (existsSync8(metadataPath)) {
2802
- metadata = JSON.parse(readFileSync8(metadataPath, "utf-8"));
2509
+ if (existsSync5(metadataPath)) {
2510
+ metadata = JSON.parse(readFileSync5(metadataPath, "utf-8"));
2803
2511
  }
2804
2512
  let remoteScripts = [];
2805
2513
  try {
2806
2514
  remoteScripts = await client.listScripts(config.siteId);
2807
- console.log(chalk4.dim(`Loaded ${remoteScripts.length} remote script(s)
2515
+ console.log(chalk3.dim(`Loaded ${remoteScripts.length} remote script(s)
2808
2516
  `));
2809
2517
  } catch (error) {
2810
- console.log(chalk4.yellow("\u26A0\uFE0F Could not load remote scripts. Will create new on change."));
2518
+ console.log(chalk3.yellow("\u26A0\uFE0F Could not load remote scripts. Will create new on change."));
2811
2519
  }
2812
2520
  const pendingChanges = /* @__PURE__ */ new Map();
2813
2521
  const DEBOUNCE_MS = 500;
@@ -2820,18 +2528,18 @@ async function watchCommand(options) {
2820
2528
  if (failedSyncs.size === 0 && successCount === 0) return;
2821
2529
  const statusParts = [];
2822
2530
  if (successCount > 0) {
2823
- statusParts.push(chalk4.green(`${successCount} synced`));
2531
+ statusParts.push(chalk3.green(`${successCount} synced`));
2824
2532
  }
2825
2533
  if (failedSyncs.size > 0) {
2826
- statusParts.push(chalk4.red(`${failedSyncs.size} pending errors`));
2534
+ statusParts.push(chalk3.red(`${failedSyncs.size} pending errors`));
2827
2535
  }
2828
- console.log(chalk4.dim(`
2536
+ console.log(chalk3.dim(`
2829
2537
  \u2500\u2500\u2500 Status: ${statusParts.join(", ")} \u2500\u2500\u2500
2830
2538
  `));
2831
2539
  };
2832
2540
  const retryFailedSyncs = async () => {
2833
2541
  for (const [filePath, failed] of failedSyncs.entries()) {
2834
- if (!existsSync8(filePath)) {
2542
+ if (!existsSync5(filePath)) {
2835
2543
  failedSyncs.delete(filePath);
2836
2544
  continue;
2837
2545
  }
@@ -2844,7 +2552,7 @@ async function watchCommand(options) {
2844
2552
  }
2845
2553
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("nb-NO");
2846
2554
  console.log(
2847
- chalk4.dim(`[${timestamp}] `) + chalk4.yellow(`\u21BB Retrying ${failed.fileName}...`) + chalk4.dim(` (attempt ${failed.attempts + 1}/${MAX_RETRY_ATTEMPTS})`)
2555
+ chalk3.dim(`[${timestamp}] `) + chalk3.yellow(`\u21BB Retrying ${failed.fileName}...`) + chalk3.dim(` (attempt ${failed.attempts + 1}/${MAX_RETRY_ATTEMPTS})`)
2848
2556
  );
2849
2557
  await handleChange(
2850
2558
  filePath,
@@ -2865,7 +2573,7 @@ async function watchCommand(options) {
2865
2573
  }
2866
2574
  const syncFile = async () => {
2867
2575
  try {
2868
- const content = readFileSync8(filePath, "utf-8");
2576
+ const content = readFileSync5(filePath, "utf-8");
2869
2577
  const remoteScript = remoteScripts.find((s) => s.slug === slug);
2870
2578
  const localMeta = metadata.find((m) => m.slug === slug);
2871
2579
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("nb-NO");
@@ -2887,16 +2595,16 @@ async function watchCommand(options) {
2887
2595
  failedSyncs.delete(filePath);
2888
2596
  if (wasRetry) {
2889
2597
  console.log(
2890
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.dim(` \u2192 v${remoteScript.current_version}`) + chalk4.cyan(" (recovered)")
2598
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.dim(` \u2192 v${remoteScript.current_version}`) + chalk3.cyan(" (recovered)")
2891
2599
  );
2892
2600
  } else {
2893
2601
  console.log(
2894
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.dim(` \u2192 v${remoteScript.current_version}`)
2602
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.dim(` \u2192 v${remoteScript.current_version}`)
2895
2603
  );
2896
2604
  }
2897
2605
  } else {
2898
2606
  console.log(
2899
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.dim(` \u2192 v${remoteScript.current_version}`)
2607
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.dim(` \u2192 v${remoteScript.current_version}`)
2900
2608
  );
2901
2609
  }
2902
2610
  successCount++;
@@ -2904,11 +2612,11 @@ async function watchCommand(options) {
2904
2612
  try {
2905
2613
  await client.deploy(config.siteId, config.environment || "staging");
2906
2614
  console.log(
2907
- chalk4.dim(`[${timestamp}] `) + chalk4.cyan(` \u21B3 Deployed to ${config.environment || "staging"}`)
2615
+ chalk3.dim(`[${timestamp}] `) + chalk3.cyan(` \u21B3 Deployed to ${config.environment || "staging"}`)
2908
2616
  );
2909
2617
  } catch (deployError) {
2910
2618
  console.log(
2911
- chalk4.dim(`[${timestamp}] `) + chalk4.red(` \u21B3 Deploy failed: ${deployError.message || "Unknown error"}`)
2619
+ chalk3.dim(`[${timestamp}] `) + chalk3.red(` \u21B3 Deploy failed: ${deployError.message || "Unknown error"}`)
2912
2620
  );
2913
2621
  }
2914
2622
  }
@@ -2924,11 +2632,11 @@ async function watchCommand(options) {
2924
2632
  if (failedSyncs.has(filePath)) {
2925
2633
  failedSyncs.delete(filePath);
2926
2634
  console.log(
2927
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.cyan(" (created, recovered)")
2635
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.cyan(" (created, recovered)")
2928
2636
  );
2929
2637
  } else {
2930
2638
  console.log(
2931
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.cyan(" (created)")
2639
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.cyan(" (created)")
2932
2640
  );
2933
2641
  }
2934
2642
  successCount++;
@@ -2959,11 +2667,11 @@ async function watchCommand(options) {
2959
2667
  errorCount++;
2960
2668
  if (attempts >= MAX_RETRY_ATTEMPTS) {
2961
2669
  console.log(
2962
- chalk4.dim(`[${timestamp}] `) + chalk4.red(`\u2717 ${fileName}`) + chalk4.dim(` - ${errorMessage}`) + chalk4.red(` (gave up after ${MAX_RETRY_ATTEMPTS} attempts)`)
2670
+ chalk3.dim(`[${timestamp}] `) + chalk3.red(`\u2717 ${fileName}`) + chalk3.dim(` - ${errorMessage}`) + chalk3.red(` (gave up after ${MAX_RETRY_ATTEMPTS} attempts)`)
2963
2671
  );
2964
2672
  } else {
2965
2673
  console.log(
2966
- chalk4.dim(`[${timestamp}] `) + chalk4.red(`\u2717 ${fileName}`) + chalk4.dim(` - ${errorMessage}`) + chalk4.yellow(` (will retry in ${RETRY_DELAY_MS / 1e3}s)`)
2674
+ chalk3.dim(`[${timestamp}] `) + chalk3.red(`\u2717 ${fileName}`) + chalk3.dim(` - ${errorMessage}`) + chalk3.yellow(` (will retry in ${RETRY_DELAY_MS / 1e3}s)`)
2967
2675
  );
2968
2676
  }
2969
2677
  printStatus();
@@ -2979,7 +2687,7 @@ async function watchCommand(options) {
2979
2687
  }, DEBOUNCE_MS);
2980
2688
  pendingChanges.set(filePath, timeout);
2981
2689
  };
2982
- const watcher = chokidar.watch(join8(scriptsDir, "**/*.{js,css}"), {
2690
+ const watcher = chokidar.watch(join5(scriptsDir, "**/*.{js,css}"), {
2983
2691
  persistent: true,
2984
2692
  ignoreInitial: true,
2985
2693
  awaitWriteFinish: {
@@ -2993,21 +2701,21 @@ async function watchCommand(options) {
2993
2701
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("nb-NO");
2994
2702
  const fileName = basename2(filePath);
2995
2703
  console.log(
2996
- chalk4.dim(`[${timestamp}] `) + chalk4.yellow(`\u26A0 ${fileName} deleted locally`) + chalk4.dim(" (remote not affected)")
2704
+ chalk3.dim(`[${timestamp}] `) + chalk3.yellow(`\u26A0 ${fileName} deleted locally`) + chalk3.dim(" (remote not affected)")
2997
2705
  );
2998
2706
  });
2999
2707
  process.on("SIGINT", () => {
3000
2708
  clearInterval(retryInterval);
3001
- console.log(chalk4.dim("\n\nStopping watch...\n"));
2709
+ console.log(chalk3.dim("\n\nStopping watch...\n"));
3002
2710
  if (successCount > 0 || failedSyncs.size > 0) {
3003
- console.log(chalk4.bold("Session summary:"));
2711
+ console.log(chalk3.bold("Session summary:"));
3004
2712
  if (successCount > 0) {
3005
- console.log(chalk4.green(` \u2713 ${successCount} file(s) synced`));
2713
+ console.log(chalk3.green(` \u2713 ${successCount} file(s) synced`));
3006
2714
  }
3007
2715
  if (failedSyncs.size > 0) {
3008
- console.log(chalk4.red(` \u2717 ${failedSyncs.size} file(s) failed:`));
2716
+ console.log(chalk3.red(` \u2717 ${failedSyncs.size} file(s) failed:`));
3009
2717
  for (const failed of failedSyncs.values()) {
3010
- console.log(chalk4.dim(` - ${failed.fileName}: ${failed.error}`));
2718
+ console.log(chalk3.dim(` - ${failed.fileName}: ${failed.error}`));
3011
2719
  }
3012
2720
  }
3013
2721
  console.log();
@@ -3018,10 +2726,10 @@ async function watchCommand(options) {
3018
2726
  }
3019
2727
 
3020
2728
  // src/commands/deploy.ts
3021
- import chalk5 from "chalk";
3022
- import ora4 from "ora";
3023
- import { readFileSync as readFileSync9, existsSync as existsSync9, readdirSync as readdirSync2 } from "fs";
3024
- import { join as join9, basename as basename3, extname as extname3 } from "path";
2729
+ import chalk4 from "chalk";
2730
+ import ora3 from "ora";
2731
+ import { readFileSync as readFileSync6, existsSync as existsSync6, readdirSync as readdirSync2 } from "fs";
2732
+ import { join as join6, basename as basename3, extname as extname3 } from "path";
3025
2733
  function formatBytes(bytes) {
3026
2734
  if (bytes < 1024) return `${bytes} B`;
3027
2735
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -3030,7 +2738,7 @@ function formatBytes(bytes) {
3030
2738
  async function showDeploymentPreview(config, projectRoot) {
3031
2739
  if (!config) return;
3032
2740
  const client = createApiClient(config);
3033
- const spinner = ora4("Analyserer deployment...").start();
2741
+ const spinner = ora3("Analyserer deployment...").start();
3034
2742
  try {
3035
2743
  const [remoteScripts, deployStatus] = await Promise.all([
3036
2744
  client.listScripts(config.siteId),
@@ -3038,39 +2746,39 @@ async function showDeploymentPreview(config, projectRoot) {
3038
2746
  ]);
3039
2747
  spinner.stop();
3040
2748
  console.log();
3041
- console.log(chalk5.bold("\u{1F50D} Deployment Preview (t\xF8rrkj\xF8ring)"));
3042
- console.log(chalk5.dim(` M\xE5l: staging`));
2749
+ console.log(chalk4.bold("\u{1F50D} Deployment Preview (t\xF8rrkj\xF8ring)"));
2750
+ console.log(chalk4.dim(` M\xE5l: staging`));
3043
2751
  console.log();
3044
2752
  const stagingVersion = deployStatus.staging.lastSuccessful?.version || null;
3045
2753
  const productionVersion = deployStatus.production.lastSuccessful?.version || null;
3046
- console.log(chalk5.bold("N\xE5v\xE6rende status"));
2754
+ console.log(chalk4.bold("N\xE5v\xE6rende status"));
3047
2755
  if (stagingVersion) {
3048
- console.log(chalk5.dim(` Staging: v${stagingVersion}`));
2756
+ console.log(chalk4.dim(` Staging: v${stagingVersion}`));
3049
2757
  } else {
3050
- console.log(chalk5.dim(` Staging: ingen deployments`));
2758
+ console.log(chalk4.dim(` Staging: ingen deployments`));
3051
2759
  }
3052
2760
  if (deployStatus.productionEnabled) {
3053
2761
  if (productionVersion) {
3054
- console.log(chalk5.dim(` Production: v${productionVersion}`));
2762
+ console.log(chalk4.dim(` Production: v${productionVersion}`));
3055
2763
  } else {
3056
- console.log(chalk5.dim(` Production: aktivert, ingen deployments`));
2764
+ console.log(chalk4.dim(` Production: aktivert, ingen deployments`));
3057
2765
  }
3058
2766
  }
3059
2767
  console.log();
3060
2768
  const scriptsDir = getScriptsDir(projectRoot, config);
3061
- const localFiles = existsSync9(scriptsDir) ? readdirSync2(scriptsDir).filter((f) => f.endsWith(".js") || f.endsWith(".css")) : [];
3062
- const metadataPath = join9(projectRoot, ".cure-kode", "scripts.json");
2769
+ const localFiles = existsSync6(scriptsDir) ? readdirSync2(scriptsDir).filter((f) => f.endsWith(".js") || f.endsWith(".css")) : [];
2770
+ const metadataPath = join6(projectRoot, ".cure-kode", "scripts.json");
3063
2771
  let metadata = [];
3064
- if (existsSync9(metadataPath)) {
2772
+ if (existsSync6(metadataPath)) {
3065
2773
  try {
3066
- metadata = JSON.parse(readFileSync9(metadataPath, "utf-8"));
2774
+ metadata = JSON.parse(readFileSync6(metadataPath, "utf-8"));
3067
2775
  } catch {
3068
2776
  }
3069
2777
  }
3070
2778
  const localBySlug = /* @__PURE__ */ new Map();
3071
2779
  for (const file of localFiles) {
3072
2780
  const slug = basename3(file, extname3(file));
3073
- const content = readFileSync9(join9(scriptsDir, file), "utf-8");
2781
+ const content = readFileSync6(join6(scriptsDir, file), "utf-8");
3074
2782
  localBySlug.set(slug, { content, size: Buffer.byteLength(content, "utf-8") });
3075
2783
  }
3076
2784
  const remoteBySlug = /* @__PURE__ */ new Map();
@@ -3127,63 +2835,63 @@ async function showDeploymentPreview(config, projectRoot) {
3127
2835
  }
3128
2836
  }
3129
2837
  if (changes.length > 0) {
3130
- console.log(chalk5.bold("Endringer"));
2838
+ console.log(chalk4.bold("Endringer"));
3131
2839
  console.log();
3132
2840
  console.log(
3133
- chalk5.dim(" ") + chalk5.dim("Skript".padEnd(25)) + chalk5.dim("F\xF8r".padStart(8)) + chalk5.dim("Etter".padStart(8)) + chalk5.dim("Endring".padStart(15))
2841
+ chalk4.dim(" ") + chalk4.dim("Skript".padEnd(25)) + chalk4.dim("F\xF8r".padStart(8)) + chalk4.dim("Etter".padStart(8)) + chalk4.dim("Endring".padStart(15))
3134
2842
  );
3135
- console.log(chalk5.dim(" " + "\u2500".repeat(56)));
2843
+ console.log(chalk4.dim(" " + "\u2500".repeat(56)));
3136
2844
  for (const change of changes) {
3137
2845
  const beforeStr = change.beforeVersion ? `v${change.beforeVersion}` : "-";
3138
2846
  const afterStr = `v${change.afterVersion}`;
3139
2847
  let diffStr;
3140
2848
  if (change.isNew) {
3141
- diffStr = chalk5.cyan(`+${change.linesDiff.added} linjer`);
2849
+ diffStr = chalk4.cyan(`+${change.linesDiff.added} linjer`);
3142
2850
  } else {
3143
2851
  const parts = [];
3144
- if (change.linesDiff.added > 0) parts.push(chalk5.green(`+${change.linesDiff.added}`));
3145
- if (change.linesDiff.removed > 0) parts.push(chalk5.red(`-${change.linesDiff.removed}`));
2852
+ if (change.linesDiff.added > 0) parts.push(chalk4.green(`+${change.linesDiff.added}`));
2853
+ if (change.linesDiff.removed > 0) parts.push(chalk4.red(`-${change.linesDiff.removed}`));
3146
2854
  diffStr = parts.join(" ") + " linjer";
3147
2855
  }
3148
- const nameColor = change.isNew ? chalk5.cyan : chalk5.white;
2856
+ const nameColor = change.isNew ? chalk4.cyan : chalk4.white;
3149
2857
  console.log(
3150
- ` ${nameColor(change.fileName.padEnd(25))}${chalk5.dim(beforeStr.padStart(8))}${afterStr.padStart(8)}${diffStr.padStart(15)}`
2858
+ ` ${nameColor(change.fileName.padEnd(25))}${chalk4.dim(beforeStr.padStart(8))}${afterStr.padStart(8)}${diffStr.padStart(15)}`
3151
2859
  );
3152
2860
  }
3153
2861
  console.log();
3154
2862
  const sizeDiff = totalAfterSize - totalBeforeSize;
3155
- const sizeDiffStr = sizeDiff > 0 ? chalk5.yellow(`+${formatBytes(sizeDiff)}`) : sizeDiff < 0 ? chalk5.green(`-${formatBytes(Math.abs(sizeDiff))}`) : chalk5.dim("uendret");
2863
+ const sizeDiffStr = sizeDiff > 0 ? chalk4.yellow(`+${formatBytes(sizeDiff)}`) : sizeDiff < 0 ? chalk4.green(`-${formatBytes(Math.abs(sizeDiff))}`) : chalk4.dim("uendret");
3156
2864
  console.log(
3157
- chalk5.dim(` Total: ${formatBytes(totalBeforeSize)} \u2192 ${formatBytes(totalAfterSize)} (${sizeDiffStr})`)
2865
+ chalk4.dim(` Total: ${formatBytes(totalBeforeSize)} \u2192 ${formatBytes(totalAfterSize)} (${sizeDiffStr})`)
3158
2866
  );
3159
2867
  } else {
3160
- console.log(chalk5.dim(" Ingen endringer \xE5 deploye"));
2868
+ console.log(chalk4.dim(" Ingen endringer \xE5 deploye"));
3161
2869
  }
3162
2870
  if (warnings.length > 0) {
3163
2871
  console.log();
3164
- console.log(chalk5.bold("Advarsler"));
2872
+ console.log(chalk4.bold("Advarsler"));
3165
2873
  for (const warning of warnings) {
3166
- console.log(chalk5.yellow(` \u26A0 ${warning}`));
2874
+ console.log(chalk4.yellow(` \u26A0 ${warning}`));
3167
2875
  }
3168
2876
  }
3169
2877
  console.log();
3170
- console.log(chalk5.dim('Dette er en t\xF8rrkj\xF8ring. Kj\xF8r "kode deploy" for \xE5 deploye.'));
2878
+ console.log(chalk4.dim('Dette er en t\xF8rrkj\xF8ring. Kj\xF8r "kode deploy" for \xE5 deploye.'));
3171
2879
  console.log();
3172
2880
  } catch (error) {
3173
2881
  spinner.fail("Kunne ikke analysere deployment");
3174
- console.error(chalk5.red("\nFeil:"), error.message || error);
2882
+ console.error(chalk4.red("\nFeil:"), error.message || error);
3175
2883
  }
3176
2884
  }
3177
2885
  async function deployCommand(environment, options) {
3178
2886
  const projectRoot = findProjectRoot();
3179
2887
  if (!projectRoot) {
3180
- console.log(chalk5.red("\u274C Not in a Cure Kode project."));
3181
- console.log(chalk5.dim(' Run "kode init" first.'));
2888
+ console.log(chalk4.red("\u274C Not in a Cure Kode project."));
2889
+ console.log(chalk4.dim(' Run "kode init" first.'));
3182
2890
  return;
3183
2891
  }
3184
2892
  const config = getProjectConfig(projectRoot);
3185
2893
  if (!config) {
3186
- console.log(chalk5.red("\u274C Could not read project configuration."));
2894
+ console.log(chalk4.red("\u274C Could not read project configuration."));
3187
2895
  return;
3188
2896
  }
3189
2897
  if (options?.dryRun) {
@@ -3193,15 +2901,15 @@ async function deployCommand(environment, options) {
3193
2901
  const shouldPromote = options?.promote || environment === "production";
3194
2902
  if (shouldPromote) {
3195
2903
  const client2 = createApiClient(config);
3196
- const spinner2 = ora4("Sjekker produksjonsstatus...").start();
2904
+ const spinner2 = ora3("Sjekker produksjonsstatus...").start();
3197
2905
  try {
3198
2906
  const status = await client2.getDeploymentStatus(config.siteId);
3199
2907
  if (!status.productionEnabled) {
3200
2908
  spinner2.fail("Produksjon er ikke aktivert");
3201
2909
  console.log();
3202
- console.log(chalk5.yellow("\u26A0\uFE0F Produksjon er deaktivert for dette prosjektet."));
3203
- console.log(chalk5.dim(" Aktiver produksjon f\xF8rst:"));
3204
- console.log(chalk5.dim(" kode production enable [--domain <domain>]"));
2910
+ console.log(chalk4.yellow("\u26A0\uFE0F Produksjon er deaktivert for dette prosjektet."));
2911
+ console.log(chalk4.dim(" Aktiver produksjon f\xF8rst:"));
2912
+ console.log(chalk4.dim(" kode production enable [--domain <domain>]"));
3205
2913
  console.log();
3206
2914
  return;
3207
2915
  }
@@ -3209,23 +2917,23 @@ async function deployCommand(environment, options) {
3209
2917
  const deployment = await client2.promoteToProduction(config.siteId);
3210
2918
  spinner2.succeed("Promoted to production");
3211
2919
  console.log();
3212
- console.log(chalk5.dim("Deployment details:"));
3213
- console.log(chalk5.dim(` Version: ${deployment.version}`));
3214
- console.log(chalk5.dim(` Status: ${deployment.status}`));
2920
+ console.log(chalk4.dim("Deployment details:"));
2921
+ console.log(chalk4.dim(` Version: ${deployment.version}`));
2922
+ console.log(chalk4.dim(` Status: ${deployment.status}`));
3215
2923
  console.log();
3216
- console.log(chalk5.bold("CDN URL:"));
3217
- console.log(chalk5.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
2924
+ console.log(chalk4.bold("CDN URL:"));
2925
+ console.log(chalk4.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
3218
2926
  console.log();
3219
- console.log(chalk5.green("\u2705 Production is now running the latest staging version!"));
2927
+ console.log(chalk4.green("\u2705 Production is now running the latest staging version!"));
3220
2928
  } catch (error) {
3221
2929
  spinner2.fail("Promotion failed");
3222
- console.error(chalk5.red("\nError:"), error.message || error);
2930
+ console.error(chalk4.red("\nError:"), error.message || error);
3223
2931
  }
3224
2932
  return;
3225
2933
  }
3226
2934
  const client = createApiClient(config);
3227
2935
  if (options?.force) {
3228
- const forceSpinner = ora4("Sjekker l\xE5s...").start();
2936
+ const forceSpinner = ora3("Sjekker l\xE5s...").start();
3229
2937
  try {
3230
2938
  const lockStatus = await client.getLockStatus(config.siteId);
3231
2939
  if (lockStatus.isLocked) {
@@ -3233,18 +2941,18 @@ async function deployCommand(environment, options) {
3233
2941
  forceSpinner.text = "Frigj\xF8r gammel l\xE5s...";
3234
2942
  } else {
3235
2943
  forceSpinner.warn("Aktiv l\xE5s funnet");
3236
- console.log(chalk5.yellow("\n\u26A0\uFE0F Deployment er l\xE5st av en annen prosess."));
3237
- console.log(chalk5.dim(` L\xE5st siden: ${lockStatus.acquiredAt ? new Date(lockStatus.acquiredAt).toLocaleString("nb-NO") : "ukjent"}`));
3238
- console.log(chalk5.dim(` L\xE5s-ID: ${lockStatus.lockHolder}`));
2944
+ console.log(chalk4.yellow("\n\u26A0\uFE0F Deployment er l\xE5st av en annen prosess."));
2945
+ console.log(chalk4.dim(` L\xE5st siden: ${lockStatus.acquiredAt ? new Date(lockStatus.acquiredAt).toLocaleString("nb-NO") : "ukjent"}`));
2946
+ console.log(chalk4.dim(` L\xE5s-ID: ${lockStatus.lockHolder}`));
3239
2947
  console.log();
3240
- console.log(chalk5.yellow(" Hvis du er sikker p\xE5 at l\xE5sen er foreldet, kj\xF8r med --force igjen."));
3241
- console.log(chalk5.dim(" L\xE5sen vil utl\xF8pe automatisk etter 10 minutter."));
2948
+ console.log(chalk4.yellow(" Hvis du er sikker p\xE5 at l\xE5sen er foreldet, kj\xF8r med --force igjen."));
2949
+ console.log(chalk4.dim(" L\xE5sen vil utl\xF8pe automatisk etter 10 minutter."));
3242
2950
  return;
3243
2951
  }
3244
2952
  const result = await client.forceReleaseLock(config.siteId);
3245
2953
  if (result.wasLocked) {
3246
2954
  forceSpinner.succeed("L\xE5s frigjort");
3247
- console.log(chalk5.dim(` Tidligere l\xE5s fra: ${result.acquiredAt ? new Date(result.acquiredAt).toLocaleString("nb-NO") : "ukjent"}`));
2955
+ console.log(chalk4.dim(` Tidligere l\xE5s fra: ${result.acquiredAt ? new Date(result.acquiredAt).toLocaleString("nb-NO") : "ukjent"}`));
3248
2956
  console.log();
3249
2957
  } else {
3250
2958
  forceSpinner.info("Ingen l\xE5s \xE5 frigj\xF8re");
@@ -3254,11 +2962,11 @@ async function deployCommand(environment, options) {
3254
2962
  }
3255
2963
  } catch (error) {
3256
2964
  forceSpinner.fail("Kunne ikke sjekke/frigj\xF8re l\xE5s");
3257
- console.error(chalk5.red("\nError:"), error.message || error);
2965
+ console.error(chalk4.red("\nError:"), error.message || error);
3258
2966
  return;
3259
2967
  }
3260
2968
  }
3261
- const preCheckSpinner = ora4("Sjekker scripts...").start();
2969
+ const preCheckSpinner = ora3("Sjekker scripts...").start();
3262
2970
  try {
3263
2971
  const scripts = await client.listScripts(config.siteId);
3264
2972
  const emptyScripts = scripts.filter(
@@ -3266,45 +2974,45 @@ async function deployCommand(environment, options) {
3266
2974
  );
3267
2975
  if (emptyScripts.length > 0) {
3268
2976
  preCheckSpinner.warn(`${emptyScripts.length} tomme script(s) funnet`);
3269
- console.log(chalk5.yellow("\n\u26A0\uFE0F F\xF8lgende scripts er tomme:"));
2977
+ console.log(chalk4.yellow("\n\u26A0\uFE0F F\xF8lgende scripts er tomme:"));
3270
2978
  emptyScripts.forEach((s) => {
3271
- console.log(chalk5.dim(` - ${s.slug}.${s.type === "javascript" ? "js" : "css"}`));
2979
+ console.log(chalk4.dim(` - ${s.slug}.${s.type === "javascript" ? "js" : "css"}`));
3272
2980
  });
3273
- console.log(chalk5.dim(" Tomme scripts har ingen effekt n\xE5r de er deployet.\n"));
2981
+ console.log(chalk4.dim(" Tomme scripts har ingen effekt n\xE5r de er deployet.\n"));
3274
2982
  } else {
3275
2983
  preCheckSpinner.succeed(`${scripts.filter((s) => s.is_active).length} script(s) klare`);
3276
2984
  }
3277
2985
  } catch {
3278
2986
  preCheckSpinner.info("Kunne ikke sjekke scripts");
3279
2987
  }
3280
- const spinner = ora4("Deploying to staging...").start();
2988
+ const spinner = ora3("Deploying to staging...").start();
3281
2989
  try {
3282
2990
  const deployment = await client.deploy(config.siteId, "staging");
3283
2991
  spinner.succeed("Deployed to staging");
3284
2992
  console.log();
3285
- console.log(chalk5.dim("Deployment details:"));
3286
- console.log(chalk5.dim(` Version: ${deployment.version}`));
3287
- console.log(chalk5.dim(` Status: ${deployment.status}`));
3288
- console.log(chalk5.dim(` Started: ${new Date(deployment.started_at).toLocaleString("nb-NO")}`));
2993
+ console.log(chalk4.dim("Deployment details:"));
2994
+ console.log(chalk4.dim(` Version: ${deployment.version}`));
2995
+ console.log(chalk4.dim(` Status: ${deployment.status}`));
2996
+ console.log(chalk4.dim(` Started: ${new Date(deployment.started_at).toLocaleString("nb-NO")}`));
3289
2997
  console.log();
3290
- console.log(chalk5.bold("CDN URL:"));
3291
- console.log(chalk5.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
2998
+ console.log(chalk4.bold("CDN URL:"));
2999
+ console.log(chalk4.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
3292
3000
  console.log();
3293
- console.log(chalk5.cyan('\u{1F4A1} Tip: Use "kode deploy production" to promote to production.'));
3001
+ console.log(chalk4.cyan('\u{1F4A1} Tip: Use "kode deploy production" to promote to production.'));
3294
3002
  } catch (error) {
3295
3003
  spinner.fail("Deployment failed");
3296
- console.error(chalk5.red("\nError:"), error.message || error);
3004
+ console.error(chalk4.red("\nError:"), error.message || error);
3297
3005
  }
3298
3006
  }
3299
3007
 
3300
3008
  // src/commands/html.ts
3301
- import chalk6 from "chalk";
3302
- import ora5 from "ora";
3009
+ import chalk5 from "chalk";
3010
+ import ora4 from "ora";
3303
3011
 
3304
3012
  // src/lib/page-cache.ts
3305
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync8, unlinkSync } from "fs";
3306
- import { join as join10, basename as basename4 } from "path";
3307
- var PROJECT_CONFIG_DIR3 = ".cure-kode";
3013
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync5, unlinkSync } from "fs";
3014
+ import { join as join7, basename as basename4 } from "path";
3015
+ var PROJECT_CONFIG_DIR2 = ".cure-kode";
3308
3016
  var PAGES_DIR = "pages";
3309
3017
  function urlToSlug(url) {
3310
3018
  try {
@@ -3317,32 +3025,32 @@ function urlToSlug(url) {
3317
3025
  }
3318
3026
  }
3319
3027
  function getPagesDir(projectRoot) {
3320
- return join10(projectRoot, PROJECT_CONFIG_DIR3, PAGES_DIR);
3028
+ return join7(projectRoot, PROJECT_CONFIG_DIR2, PAGES_DIR);
3321
3029
  }
3322
3030
  function getPageCachePath(projectRoot, urlOrSlug) {
3323
3031
  const slug = urlOrSlug.startsWith("http") ? urlToSlug(urlOrSlug) : urlOrSlug;
3324
- return join10(getPagesDir(projectRoot), `${slug}.json`);
3032
+ return join7(getPagesDir(projectRoot), `${slug}.json`);
3325
3033
  }
3326
3034
  function ensurePagesDir(projectRoot) {
3327
3035
  const pagesDir = getPagesDir(projectRoot);
3328
- if (!existsSync10(pagesDir)) {
3329
- mkdirSync5(pagesDir, { recursive: true });
3036
+ if (!existsSync7(pagesDir)) {
3037
+ mkdirSync3(pagesDir, { recursive: true });
3330
3038
  }
3331
3039
  }
3332
3040
  function savePageContext(projectRoot, context) {
3333
3041
  ensurePagesDir(projectRoot);
3334
3042
  const slug = urlToSlug(context.url);
3335
3043
  const cachePath = getPageCachePath(projectRoot, slug);
3336
- writeFileSync8(cachePath, JSON.stringify(context, null, 2), "utf-8");
3044
+ writeFileSync5(cachePath, JSON.stringify(context, null, 2), "utf-8");
3337
3045
  return slug;
3338
3046
  }
3339
3047
  function readPageContext(projectRoot, urlOrSlug) {
3340
3048
  const cachePath = getPageCachePath(projectRoot, urlOrSlug);
3341
- if (!existsSync10(cachePath)) {
3049
+ if (!existsSync7(cachePath)) {
3342
3050
  return null;
3343
3051
  }
3344
3052
  try {
3345
- const content = readFileSync10(cachePath, "utf-8");
3053
+ const content = readFileSync7(cachePath, "utf-8");
3346
3054
  return JSON.parse(content);
3347
3055
  } catch {
3348
3056
  return null;
@@ -3350,7 +3058,7 @@ function readPageContext(projectRoot, urlOrSlug) {
3350
3058
  }
3351
3059
  function deletePageContext(projectRoot, urlOrSlug) {
3352
3060
  const cachePath = getPageCachePath(projectRoot, urlOrSlug);
3353
- if (existsSync10(cachePath)) {
3061
+ if (existsSync7(cachePath)) {
3354
3062
  unlinkSync(cachePath);
3355
3063
  return true;
3356
3064
  }
@@ -3358,7 +3066,7 @@ function deletePageContext(projectRoot, urlOrSlug) {
3358
3066
  }
3359
3067
  function listCachedPages(projectRoot) {
3360
3068
  const pagesDir = getPagesDir(projectRoot);
3361
- if (!existsSync10(pagesDir)) {
3069
+ if (!existsSync7(pagesDir)) {
3362
3070
  return [];
3363
3071
  }
3364
3072
  const files = readdirSync3(pagesDir).filter((f) => f.endsWith(".json"));
@@ -3423,34 +3131,34 @@ function toCachedContext(structure) {
3423
3131
  async function htmlCommand(url, options) {
3424
3132
  const projectRoot = findProjectRoot();
3425
3133
  if (!projectRoot) {
3426
- console.log(chalk6.red("\u274C Not in a Cure Kode project."));
3427
- console.log(chalk6.dim(' Run "kode init" first.'));
3134
+ console.log(chalk5.red("\u274C Not in a Cure Kode project."));
3135
+ console.log(chalk5.dim(' Run "kode init" first.'));
3428
3136
  return;
3429
3137
  }
3430
3138
  const config = getProjectConfig(projectRoot);
3431
3139
  if (!config) {
3432
- console.log(chalk6.red("\u274C Could not read project configuration."));
3140
+ console.log(chalk5.red("\u274C Could not read project configuration."));
3433
3141
  return;
3434
3142
  }
3435
3143
  let parsedUrl;
3436
3144
  try {
3437
3145
  parsedUrl = new URL(url.startsWith("http") ? url : `https://${url}`);
3438
3146
  } catch {
3439
- console.log(chalk6.red("\u274C Invalid URL."));
3147
+ console.log(chalk5.red("\u274C Invalid URL."));
3440
3148
  return;
3441
3149
  }
3442
3150
  if (options?.save && !options?.force) {
3443
3151
  const slug = urlToSlug(parsedUrl.toString());
3444
3152
  const cached = readPageContext(projectRoot, slug);
3445
3153
  if (cached) {
3446
- console.log(chalk6.dim(`Using cached version from ${cached.extractedAt}`));
3447
- console.log(chalk6.dim(`Use --force to refresh`));
3154
+ console.log(chalk5.dim(`Using cached version from ${cached.extractedAt}`));
3155
+ console.log(chalk5.dim(`Use --force to refresh`));
3448
3156
  console.log();
3449
3157
  printPageContext(cached);
3450
3158
  return;
3451
3159
  }
3452
3160
  }
3453
- const spinner = ora5(`Fetching ${parsedUrl.hostname}${parsedUrl.pathname}...`).start();
3161
+ const spinner = ora4(`Fetching ${parsedUrl.hostname}${parsedUrl.pathname}...`).start();
3454
3162
  try {
3455
3163
  const client = createApiClient(config);
3456
3164
  if (options?.save) {
@@ -3471,7 +3179,7 @@ async function htmlCommand(url, options) {
3471
3179
  spinner.succeed("Page structure extracted");
3472
3180
  const cachedContext = toCachedContext(structure);
3473
3181
  const slug = savePageContext(projectRoot, cachedContext);
3474
- console.log(chalk6.dim(`Saved to .cure-kode/pages/${slug}.json`));
3182
+ console.log(chalk5.dim(`Saved to .cure-kode/pages/${slug}.json`));
3475
3183
  const contextPage = {
3476
3184
  slug,
3477
3185
  url: structure.url,
@@ -3482,7 +3190,7 @@ async function htmlCommand(url, options) {
3482
3190
  cms: structure.cmsPatterns.length > 0 ? structure.cmsPatterns.map((c) => `${c.containerClass} (${c.itemCount})`).join(", ") : void 0
3483
3191
  };
3484
3192
  upsertPage(projectRoot, contextPage, "kode html --save");
3485
- console.log(chalk6.dim(`Updated .cure-kode/context.md`));
3193
+ console.log(chalk5.dim(`Updated .cure-kode/context.md`));
3486
3194
  console.log();
3487
3195
  printPageContext(cachedContext);
3488
3196
  return;
@@ -3494,115 +3202,115 @@ async function htmlCommand(url, options) {
3494
3202
  return;
3495
3203
  }
3496
3204
  console.log();
3497
- console.log(chalk6.bold(result.title || parsedUrl.hostname));
3498
- console.log(chalk6.dim(result.url));
3205
+ console.log(chalk5.bold(result.title || parsedUrl.hostname));
3206
+ console.log(chalk5.dim(result.url));
3499
3207
  console.log();
3500
3208
  const hasCureKode = result.scripts.cureKode.length > 0;
3501
3209
  if (hasCureKode) {
3502
- console.log(chalk6.green("\u2705 Cure Kode installed"));
3210
+ console.log(chalk5.green("\u2705 Cure Kode installed"));
3503
3211
  } else {
3504
- console.log(chalk6.yellow("\u26A0\uFE0F Cure Kode not found"));
3505
- console.log(chalk6.dim(" Add this to your Webflow site:"));
3506
- console.log(chalk6.cyan(` <script src="https://app.cure.no/api/cdn/${config.siteSlug}/init.js"></script>`));
3212
+ console.log(chalk5.yellow("\u26A0\uFE0F Cure Kode not found"));
3213
+ console.log(chalk5.dim(" Add this to your Webflow site:"));
3214
+ console.log(chalk5.cyan(` <script src="https://app.cure.no/api/cdn/${config.siteSlug}/init.js"></script>`));
3507
3215
  }
3508
3216
  console.log();
3509
- console.log(chalk6.dim("\u2500".repeat(50)));
3217
+ console.log(chalk5.dim("\u2500".repeat(50)));
3510
3218
  console.log(
3511
- ` Scripts: ${result.stats.totalScripts}` + chalk6.dim(` (${result.stats.externalScripts} external, ${result.stats.inlineScripts} inline)`)
3219
+ ` Scripts: ${result.stats.totalScripts}` + chalk5.dim(` (${result.stats.externalScripts} external, ${result.stats.inlineScripts} inline)`)
3512
3220
  );
3513
3221
  console.log(` Styles: ${result.stats.totalStyles}`);
3514
- console.log(chalk6.dim("\u2500".repeat(50)));
3222
+ console.log(chalk5.dim("\u2500".repeat(50)));
3515
3223
  console.log();
3516
3224
  if (!options?.styles) {
3517
- console.log(chalk6.bold("Scripts"));
3225
+ console.log(chalk5.bold("Scripts"));
3518
3226
  console.log();
3519
3227
  if (result.scripts.webflow.length > 0) {
3520
- console.log(chalk6.blue(" Webflow:"));
3228
+ console.log(chalk5.blue(" Webflow:"));
3521
3229
  result.scripts.webflow.forEach((s) => {
3522
- console.log(chalk6.dim(` ${s.src || "(inline)"}`));
3230
+ console.log(chalk5.dim(` ${s.src || "(inline)"}`));
3523
3231
  });
3524
3232
  }
3525
3233
  if (result.scripts.cureKode.length > 0) {
3526
- console.log(chalk6.green(" Cure Kode:"));
3234
+ console.log(chalk5.green(" Cure Kode:"));
3527
3235
  result.scripts.cureKode.forEach((s) => {
3528
- console.log(chalk6.dim(` ${s.src || "(inline)"}`));
3236
+ console.log(chalk5.dim(` ${s.src || "(inline)"}`));
3529
3237
  });
3530
3238
  }
3531
3239
  if (result.scripts.thirdParty.length > 0) {
3532
- console.log(chalk6.yellow(" Third-party:"));
3240
+ console.log(chalk5.yellow(" Third-party:"));
3533
3241
  result.scripts.thirdParty.forEach((s) => {
3534
- console.log(chalk6.dim(` ${s.src || "(inline)"}`));
3242
+ console.log(chalk5.dim(` ${s.src || "(inline)"}`));
3535
3243
  });
3536
3244
  }
3537
3245
  if (result.scripts.custom.length > 0) {
3538
- console.log(chalk6.magenta(" Custom:"));
3246
+ console.log(chalk5.magenta(" Custom:"));
3539
3247
  result.scripts.custom.forEach((s) => {
3540
3248
  const label = s.src || (s.inline ? `(inline, ${s.content?.length || 0} chars)` : "(inline)");
3541
- console.log(chalk6.dim(` ${label}`));
3249
+ console.log(chalk5.dim(` ${label}`));
3542
3250
  });
3543
3251
  }
3544
3252
  console.log();
3545
3253
  }
3546
3254
  if (result.detectedComponents.length > 0) {
3547
- console.log(chalk6.bold("Detected Components"));
3255
+ console.log(chalk5.bold("Detected Components"));
3548
3256
  console.log();
3549
3257
  result.detectedComponents.forEach((comp) => {
3550
- console.log(chalk6.dim(` \u2022 ${comp}`));
3258
+ console.log(chalk5.dim(` \u2022 ${comp}`));
3551
3259
  });
3552
3260
  console.log();
3553
3261
  }
3554
3262
  if (options?.styles) {
3555
- console.log(chalk6.bold("Stylesheets"));
3263
+ console.log(chalk5.bold("Stylesheets"));
3556
3264
  console.log();
3557
3265
  result.styles.forEach((style) => {
3558
3266
  if (style.href) {
3559
- const isWebflow = style.isWebflow ? chalk6.blue(" [WF]") : "";
3560
- console.log(chalk6.dim(` ${style.href}${isWebflow}`));
3267
+ const isWebflow = style.isWebflow ? chalk5.blue(" [WF]") : "";
3268
+ console.log(chalk5.dim(` ${style.href}${isWebflow}`));
3561
3269
  } else {
3562
- console.log(chalk6.dim(" (inline style)"));
3270
+ console.log(chalk5.dim(" (inline style)"));
3563
3271
  }
3564
3272
  });
3565
3273
  console.log();
3566
3274
  }
3567
3275
  } catch (error) {
3568
3276
  spinner.fail("Failed to fetch HTML");
3569
- console.error(chalk6.red("\nError:"), error.message || error);
3277
+ console.error(chalk5.red("\nError:"), error.message || error);
3570
3278
  }
3571
3279
  }
3572
3280
  function printPageContext(context) {
3573
- console.log(chalk6.bold(context.title || context.url));
3574
- console.log(chalk6.dim(context.url));
3281
+ console.log(chalk5.bold(context.title || context.url));
3282
+ console.log(chalk5.dim(context.url));
3575
3283
  console.log();
3576
3284
  if (context.sections.length > 0) {
3577
- console.log(chalk6.bold("Sections"));
3285
+ console.log(chalk5.bold("Sections"));
3578
3286
  for (const section of context.sections.slice(0, 8)) {
3579
3287
  const name = section.heading || section.id || section.className?.split(" ")[0] || "section";
3580
3288
  const badges = [];
3581
- if (section.hasCms) badges.push(chalk6.cyan("CMS"));
3582
- if (section.hasForm) badges.push(chalk6.yellow("Form"));
3289
+ if (section.hasCms) badges.push(chalk5.cyan("CMS"));
3290
+ if (section.hasForm) badges.push(chalk5.yellow("Form"));
3583
3291
  const badgeStr = badges.length > 0 ? ` [${badges.join(", ")}]` : "";
3584
3292
  console.log(` \u2022 ${name}${badgeStr}`);
3585
3293
  if (section.textSample) {
3586
- console.log(chalk6.dim(` "${section.textSample.slice(0, 60)}..."`));
3294
+ console.log(chalk5.dim(` "${section.textSample.slice(0, 60)}..."`));
3587
3295
  }
3588
3296
  }
3589
3297
  if (context.sections.length > 8) {
3590
- console.log(chalk6.dim(` ... and ${context.sections.length - 8} more`));
3298
+ console.log(chalk5.dim(` ... and ${context.sections.length - 8} more`));
3591
3299
  }
3592
3300
  console.log();
3593
3301
  }
3594
3302
  if (context.ctas.length > 0) {
3595
- console.log(chalk6.bold("CTAs"));
3303
+ console.log(chalk5.bold("CTAs"));
3596
3304
  for (const cta of context.ctas.slice(0, 6)) {
3597
- console.log(` \u2022 "${cta.text}" ${chalk6.dim(`(${cta.location})`)}`);
3305
+ console.log(` \u2022 "${cta.text}" ${chalk5.dim(`(${cta.location})`)}`);
3598
3306
  }
3599
3307
  if (context.ctas.length > 6) {
3600
- console.log(chalk6.dim(` ... and ${context.ctas.length - 6} more`));
3308
+ console.log(chalk5.dim(` ... and ${context.ctas.length - 6} more`));
3601
3309
  }
3602
3310
  console.log();
3603
3311
  }
3604
3312
  if (context.forms.length > 0) {
3605
- console.log(chalk6.bold("Forms"));
3313
+ console.log(chalk5.bold("Forms"));
3606
3314
  for (const form of context.forms) {
3607
3315
  const fields = form.fields.map((f) => f.label || f.type).slice(0, 4).join(", ");
3608
3316
  const more = form.fields.length > 4 ? ` +${form.fields.length - 4}` : "";
@@ -3611,17 +3319,17 @@ function printPageContext(context) {
3611
3319
  console.log();
3612
3320
  }
3613
3321
  if (context.cmsPatterns.length > 0) {
3614
- console.log(chalk6.bold("CMS Collections"));
3322
+ console.log(chalk5.bold("CMS Collections"));
3615
3323
  for (const cms of context.cmsPatterns) {
3616
- console.log(` \u2022 ${cms.containerClass}: ${chalk6.cyan(`${cms.itemCount} items`)}`);
3324
+ console.log(` \u2022 ${cms.containerClass}: ${chalk5.cyan(`${cms.itemCount} items`)}`);
3617
3325
  if (cms.templateFields.length > 0) {
3618
- console.log(chalk6.dim(` Fields: ${cms.templateFields.slice(0, 5).join(", ")}`));
3326
+ console.log(chalk5.dim(` Fields: ${cms.templateFields.slice(0, 5).join(", ")}`));
3619
3327
  }
3620
3328
  }
3621
3329
  console.log();
3622
3330
  }
3623
3331
  if (context.navigation.length > 0) {
3624
- console.log(chalk6.bold("Navigation"));
3332
+ console.log(chalk5.bold("Navigation"));
3625
3333
  for (const nav of context.navigation) {
3626
3334
  const items = nav.items.slice(0, 5).map((i) => i.text).join(", ");
3627
3335
  const more = nav.items.length > 5 ? ` +${nav.items.length - 5}` : "";
@@ -3630,7 +3338,7 @@ function printPageContext(context) {
3630
3338
  console.log();
3631
3339
  }
3632
3340
  if (context.notes && context.notes.length > 0) {
3633
- console.log(chalk6.bold("Notes"));
3341
+ console.log(chalk5.bold("Notes"));
3634
3342
  for (const note of context.notes) {
3635
3343
  console.log(` \u2022 ${note}`);
3636
3344
  }
@@ -3639,13 +3347,13 @@ function printPageContext(context) {
3639
3347
  }
3640
3348
 
3641
3349
  // src/commands/status.ts
3642
- import chalk7 from "chalk";
3643
- import ora6 from "ora";
3644
- import { readFileSync as readFileSync11, existsSync as existsSync11, readdirSync as readdirSync4, statSync } from "fs";
3645
- import { join as join11, basename as basename5, extname as extname4 } from "path";
3646
- import { createHash as createHash3 } from "crypto";
3647
- function hashContent3(content) {
3648
- return createHash3("sha256").update(content).digest("hex").substring(0, 16);
3350
+ import chalk6 from "chalk";
3351
+ import ora5 from "ora";
3352
+ import { readFileSync as readFileSync8, existsSync as existsSync8, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
3353
+ import { join as join8, basename as basename5, extname as extname4 } from "path";
3354
+ import { createHash as createHash2 } from "crypto";
3355
+ function hashContent2(content) {
3356
+ return createHash2("sha256").update(content).digest("hex").substring(0, 16);
3649
3357
  }
3650
3358
  function formatRelativeTime(dateStr) {
3651
3359
  const date = new Date(dateStr);
@@ -3680,36 +3388,36 @@ function isSyncStale(metadata) {
3680
3388
  async function statusCommand(options) {
3681
3389
  const projectRoot = findProjectRoot();
3682
3390
  if (!projectRoot) {
3683
- console.log(chalk7.red("\u274C Not in a Cure Kode project."));
3684
- console.log(chalk7.dim(' Run "kode init" first.'));
3391
+ console.log(chalk6.red("\u274C Not in a Cure Kode project."));
3392
+ console.log(chalk6.dim(' Run "kode init" first.'));
3685
3393
  return;
3686
3394
  }
3687
3395
  const config = getProjectConfig(projectRoot);
3688
3396
  if (!config) {
3689
- console.log(chalk7.red("\u274C Could not read project configuration."));
3397
+ console.log(chalk6.red("\u274C Could not read project configuration."));
3690
3398
  return;
3691
3399
  }
3692
- const metadataPath = join11(projectRoot, ".cure-kode", "scripts.json");
3400
+ const metadataPath = join8(projectRoot, ".cure-kode", "scripts.json");
3693
3401
  let syncMetadata = [];
3694
- if (existsSync11(metadataPath)) {
3402
+ if (existsSync8(metadataPath)) {
3695
3403
  try {
3696
- syncMetadata = JSON.parse(readFileSync11(metadataPath, "utf-8"));
3404
+ syncMetadata = JSON.parse(readFileSync8(metadataPath, "utf-8"));
3697
3405
  } catch {
3698
3406
  }
3699
3407
  }
3700
3408
  console.log();
3701
- console.log(chalk7.bold(`\u{1F4E6} ${config.siteName}`));
3702
- console.log(chalk7.dim(` Slug: ${config.siteSlug}`));
3703
- console.log(chalk7.dim(` ID: ${config.siteId}`));
3409
+ console.log(chalk6.bold(`\u{1F4E6} ${config.siteName}`));
3410
+ console.log(chalk6.dim(` Slug: ${config.siteSlug}`));
3411
+ console.log(chalk6.dim(` ID: ${config.siteId}`));
3704
3412
  console.log();
3705
- console.log(chalk7.bold("CDN URL"));
3413
+ console.log(chalk6.bold("CDN URL"));
3706
3414
  console.log();
3707
- console.log(chalk7.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
3415
+ console.log(chalk6.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
3708
3416
  console.log();
3709
- console.log(chalk7.dim(" Add to Webflow \u2192 Project Settings \u2192 Custom Code \u2192 Body (before </body>):"));
3710
- console.log(chalk7.dim(` <script src="https://app.cure.no/api/cdn/${config.siteSlug}/init.js"></script>`));
3417
+ console.log(chalk6.dim(" Add to Webflow \u2192 Project Settings \u2192 Custom Code \u2192 Body (before </body>):"));
3418
+ console.log(chalk6.dim(` <script src="https://app.cure.no/api/cdn/${config.siteSlug}/init.js"></script>`));
3711
3419
  console.log();
3712
- const spinner = ora6("Fetching status...").start();
3420
+ const spinner = ora5("Fetching status...").start();
3713
3421
  try {
3714
3422
  const client = createApiClient(config);
3715
3423
  const [remoteScripts, deployStatus] = await Promise.all([
@@ -3717,46 +3425,46 @@ async function statusCommand(options) {
3717
3425
  client.getDeploymentStatus(config.siteId)
3718
3426
  ]);
3719
3427
  spinner.stop();
3720
- console.log(chalk7.bold("Environments"));
3428
+ console.log(chalk6.bold("Environments"));
3721
3429
  console.log();
3722
3430
  const stagingStatus = deployStatus.staging.lastSuccessful;
3723
3431
  if (stagingStatus) {
3724
3432
  console.log(
3725
- chalk7.blue(" Staging: ") + chalk7.green("\u25CF") + chalk7.dim(` v${stagingStatus.version}`) + chalk7.dim(` (${formatDate(stagingStatus.completedAt)})`)
3433
+ chalk6.blue(" Staging: ") + chalk6.green("\u25CF") + chalk6.dim(` v${stagingStatus.version}`) + chalk6.dim(` (${formatDate(stagingStatus.completedAt)})`)
3726
3434
  );
3727
3435
  } else {
3728
- console.log(chalk7.blue(" Staging: ") + chalk7.yellow("\u25CB") + chalk7.dim(" No deployments"));
3436
+ console.log(chalk6.blue(" Staging: ") + chalk6.yellow("\u25CB") + chalk6.dim(" No deployments"));
3729
3437
  }
3730
3438
  const productionEnabled = deployStatus.productionEnabled ?? false;
3731
3439
  const prodStatus = deployStatus.production.lastSuccessful;
3732
3440
  if (!productionEnabled) {
3733
3441
  console.log(
3734
- chalk7.gray(" Production: ") + chalk7.gray("\u25CB") + chalk7.gray(" Deaktivert") + chalk7.dim(" (kun staging)")
3442
+ chalk6.gray(" Production: ") + chalk6.gray("\u25CB") + chalk6.gray(" Deaktivert") + chalk6.dim(" (kun staging)")
3735
3443
  );
3736
3444
  console.log();
3737
3445
  console.log(
3738
- chalk7.dim(' \u{1F4A1} Run "kode production enable" to activate production environment.')
3446
+ chalk6.dim(' \u{1F4A1} Run "kode production enable" to activate production environment.')
3739
3447
  );
3740
3448
  } else if (prodStatus) {
3741
3449
  console.log(
3742
- chalk7.green(" Production: ") + chalk7.green("\u25CF") + chalk7.dim(` v${prodStatus.version}`) + chalk7.dim(` (${formatDate(prodStatus.completedAt)})`)
3450
+ chalk6.green(" Production: ") + chalk6.green("\u25CF") + chalk6.dim(` v${prodStatus.version}`) + chalk6.dim(` (${formatDate(prodStatus.completedAt)})`)
3743
3451
  );
3744
3452
  if (deployStatus.productionDomain) {
3745
- console.log(chalk7.dim(` Domain: ${deployStatus.productionDomain}`));
3453
+ console.log(chalk6.dim(` Domain: ${deployStatus.productionDomain}`));
3746
3454
  }
3747
3455
  } else {
3748
3456
  console.log(
3749
- chalk7.green(" Production: ") + chalk7.yellow("\u25CB") + chalk7.dim(" Aktivert, ingen deployments enda")
3457
+ chalk6.green(" Production: ") + chalk6.yellow("\u25CB") + chalk6.dim(" Aktivert, ingen deployments enda")
3750
3458
  );
3751
3459
  }
3752
3460
  if (deployStatus.canPromote && productionEnabled) {
3753
3461
  console.log();
3754
3462
  console.log(
3755
- chalk7.cyan(' \u{1F4A1} Staging is ahead of production. Run "kode deploy --promote" to update.')
3463
+ chalk6.cyan(' \u{1F4A1} Staging is ahead of production. Run "kode deploy --promote" to update.')
3756
3464
  );
3757
3465
  }
3758
3466
  console.log();
3759
- console.log(chalk7.bold("Scripts"));
3467
+ console.log(chalk6.bold("Scripts"));
3760
3468
  const syncStatus = isSyncStale(syncMetadata);
3761
3469
  if (syncStatus.isStale && syncStatus.lastSyncedAt) {
3762
3470
  const syncDate = new Date(syncStatus.lastSyncedAt);
@@ -3767,20 +3475,20 @@ async function statusCommand(options) {
3767
3475
  minute: "2-digit"
3768
3476
  });
3769
3477
  console.log(
3770
- chalk7.yellow(` \u26A0 Sist synkronisert: ${formatRelativeTime(syncStatus.lastSyncedAt)}`) + chalk7.dim(` (${dateStr})`)
3478
+ chalk6.yellow(` \u26A0 Sist synkronisert: ${formatRelativeTime(syncStatus.lastSyncedAt)}`) + chalk6.dim(` (${dateStr})`)
3771
3479
  );
3772
3480
  } else if (!syncStatus.lastSyncedAt && syncMetadata.length === 0) {
3773
- console.log(chalk7.yellow(` \u26A0 Aldri synkronisert - kj\xF8r "kode pull" f\xF8rst`));
3481
+ console.log(chalk6.yellow(` \u26A0 Aldri synkronisert - kj\xF8r "kode pull" f\xF8rst`));
3774
3482
  }
3775
3483
  console.log();
3776
3484
  const scriptsDir = getScriptsDir(projectRoot, config);
3777
- const localFiles = existsSync11(scriptsDir) ? readdirSync4(scriptsDir).filter((f) => f.endsWith(".js") || f.endsWith(".css")) : [];
3485
+ const localFiles = existsSync8(scriptsDir) ? readdirSync4(scriptsDir).filter((f) => f.endsWith(".js") || f.endsWith(".css")) : [];
3778
3486
  const localBySlug = /* @__PURE__ */ new Map();
3779
3487
  for (const file of localFiles) {
3780
3488
  const slug = basename5(file, extname4(file));
3781
- const filePath = join11(scriptsDir, file);
3782
- const content = readFileSync11(filePath, "utf-8");
3783
- const stats = statSync(filePath);
3489
+ const filePath = join8(scriptsDir, file);
3490
+ const content = readFileSync8(filePath, "utf-8");
3491
+ const stats = statSync2(filePath);
3784
3492
  localBySlug.set(slug, { file, content, modified: stats.mtime });
3785
3493
  }
3786
3494
  const remoteBySlug = /* @__PURE__ */ new Map();
@@ -3798,48 +3506,48 @@ async function statusCommand(options) {
3798
3506
  const remote = remoteBySlug.get(slug);
3799
3507
  const meta = metadataBySlug.get(slug);
3800
3508
  if (local && remote) {
3801
- const scopeTag = remote.scope === "global" ? chalk7.blue("[G]") : chalk7.magenta("[P]");
3802
- const localHash = hashContent3(local.content);
3509
+ const scopeTag = remote.scope === "global" ? chalk6.blue("[G]") : chalk6.magenta("[P]");
3510
+ const localHash = hashContent2(local.content);
3803
3511
  const hasLocalChanges = meta && localHash !== meta.contentHash;
3804
3512
  const lastPulledVersion = meta?.lastPulledVersion || 0;
3805
3513
  const hasRemoteChanges = remote.current_version > lastPulledVersion && lastPulledVersion > 0;
3806
3514
  if (hasLocalChanges && hasRemoteChanges) {
3807
3515
  console.log(
3808
- chalk7.red(" \u26A0 ") + `${local.file}` + chalk7.dim(` v${lastPulledVersion}`) + chalk7.red(` \u2192 v${remote.current_version}`) + ` ${scopeTag}` + chalk7.red(" (konflikt)")
3516
+ chalk6.red(" \u26A0 ") + `${local.file}` + chalk6.dim(` v${lastPulledVersion}`) + chalk6.red(` \u2192 v${remote.current_version}`) + ` ${scopeTag}` + chalk6.red(" (konflikt)")
3809
3517
  );
3810
3518
  outdatedCount++;
3811
3519
  } else if (hasLocalChanges) {
3812
3520
  console.log(
3813
- chalk7.yellow(" M ") + `${local.file}` + chalk7.dim(` v${remote.current_version} ${scopeTag}`) + chalk7.yellow(" (lokalt endret)")
3521
+ chalk6.yellow(" M ") + `${local.file}` + chalk6.dim(` v${remote.current_version} ${scopeTag}`) + chalk6.yellow(" (lokalt endret)")
3814
3522
  );
3815
3523
  } else if (hasRemoteChanges) {
3816
3524
  console.log(
3817
- chalk7.cyan(" \u26A0 ") + `${local.file}` + chalk7.dim(` v${lastPulledVersion}`) + chalk7.cyan(` \u2192 v${remote.current_version}`) + ` ${scopeTag}` + chalk7.cyan(" (server oppdatert)")
3525
+ chalk6.cyan(" \u26A0 ") + `${local.file}` + chalk6.dim(` v${lastPulledVersion}`) + chalk6.cyan(` \u2192 v${remote.current_version}`) + ` ${scopeTag}` + chalk6.cyan(" (server oppdatert)")
3818
3526
  );
3819
3527
  outdatedCount++;
3820
3528
  } else if (local.content !== remote.content) {
3821
3529
  console.log(
3822
- chalk7.yellow(" M ") + `${local.file}` + chalk7.dim(` v${remote.current_version} ${scopeTag}`) + chalk7.yellow(" (lokalt endret)")
3530
+ chalk6.yellow(" M ") + `${local.file}` + chalk6.dim(` v${remote.current_version} ${scopeTag}`) + chalk6.yellow(" (lokalt endret)")
3823
3531
  );
3824
3532
  } else {
3825
3533
  console.log(
3826
- chalk7.green(" \u2713 ") + chalk7.dim(`${local.file}`) + chalk7.dim(` v${remote.current_version} ${scopeTag}`)
3534
+ chalk6.green(" \u2713 ") + chalk6.dim(`${local.file}`) + chalk6.dim(` v${remote.current_version} ${scopeTag}`)
3827
3535
  );
3828
3536
  }
3829
3537
  } else if (local && !remote) {
3830
3538
  console.log(
3831
- chalk7.cyan(" + ") + `${local.file}` + chalk7.cyan(" (ny, ikke pushet)")
3539
+ chalk6.cyan(" + ") + `${local.file}` + chalk6.cyan(" (ny, ikke pushet)")
3832
3540
  );
3833
3541
  } else if (!local && remote) {
3834
3542
  const ext = remote.type === "javascript" ? "js" : "css";
3835
3543
  const fileName = `${slug}.${ext}`;
3836
3544
  console.log(
3837
- chalk7.red(" - ") + chalk7.dim(`${fileName}`) + chalk7.red(" (kun p\xE5 server, ikke pullet)")
3545
+ chalk6.red(" - ") + chalk6.dim(`${fileName}`) + chalk6.red(" (kun p\xE5 server, ikke pullet)")
3838
3546
  );
3839
3547
  }
3840
3548
  }
3841
3549
  if (allSlugs.size === 0) {
3842
- console.log(chalk7.dim(" Ingen skript enda."));
3550
+ console.log(chalk6.dim(" Ingen skript enda."));
3843
3551
  }
3844
3552
  console.log();
3845
3553
  const modified = [...allSlugs].filter((slug) => {
@@ -3847,7 +3555,7 @@ async function statusCommand(options) {
3847
3555
  const remote = remoteBySlug.get(slug);
3848
3556
  if (!local || !remote) return false;
3849
3557
  const meta = metadataBySlug.get(slug);
3850
- const localHash = hashContent3(local.content);
3558
+ const localHash = hashContent2(local.content);
3851
3559
  return meta ? localHash !== meta.contentHash : local.content !== remote.content;
3852
3560
  }).length;
3853
3561
  const newLocal = [...allSlugs].filter(
@@ -3857,25 +3565,25 @@ async function statusCommand(options) {
3857
3565
  (slug) => !localBySlug.has(slug) && remoteBySlug.has(slug)
3858
3566
  ).length;
3859
3567
  if (modified > 0 || newLocal > 0 || remoteOnly > 0 || outdatedCount > 0) {
3860
- console.log(chalk7.bold("Handlinger"));
3568
+ console.log(chalk6.bold("Handlinger"));
3861
3569
  console.log();
3862
3570
  if (modified > 0) {
3863
- console.log(chalk7.yellow(` ${modified} endret lokalt`) + chalk7.dim(' \u2192 "kode push"'));
3571
+ console.log(chalk6.yellow(` ${modified} endret lokalt`) + chalk6.dim(' \u2192 "kode push"'));
3864
3572
  }
3865
3573
  if (newLocal > 0) {
3866
- console.log(chalk7.cyan(` ${newLocal} nye lokale`) + chalk7.dim(' \u2192 "kode push"'));
3574
+ console.log(chalk6.cyan(` ${newLocal} nye lokale`) + chalk6.dim(' \u2192 "kode push"'));
3867
3575
  }
3868
3576
  if (outdatedCount > 0) {
3869
- console.log(chalk7.cyan(` ${outdatedCount} utdaterte`) + chalk7.dim(' \u2192 "kode pull"'));
3577
+ console.log(chalk6.cyan(` ${outdatedCount} utdaterte`) + chalk6.dim(' \u2192 "kode pull"'));
3870
3578
  }
3871
3579
  if (remoteOnly > 0) {
3872
- console.log(chalk7.red(` ${remoteOnly} kun p\xE5 server`) + chalk7.dim(' \u2192 "kode pull"'));
3580
+ console.log(chalk6.red(` ${remoteOnly} kun p\xE5 server`) + chalk6.dim(' \u2192 "kode pull"'));
3873
3581
  }
3874
3582
  console.log();
3875
3583
  }
3876
3584
  } catch (error) {
3877
3585
  spinner.fail("Failed to fetch status");
3878
- console.error(chalk7.red("\nError:"), error.message || error);
3586
+ console.error(chalk6.red("\nError:"), error.message || error);
3879
3587
  }
3880
3588
  }
3881
3589
  function formatDate(dateStr) {
@@ -3890,25 +3598,25 @@ function formatDate(dateStr) {
3890
3598
  }
3891
3599
 
3892
3600
  // src/commands/context.ts
3893
- import chalk8 from "chalk";
3894
- import ora7 from "ora";
3601
+ import chalk7 from "chalk";
3602
+ import ora6 from "ora";
3895
3603
  import { spawn } from "child_process";
3896
3604
  async function contextCommand(options) {
3897
3605
  const projectRoot = findProjectRoot();
3898
3606
  if (!projectRoot) {
3899
- console.log(chalk8.red("Error: Not in a Cure Kode project."));
3900
- console.log(chalk8.dim('Run "kode init" first.'));
3607
+ console.log(chalk7.red("Error: Not in a Cure Kode project."));
3608
+ console.log(chalk7.dim('Run "kode init" first.'));
3901
3609
  return;
3902
3610
  }
3903
3611
  const config = getProjectConfig(projectRoot);
3904
3612
  if (!config) {
3905
- console.log(chalk8.red("Error: Invalid project configuration."));
3613
+ console.log(chalk7.red("Error: Invalid project configuration."));
3906
3614
  return;
3907
3615
  }
3908
3616
  const contextPath = getContextPath(projectRoot);
3909
3617
  const context = readContext(projectRoot);
3910
3618
  if (options.refresh) {
3911
- const spinner = ora7("Refreshing context from server...").start();
3619
+ const spinner = ora6("Refreshing context from server...").start();
3912
3620
  try {
3913
3621
  const siteResponse = await fetch(
3914
3622
  `https://app.cure.no/api/cdn/sites/${config.siteId}`,
@@ -3957,28 +3665,28 @@ async function contextCommand(options) {
3957
3665
  };
3958
3666
  writeContext(projectRoot, newContext);
3959
3667
  spinner.succeed("Context refreshed");
3960
- console.log(chalk8.dim(`Updated: ${contextPath}`));
3668
+ console.log(chalk7.dim(`Updated: ${contextPath}`));
3961
3669
  return;
3962
3670
  } catch (error) {
3963
3671
  spinner.fail("Failed to refresh context");
3964
- console.log(chalk8.red(error instanceof Error ? error.message : "Unknown error"));
3672
+ console.log(chalk7.red(error instanceof Error ? error.message : "Unknown error"));
3965
3673
  return;
3966
3674
  }
3967
3675
  }
3968
3676
  if (options.edit) {
3969
3677
  if (!context) {
3970
- console.log(chalk8.red("Error: No context file found."));
3971
- console.log(chalk8.dim('Run "kode init" or "kode context --refresh" first.'));
3678
+ console.log(chalk7.red("Error: No context file found."));
3679
+ console.log(chalk7.dim('Run "kode init" or "kode context --refresh" first.'));
3972
3680
  return;
3973
3681
  }
3974
3682
  const editor = process.env.EDITOR || process.env.VISUAL || "vim";
3975
- console.log(chalk8.dim(`Opening ${contextPath} in ${editor}...`));
3683
+ console.log(chalk7.dim(`Opening ${contextPath} in ${editor}...`));
3976
3684
  const child = spawn(editor, [contextPath], {
3977
3685
  stdio: "inherit"
3978
3686
  });
3979
3687
  child.on("error", (err) => {
3980
- console.log(chalk8.red(`Failed to open editor: ${err.message}`));
3981
- console.log(chalk8.dim(`You can edit the file manually: ${contextPath}`));
3688
+ console.log(chalk7.red(`Failed to open editor: ${err.message}`));
3689
+ console.log(chalk7.dim(`You can edit the file manually: ${contextPath}`));
3982
3690
  });
3983
3691
  return;
3984
3692
  }
@@ -3991,38 +3699,38 @@ async function contextCommand(options) {
3991
3699
  return;
3992
3700
  }
3993
3701
  if (!context) {
3994
- console.log(chalk8.yellow("No context file found."));
3995
- console.log(chalk8.dim('Run "kode context --refresh" to create one.'));
3702
+ console.log(chalk7.yellow("No context file found."));
3703
+ console.log(chalk7.dim('Run "kode context --refresh" to create one.'));
3996
3704
  return;
3997
3705
  }
3998
- console.log(chalk8.bold(`Context: ${context.site.name}`));
3999
- console.log(chalk8.dim(`Last updated: ${context.lastUpdated}`));
4000
- console.log(chalk8.dim(`Updated by: ${context.updatedBy}`));
3706
+ console.log(chalk7.bold(`Context: ${context.site.name}`));
3707
+ console.log(chalk7.dim(`Last updated: ${context.lastUpdated}`));
3708
+ console.log(chalk7.dim(`Updated by: ${context.updatedBy}`));
4001
3709
  console.log();
4002
3710
  if (context.site.domain || context.site.stagingDomain) {
4003
3711
  if (context.site.domain) {
4004
- console.log(chalk8.dim("Domain: ") + context.site.domain);
3712
+ console.log(chalk7.dim("Domain: ") + context.site.domain);
4005
3713
  }
4006
3714
  if (context.site.stagingDomain) {
4007
- console.log(chalk8.dim("Staging: ") + context.site.stagingDomain);
3715
+ console.log(chalk7.dim("Staging: ") + context.site.stagingDomain);
4008
3716
  }
4009
3717
  console.log();
4010
3718
  }
4011
- console.log(chalk8.bold("Scripts:"));
3719
+ console.log(chalk7.bold("Scripts:"));
4012
3720
  if (context.scripts.length === 0) {
4013
- console.log(chalk8.dim(" (no scripts)"));
3721
+ console.log(chalk7.dim(" (no scripts)"));
4014
3722
  } else {
4015
3723
  for (const script of context.scripts) {
4016
3724
  const typeIcon = script.type === "css" ? "\u{1F3A8}" : "\u{1F4DC}";
4017
- const scopeLabel = script.scope === "global" ? chalk8.cyan("global") : chalk8.yellow("page");
4018
- const purpose = script.purpose ? chalk8.dim(` - ${script.purpose}`) : "";
3725
+ const scopeLabel = script.scope === "global" ? chalk7.cyan("global") : chalk7.yellow("page");
3726
+ const purpose = script.purpose ? chalk7.dim(` - ${script.purpose}`) : "";
4019
3727
  console.log(` ${typeIcon} ${script.slug} [${scopeLabel}]${purpose}`);
4020
3728
  }
4021
3729
  }
4022
3730
  console.log();
4023
- console.log(chalk8.bold("Notes:"));
3731
+ console.log(chalk7.bold("Notes:"));
4024
3732
  if (context.notes.length === 0 || context.notes.length === 3 && context.notes[0].startsWith("(HTML")) {
4025
- console.log(chalk8.dim(" (no notes yet)"));
3733
+ console.log(chalk7.dim(" (no notes yet)"));
4026
3734
  } else {
4027
3735
  for (const note of context.notes) {
4028
3736
  if (!note.startsWith("(")) {
@@ -4031,67 +3739,67 @@ async function contextCommand(options) {
4031
3739
  }
4032
3740
  }
4033
3741
  console.log();
4034
- console.log(chalk8.bold("Recent Sessions:"));
3742
+ console.log(chalk7.bold("Recent Sessions:"));
4035
3743
  if (context.sessions.length === 0) {
4036
- console.log(chalk8.dim(" (no sessions recorded)"));
3744
+ console.log(chalk7.dim(" (no sessions recorded)"));
4037
3745
  } else {
4038
3746
  const recentSessions = context.sessions.slice(0, 3);
4039
3747
  for (const session of recentSessions) {
4040
- console.log(` ${chalk8.dim(session.date)} ${session.agent}`);
3748
+ console.log(` ${chalk7.dim(session.date)} ${session.agent}`);
4041
3749
  console.log(` ${session.task}`);
4042
3750
  if (session.changes.length > 0) {
4043
- console.log(chalk8.dim(` ${session.changes.length} change(s)`));
3751
+ console.log(chalk7.dim(` ${session.changes.length} change(s)`));
4044
3752
  }
4045
3753
  }
4046
3754
  if (context.sessions.length > 3) {
4047
- console.log(chalk8.dim(` ... and ${context.sessions.length - 3} more sessions`));
3755
+ console.log(chalk7.dim(` ... and ${context.sessions.length - 3} more sessions`));
4048
3756
  }
4049
3757
  }
4050
3758
  console.log();
4051
- console.log(chalk8.dim(`Context file: ${contextPath}`));
4052
- console.log(chalk8.dim("Use --edit to open in editor, --refresh to update from server"));
3759
+ console.log(chalk7.dim(`Context file: ${contextPath}`));
3760
+ console.log(chalk7.dim("Use --edit to open in editor, --refresh to update from server"));
4053
3761
  }
4054
3762
 
4055
3763
  // src/commands/sync-config.ts
4056
- import chalk9 from "chalk";
4057
- import ora8 from "ora";
4058
- import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
4059
- import { join as join12 } from "path";
3764
+ import chalk8 from "chalk";
3765
+ import ora7 from "ora";
3766
+ import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
3767
+ import { join as join9 } from "path";
4060
3768
  async function syncConfigCommand() {
4061
3769
  const cwd = process.cwd();
4062
3770
  const projectRoot = findProjectRoot(cwd);
4063
3771
  if (!projectRoot) {
4064
- console.log(chalk9.red(" Feil: Cure Kode er ikke initialisert i denne mappen."));
4065
- console.log(chalk9.dim(" Kj\xF8r ") + chalk9.cyan("kode init") + chalk9.dim(" f\xF8rst."));
3772
+ console.log(chalk8.red(" Feil: Cure Kode er ikke initialisert i denne mappen."));
3773
+ console.log(chalk8.dim(" Kj\xF8r ") + chalk8.cyan("kode init") + chalk8.dim(" f\xF8rst."));
4066
3774
  return;
4067
3775
  }
4068
3776
  const config = getProjectConfig(projectRoot);
4069
3777
  if (!config) {
4070
- console.log(chalk9.red(" Feil: Kunne ikke lese prosjektkonfigurasjon."));
3778
+ console.log(chalk8.red(" Feil: Kunne ikke lese prosjektkonfigurasjon."));
4071
3779
  return;
4072
3780
  }
4073
3781
  if (!config.projectId) {
4074
- console.log(chalk9.yellow(" Nettstedet er ikke koblet til et prosjekt."));
4075
- console.log(chalk9.dim(' Koble til via Curie: "Koble denne Kode-siten til prosjekt X"'));
3782
+ console.log(chalk8.yellow(" Nettstedet er ikke koblet til et prosjekt."));
3783
+ console.log(chalk8.dim(' Koble til via Curie: "Koble denne Kode-siten til prosjekt X"'));
4076
3784
  return;
4077
3785
  }
4078
- const spinner = ora8("Henter prosjektkonfigurasjon...").start();
3786
+ const spinner = ora7("Henter prosjektkonfigurasjon...").start();
4079
3787
  try {
4080
3788
  const response = await fetch(`https://app.cure.no/api/cdn/sites/${config.siteId}/project`, {
4081
3789
  headers: { "X-API-Key": config.apiKey }
4082
3790
  });
4083
3791
  if (!response.ok) {
4084
3792
  spinner.fail("Kunne ikke hente prosjektkonfigurasjon");
4085
- console.log(chalk9.dim(` HTTP ${response.status}: ${response.statusText}`));
3793
+ console.log(chalk8.dim(` HTTP ${response.status}: ${response.statusText}`));
4086
3794
  return;
4087
3795
  }
4088
3796
  const projectCtx = await response.json();
4089
3797
  spinner.succeed("Prosjektkonfigurasjon hentet");
4090
- const mcpConfigPath = join12(projectRoot, ".mcp.json");
3798
+ const mcpConfigPath = join9(projectRoot, ".mcp.json");
4091
3799
  let mcpConfig = {};
4092
- if (existsSync12(mcpConfigPath)) {
3800
+ if (existsSync9(mcpConfigPath)) {
4093
3801
  try {
4094
- mcpConfig = JSON.parse(readFileSync12(mcpConfigPath, "utf-8"));
3802
+ mcpConfig = JSON.parse(readFileSync9(mcpConfigPath, "utf-8"));
4095
3803
  } catch {
4096
3804
  }
4097
3805
  }
@@ -4135,7 +3843,7 @@ async function syncConfigCommand() {
4135
3843
  added.push(server.name);
4136
3844
  }
4137
3845
  }
4138
- writeFileSync9(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
3846
+ writeFileSync6(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
4139
3847
  spinner.start("Oppdaterer dokumentasjon...");
4140
3848
  let scripts = [];
4141
3849
  let pages = [];
@@ -4171,43 +3879,36 @@ async function syncConfigCommand() {
4171
3879
  spinner.succeed("Dokumentasjon oppdatert");
4172
3880
  console.log();
4173
3881
  if (projectCtx.project) {
4174
- console.log(chalk9.bold(" Prosjekt: ") + chalk9.cyan(projectCtx.project.name));
3882
+ console.log(chalk8.bold(" Prosjekt: ") + chalk8.cyan(projectCtx.project.name));
4175
3883
  }
4176
3884
  if (added.length > 0 || updated.length > 0) {
4177
- console.log(chalk9.bold(" MCP-servere:"));
3885
+ console.log(chalk8.bold(" MCP-servere:"));
4178
3886
  for (const name of added) {
4179
- console.log(chalk9.green(` + ${name}`) + chalk9.dim(" (ny)"));
3887
+ console.log(chalk8.green(` + ${name}`) + chalk8.dim(" (ny)"));
4180
3888
  }
4181
3889
  for (const name of updated) {
4182
- console.log(chalk9.blue(` ~ ${name}`) + chalk9.dim(" (oppdatert)"));
3890
+ console.log(chalk8.blue(` ~ ${name}`) + chalk8.dim(" (oppdatert)"));
4183
3891
  }
4184
3892
  } else if (projectCtx.mcp_servers.length === 0) {
4185
- console.log(chalk9.dim(" Ingen prosjekt-MCP-servere konfigurert."));
3893
+ console.log(chalk8.dim(" Ingen prosjekt-MCP-servere konfigurert."));
4186
3894
  } else {
4187
- console.log(chalk9.dim(" Ingen endringer i MCP-servere."));
3895
+ console.log(chalk8.dim(" Ingen endringer i MCP-servere."));
4188
3896
  }
4189
3897
  if (secretWarnings.length > 0) {
4190
3898
  console.log();
4191
- console.log(chalk9.yellow(" \u26A0\uFE0F Hemmeligheter som m\xE5 settes i .mcp.json:"));
3899
+ console.log(chalk8.yellow(" \u26A0\uFE0F Hemmeligheter som m\xE5 settes i .mcp.json:"));
4192
3900
  for (const warning of secretWarnings) {
4193
- console.log(chalk9.dim(` \u2022 ${warning}`));
3901
+ console.log(chalk8.dim(` \u2022 ${warning}`));
4194
3902
  }
4195
3903
  }
4196
3904
  console.log();
4197
3905
  } catch (error) {
4198
3906
  spinner.fail("Sync feilet");
4199
- console.log(chalk9.red(` Feil: ${error.message}`));
3907
+ console.log(chalk8.red(` Feil: ${error.message}`));
4200
3908
  }
4201
3909
  }
4202
3910
 
4203
3911
  export {
4204
- findProjectRoot,
4205
- getProjectConfig,
4206
- saveProjectConfig,
4207
- getApiUrl,
4208
- getApiKey,
4209
- setGlobalConfig,
4210
- getScriptsDir,
4211
3912
  getContextPath,
4212
3913
  parseContext,
4213
3914
  serializeContext,
@@ -4218,17 +3919,9 @@ export {
4218
3919
  updateScriptPurpose,
4219
3920
  generateInitialContext,
4220
3921
  generateClaudeMd,
4221
- updateKodeDocs,
4222
- scriptsToDocsFormat,
4223
- pagesToInfoFormat,
4224
- updateClaudeMd,
4225
3922
  CLI_VERSION,
4226
3923
  showCompactBanner,
4227
3924
  initCommand,
4228
- KodeApiError,
4229
- KodeApiClient,
4230
- createApiClient,
4231
- pullCommand,
4232
3925
  pushCommand,
4233
3926
  watchCommand,
4234
3927
  deployCommand,