@curenorway/kode-cli 1.18.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/{chunk-MSXS4ARI.js → chunk-6RYN72CO.js} +727 -1172
- package/dist/chunk-GO6KLUXM.js +500 -0
- package/dist/chunk-MUW33LPZ.js +265 -0
- package/dist/chunk-R4KWWTS4.js +75 -0
- package/dist/chunk-TLLGB46I.js +418 -0
- package/dist/cli.js +345 -38
- package/dist/index.d.ts +73 -0
- package/dist/index.js +16 -12
- package/dist/pkg-DOXTOICF.js +18 -0
- package/dist/pull-G7GR67GG.js +7 -0
- package/dist/types-PZ7GFJEK.js +9 -0
- package/package.json +2 -1
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApiClient,
|
|
3
|
+
findProjectRoot,
|
|
4
|
+
getProjectConfig,
|
|
5
|
+
getScriptsDir
|
|
6
|
+
} from "./chunk-TLLGB46I.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/pull.ts
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
import { writeFileSync as writeFileSync2, readFileSync as readFileSync2, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
12
|
+
import { join as join2, dirname } from "path";
|
|
13
|
+
import { createHash } from "crypto";
|
|
14
|
+
|
|
15
|
+
// src/lib/claude-md.ts
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
17
|
+
import { join } from "path";
|
|
18
|
+
var KODE_REFERENCE = `## Cure Kode
|
|
19
|
+
|
|
20
|
+
This project uses **Cure Kode** \u2014 a TypeScript/React/JS/CSS build system for Webflow.
|
|
21
|
+
|
|
22
|
+
**Supports:** \`.ts\`, \`.tsx\`, \`.jsx\`, \`.js\`, \`.css\` \u2014 bundled with esbuild, React auto-loaded from CDN.
|
|
23
|
+
|
|
24
|
+
**Before modifying scripts:**
|
|
25
|
+
|
|
26
|
+
1. Run \`kode pull\` to get latest from server
|
|
27
|
+
2. Make your changes in \`.cure-kode-scripts/\`
|
|
28
|
+
3. Run \`kode push\` to upload, then \`kode deploy\` to publish
|
|
29
|
+
|
|
30
|
+
**Packages:** \`kode pkg add <name>\` to install, \`import { ... } from '@kode/<name>'\` to use.
|
|
31
|
+
|
|
32
|
+
**CMS Types:** Auto-generated in \`types/cms.d.ts\`. Refresh with \`kode types\`.
|
|
33
|
+
|
|
34
|
+
Full documentation: [.cure-kode/KODE.md](.cure-kode/KODE.md)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
`;
|
|
39
|
+
function hasKodeReference(content) {
|
|
40
|
+
return content.includes(".cure-kode/KODE.md") || content.includes("cure-kode/KODE.md") || content.includes("KODE.md");
|
|
41
|
+
}
|
|
42
|
+
function generateKodeMd(siteName, siteSlug, scripts, pages, options) {
|
|
43
|
+
const productionEnabled = options?.productionEnabled ?? false;
|
|
44
|
+
let md = `# Cure Kode: ${siteName}
|
|
45
|
+
|
|
46
|
+
This project uses **Cure Kode** CDN for JavaScript/CSS delivery to Webflow.
|
|
47
|
+
|
|
48
|
+
> **This file is auto-generated.** Do not edit manually - changes will be overwritten by \`kode pull\`, \`kode push\`, and \`kode sync\`.
|
|
49
|
+
|
|
50
|
+
**Produksjon:** ${productionEnabled ? "\u2713 Aktivert \u2014 deploy til staging og produksjon" : "\u25CB Deaktivert \u2014 kun staging. Ikke hent fra produksjons-URL."}
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
`;
|
|
55
|
+
md += `## CDN URL
|
|
56
|
+
|
|
57
|
+
Add this to Webflow \u2192 Project Settings \u2192 Custom Code \u2192 Head:
|
|
58
|
+
|
|
59
|
+
\`\`\`html
|
|
60
|
+
<script src="https://app.cure.no/api/cdn/${siteSlug}/init.js"></script>
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
`;
|
|
66
|
+
md += `## Scripts
|
|
67
|
+
|
|
68
|
+
`;
|
|
69
|
+
if (scripts.length > 0) {
|
|
70
|
+
md += `| Script | Type | Scope | Auto | Purpose |
|
|
71
|
+
|--------|------|-------|------|---------|
|
|
72
|
+
`;
|
|
73
|
+
for (const script of scripts) {
|
|
74
|
+
const type = script.type === "javascript" ? "JS" : "CSS";
|
|
75
|
+
const scope = script.scope === "global" ? "Global" : "Page";
|
|
76
|
+
const auto = script.autoLoad ? "\u26A1" : "\u25CB";
|
|
77
|
+
const purpose = script.purpose || script.description || "\u2014";
|
|
78
|
+
const truncated = purpose.length > 50 ? purpose.slice(0, 47) + "..." : purpose;
|
|
79
|
+
md += `| \`${script.slug}\` | ${type} | ${scope} | ${auto} | ${truncated} |
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
md += `
|
|
83
|
+
> \u26A1 = auto-loads on every page, \u25CB = manual load via \`CK.loadScript('slug')\`
|
|
84
|
+
|
|
85
|
+
`;
|
|
86
|
+
} else {
|
|
87
|
+
md += `No scripts yet. Create one with \`kode push\`.
|
|
88
|
+
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
if (pages.length > 0) {
|
|
92
|
+
md += `---
|
|
93
|
+
|
|
94
|
+
## Pages
|
|
95
|
+
|
|
96
|
+
Page-specific scripts only load when URL matches these patterns:
|
|
97
|
+
|
|
98
|
+
`;
|
|
99
|
+
for (const page of pages) {
|
|
100
|
+
md += `- **${page.name}** (\`${page.slug}\`) \u2192 \`${page.patterns.join("`, `")}\`
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
md += `
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
const pageSpecificScripts = scripts.filter(
|
|
107
|
+
(s) => s.scope === "page-specific" && s.pageAssignments && s.pageAssignments.length > 0
|
|
108
|
+
);
|
|
109
|
+
if (pageSpecificScripts.length > 0) {
|
|
110
|
+
md += `---
|
|
111
|
+
|
|
112
|
+
## Script \u2192 Page Assignments
|
|
113
|
+
|
|
114
|
+
| Script | Pages |
|
|
115
|
+
|--------|-------|
|
|
116
|
+
`;
|
|
117
|
+
for (const script of pageSpecificScripts) {
|
|
118
|
+
const pageList = script.pageAssignments.map((pa) => {
|
|
119
|
+
const page = pages.find((p) => p.slug === pa.pageSlug);
|
|
120
|
+
const patterns = page ? ` (\`${page.patterns.join("`, `")}\`)` : "";
|
|
121
|
+
return `\`${pa.pageSlug}\`${patterns}`;
|
|
122
|
+
}).join(", ");
|
|
123
|
+
md += `| \`${script.slug}\` | ${pageList} |
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
md += `
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
md += `---
|
|
130
|
+
|
|
131
|
+
## Workflow
|
|
132
|
+
|
|
133
|
+
**Before making changes:**
|
|
134
|
+
\`\`\`bash
|
|
135
|
+
kode pull # Get latest scripts, modules, packages, and CMS types
|
|
136
|
+
\`\`\`
|
|
137
|
+
|
|
138
|
+
**After making changes:**
|
|
139
|
+
\`\`\`bash
|
|
140
|
+
kode push # Upload scripts + module files (auto-bundles TS/React)
|
|
141
|
+
kode deploy # Deploy to staging
|
|
142
|
+
kode deploy --promote # When ready, promote to production
|
|
143
|
+
\`\`\`
|
|
144
|
+
|
|
145
|
+
**Packages:**
|
|
146
|
+
\`\`\`bash
|
|
147
|
+
kode pkg list # Browse available packages
|
|
148
|
+
kode pkg add <name> # Install a package
|
|
149
|
+
kode pkg remove <name> # Remove a package
|
|
150
|
+
kode pkg publish --path <path> --slug <name> --description "..." # Publish
|
|
151
|
+
\`\`\`
|
|
152
|
+
|
|
153
|
+
**CMS Types:**
|
|
154
|
+
\`\`\`bash
|
|
155
|
+
kode types # Regenerate CMS types from Webflow (also runs on pull/init)
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## CLI Commands
|
|
161
|
+
|
|
162
|
+
| Command | Description |
|
|
163
|
+
|---------|-------------|
|
|
164
|
+
| \`kode init\` | Setup project (use \`--dev\` for localhost) |
|
|
165
|
+
| \`kode pull\` | Download scripts, modules, packages, CMS types |
|
|
166
|
+
| \`kode push\` | Upload changes (bundles .ts/.tsx/.jsx with esbuild) |
|
|
167
|
+
| \`kode deploy\` | Deploy to staging |
|
|
168
|
+
| \`kode deploy --promote\` | Promote staging to production |
|
|
169
|
+
| \`kode types\` | Regenerate CMS types from Webflow |
|
|
170
|
+
| \`kode pkg list\` | List available packages |
|
|
171
|
+
| \`kode pkg add <slug>\` | Install package |
|
|
172
|
+
| \`kode pkg remove <slug>\` | Remove package |
|
|
173
|
+
| \`kode pkg publish\` | Publish package to registry |
|
|
174
|
+
| \`kode status\` | Show sync status |
|
|
175
|
+
| \`kode diff <script>\` | Compare local vs remote |
|
|
176
|
+
| \`kode doctor\` | Check config and CLI version |
|
|
177
|
+
| \`kode pages\` | Manage CDN pages |
|
|
178
|
+
| \`kode library\` | Legacy snippet library |
|
|
179
|
+
|
|
180
|
+
## Supported File Types
|
|
181
|
+
|
|
182
|
+
| Extension | Bundled | React | Description |
|
|
183
|
+
|-----------|---------|-------|-------------|
|
|
184
|
+
| \`.js\` | No | No | Plain JavaScript (passthrough) |
|
|
185
|
+
| \`.css\` | No | No | Plain CSS (passthrough) |
|
|
186
|
+
| \`.ts\` | Yes | No | TypeScript |
|
|
187
|
+
| \`.tsx\` | Yes | Yes | TypeScript + React (auto-loads React CDN) |
|
|
188
|
+
| \`.jsx\` | Yes | Yes | JavaScript + React (auto-loads React CDN) |
|
|
189
|
+
|
|
190
|
+
## MCP Tools
|
|
191
|
+
|
|
192
|
+
AI agents can use these tools directly:
|
|
193
|
+
|
|
194
|
+
- \`kode_list_scripts\` - List all scripts
|
|
195
|
+
- \`kode_push\` - Upload local files (bundles TS/React)
|
|
196
|
+
- \`kode_deploy\` / \`kode_promote\` - Deploy to staging/production
|
|
197
|
+
- \`kode_pkg\` - Package manager (add, remove, publish, list, info, update)
|
|
198
|
+
- \`kode_create_page\` - Create CDN page with URL patterns
|
|
199
|
+
- \`kode_assign_script_to_page\` - Assign script to page
|
|
200
|
+
- \`kode_library_list\` - Browse legacy snippet library
|
|
201
|
+
|
|
202
|
+
## File Structure
|
|
203
|
+
|
|
204
|
+
\`\`\`
|
|
205
|
+
.cure-kode/
|
|
206
|
+
\u251C\u2500\u2500 config.json # Site configuration (contains API key - gitignored)
|
|
207
|
+
\u251C\u2500\u2500 scripts.json # Sync state for conflict detection
|
|
208
|
+
\u251C\u2500\u2500 context.md # Dynamic context for AI agents
|
|
209
|
+
\u2514\u2500\u2500 KODE.md # This file - auto-generated docs
|
|
210
|
+
|
|
211
|
+
.cure-kode-scripts/
|
|
212
|
+
\u251C\u2500\u2500 counter.tsx # Entry point (deployed, bundled with esbuild + React)
|
|
213
|
+
\u251C\u2500\u2500 form-handler.js # Entry point (deployed, plain JS passthrough)
|
|
214
|
+
\u251C\u2500\u2500 styles.css # Entry point (deployed, plain CSS)
|
|
215
|
+
\u251C\u2500\u2500 components/ # Modules (bundled into entry points, never deployed)
|
|
216
|
+
\u2502 \u2514\u2500\u2500 Button.tsx
|
|
217
|
+
\u251C\u2500\u2500 lib/ # Modules
|
|
218
|
+
\u2502 \u2514\u2500\u2500 utils.ts
|
|
219
|
+
\u251C\u2500\u2500 packages/@kode/ # Installed packages (import via @kode/<name>)
|
|
220
|
+
\u2502 \u251C\u2500\u2500 greet/
|
|
221
|
+
\u2502 \u2514\u2500\u2500 webflow/ # Auto-generated CMS helper
|
|
222
|
+
\u2514\u2500\u2500 types/
|
|
223
|
+
\u2514\u2500\u2500 cms.d.ts # Auto-generated Webflow CMS types
|
|
224
|
+
|
|
225
|
+
.claude/skills/ # Claude Code skills
|
|
226
|
+
\u251C\u2500\u2500 deploy/ # /deploy \u2014 push and deploy workflow
|
|
227
|
+
\u2514\u2500\u2500 webflow-patterns/ # Auto-loaded Webflow DOM reference
|
|
228
|
+
\`\`\`
|
|
229
|
+
`;
|
|
230
|
+
return md;
|
|
231
|
+
}
|
|
232
|
+
function ensureClaudeMdReference(projectRoot) {
|
|
233
|
+
const claudeMdPath = join(projectRoot, "CLAUDE.md");
|
|
234
|
+
if (!existsSync(claudeMdPath)) {
|
|
235
|
+
writeFileSync(claudeMdPath, KODE_REFERENCE);
|
|
236
|
+
return { created: true, updated: false, skipped: false };
|
|
237
|
+
}
|
|
238
|
+
const content = readFileSync(claudeMdPath, "utf-8");
|
|
239
|
+
if (hasKodeReference(content)) {
|
|
240
|
+
return { created: false, updated: false, skipped: true };
|
|
241
|
+
}
|
|
242
|
+
const newContent = KODE_REFERENCE + content;
|
|
243
|
+
writeFileSync(claudeMdPath, newContent);
|
|
244
|
+
return { created: false, updated: true, skipped: false };
|
|
245
|
+
}
|
|
246
|
+
function updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options) {
|
|
247
|
+
const kodeMdPath = join(projectRoot, ".cure-kode", "KODE.md");
|
|
248
|
+
const existed = existsSync(kodeMdPath);
|
|
249
|
+
const content = generateKodeMd(siteName, siteSlug, scripts, pages, options);
|
|
250
|
+
writeFileSync(kodeMdPath, content);
|
|
251
|
+
return { created: !existed, updated: existed };
|
|
252
|
+
}
|
|
253
|
+
function updateKodeDocs(projectRoot, siteName, siteSlug, scripts, pages, options) {
|
|
254
|
+
const kodeMd = updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options);
|
|
255
|
+
const claudeMd = ensureClaudeMdReference(projectRoot);
|
|
256
|
+
return { kodeMd, claudeMd };
|
|
257
|
+
}
|
|
258
|
+
function scriptsToDocsFormat(scripts, pages) {
|
|
259
|
+
return scripts.map((s) => {
|
|
260
|
+
const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
|
|
261
|
+
const page = pages?.find((pg) => pg.id === p.page_id);
|
|
262
|
+
return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
|
|
263
|
+
}).filter((p) => p !== null);
|
|
264
|
+
return {
|
|
265
|
+
slug: s.slug,
|
|
266
|
+
name: s.name,
|
|
267
|
+
type: s.type,
|
|
268
|
+
scope: s.scope,
|
|
269
|
+
autoLoad: s.auto_load,
|
|
270
|
+
purpose: s.metadata?.purpose || s.description,
|
|
271
|
+
pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
function pagesToInfoFormat(pages) {
|
|
276
|
+
return pages.filter((p) => p.is_active).map((p) => ({
|
|
277
|
+
name: p.name,
|
|
278
|
+
slug: p.slug,
|
|
279
|
+
patterns: p.url_patterns
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
var updateClaudeMd = updateKodeDocs;
|
|
283
|
+
|
|
284
|
+
// src/commands/pull.ts
|
|
285
|
+
function hashContent(content) {
|
|
286
|
+
return createHash("sha256").update(content).digest("hex").substring(0, 16);
|
|
287
|
+
}
|
|
288
|
+
async function pullCommand(options) {
|
|
289
|
+
const projectRoot = findProjectRoot();
|
|
290
|
+
if (!projectRoot) {
|
|
291
|
+
console.log(chalk.red("Feil: Ikke i et Cure Kode-prosjekt."));
|
|
292
|
+
console.log(chalk.dim('Kj\xF8r "kode init" f\xF8rst.'));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const config = getProjectConfig(projectRoot);
|
|
296
|
+
if (!config) {
|
|
297
|
+
console.log(chalk.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const spinner = ora("Henter skript...").start();
|
|
301
|
+
try {
|
|
302
|
+
const client = createApiClient(config);
|
|
303
|
+
const scripts = await client.listScripts(config.siteId);
|
|
304
|
+
if (scripts.length === 0) {
|
|
305
|
+
spinner.info("Ingen skript funnet p\xE5 server.");
|
|
306
|
+
console.log(chalk.dim('\nOpprett skript i Cure App eller bruk "kode push" for \xE5 laste opp.'));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
spinner.succeed(`Fant ${scripts.length} skript`);
|
|
310
|
+
const scriptsDir = getScriptsDir(projectRoot, config);
|
|
311
|
+
if (!existsSync2(scriptsDir)) {
|
|
312
|
+
mkdirSync(scriptsDir, { recursive: true });
|
|
313
|
+
}
|
|
314
|
+
const metadataPath = join2(projectRoot, ".cure-kode", "scripts.json");
|
|
315
|
+
let existingMetadata = [];
|
|
316
|
+
if (existsSync2(metadataPath)) {
|
|
317
|
+
try {
|
|
318
|
+
existingMetadata = JSON.parse(readFileSync2(metadataPath, "utf-8"));
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const scriptsToPull = options.script ? scripts.filter((s) => s.slug === options.script || s.name === options.script) : scripts;
|
|
323
|
+
if (options.script && scriptsToPull.length === 0) {
|
|
324
|
+
console.log(chalk.yellow(`
|
|
325
|
+
Fant ikke skript "${options.script}".`));
|
|
326
|
+
console.log(chalk.dim("Tilgjengelige skript:"));
|
|
327
|
+
scripts.forEach((s) => {
|
|
328
|
+
console.log(chalk.dim(` - ${s.slug} (${s.name})`));
|
|
329
|
+
});
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
console.log();
|
|
333
|
+
let pulled = 0;
|
|
334
|
+
let skipped = 0;
|
|
335
|
+
let updated = 0;
|
|
336
|
+
for (const script of scriptsToPull) {
|
|
337
|
+
const hasSource = script.source_type && script.source_content;
|
|
338
|
+
const ext = hasSource ? script.source_type : script.type === "javascript" ? "js" : "css";
|
|
339
|
+
const fileContent = hasSource ? script.source_content : script.content;
|
|
340
|
+
const fileName = `${script.slug}.${ext}`;
|
|
341
|
+
const filePath = join2(scriptsDir, fileName);
|
|
342
|
+
const existingMeta = existingMetadata.find((m) => m.slug === script.slug);
|
|
343
|
+
const lastPulledVersion = existingMeta?.lastPulledVersion || 0;
|
|
344
|
+
if (hasSource) {
|
|
345
|
+
const oldExt = script.type === "javascript" ? "js" : "css";
|
|
346
|
+
if (oldExt !== ext) {
|
|
347
|
+
const oldPath = join2(scriptsDir, `${script.slug}.${oldExt}`);
|
|
348
|
+
if (existsSync2(oldPath)) {
|
|
349
|
+
const { unlinkSync } = await import("fs");
|
|
350
|
+
unlinkSync(oldPath);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (existsSync2(filePath) && !options.force) {
|
|
355
|
+
const localContent = readFileSync2(filePath, "utf-8");
|
|
356
|
+
const localHash = hashContent(localContent);
|
|
357
|
+
const hasLocalChanges = existingMeta && localHash !== existingMeta.contentHash;
|
|
358
|
+
if (hasLocalChanges) {
|
|
359
|
+
if (script.current_version > lastPulledVersion) {
|
|
360
|
+
console.log(
|
|
361
|
+
chalk.yellow(` \u26A0 ${fileName}`) + chalk.dim(` (lokal v${lastPulledVersion} \u2192 server v${script.current_version}, konflikt)`)
|
|
362
|
+
);
|
|
363
|
+
console.log(chalk.dim(` Bruk --force for \xE5 overskrive lokale endringer`));
|
|
364
|
+
} else {
|
|
365
|
+
console.log(
|
|
366
|
+
chalk.yellow(` \u26A0 ${fileName}`) + chalk.dim(" (lokale endringer, bruk --force)")
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
skipped++;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (fileContent === localContent) {
|
|
373
|
+
console.log(chalk.dim(` \u25CB ${fileName} (ingen endringer)`));
|
|
374
|
+
skipped++;
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
writeFileSync2(filePath, fileContent);
|
|
379
|
+
const scopeTag = script.scope === "global" ? chalk.blue("[G]") : chalk.magenta("[P]");
|
|
380
|
+
const loadTag = script.auto_load ? chalk.green("\u26A1") : chalk.dim("\u25CB");
|
|
381
|
+
if (lastPulledVersion > 0 && script.current_version > lastPulledVersion) {
|
|
382
|
+
console.log(
|
|
383
|
+
chalk.green(` \u2713 ${fileName}`) + chalk.dim(` v${lastPulledVersion} \u2192 v${script.current_version}`) + ` ${scopeTag} ${loadTag}`
|
|
384
|
+
);
|
|
385
|
+
updated++;
|
|
386
|
+
} else {
|
|
387
|
+
console.log(
|
|
388
|
+
chalk.green(` \u2713 ${fileName}`) + chalk.dim(` v${script.current_version}`) + ` ${scopeTag} ${loadTag}`
|
|
389
|
+
);
|
|
390
|
+
pulled++;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
console.log();
|
|
394
|
+
if (pulled > 0) {
|
|
395
|
+
console.log(chalk.green(`Hentet ${pulled} skript til ${config.scriptsDir}/`));
|
|
396
|
+
}
|
|
397
|
+
if (updated > 0) {
|
|
398
|
+
console.log(chalk.cyan(`Oppdatert ${updated} skript med nye versjoner`));
|
|
399
|
+
}
|
|
400
|
+
if (skipped > 0) {
|
|
401
|
+
console.log(chalk.dim(`Hoppet over ${skipped} skript`));
|
|
402
|
+
}
|
|
403
|
+
let pages = [];
|
|
404
|
+
try {
|
|
405
|
+
pages = await client.listPages(config.siteId);
|
|
406
|
+
} catch {
|
|
407
|
+
}
|
|
408
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
409
|
+
const metadata = scripts.map((s) => {
|
|
410
|
+
const hasSource = s.source_type && s.source_content;
|
|
411
|
+
const localExt = hasSource ? s.source_type : s.type === "javascript" ? "js" : "css";
|
|
412
|
+
const localFileName = `${s.slug}.${localExt}`;
|
|
413
|
+
const filePath = join2(scriptsDir, localFileName);
|
|
414
|
+
const localContent = existsSync2(filePath) ? readFileSync2(filePath, "utf-8") : hasSource ? s.source_content : s.content;
|
|
415
|
+
const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
|
|
416
|
+
const page = pages.find((pg) => pg.id === p.page_id);
|
|
417
|
+
return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
|
|
418
|
+
}).filter((p) => p !== null);
|
|
419
|
+
return {
|
|
420
|
+
id: s.id,
|
|
421
|
+
slug: s.slug,
|
|
422
|
+
name: s.name,
|
|
423
|
+
type: s.type,
|
|
424
|
+
scope: s.scope,
|
|
425
|
+
autoLoad: s.auto_load,
|
|
426
|
+
version: s.current_version,
|
|
427
|
+
loadOrder: s.load_order,
|
|
428
|
+
pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
|
|
429
|
+
lastPulledVersion: s.current_version,
|
|
430
|
+
lastPulledAt: now,
|
|
431
|
+
contentHash: hashContent(localContent),
|
|
432
|
+
localFileName
|
|
433
|
+
};
|
|
434
|
+
});
|
|
435
|
+
writeFileSync2(metadataPath, JSON.stringify(metadata, null, 2));
|
|
436
|
+
try {
|
|
437
|
+
const result = updateClaudeMd(
|
|
438
|
+
projectRoot,
|
|
439
|
+
config.siteName,
|
|
440
|
+
config.siteSlug,
|
|
441
|
+
scriptsToDocsFormat(scripts, pages),
|
|
442
|
+
pagesToInfoFormat(pages)
|
|
443
|
+
);
|
|
444
|
+
if (result.kodeMd.created) {
|
|
445
|
+
console.log(chalk.green("Opprettet .cure-kode/KODE.md"));
|
|
446
|
+
} else if (result.kodeMd.updated) {
|
|
447
|
+
console.log(chalk.dim("Oppdatert .cure-kode/KODE.md"));
|
|
448
|
+
}
|
|
449
|
+
if (result.claudeMd.created) {
|
|
450
|
+
console.log(chalk.green("Opprettet CLAUDE.md med referanse"));
|
|
451
|
+
} else if (result.claudeMd.updated) {
|
|
452
|
+
console.log(chalk.dim("La til Kode-referanse i CLAUDE.md"));
|
|
453
|
+
}
|
|
454
|
+
} catch {
|
|
455
|
+
}
|
|
456
|
+
console.log(chalk.dim("\n[G]=Global [P]=Sidespesifikk \u26A1=Auto-last \u25CB=Manuell"));
|
|
457
|
+
try {
|
|
458
|
+
const projectFiles = await client.getProjectFiles(config.siteId);
|
|
459
|
+
if (projectFiles && projectFiles.length > 0) {
|
|
460
|
+
let newFiles = 0;
|
|
461
|
+
let unchangedFiles = 0;
|
|
462
|
+
for (const file of projectFiles) {
|
|
463
|
+
const filePath = join2(scriptsDir, file.path);
|
|
464
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
465
|
+
if (existsSync2(filePath)) {
|
|
466
|
+
const localHash = createHash("sha256").update(readFileSync2(filePath, "utf-8")).digest("hex");
|
|
467
|
+
if (localHash === file.contentHash) {
|
|
468
|
+
unchangedFiles++;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
writeFileSync2(filePath, file.content, "utf-8");
|
|
473
|
+
console.log(chalk.green(` + ${file.path}`));
|
|
474
|
+
newFiles++;
|
|
475
|
+
}
|
|
476
|
+
if (newFiles > 0 || unchangedFiles > 0) {
|
|
477
|
+
console.log(chalk.dim(`
|
|
478
|
+
Hentet ${newFiles} prosjektfil(er)${unchangedFiles > 0 ? `, ${unchangedFiles} uendret` : ""}`));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
} catch {
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
const { generateCmsTypes } = await import("./types-PZ7GFJEK.js");
|
|
485
|
+
await generateCmsTypes({ silent: false });
|
|
486
|
+
} catch {
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
spinner.fail("Kunne ikke hente skript");
|
|
490
|
+
console.error(chalk.red("\nFeil:"), error);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export {
|
|
495
|
+
updateKodeDocs,
|
|
496
|
+
scriptsToDocsFormat,
|
|
497
|
+
pagesToInfoFormat,
|
|
498
|
+
updateClaudeMd,
|
|
499
|
+
pullCommand
|
|
500
|
+
};
|