@curenorway/kode-cli 1.18.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,285 +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
- | \`kode library\` | List global library snippets |
1359
- | \`kode library search <query>\` | Search library |
1360
- | \`kode library add <slug>\` | Copy snippet into project |
1361
-
1362
- ## MCP Tools
1363
-
1364
- AI agents can use these tools directly:
1365
-
1366
- - \`kode_list_scripts\` - List all scripts
1367
- - \`kode_push\` - Upload local files
1368
- - \`kode_deploy\` / \`kode_promote\` - Deploy to staging/production
1369
- - \`kode_create_page\` - Create CDN page with URL patterns
1370
- - \`kode_assign_script_to_page\` - Assign script to page
1371
- - \`kode_library_list\` - Browse global script library
1372
- - \`kode_library_get\` - Get snippet with full code
1373
- - \`kode_library_use\` - Copy snippet into project
1374
-
1375
- ## File Structure
1376
-
1377
- \`\`\`
1378
- .cure-kode/
1379
- \u251C\u2500\u2500 config.json # Site configuration (contains API key - gitignored)
1380
- \u251C\u2500\u2500 scripts.json # Sync state for conflict detection
1381
- \u251C\u2500\u2500 context.md # Dynamic context for AI agents
1382
- \u2514\u2500\u2500 KODE.md # This file - auto-generated docs
1383
-
1384
- .cure-kode-scripts/ # Your script files
1385
- \u251C\u2500\u2500 main.js
1386
- \u251C\u2500\u2500 form-handler.js
1387
- \u2514\u2500\u2500 library/ # Reference only (never deployed)
1388
- \u251C\u2500\u2500 animations/
1389
- \u251C\u2500\u2500 forms/
1390
- \u2514\u2500\u2500 utilities/
1391
-
1392
- .claude/skills/ # Claude Code skills
1393
- \u251C\u2500\u2500 deploy/ # /deploy \u2014 push and deploy workflow
1394
- \u2514\u2500\u2500 webflow-patterns/ # Auto-loaded Webflow DOM reference
1395
- \`\`\`
1396
- `;
1397
- return md;
1398
- }
1399
- function ensureClaudeMdReference(projectRoot) {
1400
- const claudeMdPath = join3(projectRoot, "CLAUDE.md");
1401
- if (!existsSync3(claudeMdPath)) {
1402
- writeFileSync3(claudeMdPath, KODE_REFERENCE);
1403
- return { created: true, updated: false, skipped: false };
1404
- }
1405
- const content = readFileSync3(claudeMdPath, "utf-8");
1406
- if (hasKodeReference(content)) {
1407
- return { created: false, updated: false, skipped: true };
1408
- }
1409
- const newContent = KODE_REFERENCE + content;
1410
- writeFileSync3(claudeMdPath, newContent);
1411
- return { created: false, updated: true, skipped: false };
1412
- }
1413
- function updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options) {
1414
- const kodeMdPath = join3(projectRoot, ".cure-kode", "KODE.md");
1415
- const existed = existsSync3(kodeMdPath);
1416
- const content = generateKodeMd(siteName, siteSlug, scripts, pages, options);
1417
- writeFileSync3(kodeMdPath, content);
1418
- return { created: !existed, updated: existed };
1419
- }
1420
- function updateKodeDocs(projectRoot, siteName, siteSlug, scripts, pages, options) {
1421
- const kodeMd = updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options);
1422
- const claudeMd = ensureClaudeMdReference(projectRoot);
1423
- return { kodeMd, claudeMd };
1424
- }
1425
- function scriptsToDocsFormat(scripts, pages) {
1426
- return scripts.map((s) => {
1427
- const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
1428
- const page = pages?.find((pg) => pg.id === p.page_id);
1429
- return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
1430
- }).filter((p) => p !== null);
1431
- return {
1432
- slug: s.slug,
1433
- name: s.name,
1434
- type: s.type,
1435
- scope: s.scope,
1436
- autoLoad: s.auto_load,
1437
- purpose: s.metadata?.purpose || s.description,
1438
- pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0
1439
- };
1440
- });
1441
- }
1442
- function pagesToInfoFormat(pages) {
1443
- return pages.filter((p) => p.is_active).map((p) => ({
1444
- name: p.name,
1445
- slug: p.slug,
1446
- patterns: p.url_patterns
1447
- }));
1448
- }
1449
- var updateClaudeMd = updateKodeDocs;
1450
1170
 
1451
1171
  // src/lib/skills.ts
1452
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
1453
- import { join as join4 } from "path";
1172
+ import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
1173
+ import { join as join2 } from "path";
1454
1174
  function generateSkills(projectRoot, siteSlug) {
1455
- const skillsDir = join4(projectRoot, ".claude", "skills");
1175
+ const skillsDir = join2(projectRoot, ".claude", "skills");
1456
1176
  const created = [];
1457
1177
  const skipped = [];
1458
- const deployDir = join4(skillsDir, "deploy");
1459
- const deployPath = join4(deployDir, "SKILL.md");
1460
- if (!existsSync4(deployPath)) {
1461
- mkdirSync2(deployDir, { recursive: true });
1462
- 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));
1463
1183
  created.push("deploy");
1464
1184
  } else {
1465
1185
  skipped.push("deploy");
1466
1186
  }
1467
- const libraryDir = join4(skillsDir, "library");
1468
- const libraryPath = join4(libraryDir, "SKILL.md");
1469
- if (!existsSync4(libraryPath)) {
1470
- mkdirSync2(libraryDir, { recursive: true });
1471
- writeFileSync4(libraryPath, LIBRARY_SKILL);
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);
1472
1192
  created.push("library");
1473
1193
  } else {
1474
1194
  skipped.push("library");
1475
1195
  }
1476
- const webflowDir = join4(skillsDir, "webflow-patterns");
1477
- const webflowSkillPath = join4(webflowDir, "SKILL.md");
1478
- const webflowRefPath = join4(webflowDir, "reference.md");
1479
- if (!existsSync4(webflowSkillPath)) {
1480
- mkdirSync2(webflowDir, { recursive: true });
1481
- writeFileSync4(webflowSkillPath, WEBFLOW_SKILL);
1482
- writeFileSync4(webflowRefPath, WEBFLOW_REFERENCE);
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);
1483
1203
  created.push("webflow-patterns");
1484
1204
  } else {
1485
1205
  skipped.push("webflow-patterns");
@@ -1585,7 +1305,7 @@ See [reference.md](reference.md) for:
1585
1305
  `;
1586
1306
  var LIBRARY_SKILL = `---
1587
1307
  name: library
1588
- description: Check the Cure Kode global library before writing common patterns from scratch. Contains reusable GSAP animations, form handlers, scroll effects, and utilities.
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.
1589
1309
  user-invocable: false
1590
1310
  ---
1591
1311
 
@@ -1598,7 +1318,8 @@ Before writing common JavaScript/CSS patterns, check if the global library alrea
1598
1318
  ### 1. Browse available snippets
1599
1319
 
1600
1320
  \`\`\`
1601
- kode library list
1321
+ kode library list # Flat list grouped by category
1322
+ kode library --tree # Folder tree view
1602
1323
  \`\`\`
1603
1324
 
1604
1325
  Or search for a specific pattern:
@@ -1607,7 +1328,7 @@ Or search for a specific pattern:
1607
1328
  kode library search "scroll"
1608
1329
  \`\`\`
1609
1330
 
1610
- Via MCP: use \`kode_library_list\` or \`kode_library_get\`.
1331
+ Via MCP: use \`kode_library_list\` (with category/folder filter) or \`kode_library_get\`.
1611
1332
 
1612
1333
  ### 2. Copy and adapt
1613
1334
 
@@ -1628,6 +1349,21 @@ kode push
1628
1349
  If you improve a library snippet or create a reusable pattern:
1629
1350
  \`\`\`
1630
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
1631
1367
  \`\`\`
1632
1368
 
1633
1369
  ## Categories
@@ -1642,8 +1378,9 @@ kode library push my-improved-script.js
1642
1378
 
1643
1379
  ## Local reference files
1644
1380
 
1645
- Library snippets are downloaded to \`.cure-kode-scripts/library/\` during \`kode init\`.
1381
+ Library snippets are downloaded to \`.cure-kode-scripts/library/\` during \`kode library pull\`.
1646
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).
1647
1384
  `;
1648
1385
  var WEBFLOW_REFERENCE = `# Webflow Patterns \u2014 Detailed Reference
1649
1386
 
@@ -1977,26 +1714,154 @@ async function initCommand(options) {
1977
1714
  apiKey,
1978
1715
  scriptsDir: DEFAULT_SCRIPTS_DIR,
1979
1716
  environment: "staging",
1717
+ ...options.dev && { apiUrl: "http://localhost:3000" },
1980
1718
  ...projectCtx?.project && { projectId: projectCtx.project.id }
1981
1719
  };
1982
1720
  spinner.start("Oppretter prosjektstruktur...");
1983
1721
  saveProjectConfig(config, cwd);
1984
- const scriptsPath = join5(cwd, DEFAULT_SCRIPTS_DIR);
1985
- if (!existsSync5(scriptsPath)) {
1986
- mkdirSync3(scriptsPath, { recursive: true });
1722
+ const scriptsPath = join3(cwd, DEFAULT_SCRIPTS_DIR);
1723
+ if (!existsSync3(scriptsPath)) {
1724
+ mkdirSync2(scriptsPath, { recursive: true });
1987
1725
  }
1988
- const gitignorePath = join5(cwd, ".cure-kode", ".gitignore");
1726
+ const gitignorePath = join3(cwd, ".cure-kode", ".gitignore");
1989
1727
  const gitignoreContent = `# Hold config.json privat - inneholder API-n\xF8kkel
1990
1728
  config.json
1991
1729
  `;
1992
- 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
+ }
1993
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
+ }
1994
1859
  spinner.start("Konfigurerer MCP-servere...");
1995
- const mcpConfigPath = join5(cwd, ".mcp.json");
1860
+ const mcpConfigPath = join3(cwd, ".mcp.json");
1996
1861
  let mcpConfig = {};
1997
- if (existsSync5(mcpConfigPath)) {
1862
+ if (existsSync3(mcpConfigPath)) {
1998
1863
  try {
1999
- mcpConfig = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
1864
+ mcpConfig = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
2000
1865
  } catch {
2001
1866
  }
2002
1867
  }
@@ -2045,7 +1910,7 @@ config.json
2045
1910
  mcpConfig.mcpServers[server.name] = serverConfig;
2046
1911
  }
2047
1912
  }
2048
- writeFileSync5(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
1913
+ writeFileSync3(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
2049
1914
  spinner.succeed("MCP-servere konfigurert");
2050
1915
  if (secretWarnings.length > 0) {
2051
1916
  console.log();
@@ -2097,7 +1962,7 @@ config.json
2097
1962
  production_domain: site.production_domain
2098
1963
  };
2099
1964
  const contextMdContent = generateInitialContext(config, scripts, siteInfo);
2100
- writeFileSync5(join5(cwd, ".cure-kode", "context.md"), contextMdContent);
1965
+ writeFileSync3(join3(cwd, ".cure-kode", "context.md"), contextMdContent);
2101
1966
  spinner.succeed("AI-dokumentasjon generert");
2102
1967
  spinner.start("Laster ned bibliotek-referanser...");
2103
1968
  try {
@@ -2144,6 +2009,23 @@ config.json
2144
2009
  } else {
2145
2010
  spinner.succeed("Claude Code skills finnes allerede");
2146
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
+ }
2147
2029
  console.log();
2148
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"));
2149
2031
  console.log(chalk.green(" \u2551") + chalk.bold.green(" \u2705 Cure Kode er klar! ") + chalk.green("\u2551"));
@@ -2159,6 +2041,8 @@ config.json
2159
2041
  console.log(chalk.dim(" \u251C\u2500\u2500 CLAUDE.md ") + chalk.dim("(uendret - har allerede referanse)"));
2160
2042
  }
2161
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)"));
2162
2046
  console.log(chalk.dim(" \u251C\u2500\u2500 .claude/skills/ ") + chalk.green("(Claude Code skills)"));
2163
2047
  console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 deploy/ (/deploy \u2014 push og deploy)"));
2164
2048
  console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 webflow-patterns/ (Webflow DOM-referanse)"));
@@ -2192,9 +2076,8 @@ config.json
2192
2076
  }
2193
2077
  console.log(chalk.bold(" Neste steg:"));
2194
2078
  console.log();
2195
- console.log(chalk.cyan(" 1. kode pull ") + chalk.dim("Last ned eksisterende skript"));
2196
- console.log(chalk.cyan(" 2.") + chalk.dim(" Start din AI-agent (Claude Code, Cursor, etc.)"));
2197
- 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"));
2198
2081
  console.log();
2199
2082
  console.log(chalk.bold(" MCP-verkt\xF8y tilgjengelig:"));
2200
2083
  console.log();
@@ -2216,489 +2099,70 @@ config.json
2216
2099
  }
2217
2100
  }
2218
2101
 
2219
- // src/lib/retry.ts
2220
- function isRetryableError(error) {
2221
- if (error instanceof TypeError && error.message.includes("fetch")) {
2222
- return true;
2223
- }
2224
- const err = error;
2225
- const statusCode = err.statusCode || err.status;
2226
- if (statusCode && statusCode >= 400 && statusCode < 500) {
2227
- return false;
2228
- }
2229
- if (statusCode && statusCode >= 500) {
2230
- return true;
2231
- }
2232
- if (err.code === "ECONNRESET" || err.code === "ETIMEDOUT" || err.code === "ENOTFOUND") {
2233
- return true;
2234
- }
2235
- if (error instanceof Error) {
2236
- const message = error.message.toLowerCase();
2237
- if (message.includes("network") || message.includes("timeout") || message.includes("connection") || message.includes("socket")) {
2238
- return true;
2239
- }
2240
- }
2241
- return false;
2242
- }
2243
- function calculateDelay(attempt, baseDelayMs, maxDelayMs, backoffMultiplier, jitter) {
2244
- const exponentialDelay = baseDelayMs * Math.pow(backoffMultiplier, attempt - 1);
2245
- const cappedDelay = Math.min(exponentialDelay, maxDelayMs);
2246
- if (!jitter) {
2247
- return cappedDelay;
2248
- }
2249
- const jitterRange = cappedDelay * 0.25;
2250
- const jitterOffset = (Math.random() - 0.5) * 2 * jitterRange;
2251
- return Math.max(0, Math.round(cappedDelay + jitterOffset));
2252
- }
2253
- function sleep(ms) {
2254
- return new Promise((resolve) => setTimeout(resolve, ms));
2255
- }
2256
- async function withRetry(fn, options = {}) {
2257
- const {
2258
- maxAttempts = 3,
2259
- baseDelayMs = 500,
2260
- maxDelayMs = 5e3,
2261
- backoffMultiplier = 2,
2262
- jitter = true,
2263
- isRetryable = isRetryableError,
2264
- onRetry
2265
- } = options;
2266
- let lastError;
2267
- let totalDelayMs = 0;
2268
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2269
- try {
2270
- return await fn();
2271
- } catch (error) {
2272
- lastError = error instanceof Error ? error : new Error(String(error));
2273
- if (attempt >= maxAttempts || !isRetryable(error)) {
2274
- throw lastError;
2275
- }
2276
- const delayMs = calculateDelay(
2277
- attempt,
2278
- baseDelayMs,
2279
- maxDelayMs,
2280
- backoffMultiplier,
2281
- jitter
2282
- );
2283
- totalDelayMs += delayMs;
2284
- if (onRetry) {
2285
- onRetry(attempt, error, delayMs);
2286
- }
2287
- await sleep(delayMs);
2288
- }
2289
- }
2290
- throw lastError || new Error("Retry failed");
2291
- }
2292
-
2293
- // src/api.ts
2294
- var KodeApiError = class extends Error {
2295
- constructor(message, statusCode, response) {
2296
- super(message);
2297
- this.statusCode = statusCode;
2298
- this.response = response;
2299
- this.name = "KodeApiError";
2300
- }
2301
- };
2302
- var KodeApiClient = class {
2303
- baseUrl;
2304
- apiKey;
2305
- constructor(config) {
2306
- this.baseUrl = getApiUrl(config);
2307
- const apiKey = getApiKey(config);
2308
- if (!apiKey) {
2309
- throw new Error('API key is required. Run "kode init" first.');
2310
- }
2311
- this.apiKey = apiKey;
2312
- }
2313
- async request(endpoint, options = {}) {
2314
- const url = `${this.baseUrl}${endpoint}`;
2315
- return withRetry(
2316
- async () => {
2317
- const response = await fetch(url, {
2318
- ...options,
2319
- headers: {
2320
- "Content-Type": "application/json",
2321
- "X-API-Key": this.apiKey,
2322
- ...options.headers
2323
- }
2324
- });
2325
- const data = await response.json();
2326
- if (!response.ok) {
2327
- throw new KodeApiError(
2328
- data.error || `Request failed with status ${response.status}`,
2329
- response.status,
2330
- data
2331
- );
2332
- }
2333
- return data;
2334
- },
2335
- {
2336
- maxAttempts: 3,
2337
- baseDelayMs: 500,
2338
- // Custom retry check: retry on network errors and 5xx, but not 4xx
2339
- isRetryable: (error) => {
2340
- if (error instanceof KodeApiError) {
2341
- return error.statusCode >= 500;
2342
- }
2343
- return isRetryableError(error);
2344
- }
2345
- }
2346
- );
2347
- }
2348
- // Sites
2349
- async getSite(siteId) {
2350
- return this.request(`/api/cdn/sites/${siteId}`);
2351
- }
2352
- async listSites() {
2353
- return this.request("/api/cdn/sites");
2354
- }
2355
- // Scripts
2356
- async listScripts(siteId) {
2357
- return this.request(`/api/cdn/sites/${siteId}/scripts`);
2358
- }
2359
- async getScript(scriptId) {
2360
- return this.request(`/api/cdn/scripts/${scriptId}`);
2361
- }
2362
- async createScript(siteId, data) {
2363
- return this.request(`/api/cdn/sites/${siteId}/scripts`, {
2364
- method: "POST",
2365
- body: JSON.stringify(data)
2366
- });
2367
- }
2368
- async updateScript(scriptId, data) {
2369
- return this.request(`/api/cdn/scripts/${scriptId}`, {
2370
- method: "PUT",
2371
- body: JSON.stringify(data)
2372
- });
2373
- }
2374
- async deleteScript(scriptId) {
2375
- await this.request(`/api/cdn/scripts/${scriptId}`, {
2376
- method: "DELETE"
2377
- });
2378
- }
2379
- // Upload (alternative endpoint that works with API keys)
2380
- async uploadScript(data) {
2381
- return this.request("/api/cdn/upload", {
2382
- method: "POST",
2383
- body: JSON.stringify({
2384
- ...data,
2385
- apiKey: this.apiKey
2386
- })
2387
- });
2388
- }
2389
- // Pages
2390
- async listPages(siteId) {
2391
- return this.request(`/api/cdn/sites/${siteId}/pages`);
2392
- }
2393
- async getPage(pageId) {
2394
- return this.request(`/api/cdn/pages/${pageId}`);
2395
- }
2396
- async createPage(siteId, data) {
2397
- return this.request(`/api/cdn/sites/${siteId}/pages`, {
2398
- method: "POST",
2399
- body: JSON.stringify(data)
2400
- });
2401
- }
2402
- async updatePage(pageId, data) {
2403
- return this.request(`/api/cdn/pages/${pageId}`, {
2404
- method: "PATCH",
2405
- body: JSON.stringify(data)
2406
- });
2407
- }
2408
- async deletePage(pageId) {
2409
- return this.request(`/api/cdn/pages/${pageId}`, {
2410
- method: "DELETE"
2411
- });
2412
- }
2413
- async assignScriptToPage(pageId, scriptId, loadOrderOverride) {
2414
- return this.request(`/api/cdn/pages/${pageId}/scripts`, {
2415
- method: "POST",
2416
- body: JSON.stringify({ scriptId, loadOrderOverride })
2417
- });
2418
- }
2419
- async removeScriptFromPage(pageId, scriptId) {
2420
- return this.request(`/api/cdn/pages/${pageId}/scripts/${scriptId}`, {
2421
- method: "DELETE"
2422
- });
2423
- }
2424
- async getPageScripts(pageId) {
2425
- return this.request(`/api/cdn/pages/${pageId}/scripts`);
2426
- }
2427
- // Deployments
2428
- async deploy(siteId, environment = "staging") {
2429
- return this.request("/api/cdn/deploy", {
2430
- method: "POST",
2431
- body: JSON.stringify({
2432
- siteId,
2433
- environment,
2434
- apiKey: this.apiKey
2435
- })
2436
- });
2437
- }
2438
- async promoteToProduction(siteId, stagingDeploymentId) {
2439
- return this.request("/api/cdn/deploy/promote", {
2440
- method: "POST",
2441
- body: JSON.stringify({
2442
- siteId,
2443
- stagingDeploymentId,
2444
- apiKey: this.apiKey
2445
- })
2446
- });
2447
- }
2448
- async getDeploymentStatus(siteId) {
2449
- return this.request(`/api/cdn/sites/${siteId}/deployments/status`);
2450
- }
2451
- async rollback(siteId, environment = "staging") {
2452
- return this.request("/api/cdn/deploy/rollback", {
2453
- method: "POST",
2454
- body: JSON.stringify({
2455
- siteId,
2456
- environment
2457
- })
2458
- });
2459
- }
2460
- // Production enabled toggle (v2.3)
2461
- async setProductionEnabled(siteId, enabled, productionDomain) {
2462
- return this.request(`/api/cdn/sites/${siteId}/production`, {
2463
- method: "POST",
2464
- body: JSON.stringify({
2465
- enabled,
2466
- productionDomain
2467
- })
2468
- });
2469
- }
2470
- // HTML Fetch
2471
- async fetchHtml(url) {
2472
- return this.request("/api/cdn/fetch-html", {
2473
- method: "POST",
2474
- body: JSON.stringify({ url })
2475
- });
2476
- }
2477
- // Lock management
2478
- async getLockStatus(siteId) {
2479
- return this.request(`/api/cdn/deploy/lock?siteId=${siteId}`);
2480
- }
2481
- async forceReleaseLock(siteId) {
2482
- return this.request("/api/cdn/deploy/lock", {
2483
- method: "DELETE",
2484
- body: JSON.stringify({ siteId })
2485
- });
2486
- }
2487
- // Library (global snippets)
2488
- async listLibrary(search) {
2489
- const params = new URLSearchParams();
2490
- if (search) params.set("search", search);
2491
- const qs = params.toString();
2492
- return this.request(`/api/cdn/library${qs ? `?${qs}` : ""}`);
2493
- }
2494
- async getLibrarySnippet(slugOrId) {
2495
- return this.request(`/api/cdn/library/${encodeURIComponent(slugOrId)}`);
2496
- }
2497
- async createLibrarySnippet(data) {
2498
- return this.request("/api/cdn/library", {
2499
- method: "POST",
2500
- body: JSON.stringify(data)
2501
- });
2502
- }
2503
- async recordLibraryUsage(snippetId) {
2504
- await this.request(`/api/cdn/library/${snippetId}`);
2505
- }
2506
- // Webflow Custom Code injection
2507
- async getWebflowCustomCodeStatus(siteId) {
2508
- return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`);
2509
- }
2510
- async injectWebflowCustomCode(siteId, location = "header") {
2511
- return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`, {
2512
- method: "POST",
2513
- body: JSON.stringify({ location })
2514
- });
2515
- }
2516
- async removeWebflowCustomCode(siteId) {
2517
- return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`, {
2518
- method: "DELETE"
2519
- });
2520
- }
2521
- };
2522
- function createApiClient(config) {
2523
- return new KodeApiClient(config);
2524
- }
2525
-
2526
- // src/commands/pull.ts
2102
+ // src/commands/push.ts
2527
2103
  import chalk2 from "chalk";
2528
2104
  import ora2 from "ora";
2529
- import { writeFileSync as writeFileSync6, readFileSync as readFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
2530
- 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";
2531
2107
  import { createHash } from "crypto";
2532
- function hashContent(content) {
2533
- return createHash("sha256").update(content).digest("hex").substring(0, 16);
2534
- }
2535
- async function pullCommand(options) {
2536
- const projectRoot = findProjectRoot();
2537
- if (!projectRoot) {
2538
- console.log(chalk2.red("Feil: Ikke i et Cure Kode-prosjekt."));
2539
- console.log(chalk2.dim('Kj\xF8r "kode init" f\xF8rst.'));
2540
- return;
2541
- }
2542
- const config = getProjectConfig(projectRoot);
2543
- if (!config) {
2544
- console.log(chalk2.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
2545
- return;
2546
- }
2547
- 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) {
2548
2111
  try {
2549
- const client = createApiClient(config);
2550
- const scripts = await client.listScripts(config.siteId);
2551
- if (scripts.length === 0) {
2552
- spinner.info("Ingen skript funnet p\xE5 server.");
2553
- console.log(chalk2.dim('\nOpprett skript i Cure App eller bruk "kode push" for \xE5 laste opp.'));
2554
- return;
2555
- }
2556
- spinner.succeed(`Fant ${scripts.length} skript`);
2557
- const scriptsDir = getScriptsDir(projectRoot, config);
2558
- if (!existsSync6(scriptsDir)) {
2559
- mkdirSync4(scriptsDir, { recursive: true });
2560
- }
2561
- const metadataPath = join6(projectRoot, ".cure-kode", "scripts.json");
2562
- let existingMetadata = [];
2563
- if (existsSync6(metadataPath)) {
2564
- try {
2565
- existingMetadata = JSON.parse(readFileSync6(metadataPath, "utf-8"));
2566
- } catch {
2567
- }
2568
- }
2569
- const scriptsToPull = options.script ? scripts.filter((s) => s.slug === options.script || s.name === options.script) : scripts;
2570
- if (options.script && scriptsToPull.length === 0) {
2571
- console.log(chalk2.yellow(`
2572
- Fant ikke skript "${options.script}".`));
2573
- console.log(chalk2.dim("Tilgjengelige skript:"));
2574
- scripts.forEach((s) => {
2575
- console.log(chalk2.dim(` - ${s.slug} (${s.name})`));
2576
- });
2577
- return;
2578
- }
2579
- console.log();
2580
- let pulled = 0;
2581
- let skipped = 0;
2582
- let updated = 0;
2583
- for (const script of scriptsToPull) {
2584
- const ext = script.type === "javascript" ? "js" : "css";
2585
- const fileName = `${script.slug}.${ext}`;
2586
- const filePath = join6(scriptsDir, fileName);
2587
- const existingMeta = existingMetadata.find((m) => m.slug === script.slug);
2588
- const lastPulledVersion = existingMeta?.lastPulledVersion || 0;
2589
- if (existsSync6(filePath) && !options.force) {
2590
- const localContent = readFileSync6(filePath, "utf-8");
2591
- const localHash = hashContent(localContent);
2592
- const hasLocalChanges = existingMeta && localHash !== existingMeta.contentHash;
2593
- if (hasLocalChanges) {
2594
- if (script.current_version > lastPulledVersion) {
2595
- console.log(
2596
- chalk2.yellow(` \u26A0 ${fileName}`) + chalk2.dim(` (lokal v${lastPulledVersion} \u2192 server v${script.current_version}, konflikt)`)
2597
- );
2598
- console.log(chalk2.dim(` Bruk --force for \xE5 overskrive lokale endringer`));
2599
- } else {
2600
- console.log(
2601
- chalk2.yellow(` \u26A0 ${fileName}`) + chalk2.dim(" (lokale endringer, bruk --force)")
2602
- );
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;
2603
2123
  }
2604
- skipped++;
2605
- continue;
2606
2124
  }
2607
- if (script.content === localContent) {
2608
- console.log(chalk2.dim(` \u25CB ${fileName} (ingen endringer)`));
2609
- skipped++;
2610
- continue;
2611
- }
2612
- }
2613
- writeFileSync6(filePath, script.content);
2614
- const scopeTag = script.scope === "global" ? chalk2.blue("[G]") : chalk2.magenta("[P]");
2615
- const loadTag = script.auto_load ? chalk2.green("\u26A1") : chalk2.dim("\u25CB");
2616
- if (lastPulledVersion > 0 && script.current_version > lastPulledVersion) {
2617
- console.log(
2618
- chalk2.green(` \u2713 ${fileName}`) + chalk2.dim(` v${lastPulledVersion} \u2192 v${script.current_version}`) + ` ${scopeTag} ${loadTag}`
2619
- );
2620
- updated++;
2621
- } else {
2622
- console.log(
2623
- chalk2.green(` \u2713 ${fileName}`) + chalk2.dim(` v${script.current_version}`) + ` ${scopeTag} ${loadTag}`
2624
- );
2625
- pulled++;
2626
2125
  }
2627
2126
  }
2628
- console.log();
2629
- if (pulled > 0) {
2630
- console.log(chalk2.green(`Hentet ${pulled} skript til ${config.scriptsDir}/`));
2631
- }
2632
- if (updated > 0) {
2633
- console.log(chalk2.cyan(`Oppdatert ${updated} skript med nye versjoner`));
2634
- }
2635
- if (skipped > 0) {
2636
- console.log(chalk2.dim(`Hoppet over ${skipped} skript`));
2637
- }
2638
- let pages = [];
2639
- try {
2640
- pages = await client.listPages(config.siteId);
2641
- } catch {
2642
- }
2643
- const now = (/* @__PURE__ */ new Date()).toISOString();
2644
- const metadata = scripts.map((s) => {
2645
- const filePath = join6(scriptsDir, `${s.slug}.${s.type === "javascript" ? "js" : "css"}`);
2646
- const localContent = existsSync6(filePath) ? readFileSync6(filePath, "utf-8") : s.content;
2647
- const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
2648
- const page = pages.find((pg) => pg.id === p.page_id);
2649
- return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
2650
- }).filter((p) => p !== null);
2651
- return {
2652
- id: s.id,
2653
- slug: s.slug,
2654
- name: s.name,
2655
- type: s.type,
2656
- scope: s.scope,
2657
- autoLoad: s.auto_load,
2658
- version: s.current_version,
2659
- loadOrder: s.load_order,
2660
- pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
2661
- lastPulledVersion: s.current_version,
2662
- lastPulledAt: now,
2663
- contentHash: hashContent(localContent)
2664
- };
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"
2665
2146
  });
2666
- writeFileSync6(metadataPath, JSON.stringify(metadata, null, 2));
2667
- try {
2668
- const result = updateClaudeMd(
2669
- projectRoot,
2670
- config.siteName,
2671
- config.siteSlug,
2672
- scriptsToDocsFormat(scripts, pages),
2673
- pagesToInfoFormat(pages)
2674
- );
2675
- if (result.kodeMd.created) {
2676
- console.log(chalk2.green("Opprettet .cure-kode/KODE.md"));
2677
- } else if (result.kodeMd.updated) {
2678
- console.log(chalk2.dim("Oppdatert .cure-kode/KODE.md"));
2679
- }
2680
- if (result.claudeMd.created) {
2681
- console.log(chalk2.green("Opprettet CLAUDE.md med referanse"));
2682
- } else if (result.claudeMd.updated) {
2683
- console.log(chalk2.dim("La til Kode-referanse i CLAUDE.md"));
2684
- }
2685
- } catch {
2686
- }
2687
- console.log(chalk2.dim("\n[G]=Global [P]=Sidespesifikk \u26A1=Auto-last \u25CB=Manuell"));
2688
- } catch (error) {
2689
- spinner.fail("Kunne ikke hente skript");
2690
- 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) };
2691
2162
  }
2692
2163
  }
2693
-
2694
- // src/commands/push.ts
2695
- import chalk3 from "chalk";
2696
- import ora3 from "ora";
2697
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, existsSync as existsSync7, readdirSync } from "fs";
2698
- import { join as join7, basename, extname } from "path";
2699
- import { createHash as createHash2 } from "crypto";
2700
- function hashContent2(content) {
2701
- 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);
2702
2166
  }
2703
2167
  function formatTimeDiff(date) {
2704
2168
  const diff = Date.now() - new Date(date).getTime();
@@ -2713,50 +2177,67 @@ function formatTimeDiff(date) {
2713
2177
  async function pushCommand(options) {
2714
2178
  const projectRoot = findProjectRoot();
2715
2179
  if (!projectRoot) {
2716
- console.log(chalk3.red("Feil: Ikke i et Cure Kode-prosjekt."));
2717
- 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.'));
2718
2182
  return;
2719
2183
  }
2720
2184
  const config = getProjectConfig(projectRoot);
2721
2185
  if (!config) {
2722
- console.log(chalk3.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
2186
+ console.log(chalk2.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
2723
2187
  return;
2724
2188
  }
2725
2189
  const scriptsDir = getScriptsDir(projectRoot, config);
2726
- if (!existsSync7(scriptsDir)) {
2727
- console.log(chalk3.yellow("Skriptmappen finnes ikke."));
2728
- console.log(chalk3.dim(`Forventet: ${scriptsDir}`));
2729
- 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.'));
2730
2194
  return;
2731
2195
  }
2732
- const metadataPath = join7(projectRoot, ".cure-kode", "scripts.json");
2196
+ const metadataPath = join4(projectRoot, ".cure-kode", "scripts.json");
2733
2197
  let metadata = [];
2734
- if (existsSync7(metadataPath)) {
2198
+ if (existsSync4(metadataPath)) {
2735
2199
  try {
2736
- metadata = JSON.parse(readFileSync7(metadataPath, "utf-8"));
2200
+ metadata = JSON.parse(readFileSync4(metadataPath, "utf-8"));
2737
2201
  } catch {
2738
2202
  }
2739
2203
  }
2204
+ const SUPPORTED_EXTENSIONS = [".js", ".css", ".ts", ".tsx", ".jsx"];
2740
2205
  const files = readdirSync(scriptsDir).filter(
2741
- (f) => (f.endsWith(".js") || f.endsWith(".css")) && f !== "library"
2206
+ (f) => SUPPORTED_EXTENSIONS.some((ext) => f.endsWith(ext))
2742
2207
  );
2743
2208
  if (files.length === 0) {
2744
- console.log(chalk3.yellow("Ingen skriptfiler funnet."));
2745
- 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}/`));
2746
2211
  return;
2747
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
+ }
2748
2229
  const filesToPush = options.script ? files.filter(
2749
- (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
2750
2231
  ) : files;
2751
2232
  if (options.script && filesToPush.length === 0) {
2752
- console.log(chalk3.yellow(`Fant ikke skript "${options.script}" lokalt.`));
2753
- 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:"));
2754
2235
  files.forEach((f) => {
2755
- console.log(chalk3.dim(` - ${f}`));
2236
+ console.log(chalk2.dim(` - ${f}`));
2756
2237
  });
2757
2238
  return;
2758
2239
  }
2759
- const spinner = ora3("Laster opp skript...").start();
2240
+ const spinner = ora2("Laster opp skript...").start();
2760
2241
  try {
2761
2242
  const client = createApiClient(config);
2762
2243
  const remoteScripts = await client.listScripts(config.siteId);
@@ -2768,46 +2249,74 @@ async function pushCommand(options) {
2768
2249
  console.log();
2769
2250
  let emptyScriptCount = 0;
2770
2251
  for (const file of filesToPush) {
2771
- const filePath = join7(scriptsDir, file);
2772
- const content = readFileSync7(filePath, "utf-8");
2252
+ const filePath = join4(scriptsDir, file);
2253
+ const sourceContent = readFileSync4(filePath, "utf-8");
2254
+ let content = sourceContent;
2773
2255
  const slug = basename(file, extname(file));
2774
- const type = extname(file) === ".js" ? "javascript" : "css";
2775
- if (content.trim().length === 0) {
2776
- console.log(chalk3.yellow(` \u26A0 ${file}`) + chalk3.dim(" (tom fil)"));
2777
- emptyScriptCount++;
2778
- }
2256
+ const type = extname(file) === ".css" ? "css" : "javascript";
2257
+ const needsBundle = BUNDLEABLE_EXTENSIONS.includes(extname(file));
2779
2258
  const remoteScript = remoteScripts.find((s) => s.slug === slug);
2780
- const localMeta = metadata.find((m) => m.slug === slug);
2781
- 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) {
2782
2268
  const lastPulledVersion = localMeta?.lastPulledVersion || 0;
2783
- if (remoteScript.current_version > lastPulledVersion && !options.force) {
2269
+ if (remoteScript.current_version > lastPulledVersion) {
2784
2270
  console.log();
2785
- console.log(chalk3.yellow(` \u26A0\uFE0F Advarsel: Server har nyere versjon!`));
2786
- console.log(chalk3.dim(` ${file}:`));
2787
- console.log(chalk3.dim(` Lokal: v${lastPulledVersion} (fra ${localMeta?.lastPulledAt ? formatTimeDiff(localMeta.lastPulledAt) : "ukjent"})`));
2788
- console.log(chalk3.dim(` Server: v${remoteScript.current_version}`));
2789
- console.log();
2790
- 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.`));
2791
2275
  console.log();
2792
2276
  conflicts++;
2793
2277
  continue;
2794
2278
  }
2795
- if (remoteScript.content === content && !options.all) {
2796
- console.log(chalk3.dim(` \u25CB ${file} (ingen endringer)`));
2797
- 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}`));
2798
2287
  continue;
2799
2288
  }
2800
- 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();
2801
2304
  await client.updateScript(remoteScript.id, {
2802
2305
  content,
2803
- 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
+ } : {}
2804
2312
  });
2805
2313
  updateSpinner.succeed(
2806
- 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
2807
2315
  );
2808
2316
  pushed++;
2809
2317
  } else {
2810
- const createSpinner = ora3(`Oppretter ${file}...`).start();
2318
+ const sourceExt = needsBundle ? extname(file).slice(1) : void 0;
2319
+ const createSpinner = ora2(chalk2.dim(` + ${file}`)).start();
2811
2320
  const scriptScope = localMeta?.scope || "global";
2812
2321
  const newScript = await client.createScript(config.siteId, {
2813
2322
  name: slug.charAt(0).toUpperCase() + slug.slice(1).replace(/-/g, " "),
@@ -2815,33 +2324,37 @@ async function pushCommand(options) {
2815
2324
  type,
2816
2325
  scope: scriptScope,
2817
2326
  autoLoad: options.autoLoad,
2818
- content
2327
+ content,
2328
+ ...needsBundle ? {
2329
+ sourceContent,
2330
+ sourceType: sourceExt
2331
+ } : {}
2819
2332
  });
2820
- const autoLoadInfo = newScript.auto_load ? chalk3.green("auto-last") : chalk3.dim("manuell");
2333
+ const autoLoadInfo = newScript.auto_load ? chalk2.dim("auto") : chalk2.dim("manuell");
2821
2334
  createSpinner.succeed(
2822
- chalk3.green(` \u2713 ${file}`) + chalk3.cyan(" (ny)") + ` [${autoLoadInfo}]`
2335
+ chalk2.green(` \u2713 ${file}`) + chalk2.cyan(" ny") + chalk2.dim(` [${autoLoadInfo}]`) + suffix
2823
2336
  );
2824
2337
  created++;
2825
2338
  }
2826
2339
  }
2827
2340
  console.log();
2828
2341
  if (pushed > 0) {
2829
- console.log(chalk3.green(`Oppdatert ${pushed} skript`));
2342
+ console.log(chalk2.green(`Oppdatert ${pushed} skript`));
2830
2343
  }
2831
2344
  if (created > 0) {
2832
- console.log(chalk3.cyan(`Opprettet ${created} nye skript`));
2345
+ console.log(chalk2.cyan(`Opprettet ${created} nye skript`));
2833
2346
  }
2834
2347
  if (skipped > 0) {
2835
- console.log(chalk3.dim(`Hoppet over ${skipped} uendrede skript`));
2348
+ console.log(chalk2.dim(`Hoppet over ${skipped} uendrede skript`));
2836
2349
  }
2837
2350
  if (conflicts > 0) {
2838
- console.log(chalk3.yellow(`
2351
+ console.log(chalk2.yellow(`
2839
2352
  ${conflicts} skript med konflikter (bruk --force for \xE5 overskrive)`));
2840
2353
  }
2841
2354
  if (emptyScriptCount > 0) {
2842
- console.log(chalk3.yellow(`
2355
+ console.log(chalk2.yellow(`
2843
2356
  ${emptyScriptCount} tomme skript lastet opp`));
2844
- console.log(chalk3.dim("Tomme skript har ingen effekt ved deploy."));
2357
+ console.log(chalk2.dim("Tomme skript har ingen effekt ved deploy."));
2845
2358
  }
2846
2359
  let pages = [];
2847
2360
  try {
@@ -2851,9 +2364,17 @@ ${emptyScriptCount} tomme skript lastet opp`));
2851
2364
  const updatedScripts = await client.listScripts(config.siteId);
2852
2365
  const now = (/* @__PURE__ */ new Date()).toISOString();
2853
2366
  const updatedMetadata = updatedScripts.map((s) => {
2854
- const ext = s.type === "javascript" ? "js" : "css";
2855
- const filePath = join7(scriptsDir, `${s.slug}.${ext}`);
2856
- 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
+ }
2857
2378
  const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
2858
2379
  const page = pages.find((pg) => pg.id === p.page_id);
2859
2380
  return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
@@ -2870,10 +2391,11 @@ ${emptyScriptCount} tomme skript lastet opp`));
2870
2391
  pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
2871
2392
  lastPulledVersion: s.current_version,
2872
2393
  lastPulledAt: now,
2873
- contentHash: hashContent2(localContent)
2394
+ contentHash: hashContent(localContent),
2395
+ localFileName: localFilePath ? basename(localFilePath) : void 0
2874
2396
  };
2875
2397
  });
2876
- writeFileSync7(metadataPath, JSON.stringify(updatedMetadata, null, 2));
2398
+ writeFileSync4(metadataPath, JSON.stringify(updatedMetadata, null, 2));
2877
2399
  try {
2878
2400
  const result = updateClaudeMd(
2879
2401
  projectRoot,
@@ -2883,69 +2405,117 @@ ${emptyScriptCount} tomme skript lastet opp`));
2883
2405
  pagesToInfoFormat(pages)
2884
2406
  );
2885
2407
  if (result.kodeMd.created) {
2886
- console.log(chalk3.green("Opprettet .cure-kode/KODE.md"));
2408
+ console.log(chalk2.green("Opprettet .cure-kode/KODE.md"));
2887
2409
  } else if (result.kodeMd.updated) {
2888
- console.log(chalk3.dim("Oppdatert .cure-kode/KODE.md"));
2410
+ console.log(chalk2.dim("Oppdatert .cure-kode/KODE.md"));
2889
2411
  }
2890
2412
  if (result.claudeMd.created) {
2891
- console.log(chalk3.green("Opprettet CLAUDE.md med referanse"));
2413
+ console.log(chalk2.green("Opprettet CLAUDE.md med referanse"));
2892
2414
  } else if (result.claudeMd.updated) {
2893
- 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
+ }
2894
2464
  }
2895
2465
  } catch {
2896
2466
  }
2897
2467
  } catch (error) {
2898
2468
  spinner.fail("Kunne ikke laste opp skript");
2899
- console.error(chalk3.red("\nFeil:"), error);
2469
+ console.error(chalk2.red("\nFeil:"), error);
2900
2470
  }
2901
2471
  }
2902
2472
 
2903
2473
  // src/commands/watch.ts
2904
- import chalk4 from "chalk";
2474
+ import chalk3 from "chalk";
2905
2475
  import chokidar from "chokidar";
2906
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
2907
- 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";
2908
2478
  async function watchCommand(options) {
2909
2479
  const projectRoot = findProjectRoot();
2910
2480
  if (!projectRoot) {
2911
- console.log(chalk4.red("\u274C Not in a Cure Kode project."));
2912
- 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.'));
2913
2483
  return;
2914
2484
  }
2915
2485
  const config = getProjectConfig(projectRoot);
2916
2486
  if (!config) {
2917
- console.log(chalk4.red("\u274C Could not read project configuration."));
2487
+ console.log(chalk3.red("\u274C Could not read project configuration."));
2918
2488
  return;
2919
2489
  }
2920
2490
  const scriptsDir = getScriptsDir(projectRoot, config);
2921
- if (!existsSync8(scriptsDir)) {
2922
- console.log(chalk4.yellow("\u26A0\uFE0F Scripts directory not found."));
2923
- console.log(chalk4.dim(` Expected: ${scriptsDir}`));
2924
- 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.'));
2925
2495
  return;
2926
2496
  }
2927
- console.log(chalk4.bold("\n\u{1F440} Watching for changes...\n"));
2928
- console.log(chalk4.dim(` Directory: ${scriptsDir}`));
2929
- console.log(chalk4.dim(` Site: ${config.siteName} (${config.siteSlug})`));
2930
- 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"}`));
2931
2501
  if (options.deploy) {
2932
- console.log(chalk4.cyan(` Auto-deploy: enabled`));
2502
+ console.log(chalk3.cyan(` Auto-deploy: enabled`));
2933
2503
  }
2934
2504
  console.log();
2935
- console.log(chalk4.dim("Press Ctrl+C to stop.\n"));
2505
+ console.log(chalk3.dim("Press Ctrl+C to stop.\n"));
2936
2506
  const client = createApiClient(config);
2937
- const metadataPath = join8(projectRoot, ".cure-kode", "scripts.json");
2507
+ const metadataPath = join5(projectRoot, ".cure-kode", "scripts.json");
2938
2508
  let metadata = [];
2939
- if (existsSync8(metadataPath)) {
2940
- metadata = JSON.parse(readFileSync8(metadataPath, "utf-8"));
2509
+ if (existsSync5(metadataPath)) {
2510
+ metadata = JSON.parse(readFileSync5(metadataPath, "utf-8"));
2941
2511
  }
2942
2512
  let remoteScripts = [];
2943
2513
  try {
2944
2514
  remoteScripts = await client.listScripts(config.siteId);
2945
- console.log(chalk4.dim(`Loaded ${remoteScripts.length} remote script(s)
2515
+ console.log(chalk3.dim(`Loaded ${remoteScripts.length} remote script(s)
2946
2516
  `));
2947
2517
  } catch (error) {
2948
- 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."));
2949
2519
  }
2950
2520
  const pendingChanges = /* @__PURE__ */ new Map();
2951
2521
  const DEBOUNCE_MS = 500;
@@ -2958,18 +2528,18 @@ async function watchCommand(options) {
2958
2528
  if (failedSyncs.size === 0 && successCount === 0) return;
2959
2529
  const statusParts = [];
2960
2530
  if (successCount > 0) {
2961
- statusParts.push(chalk4.green(`${successCount} synced`));
2531
+ statusParts.push(chalk3.green(`${successCount} synced`));
2962
2532
  }
2963
2533
  if (failedSyncs.size > 0) {
2964
- statusParts.push(chalk4.red(`${failedSyncs.size} pending errors`));
2534
+ statusParts.push(chalk3.red(`${failedSyncs.size} pending errors`));
2965
2535
  }
2966
- console.log(chalk4.dim(`
2536
+ console.log(chalk3.dim(`
2967
2537
  \u2500\u2500\u2500 Status: ${statusParts.join(", ")} \u2500\u2500\u2500
2968
2538
  `));
2969
2539
  };
2970
2540
  const retryFailedSyncs = async () => {
2971
2541
  for (const [filePath, failed] of failedSyncs.entries()) {
2972
- if (!existsSync8(filePath)) {
2542
+ if (!existsSync5(filePath)) {
2973
2543
  failedSyncs.delete(filePath);
2974
2544
  continue;
2975
2545
  }
@@ -2982,7 +2552,7 @@ async function watchCommand(options) {
2982
2552
  }
2983
2553
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("nb-NO");
2984
2554
  console.log(
2985
- 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})`)
2986
2556
  );
2987
2557
  await handleChange(
2988
2558
  filePath,
@@ -3003,7 +2573,7 @@ async function watchCommand(options) {
3003
2573
  }
3004
2574
  const syncFile = async () => {
3005
2575
  try {
3006
- const content = readFileSync8(filePath, "utf-8");
2576
+ const content = readFileSync5(filePath, "utf-8");
3007
2577
  const remoteScript = remoteScripts.find((s) => s.slug === slug);
3008
2578
  const localMeta = metadata.find((m) => m.slug === slug);
3009
2579
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("nb-NO");
@@ -3025,16 +2595,16 @@ async function watchCommand(options) {
3025
2595
  failedSyncs.delete(filePath);
3026
2596
  if (wasRetry) {
3027
2597
  console.log(
3028
- 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)")
3029
2599
  );
3030
2600
  } else {
3031
2601
  console.log(
3032
- 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}`)
3033
2603
  );
3034
2604
  }
3035
2605
  } else {
3036
2606
  console.log(
3037
- 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}`)
3038
2608
  );
3039
2609
  }
3040
2610
  successCount++;
@@ -3042,11 +2612,11 @@ async function watchCommand(options) {
3042
2612
  try {
3043
2613
  await client.deploy(config.siteId, config.environment || "staging");
3044
2614
  console.log(
3045
- chalk4.dim(`[${timestamp}] `) + chalk4.cyan(` \u21B3 Deployed to ${config.environment || "staging"}`)
2615
+ chalk3.dim(`[${timestamp}] `) + chalk3.cyan(` \u21B3 Deployed to ${config.environment || "staging"}`)
3046
2616
  );
3047
2617
  } catch (deployError) {
3048
2618
  console.log(
3049
- 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"}`)
3050
2620
  );
3051
2621
  }
3052
2622
  }
@@ -3062,11 +2632,11 @@ async function watchCommand(options) {
3062
2632
  if (failedSyncs.has(filePath)) {
3063
2633
  failedSyncs.delete(filePath);
3064
2634
  console.log(
3065
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.cyan(" (created, recovered)")
2635
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.cyan(" (created, recovered)")
3066
2636
  );
3067
2637
  } else {
3068
2638
  console.log(
3069
- chalk4.dim(`[${timestamp}] `) + chalk4.green(`\u2713 ${fileName}`) + chalk4.cyan(" (created)")
2639
+ chalk3.dim(`[${timestamp}] `) + chalk3.green(`\u2713 ${fileName}`) + chalk3.cyan(" (created)")
3070
2640
  );
3071
2641
  }
3072
2642
  successCount++;
@@ -3097,11 +2667,11 @@ async function watchCommand(options) {
3097
2667
  errorCount++;
3098
2668
  if (attempts >= MAX_RETRY_ATTEMPTS) {
3099
2669
  console.log(
3100
- 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)`)
3101
2671
  );
3102
2672
  } else {
3103
2673
  console.log(
3104
- 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)`)
3105
2675
  );
3106
2676
  }
3107
2677
  printStatus();
@@ -3117,7 +2687,7 @@ async function watchCommand(options) {
3117
2687
  }, DEBOUNCE_MS);
3118
2688
  pendingChanges.set(filePath, timeout);
3119
2689
  };
3120
- const watcher = chokidar.watch(join8(scriptsDir, "**/*.{js,css}"), {
2690
+ const watcher = chokidar.watch(join5(scriptsDir, "**/*.{js,css}"), {
3121
2691
  persistent: true,
3122
2692
  ignoreInitial: true,
3123
2693
  awaitWriteFinish: {
@@ -3131,21 +2701,21 @@ async function watchCommand(options) {
3131
2701
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("nb-NO");
3132
2702
  const fileName = basename2(filePath);
3133
2703
  console.log(
3134
- 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)")
3135
2705
  );
3136
2706
  });
3137
2707
  process.on("SIGINT", () => {
3138
2708
  clearInterval(retryInterval);
3139
- console.log(chalk4.dim("\n\nStopping watch...\n"));
2709
+ console.log(chalk3.dim("\n\nStopping watch...\n"));
3140
2710
  if (successCount > 0 || failedSyncs.size > 0) {
3141
- console.log(chalk4.bold("Session summary:"));
2711
+ console.log(chalk3.bold("Session summary:"));
3142
2712
  if (successCount > 0) {
3143
- console.log(chalk4.green(` \u2713 ${successCount} file(s) synced`));
2713
+ console.log(chalk3.green(` \u2713 ${successCount} file(s) synced`));
3144
2714
  }
3145
2715
  if (failedSyncs.size > 0) {
3146
- console.log(chalk4.red(` \u2717 ${failedSyncs.size} file(s) failed:`));
2716
+ console.log(chalk3.red(` \u2717 ${failedSyncs.size} file(s) failed:`));
3147
2717
  for (const failed of failedSyncs.values()) {
3148
- console.log(chalk4.dim(` - ${failed.fileName}: ${failed.error}`));
2718
+ console.log(chalk3.dim(` - ${failed.fileName}: ${failed.error}`));
3149
2719
  }
3150
2720
  }
3151
2721
  console.log();
@@ -3156,10 +2726,10 @@ async function watchCommand(options) {
3156
2726
  }
3157
2727
 
3158
2728
  // src/commands/deploy.ts
3159
- import chalk5 from "chalk";
3160
- import ora4 from "ora";
3161
- import { readFileSync as readFileSync9, existsSync as existsSync9, readdirSync as readdirSync2 } from "fs";
3162
- 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";
3163
2733
  function formatBytes(bytes) {
3164
2734
  if (bytes < 1024) return `${bytes} B`;
3165
2735
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -3168,7 +2738,7 @@ function formatBytes(bytes) {
3168
2738
  async function showDeploymentPreview(config, projectRoot) {
3169
2739
  if (!config) return;
3170
2740
  const client = createApiClient(config);
3171
- const spinner = ora4("Analyserer deployment...").start();
2741
+ const spinner = ora3("Analyserer deployment...").start();
3172
2742
  try {
3173
2743
  const [remoteScripts, deployStatus] = await Promise.all([
3174
2744
  client.listScripts(config.siteId),
@@ -3176,39 +2746,39 @@ async function showDeploymentPreview(config, projectRoot) {
3176
2746
  ]);
3177
2747
  spinner.stop();
3178
2748
  console.log();
3179
- console.log(chalk5.bold("\u{1F50D} Deployment Preview (t\xF8rrkj\xF8ring)"));
3180
- 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`));
3181
2751
  console.log();
3182
2752
  const stagingVersion = deployStatus.staging.lastSuccessful?.version || null;
3183
2753
  const productionVersion = deployStatus.production.lastSuccessful?.version || null;
3184
- console.log(chalk5.bold("N\xE5v\xE6rende status"));
2754
+ console.log(chalk4.bold("N\xE5v\xE6rende status"));
3185
2755
  if (stagingVersion) {
3186
- console.log(chalk5.dim(` Staging: v${stagingVersion}`));
2756
+ console.log(chalk4.dim(` Staging: v${stagingVersion}`));
3187
2757
  } else {
3188
- console.log(chalk5.dim(` Staging: ingen deployments`));
2758
+ console.log(chalk4.dim(` Staging: ingen deployments`));
3189
2759
  }
3190
2760
  if (deployStatus.productionEnabled) {
3191
2761
  if (productionVersion) {
3192
- console.log(chalk5.dim(` Production: v${productionVersion}`));
2762
+ console.log(chalk4.dim(` Production: v${productionVersion}`));
3193
2763
  } else {
3194
- console.log(chalk5.dim(` Production: aktivert, ingen deployments`));
2764
+ console.log(chalk4.dim(` Production: aktivert, ingen deployments`));
3195
2765
  }
3196
2766
  }
3197
2767
  console.log();
3198
2768
  const scriptsDir = getScriptsDir(projectRoot, config);
3199
- const localFiles = existsSync9(scriptsDir) ? readdirSync2(scriptsDir).filter((f) => f.endsWith(".js") || f.endsWith(".css")) : [];
3200
- 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");
3201
2771
  let metadata = [];
3202
- if (existsSync9(metadataPath)) {
2772
+ if (existsSync6(metadataPath)) {
3203
2773
  try {
3204
- metadata = JSON.parse(readFileSync9(metadataPath, "utf-8"));
2774
+ metadata = JSON.parse(readFileSync6(metadataPath, "utf-8"));
3205
2775
  } catch {
3206
2776
  }
3207
2777
  }
3208
2778
  const localBySlug = /* @__PURE__ */ new Map();
3209
2779
  for (const file of localFiles) {
3210
2780
  const slug = basename3(file, extname3(file));
3211
- const content = readFileSync9(join9(scriptsDir, file), "utf-8");
2781
+ const content = readFileSync6(join6(scriptsDir, file), "utf-8");
3212
2782
  localBySlug.set(slug, { content, size: Buffer.byteLength(content, "utf-8") });
3213
2783
  }
3214
2784
  const remoteBySlug = /* @__PURE__ */ new Map();
@@ -3265,63 +2835,63 @@ async function showDeploymentPreview(config, projectRoot) {
3265
2835
  }
3266
2836
  }
3267
2837
  if (changes.length > 0) {
3268
- console.log(chalk5.bold("Endringer"));
2838
+ console.log(chalk4.bold("Endringer"));
3269
2839
  console.log();
3270
2840
  console.log(
3271
- 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))
3272
2842
  );
3273
- console.log(chalk5.dim(" " + "\u2500".repeat(56)));
2843
+ console.log(chalk4.dim(" " + "\u2500".repeat(56)));
3274
2844
  for (const change of changes) {
3275
2845
  const beforeStr = change.beforeVersion ? `v${change.beforeVersion}` : "-";
3276
2846
  const afterStr = `v${change.afterVersion}`;
3277
2847
  let diffStr;
3278
2848
  if (change.isNew) {
3279
- diffStr = chalk5.cyan(`+${change.linesDiff.added} linjer`);
2849
+ diffStr = chalk4.cyan(`+${change.linesDiff.added} linjer`);
3280
2850
  } else {
3281
2851
  const parts = [];
3282
- if (change.linesDiff.added > 0) parts.push(chalk5.green(`+${change.linesDiff.added}`));
3283
- 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}`));
3284
2854
  diffStr = parts.join(" ") + " linjer";
3285
2855
  }
3286
- const nameColor = change.isNew ? chalk5.cyan : chalk5.white;
2856
+ const nameColor = change.isNew ? chalk4.cyan : chalk4.white;
3287
2857
  console.log(
3288
- ` ${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)}`
3289
2859
  );
3290
2860
  }
3291
2861
  console.log();
3292
2862
  const sizeDiff = totalAfterSize - totalBeforeSize;
3293
- 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");
3294
2864
  console.log(
3295
- chalk5.dim(` Total: ${formatBytes(totalBeforeSize)} \u2192 ${formatBytes(totalAfterSize)} (${sizeDiffStr})`)
2865
+ chalk4.dim(` Total: ${formatBytes(totalBeforeSize)} \u2192 ${formatBytes(totalAfterSize)} (${sizeDiffStr})`)
3296
2866
  );
3297
2867
  } else {
3298
- console.log(chalk5.dim(" Ingen endringer \xE5 deploye"));
2868
+ console.log(chalk4.dim(" Ingen endringer \xE5 deploye"));
3299
2869
  }
3300
2870
  if (warnings.length > 0) {
3301
2871
  console.log();
3302
- console.log(chalk5.bold("Advarsler"));
2872
+ console.log(chalk4.bold("Advarsler"));
3303
2873
  for (const warning of warnings) {
3304
- console.log(chalk5.yellow(` \u26A0 ${warning}`));
2874
+ console.log(chalk4.yellow(` \u26A0 ${warning}`));
3305
2875
  }
3306
2876
  }
3307
2877
  console.log();
3308
- 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.'));
3309
2879
  console.log();
3310
2880
  } catch (error) {
3311
2881
  spinner.fail("Kunne ikke analysere deployment");
3312
- console.error(chalk5.red("\nFeil:"), error.message || error);
2882
+ console.error(chalk4.red("\nFeil:"), error.message || error);
3313
2883
  }
3314
2884
  }
3315
2885
  async function deployCommand(environment, options) {
3316
2886
  const projectRoot = findProjectRoot();
3317
2887
  if (!projectRoot) {
3318
- console.log(chalk5.red("\u274C Not in a Cure Kode project."));
3319
- 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.'));
3320
2890
  return;
3321
2891
  }
3322
2892
  const config = getProjectConfig(projectRoot);
3323
2893
  if (!config) {
3324
- console.log(chalk5.red("\u274C Could not read project configuration."));
2894
+ console.log(chalk4.red("\u274C Could not read project configuration."));
3325
2895
  return;
3326
2896
  }
3327
2897
  if (options?.dryRun) {
@@ -3331,15 +2901,15 @@ async function deployCommand(environment, options) {
3331
2901
  const shouldPromote = options?.promote || environment === "production";
3332
2902
  if (shouldPromote) {
3333
2903
  const client2 = createApiClient(config);
3334
- const spinner2 = ora4("Sjekker produksjonsstatus...").start();
2904
+ const spinner2 = ora3("Sjekker produksjonsstatus...").start();
3335
2905
  try {
3336
2906
  const status = await client2.getDeploymentStatus(config.siteId);
3337
2907
  if (!status.productionEnabled) {
3338
2908
  spinner2.fail("Produksjon er ikke aktivert");
3339
2909
  console.log();
3340
- console.log(chalk5.yellow("\u26A0\uFE0F Produksjon er deaktivert for dette prosjektet."));
3341
- console.log(chalk5.dim(" Aktiver produksjon f\xF8rst:"));
3342
- 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>]"));
3343
2913
  console.log();
3344
2914
  return;
3345
2915
  }
@@ -3347,23 +2917,23 @@ async function deployCommand(environment, options) {
3347
2917
  const deployment = await client2.promoteToProduction(config.siteId);
3348
2918
  spinner2.succeed("Promoted to production");
3349
2919
  console.log();
3350
- console.log(chalk5.dim("Deployment details:"));
3351
- console.log(chalk5.dim(` Version: ${deployment.version}`));
3352
- 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}`));
3353
2923
  console.log();
3354
- console.log(chalk5.bold("CDN URL:"));
3355
- 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`));
3356
2926
  console.log();
3357
- 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!"));
3358
2928
  } catch (error) {
3359
2929
  spinner2.fail("Promotion failed");
3360
- console.error(chalk5.red("\nError:"), error.message || error);
2930
+ console.error(chalk4.red("\nError:"), error.message || error);
3361
2931
  }
3362
2932
  return;
3363
2933
  }
3364
2934
  const client = createApiClient(config);
3365
2935
  if (options?.force) {
3366
- const forceSpinner = ora4("Sjekker l\xE5s...").start();
2936
+ const forceSpinner = ora3("Sjekker l\xE5s...").start();
3367
2937
  try {
3368
2938
  const lockStatus = await client.getLockStatus(config.siteId);
3369
2939
  if (lockStatus.isLocked) {
@@ -3371,18 +2941,18 @@ async function deployCommand(environment, options) {
3371
2941
  forceSpinner.text = "Frigj\xF8r gammel l\xE5s...";
3372
2942
  } else {
3373
2943
  forceSpinner.warn("Aktiv l\xE5s funnet");
3374
- console.log(chalk5.yellow("\n\u26A0\uFE0F Deployment er l\xE5st av en annen prosess."));
3375
- console.log(chalk5.dim(` L\xE5st siden: ${lockStatus.acquiredAt ? new Date(lockStatus.acquiredAt).toLocaleString("nb-NO") : "ukjent"}`));
3376
- 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}`));
3377
2947
  console.log();
3378
- console.log(chalk5.yellow(" Hvis du er sikker p\xE5 at l\xE5sen er foreldet, kj\xF8r med --force igjen."));
3379
- 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."));
3380
2950
  return;
3381
2951
  }
3382
2952
  const result = await client.forceReleaseLock(config.siteId);
3383
2953
  if (result.wasLocked) {
3384
2954
  forceSpinner.succeed("L\xE5s frigjort");
3385
- 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"}`));
3386
2956
  console.log();
3387
2957
  } else {
3388
2958
  forceSpinner.info("Ingen l\xE5s \xE5 frigj\xF8re");
@@ -3392,11 +2962,11 @@ async function deployCommand(environment, options) {
3392
2962
  }
3393
2963
  } catch (error) {
3394
2964
  forceSpinner.fail("Kunne ikke sjekke/frigj\xF8re l\xE5s");
3395
- console.error(chalk5.red("\nError:"), error.message || error);
2965
+ console.error(chalk4.red("\nError:"), error.message || error);
3396
2966
  return;
3397
2967
  }
3398
2968
  }
3399
- const preCheckSpinner = ora4("Sjekker scripts...").start();
2969
+ const preCheckSpinner = ora3("Sjekker scripts...").start();
3400
2970
  try {
3401
2971
  const scripts = await client.listScripts(config.siteId);
3402
2972
  const emptyScripts = scripts.filter(
@@ -3404,45 +2974,45 @@ async function deployCommand(environment, options) {
3404
2974
  );
3405
2975
  if (emptyScripts.length > 0) {
3406
2976
  preCheckSpinner.warn(`${emptyScripts.length} tomme script(s) funnet`);
3407
- 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:"));
3408
2978
  emptyScripts.forEach((s) => {
3409
- console.log(chalk5.dim(` - ${s.slug}.${s.type === "javascript" ? "js" : "css"}`));
2979
+ console.log(chalk4.dim(` - ${s.slug}.${s.type === "javascript" ? "js" : "css"}`));
3410
2980
  });
3411
- 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"));
3412
2982
  } else {
3413
2983
  preCheckSpinner.succeed(`${scripts.filter((s) => s.is_active).length} script(s) klare`);
3414
2984
  }
3415
2985
  } catch {
3416
2986
  preCheckSpinner.info("Kunne ikke sjekke scripts");
3417
2987
  }
3418
- const spinner = ora4("Deploying to staging...").start();
2988
+ const spinner = ora3("Deploying to staging...").start();
3419
2989
  try {
3420
2990
  const deployment = await client.deploy(config.siteId, "staging");
3421
2991
  spinner.succeed("Deployed to staging");
3422
2992
  console.log();
3423
- console.log(chalk5.dim("Deployment details:"));
3424
- console.log(chalk5.dim(` Version: ${deployment.version}`));
3425
- console.log(chalk5.dim(` Status: ${deployment.status}`));
3426
- 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")}`));
3427
2997
  console.log();
3428
- console.log(chalk5.bold("CDN URL:"));
3429
- 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`));
3430
3000
  console.log();
3431
- 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.'));
3432
3002
  } catch (error) {
3433
3003
  spinner.fail("Deployment failed");
3434
- console.error(chalk5.red("\nError:"), error.message || error);
3004
+ console.error(chalk4.red("\nError:"), error.message || error);
3435
3005
  }
3436
3006
  }
3437
3007
 
3438
3008
  // src/commands/html.ts
3439
- import chalk6 from "chalk";
3440
- import ora5 from "ora";
3009
+ import chalk5 from "chalk";
3010
+ import ora4 from "ora";
3441
3011
 
3442
3012
  // src/lib/page-cache.ts
3443
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync8, unlinkSync } from "fs";
3444
- import { join as join10, basename as basename4 } from "path";
3445
- 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";
3446
3016
  var PAGES_DIR = "pages";
3447
3017
  function urlToSlug(url) {
3448
3018
  try {
@@ -3455,32 +3025,32 @@ function urlToSlug(url) {
3455
3025
  }
3456
3026
  }
3457
3027
  function getPagesDir(projectRoot) {
3458
- return join10(projectRoot, PROJECT_CONFIG_DIR3, PAGES_DIR);
3028
+ return join7(projectRoot, PROJECT_CONFIG_DIR2, PAGES_DIR);
3459
3029
  }
3460
3030
  function getPageCachePath(projectRoot, urlOrSlug) {
3461
3031
  const slug = urlOrSlug.startsWith("http") ? urlToSlug(urlOrSlug) : urlOrSlug;
3462
- return join10(getPagesDir(projectRoot), `${slug}.json`);
3032
+ return join7(getPagesDir(projectRoot), `${slug}.json`);
3463
3033
  }
3464
3034
  function ensurePagesDir(projectRoot) {
3465
3035
  const pagesDir = getPagesDir(projectRoot);
3466
- if (!existsSync10(pagesDir)) {
3467
- mkdirSync5(pagesDir, { recursive: true });
3036
+ if (!existsSync7(pagesDir)) {
3037
+ mkdirSync3(pagesDir, { recursive: true });
3468
3038
  }
3469
3039
  }
3470
3040
  function savePageContext(projectRoot, context) {
3471
3041
  ensurePagesDir(projectRoot);
3472
3042
  const slug = urlToSlug(context.url);
3473
3043
  const cachePath = getPageCachePath(projectRoot, slug);
3474
- writeFileSync8(cachePath, JSON.stringify(context, null, 2), "utf-8");
3044
+ writeFileSync5(cachePath, JSON.stringify(context, null, 2), "utf-8");
3475
3045
  return slug;
3476
3046
  }
3477
3047
  function readPageContext(projectRoot, urlOrSlug) {
3478
3048
  const cachePath = getPageCachePath(projectRoot, urlOrSlug);
3479
- if (!existsSync10(cachePath)) {
3049
+ if (!existsSync7(cachePath)) {
3480
3050
  return null;
3481
3051
  }
3482
3052
  try {
3483
- const content = readFileSync10(cachePath, "utf-8");
3053
+ const content = readFileSync7(cachePath, "utf-8");
3484
3054
  return JSON.parse(content);
3485
3055
  } catch {
3486
3056
  return null;
@@ -3488,7 +3058,7 @@ function readPageContext(projectRoot, urlOrSlug) {
3488
3058
  }
3489
3059
  function deletePageContext(projectRoot, urlOrSlug) {
3490
3060
  const cachePath = getPageCachePath(projectRoot, urlOrSlug);
3491
- if (existsSync10(cachePath)) {
3061
+ if (existsSync7(cachePath)) {
3492
3062
  unlinkSync(cachePath);
3493
3063
  return true;
3494
3064
  }
@@ -3496,7 +3066,7 @@ function deletePageContext(projectRoot, urlOrSlug) {
3496
3066
  }
3497
3067
  function listCachedPages(projectRoot) {
3498
3068
  const pagesDir = getPagesDir(projectRoot);
3499
- if (!existsSync10(pagesDir)) {
3069
+ if (!existsSync7(pagesDir)) {
3500
3070
  return [];
3501
3071
  }
3502
3072
  const files = readdirSync3(pagesDir).filter((f) => f.endsWith(".json"));
@@ -3561,34 +3131,34 @@ function toCachedContext(structure) {
3561
3131
  async function htmlCommand(url, options) {
3562
3132
  const projectRoot = findProjectRoot();
3563
3133
  if (!projectRoot) {
3564
- console.log(chalk6.red("\u274C Not in a Cure Kode project."));
3565
- 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.'));
3566
3136
  return;
3567
3137
  }
3568
3138
  const config = getProjectConfig(projectRoot);
3569
3139
  if (!config) {
3570
- console.log(chalk6.red("\u274C Could not read project configuration."));
3140
+ console.log(chalk5.red("\u274C Could not read project configuration."));
3571
3141
  return;
3572
3142
  }
3573
3143
  let parsedUrl;
3574
3144
  try {
3575
3145
  parsedUrl = new URL(url.startsWith("http") ? url : `https://${url}`);
3576
3146
  } catch {
3577
- console.log(chalk6.red("\u274C Invalid URL."));
3147
+ console.log(chalk5.red("\u274C Invalid URL."));
3578
3148
  return;
3579
3149
  }
3580
3150
  if (options?.save && !options?.force) {
3581
3151
  const slug = urlToSlug(parsedUrl.toString());
3582
3152
  const cached = readPageContext(projectRoot, slug);
3583
3153
  if (cached) {
3584
- console.log(chalk6.dim(`Using cached version from ${cached.extractedAt}`));
3585
- 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`));
3586
3156
  console.log();
3587
3157
  printPageContext(cached);
3588
3158
  return;
3589
3159
  }
3590
3160
  }
3591
- const spinner = ora5(`Fetching ${parsedUrl.hostname}${parsedUrl.pathname}...`).start();
3161
+ const spinner = ora4(`Fetching ${parsedUrl.hostname}${parsedUrl.pathname}...`).start();
3592
3162
  try {
3593
3163
  const client = createApiClient(config);
3594
3164
  if (options?.save) {
@@ -3609,7 +3179,7 @@ async function htmlCommand(url, options) {
3609
3179
  spinner.succeed("Page structure extracted");
3610
3180
  const cachedContext = toCachedContext(structure);
3611
3181
  const slug = savePageContext(projectRoot, cachedContext);
3612
- console.log(chalk6.dim(`Saved to .cure-kode/pages/${slug}.json`));
3182
+ console.log(chalk5.dim(`Saved to .cure-kode/pages/${slug}.json`));
3613
3183
  const contextPage = {
3614
3184
  slug,
3615
3185
  url: structure.url,
@@ -3620,7 +3190,7 @@ async function htmlCommand(url, options) {
3620
3190
  cms: structure.cmsPatterns.length > 0 ? structure.cmsPatterns.map((c) => `${c.containerClass} (${c.itemCount})`).join(", ") : void 0
3621
3191
  };
3622
3192
  upsertPage(projectRoot, contextPage, "kode html --save");
3623
- console.log(chalk6.dim(`Updated .cure-kode/context.md`));
3193
+ console.log(chalk5.dim(`Updated .cure-kode/context.md`));
3624
3194
  console.log();
3625
3195
  printPageContext(cachedContext);
3626
3196
  return;
@@ -3632,115 +3202,115 @@ async function htmlCommand(url, options) {
3632
3202
  return;
3633
3203
  }
3634
3204
  console.log();
3635
- console.log(chalk6.bold(result.title || parsedUrl.hostname));
3636
- console.log(chalk6.dim(result.url));
3205
+ console.log(chalk5.bold(result.title || parsedUrl.hostname));
3206
+ console.log(chalk5.dim(result.url));
3637
3207
  console.log();
3638
3208
  const hasCureKode = result.scripts.cureKode.length > 0;
3639
3209
  if (hasCureKode) {
3640
- console.log(chalk6.green("\u2705 Cure Kode installed"));
3210
+ console.log(chalk5.green("\u2705 Cure Kode installed"));
3641
3211
  } else {
3642
- console.log(chalk6.yellow("\u26A0\uFE0F Cure Kode not found"));
3643
- console.log(chalk6.dim(" Add this to your Webflow site:"));
3644
- 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>`));
3645
3215
  }
3646
3216
  console.log();
3647
- console.log(chalk6.dim("\u2500".repeat(50)));
3217
+ console.log(chalk5.dim("\u2500".repeat(50)));
3648
3218
  console.log(
3649
- ` 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)`)
3650
3220
  );
3651
3221
  console.log(` Styles: ${result.stats.totalStyles}`);
3652
- console.log(chalk6.dim("\u2500".repeat(50)));
3222
+ console.log(chalk5.dim("\u2500".repeat(50)));
3653
3223
  console.log();
3654
3224
  if (!options?.styles) {
3655
- console.log(chalk6.bold("Scripts"));
3225
+ console.log(chalk5.bold("Scripts"));
3656
3226
  console.log();
3657
3227
  if (result.scripts.webflow.length > 0) {
3658
- console.log(chalk6.blue(" Webflow:"));
3228
+ console.log(chalk5.blue(" Webflow:"));
3659
3229
  result.scripts.webflow.forEach((s) => {
3660
- console.log(chalk6.dim(` ${s.src || "(inline)"}`));
3230
+ console.log(chalk5.dim(` ${s.src || "(inline)"}`));
3661
3231
  });
3662
3232
  }
3663
3233
  if (result.scripts.cureKode.length > 0) {
3664
- console.log(chalk6.green(" Cure Kode:"));
3234
+ console.log(chalk5.green(" Cure Kode:"));
3665
3235
  result.scripts.cureKode.forEach((s) => {
3666
- console.log(chalk6.dim(` ${s.src || "(inline)"}`));
3236
+ console.log(chalk5.dim(` ${s.src || "(inline)"}`));
3667
3237
  });
3668
3238
  }
3669
3239
  if (result.scripts.thirdParty.length > 0) {
3670
- console.log(chalk6.yellow(" Third-party:"));
3240
+ console.log(chalk5.yellow(" Third-party:"));
3671
3241
  result.scripts.thirdParty.forEach((s) => {
3672
- console.log(chalk6.dim(` ${s.src || "(inline)"}`));
3242
+ console.log(chalk5.dim(` ${s.src || "(inline)"}`));
3673
3243
  });
3674
3244
  }
3675
3245
  if (result.scripts.custom.length > 0) {
3676
- console.log(chalk6.magenta(" Custom:"));
3246
+ console.log(chalk5.magenta(" Custom:"));
3677
3247
  result.scripts.custom.forEach((s) => {
3678
3248
  const label = s.src || (s.inline ? `(inline, ${s.content?.length || 0} chars)` : "(inline)");
3679
- console.log(chalk6.dim(` ${label}`));
3249
+ console.log(chalk5.dim(` ${label}`));
3680
3250
  });
3681
3251
  }
3682
3252
  console.log();
3683
3253
  }
3684
3254
  if (result.detectedComponents.length > 0) {
3685
- console.log(chalk6.bold("Detected Components"));
3255
+ console.log(chalk5.bold("Detected Components"));
3686
3256
  console.log();
3687
3257
  result.detectedComponents.forEach((comp) => {
3688
- console.log(chalk6.dim(` \u2022 ${comp}`));
3258
+ console.log(chalk5.dim(` \u2022 ${comp}`));
3689
3259
  });
3690
3260
  console.log();
3691
3261
  }
3692
3262
  if (options?.styles) {
3693
- console.log(chalk6.bold("Stylesheets"));
3263
+ console.log(chalk5.bold("Stylesheets"));
3694
3264
  console.log();
3695
3265
  result.styles.forEach((style) => {
3696
3266
  if (style.href) {
3697
- const isWebflow = style.isWebflow ? chalk6.blue(" [WF]") : "";
3698
- console.log(chalk6.dim(` ${style.href}${isWebflow}`));
3267
+ const isWebflow = style.isWebflow ? chalk5.blue(" [WF]") : "";
3268
+ console.log(chalk5.dim(` ${style.href}${isWebflow}`));
3699
3269
  } else {
3700
- console.log(chalk6.dim(" (inline style)"));
3270
+ console.log(chalk5.dim(" (inline style)"));
3701
3271
  }
3702
3272
  });
3703
3273
  console.log();
3704
3274
  }
3705
3275
  } catch (error) {
3706
3276
  spinner.fail("Failed to fetch HTML");
3707
- console.error(chalk6.red("\nError:"), error.message || error);
3277
+ console.error(chalk5.red("\nError:"), error.message || error);
3708
3278
  }
3709
3279
  }
3710
3280
  function printPageContext(context) {
3711
- console.log(chalk6.bold(context.title || context.url));
3712
- console.log(chalk6.dim(context.url));
3281
+ console.log(chalk5.bold(context.title || context.url));
3282
+ console.log(chalk5.dim(context.url));
3713
3283
  console.log();
3714
3284
  if (context.sections.length > 0) {
3715
- console.log(chalk6.bold("Sections"));
3285
+ console.log(chalk5.bold("Sections"));
3716
3286
  for (const section of context.sections.slice(0, 8)) {
3717
3287
  const name = section.heading || section.id || section.className?.split(" ")[0] || "section";
3718
3288
  const badges = [];
3719
- if (section.hasCms) badges.push(chalk6.cyan("CMS"));
3720
- 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"));
3721
3291
  const badgeStr = badges.length > 0 ? ` [${badges.join(", ")}]` : "";
3722
3292
  console.log(` \u2022 ${name}${badgeStr}`);
3723
3293
  if (section.textSample) {
3724
- console.log(chalk6.dim(` "${section.textSample.slice(0, 60)}..."`));
3294
+ console.log(chalk5.dim(` "${section.textSample.slice(0, 60)}..."`));
3725
3295
  }
3726
3296
  }
3727
3297
  if (context.sections.length > 8) {
3728
- console.log(chalk6.dim(` ... and ${context.sections.length - 8} more`));
3298
+ console.log(chalk5.dim(` ... and ${context.sections.length - 8} more`));
3729
3299
  }
3730
3300
  console.log();
3731
3301
  }
3732
3302
  if (context.ctas.length > 0) {
3733
- console.log(chalk6.bold("CTAs"));
3303
+ console.log(chalk5.bold("CTAs"));
3734
3304
  for (const cta of context.ctas.slice(0, 6)) {
3735
- console.log(` \u2022 "${cta.text}" ${chalk6.dim(`(${cta.location})`)}`);
3305
+ console.log(` \u2022 "${cta.text}" ${chalk5.dim(`(${cta.location})`)}`);
3736
3306
  }
3737
3307
  if (context.ctas.length > 6) {
3738
- console.log(chalk6.dim(` ... and ${context.ctas.length - 6} more`));
3308
+ console.log(chalk5.dim(` ... and ${context.ctas.length - 6} more`));
3739
3309
  }
3740
3310
  console.log();
3741
3311
  }
3742
3312
  if (context.forms.length > 0) {
3743
- console.log(chalk6.bold("Forms"));
3313
+ console.log(chalk5.bold("Forms"));
3744
3314
  for (const form of context.forms) {
3745
3315
  const fields = form.fields.map((f) => f.label || f.type).slice(0, 4).join(", ");
3746
3316
  const more = form.fields.length > 4 ? ` +${form.fields.length - 4}` : "";
@@ -3749,17 +3319,17 @@ function printPageContext(context) {
3749
3319
  console.log();
3750
3320
  }
3751
3321
  if (context.cmsPatterns.length > 0) {
3752
- console.log(chalk6.bold("CMS Collections"));
3322
+ console.log(chalk5.bold("CMS Collections"));
3753
3323
  for (const cms of context.cmsPatterns) {
3754
- console.log(` \u2022 ${cms.containerClass}: ${chalk6.cyan(`${cms.itemCount} items`)}`);
3324
+ console.log(` \u2022 ${cms.containerClass}: ${chalk5.cyan(`${cms.itemCount} items`)}`);
3755
3325
  if (cms.templateFields.length > 0) {
3756
- console.log(chalk6.dim(` Fields: ${cms.templateFields.slice(0, 5).join(", ")}`));
3326
+ console.log(chalk5.dim(` Fields: ${cms.templateFields.slice(0, 5).join(", ")}`));
3757
3327
  }
3758
3328
  }
3759
3329
  console.log();
3760
3330
  }
3761
3331
  if (context.navigation.length > 0) {
3762
- console.log(chalk6.bold("Navigation"));
3332
+ console.log(chalk5.bold("Navigation"));
3763
3333
  for (const nav of context.navigation) {
3764
3334
  const items = nav.items.slice(0, 5).map((i) => i.text).join(", ");
3765
3335
  const more = nav.items.length > 5 ? ` +${nav.items.length - 5}` : "";
@@ -3768,7 +3338,7 @@ function printPageContext(context) {
3768
3338
  console.log();
3769
3339
  }
3770
3340
  if (context.notes && context.notes.length > 0) {
3771
- console.log(chalk6.bold("Notes"));
3341
+ console.log(chalk5.bold("Notes"));
3772
3342
  for (const note of context.notes) {
3773
3343
  console.log(` \u2022 ${note}`);
3774
3344
  }
@@ -3777,13 +3347,13 @@ function printPageContext(context) {
3777
3347
  }
3778
3348
 
3779
3349
  // src/commands/status.ts
3780
- import chalk7 from "chalk";
3781
- import ora6 from "ora";
3782
- import { readFileSync as readFileSync11, existsSync as existsSync11, readdirSync as readdirSync4, statSync } from "fs";
3783
- import { join as join11, basename as basename5, extname as extname4 } from "path";
3784
- import { createHash as createHash3 } from "crypto";
3785
- function hashContent3(content) {
3786
- 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);
3787
3357
  }
3788
3358
  function formatRelativeTime(dateStr) {
3789
3359
  const date = new Date(dateStr);
@@ -3818,36 +3388,36 @@ function isSyncStale(metadata) {
3818
3388
  async function statusCommand(options) {
3819
3389
  const projectRoot = findProjectRoot();
3820
3390
  if (!projectRoot) {
3821
- console.log(chalk7.red("\u274C Not in a Cure Kode project."));
3822
- 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.'));
3823
3393
  return;
3824
3394
  }
3825
3395
  const config = getProjectConfig(projectRoot);
3826
3396
  if (!config) {
3827
- console.log(chalk7.red("\u274C Could not read project configuration."));
3397
+ console.log(chalk6.red("\u274C Could not read project configuration."));
3828
3398
  return;
3829
3399
  }
3830
- const metadataPath = join11(projectRoot, ".cure-kode", "scripts.json");
3400
+ const metadataPath = join8(projectRoot, ".cure-kode", "scripts.json");
3831
3401
  let syncMetadata = [];
3832
- if (existsSync11(metadataPath)) {
3402
+ if (existsSync8(metadataPath)) {
3833
3403
  try {
3834
- syncMetadata = JSON.parse(readFileSync11(metadataPath, "utf-8"));
3404
+ syncMetadata = JSON.parse(readFileSync8(metadataPath, "utf-8"));
3835
3405
  } catch {
3836
3406
  }
3837
3407
  }
3838
3408
  console.log();
3839
- console.log(chalk7.bold(`\u{1F4E6} ${config.siteName}`));
3840
- console.log(chalk7.dim(` Slug: ${config.siteSlug}`));
3841
- 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}`));
3842
3412
  console.log();
3843
- console.log(chalk7.bold("CDN URL"));
3413
+ console.log(chalk6.bold("CDN URL"));
3844
3414
  console.log();
3845
- 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`));
3846
3416
  console.log();
3847
- console.log(chalk7.dim(" Add to Webflow \u2192 Project Settings \u2192 Custom Code \u2192 Body (before </body>):"));
3848
- 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>`));
3849
3419
  console.log();
3850
- const spinner = ora6("Fetching status...").start();
3420
+ const spinner = ora5("Fetching status...").start();
3851
3421
  try {
3852
3422
  const client = createApiClient(config);
3853
3423
  const [remoteScripts, deployStatus] = await Promise.all([
@@ -3855,46 +3425,46 @@ async function statusCommand(options) {
3855
3425
  client.getDeploymentStatus(config.siteId)
3856
3426
  ]);
3857
3427
  spinner.stop();
3858
- console.log(chalk7.bold("Environments"));
3428
+ console.log(chalk6.bold("Environments"));
3859
3429
  console.log();
3860
3430
  const stagingStatus = deployStatus.staging.lastSuccessful;
3861
3431
  if (stagingStatus) {
3862
3432
  console.log(
3863
- 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)})`)
3864
3434
  );
3865
3435
  } else {
3866
- 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"));
3867
3437
  }
3868
3438
  const productionEnabled = deployStatus.productionEnabled ?? false;
3869
3439
  const prodStatus = deployStatus.production.lastSuccessful;
3870
3440
  if (!productionEnabled) {
3871
3441
  console.log(
3872
- 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)")
3873
3443
  );
3874
3444
  console.log();
3875
3445
  console.log(
3876
- 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.')
3877
3447
  );
3878
3448
  } else if (prodStatus) {
3879
3449
  console.log(
3880
- 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)})`)
3881
3451
  );
3882
3452
  if (deployStatus.productionDomain) {
3883
- console.log(chalk7.dim(` Domain: ${deployStatus.productionDomain}`));
3453
+ console.log(chalk6.dim(` Domain: ${deployStatus.productionDomain}`));
3884
3454
  }
3885
3455
  } else {
3886
3456
  console.log(
3887
- 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")
3888
3458
  );
3889
3459
  }
3890
3460
  if (deployStatus.canPromote && productionEnabled) {
3891
3461
  console.log();
3892
3462
  console.log(
3893
- 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.')
3894
3464
  );
3895
3465
  }
3896
3466
  console.log();
3897
- console.log(chalk7.bold("Scripts"));
3467
+ console.log(chalk6.bold("Scripts"));
3898
3468
  const syncStatus = isSyncStale(syncMetadata);
3899
3469
  if (syncStatus.isStale && syncStatus.lastSyncedAt) {
3900
3470
  const syncDate = new Date(syncStatus.lastSyncedAt);
@@ -3905,20 +3475,20 @@ async function statusCommand(options) {
3905
3475
  minute: "2-digit"
3906
3476
  });
3907
3477
  console.log(
3908
- chalk7.yellow(` \u26A0 Sist synkronisert: ${formatRelativeTime(syncStatus.lastSyncedAt)}`) + chalk7.dim(` (${dateStr})`)
3478
+ chalk6.yellow(` \u26A0 Sist synkronisert: ${formatRelativeTime(syncStatus.lastSyncedAt)}`) + chalk6.dim(` (${dateStr})`)
3909
3479
  );
3910
3480
  } else if (!syncStatus.lastSyncedAt && syncMetadata.length === 0) {
3911
- 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`));
3912
3482
  }
3913
3483
  console.log();
3914
3484
  const scriptsDir = getScriptsDir(projectRoot, config);
3915
- 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")) : [];
3916
3486
  const localBySlug = /* @__PURE__ */ new Map();
3917
3487
  for (const file of localFiles) {
3918
3488
  const slug = basename5(file, extname4(file));
3919
- const filePath = join11(scriptsDir, file);
3920
- const content = readFileSync11(filePath, "utf-8");
3921
- const stats = statSync(filePath);
3489
+ const filePath = join8(scriptsDir, file);
3490
+ const content = readFileSync8(filePath, "utf-8");
3491
+ const stats = statSync2(filePath);
3922
3492
  localBySlug.set(slug, { file, content, modified: stats.mtime });
3923
3493
  }
3924
3494
  const remoteBySlug = /* @__PURE__ */ new Map();
@@ -3936,48 +3506,48 @@ async function statusCommand(options) {
3936
3506
  const remote = remoteBySlug.get(slug);
3937
3507
  const meta = metadataBySlug.get(slug);
3938
3508
  if (local && remote) {
3939
- const scopeTag = remote.scope === "global" ? chalk7.blue("[G]") : chalk7.magenta("[P]");
3940
- const localHash = hashContent3(local.content);
3509
+ const scopeTag = remote.scope === "global" ? chalk6.blue("[G]") : chalk6.magenta("[P]");
3510
+ const localHash = hashContent2(local.content);
3941
3511
  const hasLocalChanges = meta && localHash !== meta.contentHash;
3942
3512
  const lastPulledVersion = meta?.lastPulledVersion || 0;
3943
3513
  const hasRemoteChanges = remote.current_version > lastPulledVersion && lastPulledVersion > 0;
3944
3514
  if (hasLocalChanges && hasRemoteChanges) {
3945
3515
  console.log(
3946
- 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)")
3947
3517
  );
3948
3518
  outdatedCount++;
3949
3519
  } else if (hasLocalChanges) {
3950
3520
  console.log(
3951
- 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)")
3952
3522
  );
3953
3523
  } else if (hasRemoteChanges) {
3954
3524
  console.log(
3955
- 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)")
3956
3526
  );
3957
3527
  outdatedCount++;
3958
3528
  } else if (local.content !== remote.content) {
3959
3529
  console.log(
3960
- 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)")
3961
3531
  );
3962
3532
  } else {
3963
3533
  console.log(
3964
- 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}`)
3965
3535
  );
3966
3536
  }
3967
3537
  } else if (local && !remote) {
3968
3538
  console.log(
3969
- chalk7.cyan(" + ") + `${local.file}` + chalk7.cyan(" (ny, ikke pushet)")
3539
+ chalk6.cyan(" + ") + `${local.file}` + chalk6.cyan(" (ny, ikke pushet)")
3970
3540
  );
3971
3541
  } else if (!local && remote) {
3972
3542
  const ext = remote.type === "javascript" ? "js" : "css";
3973
3543
  const fileName = `${slug}.${ext}`;
3974
3544
  console.log(
3975
- 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)")
3976
3546
  );
3977
3547
  }
3978
3548
  }
3979
3549
  if (allSlugs.size === 0) {
3980
- console.log(chalk7.dim(" Ingen skript enda."));
3550
+ console.log(chalk6.dim(" Ingen skript enda."));
3981
3551
  }
3982
3552
  console.log();
3983
3553
  const modified = [...allSlugs].filter((slug) => {
@@ -3985,7 +3555,7 @@ async function statusCommand(options) {
3985
3555
  const remote = remoteBySlug.get(slug);
3986
3556
  if (!local || !remote) return false;
3987
3557
  const meta = metadataBySlug.get(slug);
3988
- const localHash = hashContent3(local.content);
3558
+ const localHash = hashContent2(local.content);
3989
3559
  return meta ? localHash !== meta.contentHash : local.content !== remote.content;
3990
3560
  }).length;
3991
3561
  const newLocal = [...allSlugs].filter(
@@ -3995,25 +3565,25 @@ async function statusCommand(options) {
3995
3565
  (slug) => !localBySlug.has(slug) && remoteBySlug.has(slug)
3996
3566
  ).length;
3997
3567
  if (modified > 0 || newLocal > 0 || remoteOnly > 0 || outdatedCount > 0) {
3998
- console.log(chalk7.bold("Handlinger"));
3568
+ console.log(chalk6.bold("Handlinger"));
3999
3569
  console.log();
4000
3570
  if (modified > 0) {
4001
- 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"'));
4002
3572
  }
4003
3573
  if (newLocal > 0) {
4004
- 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"'));
4005
3575
  }
4006
3576
  if (outdatedCount > 0) {
4007
- console.log(chalk7.cyan(` ${outdatedCount} utdaterte`) + chalk7.dim(' \u2192 "kode pull"'));
3577
+ console.log(chalk6.cyan(` ${outdatedCount} utdaterte`) + chalk6.dim(' \u2192 "kode pull"'));
4008
3578
  }
4009
3579
  if (remoteOnly > 0) {
4010
- 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"'));
4011
3581
  }
4012
3582
  console.log();
4013
3583
  }
4014
3584
  } catch (error) {
4015
3585
  spinner.fail("Failed to fetch status");
4016
- console.error(chalk7.red("\nError:"), error.message || error);
3586
+ console.error(chalk6.red("\nError:"), error.message || error);
4017
3587
  }
4018
3588
  }
4019
3589
  function formatDate(dateStr) {
@@ -4028,25 +3598,25 @@ function formatDate(dateStr) {
4028
3598
  }
4029
3599
 
4030
3600
  // src/commands/context.ts
4031
- import chalk8 from "chalk";
4032
- import ora7 from "ora";
3601
+ import chalk7 from "chalk";
3602
+ import ora6 from "ora";
4033
3603
  import { spawn } from "child_process";
4034
3604
  async function contextCommand(options) {
4035
3605
  const projectRoot = findProjectRoot();
4036
3606
  if (!projectRoot) {
4037
- console.log(chalk8.red("Error: Not in a Cure Kode project."));
4038
- 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.'));
4039
3609
  return;
4040
3610
  }
4041
3611
  const config = getProjectConfig(projectRoot);
4042
3612
  if (!config) {
4043
- console.log(chalk8.red("Error: Invalid project configuration."));
3613
+ console.log(chalk7.red("Error: Invalid project configuration."));
4044
3614
  return;
4045
3615
  }
4046
3616
  const contextPath = getContextPath(projectRoot);
4047
3617
  const context = readContext(projectRoot);
4048
3618
  if (options.refresh) {
4049
- const spinner = ora7("Refreshing context from server...").start();
3619
+ const spinner = ora6("Refreshing context from server...").start();
4050
3620
  try {
4051
3621
  const siteResponse = await fetch(
4052
3622
  `https://app.cure.no/api/cdn/sites/${config.siteId}`,
@@ -4095,28 +3665,28 @@ async function contextCommand(options) {
4095
3665
  };
4096
3666
  writeContext(projectRoot, newContext);
4097
3667
  spinner.succeed("Context refreshed");
4098
- console.log(chalk8.dim(`Updated: ${contextPath}`));
3668
+ console.log(chalk7.dim(`Updated: ${contextPath}`));
4099
3669
  return;
4100
3670
  } catch (error) {
4101
3671
  spinner.fail("Failed to refresh context");
4102
- console.log(chalk8.red(error instanceof Error ? error.message : "Unknown error"));
3672
+ console.log(chalk7.red(error instanceof Error ? error.message : "Unknown error"));
4103
3673
  return;
4104
3674
  }
4105
3675
  }
4106
3676
  if (options.edit) {
4107
3677
  if (!context) {
4108
- console.log(chalk8.red("Error: No context file found."));
4109
- 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.'));
4110
3680
  return;
4111
3681
  }
4112
3682
  const editor = process.env.EDITOR || process.env.VISUAL || "vim";
4113
- console.log(chalk8.dim(`Opening ${contextPath} in ${editor}...`));
3683
+ console.log(chalk7.dim(`Opening ${contextPath} in ${editor}...`));
4114
3684
  const child = spawn(editor, [contextPath], {
4115
3685
  stdio: "inherit"
4116
3686
  });
4117
3687
  child.on("error", (err) => {
4118
- console.log(chalk8.red(`Failed to open editor: ${err.message}`));
4119
- 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}`));
4120
3690
  });
4121
3691
  return;
4122
3692
  }
@@ -4129,38 +3699,38 @@ async function contextCommand(options) {
4129
3699
  return;
4130
3700
  }
4131
3701
  if (!context) {
4132
- console.log(chalk8.yellow("No context file found."));
4133
- 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.'));
4134
3704
  return;
4135
3705
  }
4136
- console.log(chalk8.bold(`Context: ${context.site.name}`));
4137
- console.log(chalk8.dim(`Last updated: ${context.lastUpdated}`));
4138
- 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}`));
4139
3709
  console.log();
4140
3710
  if (context.site.domain || context.site.stagingDomain) {
4141
3711
  if (context.site.domain) {
4142
- console.log(chalk8.dim("Domain: ") + context.site.domain);
3712
+ console.log(chalk7.dim("Domain: ") + context.site.domain);
4143
3713
  }
4144
3714
  if (context.site.stagingDomain) {
4145
- console.log(chalk8.dim("Staging: ") + context.site.stagingDomain);
3715
+ console.log(chalk7.dim("Staging: ") + context.site.stagingDomain);
4146
3716
  }
4147
3717
  console.log();
4148
3718
  }
4149
- console.log(chalk8.bold("Scripts:"));
3719
+ console.log(chalk7.bold("Scripts:"));
4150
3720
  if (context.scripts.length === 0) {
4151
- console.log(chalk8.dim(" (no scripts)"));
3721
+ console.log(chalk7.dim(" (no scripts)"));
4152
3722
  } else {
4153
3723
  for (const script of context.scripts) {
4154
3724
  const typeIcon = script.type === "css" ? "\u{1F3A8}" : "\u{1F4DC}";
4155
- const scopeLabel = script.scope === "global" ? chalk8.cyan("global") : chalk8.yellow("page");
4156
- 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}`) : "";
4157
3727
  console.log(` ${typeIcon} ${script.slug} [${scopeLabel}]${purpose}`);
4158
3728
  }
4159
3729
  }
4160
3730
  console.log();
4161
- console.log(chalk8.bold("Notes:"));
3731
+ console.log(chalk7.bold("Notes:"));
4162
3732
  if (context.notes.length === 0 || context.notes.length === 3 && context.notes[0].startsWith("(HTML")) {
4163
- console.log(chalk8.dim(" (no notes yet)"));
3733
+ console.log(chalk7.dim(" (no notes yet)"));
4164
3734
  } else {
4165
3735
  for (const note of context.notes) {
4166
3736
  if (!note.startsWith("(")) {
@@ -4169,67 +3739,67 @@ async function contextCommand(options) {
4169
3739
  }
4170
3740
  }
4171
3741
  console.log();
4172
- console.log(chalk8.bold("Recent Sessions:"));
3742
+ console.log(chalk7.bold("Recent Sessions:"));
4173
3743
  if (context.sessions.length === 0) {
4174
- console.log(chalk8.dim(" (no sessions recorded)"));
3744
+ console.log(chalk7.dim(" (no sessions recorded)"));
4175
3745
  } else {
4176
3746
  const recentSessions = context.sessions.slice(0, 3);
4177
3747
  for (const session of recentSessions) {
4178
- console.log(` ${chalk8.dim(session.date)} ${session.agent}`);
3748
+ console.log(` ${chalk7.dim(session.date)} ${session.agent}`);
4179
3749
  console.log(` ${session.task}`);
4180
3750
  if (session.changes.length > 0) {
4181
- console.log(chalk8.dim(` ${session.changes.length} change(s)`));
3751
+ console.log(chalk7.dim(` ${session.changes.length} change(s)`));
4182
3752
  }
4183
3753
  }
4184
3754
  if (context.sessions.length > 3) {
4185
- console.log(chalk8.dim(` ... and ${context.sessions.length - 3} more sessions`));
3755
+ console.log(chalk7.dim(` ... and ${context.sessions.length - 3} more sessions`));
4186
3756
  }
4187
3757
  }
4188
3758
  console.log();
4189
- console.log(chalk8.dim(`Context file: ${contextPath}`));
4190
- 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"));
4191
3761
  }
4192
3762
 
4193
3763
  // src/commands/sync-config.ts
4194
- import chalk9 from "chalk";
4195
- import ora8 from "ora";
4196
- import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
4197
- 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";
4198
3768
  async function syncConfigCommand() {
4199
3769
  const cwd = process.cwd();
4200
3770
  const projectRoot = findProjectRoot(cwd);
4201
3771
  if (!projectRoot) {
4202
- console.log(chalk9.red(" Feil: Cure Kode er ikke initialisert i denne mappen."));
4203
- 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."));
4204
3774
  return;
4205
3775
  }
4206
3776
  const config = getProjectConfig(projectRoot);
4207
3777
  if (!config) {
4208
- console.log(chalk9.red(" Feil: Kunne ikke lese prosjektkonfigurasjon."));
3778
+ console.log(chalk8.red(" Feil: Kunne ikke lese prosjektkonfigurasjon."));
4209
3779
  return;
4210
3780
  }
4211
3781
  if (!config.projectId) {
4212
- console.log(chalk9.yellow(" Nettstedet er ikke koblet til et prosjekt."));
4213
- 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"'));
4214
3784
  return;
4215
3785
  }
4216
- const spinner = ora8("Henter prosjektkonfigurasjon...").start();
3786
+ const spinner = ora7("Henter prosjektkonfigurasjon...").start();
4217
3787
  try {
4218
3788
  const response = await fetch(`https://app.cure.no/api/cdn/sites/${config.siteId}/project`, {
4219
3789
  headers: { "X-API-Key": config.apiKey }
4220
3790
  });
4221
3791
  if (!response.ok) {
4222
3792
  spinner.fail("Kunne ikke hente prosjektkonfigurasjon");
4223
- console.log(chalk9.dim(` HTTP ${response.status}: ${response.statusText}`));
3793
+ console.log(chalk8.dim(` HTTP ${response.status}: ${response.statusText}`));
4224
3794
  return;
4225
3795
  }
4226
3796
  const projectCtx = await response.json();
4227
3797
  spinner.succeed("Prosjektkonfigurasjon hentet");
4228
- const mcpConfigPath = join12(projectRoot, ".mcp.json");
3798
+ const mcpConfigPath = join9(projectRoot, ".mcp.json");
4229
3799
  let mcpConfig = {};
4230
- if (existsSync12(mcpConfigPath)) {
3800
+ if (existsSync9(mcpConfigPath)) {
4231
3801
  try {
4232
- mcpConfig = JSON.parse(readFileSync12(mcpConfigPath, "utf-8"));
3802
+ mcpConfig = JSON.parse(readFileSync9(mcpConfigPath, "utf-8"));
4233
3803
  } catch {
4234
3804
  }
4235
3805
  }
@@ -4273,7 +3843,7 @@ async function syncConfigCommand() {
4273
3843
  added.push(server.name);
4274
3844
  }
4275
3845
  }
4276
- writeFileSync9(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
3846
+ writeFileSync6(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
4277
3847
  spinner.start("Oppdaterer dokumentasjon...");
4278
3848
  let scripts = [];
4279
3849
  let pages = [];
@@ -4309,43 +3879,36 @@ async function syncConfigCommand() {
4309
3879
  spinner.succeed("Dokumentasjon oppdatert");
4310
3880
  console.log();
4311
3881
  if (projectCtx.project) {
4312
- console.log(chalk9.bold(" Prosjekt: ") + chalk9.cyan(projectCtx.project.name));
3882
+ console.log(chalk8.bold(" Prosjekt: ") + chalk8.cyan(projectCtx.project.name));
4313
3883
  }
4314
3884
  if (added.length > 0 || updated.length > 0) {
4315
- console.log(chalk9.bold(" MCP-servere:"));
3885
+ console.log(chalk8.bold(" MCP-servere:"));
4316
3886
  for (const name of added) {
4317
- console.log(chalk9.green(` + ${name}`) + chalk9.dim(" (ny)"));
3887
+ console.log(chalk8.green(` + ${name}`) + chalk8.dim(" (ny)"));
4318
3888
  }
4319
3889
  for (const name of updated) {
4320
- console.log(chalk9.blue(` ~ ${name}`) + chalk9.dim(" (oppdatert)"));
3890
+ console.log(chalk8.blue(` ~ ${name}`) + chalk8.dim(" (oppdatert)"));
4321
3891
  }
4322
3892
  } else if (projectCtx.mcp_servers.length === 0) {
4323
- console.log(chalk9.dim(" Ingen prosjekt-MCP-servere konfigurert."));
3893
+ console.log(chalk8.dim(" Ingen prosjekt-MCP-servere konfigurert."));
4324
3894
  } else {
4325
- console.log(chalk9.dim(" Ingen endringer i MCP-servere."));
3895
+ console.log(chalk8.dim(" Ingen endringer i MCP-servere."));
4326
3896
  }
4327
3897
  if (secretWarnings.length > 0) {
4328
3898
  console.log();
4329
- 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:"));
4330
3900
  for (const warning of secretWarnings) {
4331
- console.log(chalk9.dim(` \u2022 ${warning}`));
3901
+ console.log(chalk8.dim(` \u2022 ${warning}`));
4332
3902
  }
4333
3903
  }
4334
3904
  console.log();
4335
3905
  } catch (error) {
4336
3906
  spinner.fail("Sync feilet");
4337
- console.log(chalk9.red(` Feil: ${error.message}`));
3907
+ console.log(chalk8.red(` Feil: ${error.message}`));
4338
3908
  }
4339
3909
  }
4340
3910
 
4341
3911
  export {
4342
- findProjectRoot,
4343
- getProjectConfig,
4344
- saveProjectConfig,
4345
- getApiUrl,
4346
- getApiKey,
4347
- setGlobalConfig,
4348
- getScriptsDir,
4349
3912
  getContextPath,
4350
3913
  parseContext,
4351
3914
  serializeContext,
@@ -4356,17 +3919,9 @@ export {
4356
3919
  updateScriptPurpose,
4357
3920
  generateInitialContext,
4358
3921
  generateClaudeMd,
4359
- updateKodeDocs,
4360
- scriptsToDocsFormat,
4361
- pagesToInfoFormat,
4362
- updateClaudeMd,
4363
3922
  CLI_VERSION,
4364
3923
  showCompactBanner,
4365
3924
  initCommand,
4366
- KodeApiError,
4367
- KodeApiClient,
4368
- createApiClient,
4369
- pullCommand,
4370
3925
  pushCommand,
4371
3926
  watchCommand,
4372
3927
  deployCommand,