@curenorway/kode-cli 1.17.1 → 1.18.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 +19 -1
- package/dist/{chunk-7EPXFFNR.js → chunk-MSXS4ARI.js} +141 -3
- package/dist/cli.js +234 -1
- package/dist/index.d.ts +38 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -160,6 +160,20 @@ kode pages # List all cached pages
|
|
|
160
160
|
kode pages --json # Output as JSON
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
+
### `kode library`
|
|
164
|
+
|
|
165
|
+
Browse and use the global script library (Bibliotek). Contains reusable snippets like GSAP animations, form handlers, scroll effects.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
kode library # List all library snippets
|
|
169
|
+
kode library search "scroll" # Search by name or tags
|
|
170
|
+
kode library add gsap-scroll-reveal # Copy snippet into project
|
|
171
|
+
kode library pull # Download all as local references
|
|
172
|
+
kode library push my-script.js # Push a local script to the library
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Library snippets are reference material — they live in `.cure-kode-scripts/library/` and are never deployed. Use `kode library add` to copy a snippet into your project scripts, then adapt it.
|
|
176
|
+
|
|
163
177
|
### `kode context`
|
|
164
178
|
|
|
165
179
|
View and manage AI context.
|
|
@@ -279,7 +293,11 @@ your-project/
|
|
|
279
293
|
├── .cure-kode-scripts/ # Your scripts directory
|
|
280
294
|
│ ├── main.js
|
|
281
295
|
│ ├── form-handler.js
|
|
282
|
-
│
|
|
296
|
+
│ ├── styles.css
|
|
297
|
+
│ └── library/ # Reference only (never deployed)
|
|
298
|
+
│ ├── animations/
|
|
299
|
+
│ ├── forms/
|
|
300
|
+
│ └── utilities/
|
|
283
301
|
├── .mcp.json # MCP server configuration
|
|
284
302
|
└── CLAUDE.md # Reference to KODE.md (your content preserved)
|
|
285
303
|
```
|
|
@@ -1355,6 +1355,9 @@ kode doctor # Check for issues and CLI updates
|
|
|
1355
1355
|
| \`kode pages\` | List CDN pages |
|
|
1356
1356
|
| \`kode pages create <name> -p /path\` | Create a page with URL patterns |
|
|
1357
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 |
|
|
1358
1361
|
|
|
1359
1362
|
## MCP Tools
|
|
1360
1363
|
|
|
@@ -1365,6 +1368,9 @@ AI agents can use these tools directly:
|
|
|
1365
1368
|
- \`kode_deploy\` / \`kode_promote\` - Deploy to staging/production
|
|
1366
1369
|
- \`kode_create_page\` - Create CDN page with URL patterns
|
|
1367
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
|
|
1368
1374
|
|
|
1369
1375
|
## File Structure
|
|
1370
1376
|
|
|
@@ -1378,7 +1384,10 @@ AI agents can use these tools directly:
|
|
|
1378
1384
|
.cure-kode-scripts/ # Your script files
|
|
1379
1385
|
\u251C\u2500\u2500 main.js
|
|
1380
1386
|
\u251C\u2500\u2500 form-handler.js
|
|
1381
|
-
\u2514\u2500\u2500
|
|
1387
|
+
\u2514\u2500\u2500 library/ # Reference only (never deployed)
|
|
1388
|
+
\u251C\u2500\u2500 animations/
|
|
1389
|
+
\u251C\u2500\u2500 forms/
|
|
1390
|
+
\u2514\u2500\u2500 utilities/
|
|
1382
1391
|
|
|
1383
1392
|
.claude/skills/ # Claude Code skills
|
|
1384
1393
|
\u251C\u2500\u2500 deploy/ # /deploy \u2014 push and deploy workflow
|
|
@@ -1455,6 +1464,15 @@ function generateSkills(projectRoot, siteSlug) {
|
|
|
1455
1464
|
} else {
|
|
1456
1465
|
skipped.push("deploy");
|
|
1457
1466
|
}
|
|
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);
|
|
1472
|
+
created.push("library");
|
|
1473
|
+
} else {
|
|
1474
|
+
skipped.push("library");
|
|
1475
|
+
}
|
|
1458
1476
|
const webflowDir = join4(skillsDir, "webflow-patterns");
|
|
1459
1477
|
const webflowSkillPath = join4(webflowDir, "SKILL.md");
|
|
1460
1478
|
const webflowRefPath = join4(webflowDir, "reference.md");
|
|
@@ -1565,6 +1583,68 @@ See [reference.md](reference.md) for:
|
|
|
1565
1583
|
- Animation and interaction scripting
|
|
1566
1584
|
- Cure Kode script loading and execution order
|
|
1567
1585
|
`;
|
|
1586
|
+
var LIBRARY_SKILL = `---
|
|
1587
|
+
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.
|
|
1589
|
+
user-invocable: false
|
|
1590
|
+
---
|
|
1591
|
+
|
|
1592
|
+
# Cure Kode Library (Bibliotek)
|
|
1593
|
+
|
|
1594
|
+
Before writing common JavaScript/CSS patterns, check if the global library already has a reusable snippet.
|
|
1595
|
+
|
|
1596
|
+
## Workflow
|
|
1597
|
+
|
|
1598
|
+
### 1. Browse available snippets
|
|
1599
|
+
|
|
1600
|
+
\`\`\`
|
|
1601
|
+
kode library list
|
|
1602
|
+
\`\`\`
|
|
1603
|
+
|
|
1604
|
+
Or search for a specific pattern:
|
|
1605
|
+
|
|
1606
|
+
\`\`\`
|
|
1607
|
+
kode library search "scroll"
|
|
1608
|
+
\`\`\`
|
|
1609
|
+
|
|
1610
|
+
Via MCP: use \`kode_library_list\` or \`kode_library_get\`.
|
|
1611
|
+
|
|
1612
|
+
### 2. Copy and adapt
|
|
1613
|
+
|
|
1614
|
+
**Direct copy** (for utilities that don't need changes):
|
|
1615
|
+
\`\`\`
|
|
1616
|
+
kode library add debounce-throttle
|
|
1617
|
+
kode push
|
|
1618
|
+
\`\`\`
|
|
1619
|
+
|
|
1620
|
+
**Copy-and-adapt** (for patterns that need project-specific selectors):
|
|
1621
|
+
1. Read the snippet: \`kode library search gsap\`
|
|
1622
|
+
2. Copy it: \`kode library add gsap-scroll-reveal\`
|
|
1623
|
+
3. Edit the local file \u2014 update CSS selectors, classes, timing
|
|
1624
|
+
4. Push: \`kode push\`
|
|
1625
|
+
|
|
1626
|
+
### 3. Contribute back
|
|
1627
|
+
|
|
1628
|
+
If you improve a library snippet or create a reusable pattern:
|
|
1629
|
+
\`\`\`
|
|
1630
|
+
kode library push my-improved-script.js
|
|
1631
|
+
\`\`\`
|
|
1632
|
+
|
|
1633
|
+
## Categories
|
|
1634
|
+
|
|
1635
|
+
| Category | Content |
|
|
1636
|
+
|----------|---------|
|
|
1637
|
+
| \`animations\` | GSAP scroll reveals, smooth scrolling, parallax, counters |
|
|
1638
|
+
| \`forms\` | Form validation, multi-step forms, Webflow form intercept |
|
|
1639
|
+
| \`utilities\` | Debounce/throttle, viewport detection, cookie helpers |
|
|
1640
|
+
| \`tracking\` | Event tracking, scroll depth, click maps |
|
|
1641
|
+
| \`integrations\` | Third-party widget loaders, API connectors |
|
|
1642
|
+
|
|
1643
|
+
## Local reference files
|
|
1644
|
+
|
|
1645
|
+
Library snippets are downloaded to \`.cure-kode-scripts/library/\` during \`kode init\`.
|
|
1646
|
+
These are **reference only** \u2014 they are never deployed. Only files in the root of \`.cure-kode-scripts/\` are pushed.
|
|
1647
|
+
`;
|
|
1568
1648
|
var WEBFLOW_REFERENCE = `# Webflow Patterns \u2014 Detailed Reference
|
|
1569
1649
|
|
|
1570
1650
|
## CMS Collection Lists
|
|
@@ -2019,6 +2099,44 @@ config.json
|
|
|
2019
2099
|
const contextMdContent = generateInitialContext(config, scripts, siteInfo);
|
|
2020
2100
|
writeFileSync5(join5(cwd, ".cure-kode", "context.md"), contextMdContent);
|
|
2021
2101
|
spinner.succeed("AI-dokumentasjon generert");
|
|
2102
|
+
spinner.start("Laster ned bibliotek-referanser...");
|
|
2103
|
+
try {
|
|
2104
|
+
const libResponse = await fetch("https://app.cure.no/api/cdn/library", {
|
|
2105
|
+
headers: { "X-API-Key": apiKey }
|
|
2106
|
+
});
|
|
2107
|
+
if (libResponse.ok) {
|
|
2108
|
+
const libSnippets = await libResponse.json();
|
|
2109
|
+
if (libSnippets.length > 0) {
|
|
2110
|
+
const { existsSync: exists, mkdirSync: mkDir, writeFileSync: writeFile } = await import("fs");
|
|
2111
|
+
const { join: joinPath } = await import("path");
|
|
2112
|
+
const libDir = joinPath(scriptsPath, "library");
|
|
2113
|
+
let downloaded = 0;
|
|
2114
|
+
for (const s of libSnippets) {
|
|
2115
|
+
const catDir = joinPath(libDir, s.category || "other");
|
|
2116
|
+
if (!exists(catDir)) mkDir(catDir, { recursive: true });
|
|
2117
|
+
const ext = s.type === "javascript" ? "js" : "css";
|
|
2118
|
+
try {
|
|
2119
|
+
const snippetRes = await fetch(`https://app.cure.no/api/cdn/library/${s.slug}`, {
|
|
2120
|
+
headers: { "X-API-Key": apiKey }
|
|
2121
|
+
});
|
|
2122
|
+
if (snippetRes.ok) {
|
|
2123
|
+
const full = await snippetRes.json();
|
|
2124
|
+
writeFile(joinPath(catDir, `${s.slug}.${ext}`), full.code);
|
|
2125
|
+
downloaded++;
|
|
2126
|
+
}
|
|
2127
|
+
} catch {
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
spinner.succeed(`${downloaded} bibliotek-referanser lastet ned`);
|
|
2131
|
+
} else {
|
|
2132
|
+
spinner.succeed("Biblioteket er tomt");
|
|
2133
|
+
}
|
|
2134
|
+
} else {
|
|
2135
|
+
spinner.succeed("Bibliotek ikke tilgjengelig");
|
|
2136
|
+
}
|
|
2137
|
+
} catch {
|
|
2138
|
+
spinner.succeed("Bibliotek hoppet over");
|
|
2139
|
+
}
|
|
2022
2140
|
spinner.start("Genererer Claude Code skills...");
|
|
2023
2141
|
const skillsResult = generateSkills(cwd, config.siteSlug);
|
|
2024
2142
|
if (skillsResult.created.length > 0) {
|
|
@@ -2043,7 +2161,8 @@ config.json
|
|
|
2043
2161
|
console.log(chalk.dim(" \u251C\u2500\u2500 .mcp.json ") + chalk.green("(MCP-servere)"));
|
|
2044
2162
|
console.log(chalk.dim(" \u251C\u2500\u2500 .claude/skills/ ") + chalk.green("(Claude Code skills)"));
|
|
2045
2163
|
console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 deploy/ (/deploy \u2014 push og deploy)"));
|
|
2046
|
-
console.log(chalk.dim(" \u2502 \
|
|
2164
|
+
console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 webflow-patterns/ (Webflow DOM-referanse)"));
|
|
2165
|
+
console.log(chalk.dim(" \u2502 \u2514\u2500\u2500 library/ (Bibliotek-referanse)"));
|
|
2047
2166
|
console.log(chalk.dim(" \u251C\u2500\u2500 .cure-kode/"));
|
|
2048
2167
|
console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 config.json (konfigurasjon)"));
|
|
2049
2168
|
console.log(chalk.dim(" \u2502 \u251C\u2500\u2500 KODE.md ") + chalk.green("(Kode-dokumentasjon)"));
|
|
@@ -2365,6 +2484,25 @@ var KodeApiClient = class {
|
|
|
2365
2484
|
body: JSON.stringify({ siteId })
|
|
2366
2485
|
});
|
|
2367
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
|
+
}
|
|
2368
2506
|
// Webflow Custom Code injection
|
|
2369
2507
|
async getWebflowCustomCodeStatus(siteId) {
|
|
2370
2508
|
return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`);
|
|
@@ -2600,7 +2738,7 @@ async function pushCommand(options) {
|
|
|
2600
2738
|
}
|
|
2601
2739
|
}
|
|
2602
2740
|
const files = readdirSync(scriptsDir).filter(
|
|
2603
|
-
(f) => f.endsWith(".js") || f.endsWith(".css")
|
|
2741
|
+
(f) => (f.endsWith(".js") || f.endsWith(".css")) && f !== "library"
|
|
2604
2742
|
);
|
|
2605
2743
|
if (files.length === 0) {
|
|
2606
2744
|
console.log(chalk3.yellow("Ingen skriptfiler funnet."));
|
package/dist/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
updateClaudeMd,
|
|
24
24
|
updateKodeDocs,
|
|
25
25
|
watchCommand
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-MSXS4ARI.js";
|
|
27
27
|
|
|
28
28
|
// src/cli.ts
|
|
29
29
|
import { Command } from "commander";
|
|
@@ -1787,6 +1787,223 @@ async function webflowStatusCommand() {
|
|
|
1787
1787
|
}
|
|
1788
1788
|
}
|
|
1789
1789
|
|
|
1790
|
+
// src/commands/library.ts
|
|
1791
|
+
import chalk12 from "chalk";
|
|
1792
|
+
import ora8 from "ora";
|
|
1793
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
1794
|
+
import { join as join5, basename as basename2, extname as extname2 } from "path";
|
|
1795
|
+
async function libraryListCommand(options) {
|
|
1796
|
+
const projectRoot = findProjectRoot();
|
|
1797
|
+
if (!projectRoot) {
|
|
1798
|
+
console.log(chalk12.red('Feil: Ikke i et Cure Kode-prosjekt. Kj\xF8r "kode init" f\xF8rst.'));
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
const config = getProjectConfig(projectRoot);
|
|
1802
|
+
if (!config) {
|
|
1803
|
+
console.log(chalk12.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
1804
|
+
return;
|
|
1805
|
+
}
|
|
1806
|
+
const spinner = ora8("Henter bibliotek...").start();
|
|
1807
|
+
try {
|
|
1808
|
+
const client = createApiClient(config);
|
|
1809
|
+
const snippets = await client.listLibrary();
|
|
1810
|
+
spinner.stop();
|
|
1811
|
+
if (snippets.length === 0) {
|
|
1812
|
+
console.log(chalk12.dim("Biblioteket er tomt."));
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
if (options.json) {
|
|
1816
|
+
console.log(JSON.stringify(snippets, null, 2));
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
console.log();
|
|
1820
|
+
console.log(chalk12.bold(` Bibliotek (${snippets.length} snippets)`));
|
|
1821
|
+
console.log();
|
|
1822
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1823
|
+
for (const s of snippets) {
|
|
1824
|
+
const cat = s.category || "other";
|
|
1825
|
+
if (!grouped.has(cat)) grouped.set(cat, []);
|
|
1826
|
+
grouped.get(cat).push(s);
|
|
1827
|
+
}
|
|
1828
|
+
for (const [category, items] of grouped) {
|
|
1829
|
+
console.log(chalk12.dim(` ${category}/`));
|
|
1830
|
+
for (const s of items) {
|
|
1831
|
+
const typeLabel = s.type === "javascript" ? chalk12.yellow("JS") : chalk12.blue("CSS");
|
|
1832
|
+
const tags = s.tags.length > 0 ? chalk12.dim(` [${s.tags.join(", ")}]`) : "";
|
|
1833
|
+
console.log(` ${typeLabel} ${s.name}${chalk12.dim(` v${s.version}`)}${tags}`);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
console.log();
|
|
1837
|
+
} catch (error) {
|
|
1838
|
+
spinner.fail("Kunne ikke hente bibliotek");
|
|
1839
|
+
console.error(chalk12.red("Feil:"), error);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
async function librarySearchCommand(query) {
|
|
1843
|
+
const projectRoot = findProjectRoot();
|
|
1844
|
+
if (!projectRoot) {
|
|
1845
|
+
console.log(chalk12.red('Feil: Ikke i et Cure Kode-prosjekt. Kj\xF8r "kode init" f\xF8rst.'));
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
const config = getProjectConfig(projectRoot);
|
|
1849
|
+
if (!config) {
|
|
1850
|
+
console.log(chalk12.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
const spinner = ora8(`S\xF8ker etter "${query}"...`).start();
|
|
1854
|
+
try {
|
|
1855
|
+
const client = createApiClient(config);
|
|
1856
|
+
const snippets = await client.listLibrary(query);
|
|
1857
|
+
spinner.stop();
|
|
1858
|
+
if (snippets.length === 0) {
|
|
1859
|
+
console.log(chalk12.dim(`Ingen treff for "${query}".`));
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
console.log();
|
|
1863
|
+
console.log(chalk12.bold(` ${snippets.length} treff for "${query}"`));
|
|
1864
|
+
console.log();
|
|
1865
|
+
for (const s of snippets) {
|
|
1866
|
+
const typeLabel = s.type === "javascript" ? chalk12.yellow("JS") : chalk12.blue("CSS");
|
|
1867
|
+
const desc = s.description ? chalk12.dim(` \u2014 ${s.description}`) : "";
|
|
1868
|
+
console.log(` ${typeLabel} ${s.name}${chalk12.dim(` v${s.version}`)}${desc}`);
|
|
1869
|
+
}
|
|
1870
|
+
console.log();
|
|
1871
|
+
} catch (error) {
|
|
1872
|
+
spinner.fail("S\xF8k feilet");
|
|
1873
|
+
console.error(chalk12.red("Feil:"), error);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
async function libraryAddCommand(slug) {
|
|
1877
|
+
const projectRoot = findProjectRoot();
|
|
1878
|
+
if (!projectRoot) {
|
|
1879
|
+
console.log(chalk12.red('Feil: Ikke i et Cure Kode-prosjekt. Kj\xF8r "kode init" f\xF8rst.'));
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const config = getProjectConfig(projectRoot);
|
|
1883
|
+
if (!config) {
|
|
1884
|
+
console.log(chalk12.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
const spinner = ora8(`Henter snippet "${slug}"...`).start();
|
|
1888
|
+
try {
|
|
1889
|
+
const client = createApiClient(config);
|
|
1890
|
+
const snippet = await client.getLibrarySnippet(slug);
|
|
1891
|
+
const ext = snippet.type === "javascript" ? "js" : "css";
|
|
1892
|
+
const scriptsDir = getScriptsDir(projectRoot, config);
|
|
1893
|
+
if (!existsSync5(scriptsDir)) {
|
|
1894
|
+
mkdirSync2(scriptsDir, { recursive: true });
|
|
1895
|
+
}
|
|
1896
|
+
const filePath = join5(scriptsDir, `${snippet.slug}.${ext}`);
|
|
1897
|
+
if (existsSync5(filePath)) {
|
|
1898
|
+
spinner.fail(`Filen finnes allerede: ${snippet.slug}.${ext}`);
|
|
1899
|
+
console.log(chalk12.dim("Slett den f\xF8rst eller bruk et annet navn."));
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
writeFileSync3(filePath, snippet.code);
|
|
1903
|
+
try {
|
|
1904
|
+
await client.recordLibraryUsage(snippet.id);
|
|
1905
|
+
} catch {
|
|
1906
|
+
}
|
|
1907
|
+
spinner.succeed(chalk12.green(`${snippet.slug}.${ext}`) + chalk12.dim(` \u2190 ${snippet.name}`));
|
|
1908
|
+
console.log();
|
|
1909
|
+
console.log(chalk12.dim(" Filen er kopiert til prosjektet ditt."));
|
|
1910
|
+
console.log(chalk12.dim(" Kj\xF8r ") + chalk12.cyan("kode push") + chalk12.dim(" for \xE5 laste opp til CDN."));
|
|
1911
|
+
console.log();
|
|
1912
|
+
} catch (error) {
|
|
1913
|
+
spinner.fail(`Fant ikke snippet "${slug}"`);
|
|
1914
|
+
console.error(chalk12.red("Feil:"), error);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
async function libraryPullCommand() {
|
|
1918
|
+
const projectRoot = findProjectRoot();
|
|
1919
|
+
if (!projectRoot) {
|
|
1920
|
+
console.log(chalk12.red('Feil: Ikke i et Cure Kode-prosjekt. Kj\xF8r "kode init" f\xF8rst.'));
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const config = getProjectConfig(projectRoot);
|
|
1924
|
+
if (!config) {
|
|
1925
|
+
console.log(chalk12.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
const spinner = ora8("Henter bibliotek...").start();
|
|
1929
|
+
try {
|
|
1930
|
+
const client = createApiClient(config);
|
|
1931
|
+
const snippets = await client.listLibrary();
|
|
1932
|
+
if (snippets.length === 0) {
|
|
1933
|
+
spinner.succeed("Biblioteket er tomt \u2014 ingenting \xE5 laste ned.");
|
|
1934
|
+
return;
|
|
1935
|
+
}
|
|
1936
|
+
const scriptsDir = getScriptsDir(projectRoot, config);
|
|
1937
|
+
const libraryDir = join5(scriptsDir, "library");
|
|
1938
|
+
let downloaded = 0;
|
|
1939
|
+
for (const s of snippets) {
|
|
1940
|
+
const categoryDir = join5(libraryDir, s.category || "other");
|
|
1941
|
+
if (!existsSync5(categoryDir)) {
|
|
1942
|
+
mkdirSync2(categoryDir, { recursive: true });
|
|
1943
|
+
}
|
|
1944
|
+
const ext = s.type === "javascript" ? "js" : "css";
|
|
1945
|
+
const filePath = join5(categoryDir, `${s.slug}.${ext}`);
|
|
1946
|
+
try {
|
|
1947
|
+
const full = await client.getLibrarySnippet(s.slug);
|
|
1948
|
+
writeFileSync3(filePath, full.code);
|
|
1949
|
+
downloaded++;
|
|
1950
|
+
} catch {
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
spinner.succeed(`Lastet ned ${downloaded} snippets til ${chalk12.dim("library/")}`);
|
|
1954
|
+
console.log(chalk12.dim(" Disse filene er kun referanse \u2014 de deployes ikke."));
|
|
1955
|
+
console.log();
|
|
1956
|
+
} catch (error) {
|
|
1957
|
+
spinner.fail("Kunne ikke laste ned bibliotek");
|
|
1958
|
+
console.error(chalk12.red("Feil:"), error);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
async function libraryPushCommand(file) {
|
|
1962
|
+
const projectRoot = findProjectRoot();
|
|
1963
|
+
if (!projectRoot) {
|
|
1964
|
+
console.log(chalk12.red('Feil: Ikke i et Cure Kode-prosjekt. Kj\xF8r "kode init" f\xF8rst.'));
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
const config = getProjectConfig(projectRoot);
|
|
1968
|
+
if (!config) {
|
|
1969
|
+
console.log(chalk12.red("Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
const scriptsDir = getScriptsDir(projectRoot, config);
|
|
1973
|
+
const filePath = existsSync5(file) ? file : join5(scriptsDir, file);
|
|
1974
|
+
if (!existsSync5(filePath)) {
|
|
1975
|
+
console.log(chalk12.red(`Filen finnes ikke: ${file}`));
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
1979
|
+
const name = basename2(file, extname2(file));
|
|
1980
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1981
|
+
const type = extname2(filePath) === ".css" ? "css" : "javascript";
|
|
1982
|
+
console.log();
|
|
1983
|
+
console.log(chalk12.bold(" Push til globalt bibliotek"));
|
|
1984
|
+
console.log();
|
|
1985
|
+
console.log(chalk12.dim(` Fil: ${basename2(filePath)}`));
|
|
1986
|
+
console.log(chalk12.dim(` Slug: ${slug}`));
|
|
1987
|
+
console.log(chalk12.dim(` Type: ${type}`));
|
|
1988
|
+
console.log(chalk12.dim(` St\xF8rrelse: ${content.length} tegn`));
|
|
1989
|
+
console.log();
|
|
1990
|
+
const spinner = ora8("Laster opp til bibliotek...").start();
|
|
1991
|
+
try {
|
|
1992
|
+
const client = createApiClient(config);
|
|
1993
|
+
await client.createLibrarySnippet({
|
|
1994
|
+
name: name.charAt(0).toUpperCase() + name.slice(1).replace(/-/g, " "),
|
|
1995
|
+
slug,
|
|
1996
|
+
type,
|
|
1997
|
+
code: content
|
|
1998
|
+
});
|
|
1999
|
+
spinner.succeed(chalk12.green(`"${name}" lagt til i biblioteket`));
|
|
2000
|
+
console.log();
|
|
2001
|
+
} catch (error) {
|
|
2002
|
+
spinner.fail("Kunne ikke laste opp til bibliotek");
|
|
2003
|
+
console.error(chalk12.red("Feil:"), error?.message || error);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1790
2007
|
// src/cli.ts
|
|
1791
2008
|
var program = new Command();
|
|
1792
2009
|
program.name("kode").description("CLI for Cure Kode - manage JS/CSS scripts for Webflow sites").version(CLI_VERSION);
|
|
@@ -1876,6 +2093,22 @@ webflowCmd.command("remove").description("Remove Cure Kode init.js from Webflow"
|
|
|
1876
2093
|
webflowCmd.command("status", { isDefault: true }).description("Show current Webflow injection status").action(() => {
|
|
1877
2094
|
webflowStatusCommand();
|
|
1878
2095
|
});
|
|
2096
|
+
var libraryCmd = program.command("library").description("Browse and use the global script library (Bibliotek)");
|
|
2097
|
+
libraryCmd.command("list", { isDefault: true }).description("List all library snippets").option("-j, --json", "Output as JSON").action((options) => {
|
|
2098
|
+
libraryListCommand(options);
|
|
2099
|
+
});
|
|
2100
|
+
libraryCmd.command("search <query>").description("Search library by name or tags").action((query) => {
|
|
2101
|
+
librarySearchCommand(query);
|
|
2102
|
+
});
|
|
2103
|
+
libraryCmd.command("add <slug>").description("Copy a library snippet into your project scripts").action((slug) => {
|
|
2104
|
+
libraryAddCommand(slug);
|
|
2105
|
+
});
|
|
2106
|
+
libraryCmd.command("pull").description("Download all library snippets as local references").action(() => {
|
|
2107
|
+
libraryPullCommand();
|
|
2108
|
+
});
|
|
2109
|
+
libraryCmd.command("push <file>").description("Push a local script to the global library").action((file) => {
|
|
2110
|
+
libraryPushCommand(file);
|
|
2111
|
+
});
|
|
1879
2112
|
program.command("doctor").description("Diagnose configuration and environment issues").action(() => {
|
|
1880
2113
|
doctorCommand();
|
|
1881
2114
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -240,6 +240,44 @@ declare class KodeApiClient {
|
|
|
240
240
|
acquiredAt?: string;
|
|
241
241
|
duration_ms?: number;
|
|
242
242
|
}>;
|
|
243
|
+
listLibrary(search?: string): Promise<Array<{
|
|
244
|
+
id: string;
|
|
245
|
+
name: string;
|
|
246
|
+
slug: string;
|
|
247
|
+
description: string | null;
|
|
248
|
+
type: 'javascript' | 'css';
|
|
249
|
+
category: string | null;
|
|
250
|
+
tags: string[];
|
|
251
|
+
version: number;
|
|
252
|
+
usage_count: number;
|
|
253
|
+
}>>;
|
|
254
|
+
getLibrarySnippet(slugOrId: string): Promise<{
|
|
255
|
+
id: string;
|
|
256
|
+
name: string;
|
|
257
|
+
slug: string;
|
|
258
|
+
description: string | null;
|
|
259
|
+
type: 'javascript' | 'css';
|
|
260
|
+
code: string;
|
|
261
|
+
category: string | null;
|
|
262
|
+
tags: string[];
|
|
263
|
+
version: number;
|
|
264
|
+
usage_count: number;
|
|
265
|
+
example_usage: string | null;
|
|
266
|
+
}>;
|
|
267
|
+
createLibrarySnippet(data: {
|
|
268
|
+
name: string;
|
|
269
|
+
slug: string;
|
|
270
|
+
type: 'javascript' | 'css';
|
|
271
|
+
code: string;
|
|
272
|
+
description?: string;
|
|
273
|
+
category?: string;
|
|
274
|
+
tags?: string[];
|
|
275
|
+
exampleUsage?: string;
|
|
276
|
+
}): Promise<{
|
|
277
|
+
id: string;
|
|
278
|
+
slug: string;
|
|
279
|
+
}>;
|
|
280
|
+
recordLibraryUsage(snippetId: string): Promise<void>;
|
|
243
281
|
getWebflowCustomCodeStatus(siteId: string): Promise<{
|
|
244
282
|
injected: boolean;
|
|
245
283
|
scriptId: string | null;
|
package/dist/index.js
CHANGED