@curenorway/kode-cli 1.13.0 → 1.15.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/dist/{chunk-C2BM7IJ6.js → chunk-E7DFDYOS.js} +281 -15
- package/dist/cli.js +202 -4
- package/dist/index.d.ts +31 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
|
@@ -1201,7 +1201,7 @@ Option C: Full rollback
|
|
|
1201
1201
|
}
|
|
1202
1202
|
|
|
1203
1203
|
// src/version.ts
|
|
1204
|
-
var CLI_VERSION = "1.
|
|
1204
|
+
var CLI_VERSION = "1.13.0";
|
|
1205
1205
|
|
|
1206
1206
|
// src/commands/init.ts
|
|
1207
1207
|
import chalk from "chalk";
|
|
@@ -1229,13 +1229,16 @@ Full documentation: [.cure-kode/KODE.md](.cure-kode/KODE.md)
|
|
|
1229
1229
|
function hasKodeReference(content) {
|
|
1230
1230
|
return content.includes(".cure-kode/KODE.md") || content.includes("cure-kode/KODE.md") || content.includes("KODE.md");
|
|
1231
1231
|
}
|
|
1232
|
-
function generateKodeMd(siteName, siteSlug, scripts, pages) {
|
|
1232
|
+
function generateKodeMd(siteName, siteSlug, scripts, pages, options) {
|
|
1233
|
+
const productionEnabled = options?.productionEnabled ?? false;
|
|
1233
1234
|
let md = `# Cure Kode: ${siteName}
|
|
1234
1235
|
|
|
1235
1236
|
This project uses **Cure Kode** CDN for JavaScript/CSS delivery to Webflow.
|
|
1236
1237
|
|
|
1237
1238
|
> **This file is auto-generated.** Do not edit manually - changes will be overwritten by \`kode pull\`, \`kode push\`, and \`kode sync\`.
|
|
1238
1239
|
|
|
1240
|
+
**Produksjon:** ${productionEnabled ? "\u2713 Aktivert \u2014 deploy til staging og produksjon" : "\u25CB Deaktivert \u2014 kun staging. Ikke hent fra produksjons-URL."}
|
|
1241
|
+
|
|
1239
1242
|
---
|
|
1240
1243
|
|
|
1241
1244
|
`;
|
|
@@ -1394,15 +1397,15 @@ function ensureClaudeMdReference(projectRoot) {
|
|
|
1394
1397
|
writeFileSync3(claudeMdPath, newContent);
|
|
1395
1398
|
return { created: false, updated: true, skipped: false };
|
|
1396
1399
|
}
|
|
1397
|
-
function updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages) {
|
|
1400
|
+
function updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options) {
|
|
1398
1401
|
const kodeMdPath = join3(projectRoot, ".cure-kode", "KODE.md");
|
|
1399
1402
|
const existed = existsSync3(kodeMdPath);
|
|
1400
|
-
const content = generateKodeMd(siteName, siteSlug, scripts, pages);
|
|
1403
|
+
const content = generateKodeMd(siteName, siteSlug, scripts, pages, options);
|
|
1401
1404
|
writeFileSync3(kodeMdPath, content);
|
|
1402
1405
|
return { created: !existed, updated: existed };
|
|
1403
1406
|
}
|
|
1404
|
-
function updateKodeDocs(projectRoot, siteName, siteSlug, scripts, pages) {
|
|
1405
|
-
const kodeMd = updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages);
|
|
1407
|
+
function updateKodeDocs(projectRoot, siteName, siteSlug, scripts, pages, options) {
|
|
1408
|
+
const kodeMd = updateKodeMd(projectRoot, siteName, siteSlug, scripts, pages, options);
|
|
1406
1409
|
const claudeMd = ensureClaudeMdReference(projectRoot);
|
|
1407
1410
|
return { kodeMd, claudeMd };
|
|
1408
1411
|
}
|
|
@@ -1448,6 +1451,12 @@ function showBanner() {
|
|
|
1448
1451
|
console.log(chalk.dim(" JS/CSS delivery for Webflow sites"));
|
|
1449
1452
|
console.log();
|
|
1450
1453
|
}
|
|
1454
|
+
function showCompactBanner() {
|
|
1455
|
+
console.log();
|
|
1456
|
+
console.log(chalk.bold(" Cure Kode CLI") + chalk.dim(` v${CLI_VERSION}`));
|
|
1457
|
+
console.log(chalk.dim(" Manage JS/CSS for Webflow sites"));
|
|
1458
|
+
console.log();
|
|
1459
|
+
}
|
|
1451
1460
|
async function initCommand(options) {
|
|
1452
1461
|
const cwd = process.cwd();
|
|
1453
1462
|
showBanner();
|
|
@@ -1540,13 +1549,34 @@ async function initCommand(options) {
|
|
|
1540
1549
|
}
|
|
1541
1550
|
console.log(chalk.dim(" Webflow: ") + chalk.green("\u2713 Konfigurert"));
|
|
1542
1551
|
console.log();
|
|
1552
|
+
let projectCtx = null;
|
|
1553
|
+
try {
|
|
1554
|
+
const projResponse = await fetch(`https://app.cure.no/api/cdn/sites/${site.id}/project`, {
|
|
1555
|
+
headers: { "X-API-Key": apiKey }
|
|
1556
|
+
});
|
|
1557
|
+
if (projResponse.ok) {
|
|
1558
|
+
projectCtx = await projResponse.json();
|
|
1559
|
+
}
|
|
1560
|
+
} catch {
|
|
1561
|
+
}
|
|
1562
|
+
if (projectCtx?.project) {
|
|
1563
|
+
console.log(chalk.dim(" Prosjekt: ") + chalk.cyan(projectCtx.project.name));
|
|
1564
|
+
if (projectCtx.github_repo) {
|
|
1565
|
+
console.log(chalk.dim(" GitHub: ") + chalk.cyan(projectCtx.github_repo) + chalk.dim(` (${projectCtx.github_branch})`));
|
|
1566
|
+
}
|
|
1567
|
+
if (projectCtx.mcp_servers.length > 0) {
|
|
1568
|
+
console.log(chalk.dim(" MCP-servere: ") + chalk.cyan(`${projectCtx.mcp_servers.length} fra prosjekt`));
|
|
1569
|
+
}
|
|
1570
|
+
console.log();
|
|
1571
|
+
}
|
|
1543
1572
|
const config = {
|
|
1544
1573
|
siteId: site.id,
|
|
1545
1574
|
siteSlug: site.slug,
|
|
1546
1575
|
siteName: site.name,
|
|
1547
1576
|
apiKey,
|
|
1548
1577
|
scriptsDir: DEFAULT_SCRIPTS_DIR,
|
|
1549
|
-
environment: "staging"
|
|
1578
|
+
environment: "staging",
|
|
1579
|
+
...projectCtx?.project && { projectId: projectCtx.project.id }
|
|
1550
1580
|
};
|
|
1551
1581
|
spinner.start("Oppretter prosjektstruktur...");
|
|
1552
1582
|
saveProjectConfig(config, cwd);
|
|
@@ -1588,18 +1618,56 @@ config.json
|
|
|
1588
1618
|
command: "npx",
|
|
1589
1619
|
args: ["-y", "@playwright/mcp@^0.0.21"]
|
|
1590
1620
|
};
|
|
1621
|
+
const secretWarnings = [];
|
|
1622
|
+
if (projectCtx?.mcp_servers && projectCtx.mcp_servers.length > 0) {
|
|
1623
|
+
for (const server of projectCtx.mcp_servers) {
|
|
1624
|
+
const serverConfig = { type: server.transport };
|
|
1625
|
+
if (server.transport === "sse" && server.url) {
|
|
1626
|
+
serverConfig.url = server.url;
|
|
1627
|
+
} else if (server.transport === "stdio") {
|
|
1628
|
+
if (server.command) serverConfig.command = server.command;
|
|
1629
|
+
if (server.args) serverConfig.args = server.args;
|
|
1630
|
+
}
|
|
1631
|
+
if (server.env_vars && Object.keys(server.env_vars).length > 0) {
|
|
1632
|
+
const env = {};
|
|
1633
|
+
for (const [key, value] of Object.entries(server.env_vars)) {
|
|
1634
|
+
if (value.startsWith("$SECRET:")) {
|
|
1635
|
+
const secretKey = value.replace("$SECRET:", "");
|
|
1636
|
+
env[key] = `<SET_ME:${secretKey}>`;
|
|
1637
|
+
secretWarnings.push(`${server.name}: ${key} \u2192 hent fra hemmelighetsvelvet (${secretKey})`);
|
|
1638
|
+
} else {
|
|
1639
|
+
env[key] = value;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
serverConfig.env = env;
|
|
1643
|
+
}
|
|
1644
|
+
mcpConfig.mcpServers[server.name] = serverConfig;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1591
1647
|
writeFileSync4(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
1592
1648
|
spinner.succeed("MCP-servere konfigurert");
|
|
1649
|
+
if (secretWarnings.length > 0) {
|
|
1650
|
+
console.log();
|
|
1651
|
+
console.log(chalk.yellow(" \u26A0\uFE0F Noen MCP-servere krever hemmeligheter som m\xE5 settes lokalt:"));
|
|
1652
|
+
for (const warning of secretWarnings) {
|
|
1653
|
+
console.log(chalk.dim(` \u2022 ${warning}`));
|
|
1654
|
+
}
|
|
1655
|
+
console.log(chalk.dim(" Rediger .mcp.json og erstatt <SET_ME:...> med faktiske verdier."));
|
|
1656
|
+
}
|
|
1593
1657
|
spinner.start("Genererer AI-dokumentasjon...");
|
|
1594
1658
|
let scripts = [];
|
|
1595
1659
|
let pages = [];
|
|
1660
|
+
let productionEnabled = false;
|
|
1596
1661
|
try {
|
|
1597
|
-
const [scriptsResponse, pagesResponse] = await Promise.all([
|
|
1662
|
+
const [scriptsResponse, pagesResponse, prodResponse] = await Promise.all([
|
|
1598
1663
|
fetch(`https://app.cure.no/api/cdn/sites/${site.id}/scripts`, {
|
|
1599
1664
|
headers: { "X-API-Key": apiKey }
|
|
1600
1665
|
}),
|
|
1601
1666
|
fetch(`https://app.cure.no/api/cdn/sites/${site.id}/pages`, {
|
|
1602
1667
|
headers: { "X-API-Key": apiKey }
|
|
1668
|
+
}),
|
|
1669
|
+
fetch(`https://app.cure.no/api/cdn/sites/${site.id}/production`, {
|
|
1670
|
+
headers: { "X-API-Key": apiKey }
|
|
1603
1671
|
})
|
|
1604
1672
|
]);
|
|
1605
1673
|
if (scriptsResponse.ok) {
|
|
@@ -1608,6 +1676,10 @@ config.json
|
|
|
1608
1676
|
if (pagesResponse.ok) {
|
|
1609
1677
|
pages = await pagesResponse.json();
|
|
1610
1678
|
}
|
|
1679
|
+
if (prodResponse.ok) {
|
|
1680
|
+
const prodData = await prodResponse.json();
|
|
1681
|
+
productionEnabled = prodData.production_enabled ?? false;
|
|
1682
|
+
}
|
|
1611
1683
|
} catch {
|
|
1612
1684
|
}
|
|
1613
1685
|
const docsResult = updateKodeDocs(
|
|
@@ -1615,7 +1687,8 @@ config.json
|
|
|
1615
1687
|
config.siteName,
|
|
1616
1688
|
config.siteSlug,
|
|
1617
1689
|
scriptsToDocsFormat(scripts, pages),
|
|
1618
|
-
pagesToInfoFormat(pages)
|
|
1690
|
+
pagesToInfoFormat(pages),
|
|
1691
|
+
{ productionEnabled }
|
|
1619
1692
|
);
|
|
1620
1693
|
const siteInfo = {
|
|
1621
1694
|
domain: site.domain,
|
|
@@ -1648,11 +1721,39 @@ config.json
|
|
|
1648
1721
|
console.log(chalk.dim(` \u2514\u2500\u2500 ${DEFAULT_SCRIPTS_DIR}/`));
|
|
1649
1722
|
console.log(chalk.dim(" \u2514\u2500\u2500 (skriptene dine her)"));
|
|
1650
1723
|
console.log();
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1724
|
+
spinner.start("Legger til init.js i Webflow...");
|
|
1725
|
+
let webflowInjected = false;
|
|
1726
|
+
try {
|
|
1727
|
+
const injectResponse = await fetch(`https://app.cure.no/api/cdn/sites/${site.id}/webflow/custom-code`, {
|
|
1728
|
+
method: "POST",
|
|
1729
|
+
headers: {
|
|
1730
|
+
"Content-Type": "application/json",
|
|
1731
|
+
"X-API-Key": apiKey
|
|
1732
|
+
},
|
|
1733
|
+
body: JSON.stringify({ location: "header" })
|
|
1734
|
+
});
|
|
1735
|
+
if (injectResponse.ok) {
|
|
1736
|
+
spinner.succeed("init.js lagt til i Webflow <head>");
|
|
1737
|
+
webflowInjected = true;
|
|
1738
|
+
} else {
|
|
1739
|
+
const errData = await injectResponse.json().catch(() => ({}));
|
|
1740
|
+
spinner.warn("Kunne ikke legge til init.js automatisk");
|
|
1741
|
+
console.log(chalk.dim(` ${errData.error || "Ukjent feil"}`));
|
|
1742
|
+
}
|
|
1743
|
+
} catch {
|
|
1744
|
+
spinner.warn("Kunne ikke koble til Webflow API");
|
|
1745
|
+
}
|
|
1746
|
+
if (webflowInjected) {
|
|
1747
|
+
console.log(chalk.yellow(" OBS: Publiser Webflow-nettstedet for at skriptet skal vises."));
|
|
1748
|
+
console.log();
|
|
1749
|
+
} else {
|
|
1750
|
+
console.log(chalk.dim(" Legg til dette i Webflow <head> manuelt:"));
|
|
1751
|
+
console.log();
|
|
1752
|
+
console.log(chalk.cyan(` <script defer src="https://app.cure.no/api/cdn/${site.slug}/init.js"></script>`));
|
|
1753
|
+
console.log();
|
|
1754
|
+
console.log(chalk.dim(" Eller kjor ") + chalk.cyan("kode webflow inject") + chalk.dim(" nar du er klar."));
|
|
1755
|
+
console.log();
|
|
1756
|
+
}
|
|
1656
1757
|
console.log(chalk.bold(" Neste steg:"));
|
|
1657
1758
|
console.log();
|
|
1658
1759
|
console.log(chalk.cyan(" 1. kode pull ") + chalk.dim("Last ned eksisterende skript"));
|
|
@@ -1947,6 +2048,21 @@ var KodeApiClient = class {
|
|
|
1947
2048
|
body: JSON.stringify({ siteId })
|
|
1948
2049
|
});
|
|
1949
2050
|
}
|
|
2051
|
+
// Webflow Custom Code injection
|
|
2052
|
+
async getWebflowCustomCodeStatus(siteId) {
|
|
2053
|
+
return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`);
|
|
2054
|
+
}
|
|
2055
|
+
async injectWebflowCustomCode(siteId, location = "header") {
|
|
2056
|
+
return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`, {
|
|
2057
|
+
method: "POST",
|
|
2058
|
+
body: JSON.stringify({ location })
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
async removeWebflowCustomCode(siteId) {
|
|
2062
|
+
return this.request(`/api/cdn/sites/${siteId}/webflow/custom-code`, {
|
|
2063
|
+
method: "DELETE"
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
1950
2066
|
};
|
|
1951
2067
|
function createApiClient(config) {
|
|
1952
2068
|
return new KodeApiClient(config);
|
|
@@ -3619,6 +3735,154 @@ async function contextCommand(options) {
|
|
|
3619
3735
|
console.log(chalk8.dim("Use --edit to open in editor, --refresh to update from server"));
|
|
3620
3736
|
}
|
|
3621
3737
|
|
|
3738
|
+
// src/commands/sync-config.ts
|
|
3739
|
+
import chalk9 from "chalk";
|
|
3740
|
+
import ora8 from "ora";
|
|
3741
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
|
|
3742
|
+
import { join as join11 } from "path";
|
|
3743
|
+
async function syncConfigCommand() {
|
|
3744
|
+
const cwd = process.cwd();
|
|
3745
|
+
const projectRoot = findProjectRoot(cwd);
|
|
3746
|
+
if (!projectRoot) {
|
|
3747
|
+
console.log(chalk9.red(" Feil: Cure Kode er ikke initialisert i denne mappen."));
|
|
3748
|
+
console.log(chalk9.dim(" Kj\xF8r ") + chalk9.cyan("kode init") + chalk9.dim(" f\xF8rst."));
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3751
|
+
const config = getProjectConfig(projectRoot);
|
|
3752
|
+
if (!config) {
|
|
3753
|
+
console.log(chalk9.red(" Feil: Kunne ikke lese prosjektkonfigurasjon."));
|
|
3754
|
+
return;
|
|
3755
|
+
}
|
|
3756
|
+
if (!config.projectId) {
|
|
3757
|
+
console.log(chalk9.yellow(" Nettstedet er ikke koblet til et prosjekt."));
|
|
3758
|
+
console.log(chalk9.dim(' Koble til via Curie: "Koble denne Kode-siten til prosjekt X"'));
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
const spinner = ora8("Henter prosjektkonfigurasjon...").start();
|
|
3762
|
+
try {
|
|
3763
|
+
const response = await fetch(`https://app.cure.no/api/cdn/sites/${config.siteId}/project`, {
|
|
3764
|
+
headers: { "X-API-Key": config.apiKey }
|
|
3765
|
+
});
|
|
3766
|
+
if (!response.ok) {
|
|
3767
|
+
spinner.fail("Kunne ikke hente prosjektkonfigurasjon");
|
|
3768
|
+
console.log(chalk9.dim(` HTTP ${response.status}: ${response.statusText}`));
|
|
3769
|
+
return;
|
|
3770
|
+
}
|
|
3771
|
+
const projectCtx = await response.json();
|
|
3772
|
+
spinner.succeed("Prosjektkonfigurasjon hentet");
|
|
3773
|
+
const mcpConfigPath = join11(projectRoot, ".mcp.json");
|
|
3774
|
+
let mcpConfig = {};
|
|
3775
|
+
if (existsSync11(mcpConfigPath)) {
|
|
3776
|
+
try {
|
|
3777
|
+
mcpConfig = JSON.parse(readFileSync11(mcpConfigPath, "utf-8"));
|
|
3778
|
+
} catch {
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
mcpConfig.mcpServers = mcpConfig.mcpServers || {};
|
|
3782
|
+
const coreServers = /* @__PURE__ */ new Set(["cure-kode", "webflow", "playwright"]);
|
|
3783
|
+
const projectServerNames = new Set(projectCtx.mcp_servers.map((s) => s.name));
|
|
3784
|
+
const removed = [];
|
|
3785
|
+
for (const name of Object.keys(mcpConfig.mcpServers)) {
|
|
3786
|
+
if (!coreServers.has(name) && !projectServerNames.has(name)) {
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
const added = [];
|
|
3790
|
+
const updated = [];
|
|
3791
|
+
const secretWarnings = [];
|
|
3792
|
+
for (const server of projectCtx.mcp_servers) {
|
|
3793
|
+
const existed = mcpConfig.mcpServers[server.name] !== void 0;
|
|
3794
|
+
const serverConfig = { type: server.transport };
|
|
3795
|
+
if (server.transport === "sse" && server.url) {
|
|
3796
|
+
serverConfig.url = server.url;
|
|
3797
|
+
} else if (server.transport === "stdio") {
|
|
3798
|
+
if (server.command) serverConfig.command = server.command;
|
|
3799
|
+
if (server.args) serverConfig.args = server.args;
|
|
3800
|
+
}
|
|
3801
|
+
if (server.env_vars && Object.keys(server.env_vars).length > 0) {
|
|
3802
|
+
const env = {};
|
|
3803
|
+
for (const [key, value] of Object.entries(server.env_vars)) {
|
|
3804
|
+
if (value.startsWith("$SECRET:")) {
|
|
3805
|
+
const secretKey = value.replace("$SECRET:", "");
|
|
3806
|
+
env[key] = `<SET_ME:${secretKey}>`;
|
|
3807
|
+
secretWarnings.push(`${server.name}: ${key} \u2192 ${secretKey}`);
|
|
3808
|
+
} else {
|
|
3809
|
+
env[key] = value;
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
serverConfig.env = env;
|
|
3813
|
+
}
|
|
3814
|
+
mcpConfig.mcpServers[server.name] = serverConfig;
|
|
3815
|
+
if (existed) {
|
|
3816
|
+
updated.push(server.name);
|
|
3817
|
+
} else {
|
|
3818
|
+
added.push(server.name);
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
writeFileSync8(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
3822
|
+
spinner.start("Oppdaterer dokumentasjon...");
|
|
3823
|
+
let scripts = [];
|
|
3824
|
+
let pages = [];
|
|
3825
|
+
let productionEnabled = false;
|
|
3826
|
+
try {
|
|
3827
|
+
const [scriptsRes, pagesRes, prodRes] = await Promise.all([
|
|
3828
|
+
fetch(`https://app.cure.no/api/cdn/sites/${config.siteId}/scripts`, {
|
|
3829
|
+
headers: { "X-API-Key": config.apiKey }
|
|
3830
|
+
}),
|
|
3831
|
+
fetch(`https://app.cure.no/api/cdn/sites/${config.siteId}/pages`, {
|
|
3832
|
+
headers: { "X-API-Key": config.apiKey }
|
|
3833
|
+
}),
|
|
3834
|
+
fetch(`https://app.cure.no/api/cdn/sites/${config.siteId}/production`, {
|
|
3835
|
+
headers: { "X-API-Key": config.apiKey }
|
|
3836
|
+
})
|
|
3837
|
+
]);
|
|
3838
|
+
if (scriptsRes.ok) scripts = await scriptsRes.json();
|
|
3839
|
+
if (pagesRes.ok) pages = await pagesRes.json();
|
|
3840
|
+
if (prodRes.ok) {
|
|
3841
|
+
const prodData = await prodRes.json();
|
|
3842
|
+
productionEnabled = prodData.production_enabled ?? false;
|
|
3843
|
+
}
|
|
3844
|
+
} catch {
|
|
3845
|
+
}
|
|
3846
|
+
updateKodeDocs(
|
|
3847
|
+
projectRoot,
|
|
3848
|
+
config.siteName,
|
|
3849
|
+
config.siteSlug,
|
|
3850
|
+
scriptsToDocsFormat(scripts, pages),
|
|
3851
|
+
pagesToInfoFormat(pages),
|
|
3852
|
+
{ productionEnabled }
|
|
3853
|
+
);
|
|
3854
|
+
spinner.succeed("Dokumentasjon oppdatert");
|
|
3855
|
+
console.log();
|
|
3856
|
+
if (projectCtx.project) {
|
|
3857
|
+
console.log(chalk9.bold(" Prosjekt: ") + chalk9.cyan(projectCtx.project.name));
|
|
3858
|
+
}
|
|
3859
|
+
if (added.length > 0 || updated.length > 0) {
|
|
3860
|
+
console.log(chalk9.bold(" MCP-servere:"));
|
|
3861
|
+
for (const name of added) {
|
|
3862
|
+
console.log(chalk9.green(` + ${name}`) + chalk9.dim(" (ny)"));
|
|
3863
|
+
}
|
|
3864
|
+
for (const name of updated) {
|
|
3865
|
+
console.log(chalk9.blue(` ~ ${name}`) + chalk9.dim(" (oppdatert)"));
|
|
3866
|
+
}
|
|
3867
|
+
} else if (projectCtx.mcp_servers.length === 0) {
|
|
3868
|
+
console.log(chalk9.dim(" Ingen prosjekt-MCP-servere konfigurert."));
|
|
3869
|
+
} else {
|
|
3870
|
+
console.log(chalk9.dim(" Ingen endringer i MCP-servere."));
|
|
3871
|
+
}
|
|
3872
|
+
if (secretWarnings.length > 0) {
|
|
3873
|
+
console.log();
|
|
3874
|
+
console.log(chalk9.yellow(" \u26A0\uFE0F Hemmeligheter som m\xE5 settes i .mcp.json:"));
|
|
3875
|
+
for (const warning of secretWarnings) {
|
|
3876
|
+
console.log(chalk9.dim(` \u2022 ${warning}`));
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
console.log();
|
|
3880
|
+
} catch (error) {
|
|
3881
|
+
spinner.fail("Sync feilet");
|
|
3882
|
+
console.log(chalk9.red(` Feil: ${error.message}`));
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3622
3886
|
export {
|
|
3623
3887
|
findProjectRoot,
|
|
3624
3888
|
getProjectConfig,
|
|
@@ -3642,6 +3906,7 @@ export {
|
|
|
3642
3906
|
pagesToInfoFormat,
|
|
3643
3907
|
updateClaudeMd,
|
|
3644
3908
|
CLI_VERSION,
|
|
3909
|
+
showCompactBanner,
|
|
3645
3910
|
initCommand,
|
|
3646
3911
|
KodeApiError,
|
|
3647
3912
|
KodeApiClient,
|
|
@@ -3655,5 +3920,6 @@ export {
|
|
|
3655
3920
|
listCachedPages,
|
|
3656
3921
|
htmlCommand,
|
|
3657
3922
|
statusCommand,
|
|
3658
|
-
contextCommand
|
|
3923
|
+
contextCommand,
|
|
3924
|
+
syncConfigCommand
|
|
3659
3925
|
};
|
package/dist/cli.js
CHANGED
|
@@ -17,11 +17,13 @@ import {
|
|
|
17
17
|
pushCommand,
|
|
18
18
|
readPageContext,
|
|
19
19
|
scriptsToDocsFormat,
|
|
20
|
+
showCompactBanner,
|
|
20
21
|
statusCommand,
|
|
22
|
+
syncConfigCommand,
|
|
21
23
|
updateClaudeMd,
|
|
22
24
|
updateKodeDocs,
|
|
23
25
|
watchCommand
|
|
24
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-E7DFDYOS.js";
|
|
25
27
|
|
|
26
28
|
// src/cli.ts
|
|
27
29
|
import { Command } from "commander";
|
|
@@ -836,9 +838,10 @@ async function updateClaudeMdCommand() {
|
|
|
836
838
|
const spinner = ora5("Henter skript og sider...").start();
|
|
837
839
|
try {
|
|
838
840
|
const client = createApiClient(config);
|
|
839
|
-
const [scripts, pages] = await Promise.all([
|
|
841
|
+
const [scripts, pages, deployStatus] = await Promise.all([
|
|
840
842
|
client.listScripts(config.siteId),
|
|
841
|
-
client.listPages(config.siteId)
|
|
843
|
+
client.listPages(config.siteId),
|
|
844
|
+
client.getDeploymentStatus(config.siteId).catch(() => null)
|
|
842
845
|
]);
|
|
843
846
|
spinner.succeed(`Fant ${scripts.length} skript og ${pages.length} sider`);
|
|
844
847
|
const result = updateKodeDocs(
|
|
@@ -846,7 +849,8 @@ async function updateClaudeMdCommand() {
|
|
|
846
849
|
config.siteName,
|
|
847
850
|
config.siteSlug,
|
|
848
851
|
scriptsToDocsFormat(scripts, pages),
|
|
849
|
-
pagesToInfoFormat(pages)
|
|
852
|
+
pagesToInfoFormat(pages),
|
|
853
|
+
{ productionEnabled: deployStatus?.productionEnabled ?? false }
|
|
850
854
|
);
|
|
851
855
|
if (result.kodeMd.created) {
|
|
852
856
|
console.log(chalk6.green("\u2705 Opprettet .cure-kode/KODE.md"));
|
|
@@ -1605,6 +1609,184 @@ function printResults(results) {
|
|
|
1605
1609
|
console.log();
|
|
1606
1610
|
}
|
|
1607
1611
|
|
|
1612
|
+
// src/commands/delete.ts
|
|
1613
|
+
import chalk10 from "chalk";
|
|
1614
|
+
async function deleteCommand(scriptSlug, options) {
|
|
1615
|
+
const projectRoot = findProjectRoot();
|
|
1616
|
+
if (!projectRoot) {
|
|
1617
|
+
console.log(chalk10.red("Feil: Ikke i et Cure Kode-prosjekt."));
|
|
1618
|
+
console.log(chalk10.dim('Kj\xF8r "kode init" f\xF8rst.'));
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
const config = getProjectConfig(projectRoot);
|
|
1622
|
+
if (!config) {
|
|
1623
|
+
console.log(chalk10.red("Feil: Ugyldig prosjektkonfigurasjon."));
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
try {
|
|
1627
|
+
const api = createApiClient(config);
|
|
1628
|
+
const scripts = await api.listScripts(config.siteId);
|
|
1629
|
+
const script = scripts.find(
|
|
1630
|
+
(s) => s.slug === scriptSlug || s.name === scriptSlug || s.id === scriptSlug
|
|
1631
|
+
);
|
|
1632
|
+
if (!script) {
|
|
1633
|
+
console.log(chalk10.red(`Feil: Finner ikke skript "${scriptSlug}"`));
|
|
1634
|
+
console.log(chalk10.dim("Tilgjengelige skript:"));
|
|
1635
|
+
for (const s of scripts) {
|
|
1636
|
+
console.log(chalk10.dim(` - ${s.slug} (${s.name})`));
|
|
1637
|
+
}
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
if (!options.force) {
|
|
1641
|
+
console.log(chalk10.yellow(`
|
|
1642
|
+
Vil du slette skriptet "${script.name}" (${script.slug})?`));
|
|
1643
|
+
console.log(chalk10.dim(` Type: ${script.type}`));
|
|
1644
|
+
console.log(chalk10.dim(` Scope: ${script.scope}`));
|
|
1645
|
+
console.log(chalk10.dim(` Versjon: v${script.current_version}`));
|
|
1646
|
+
console.log();
|
|
1647
|
+
console.log(chalk10.yellow("Bruk --force for \xE5 bekrefte sletting."));
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
await api.deleteScript(script.id);
|
|
1651
|
+
console.log(chalk10.green(`\u2713 Skript slettet: ${script.name} (${script.slug})`));
|
|
1652
|
+
console.log(chalk10.dim(' Kj\xF8r "kode deploy" for \xE5 oppdatere staging.'));
|
|
1653
|
+
} catch (error) {
|
|
1654
|
+
const apiError = error;
|
|
1655
|
+
console.log(chalk10.red(`Feil: ${apiError.message}`));
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
// src/commands/webflow.ts
|
|
1660
|
+
import chalk11 from "chalk";
|
|
1661
|
+
import ora7 from "ora";
|
|
1662
|
+
import enquirer from "enquirer";
|
|
1663
|
+
var { prompt } = enquirer;
|
|
1664
|
+
function loadConfig() {
|
|
1665
|
+
const projectRoot = findProjectRoot(process.cwd());
|
|
1666
|
+
if (!projectRoot) {
|
|
1667
|
+
console.log(chalk11.red(" Ikke et Cure Kode-prosjekt. Kjor kode init forst."));
|
|
1668
|
+
console.log();
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
const config = getProjectConfig(projectRoot);
|
|
1672
|
+
if (!config) {
|
|
1673
|
+
console.log(chalk11.red(" Kunne ikke lese prosjektkonfigurasjon."));
|
|
1674
|
+
console.log();
|
|
1675
|
+
return null;
|
|
1676
|
+
}
|
|
1677
|
+
return config;
|
|
1678
|
+
}
|
|
1679
|
+
async function webflowInjectCommand(options) {
|
|
1680
|
+
showCompactBanner();
|
|
1681
|
+
const config = loadConfig();
|
|
1682
|
+
if (!config) return;
|
|
1683
|
+
const api = createApiClient(config);
|
|
1684
|
+
const spinner = ora7("Sjekker Webflow-status...").start();
|
|
1685
|
+
try {
|
|
1686
|
+
const status = await api.getWebflowCustomCodeStatus(config.siteId);
|
|
1687
|
+
if (status.injected) {
|
|
1688
|
+
spinner.info("Cure Kode er allerede injisert i Webflow");
|
|
1689
|
+
console.log();
|
|
1690
|
+
console.log(chalk11.dim(" Skript-URL: ") + chalk11.cyan(status.scriptUrl));
|
|
1691
|
+
console.log(chalk11.dim(" Plassering: ") + (status.location === "header" ? "<head>" : "<body>"));
|
|
1692
|
+
console.log(chalk11.dim(" Injisert: ") + new Date(status.injectedAt).toLocaleString("nb-NO"));
|
|
1693
|
+
console.log();
|
|
1694
|
+
console.log(chalk11.dim(" Bruk ") + chalk11.cyan("kode webflow remove") + chalk11.dim(" for a fjerne den."));
|
|
1695
|
+
console.log();
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
spinner.text = "Registrerer skript i Webflow...";
|
|
1699
|
+
const location = options.location === "footer" ? "footer" : "header";
|
|
1700
|
+
const result = await api.injectWebflowCustomCode(config.siteId, location);
|
|
1701
|
+
spinner.succeed("Cure Kode injisert i Webflow!");
|
|
1702
|
+
console.log();
|
|
1703
|
+
console.log(chalk11.green(" Skriptet er lagt til i Webflow Custom Code."));
|
|
1704
|
+
console.log();
|
|
1705
|
+
console.log(chalk11.dim(" Skript-URL: ") + chalk11.cyan(result.scriptUrl));
|
|
1706
|
+
console.log(chalk11.dim(" Plassering: ") + (result.location === "header" ? "<head>" : "<body>"));
|
|
1707
|
+
console.log();
|
|
1708
|
+
console.log(chalk11.yellow(" OBS: Du ma publisere Webflow-nettstedet for at endringene skal vises."));
|
|
1709
|
+
console.log();
|
|
1710
|
+
} catch (error) {
|
|
1711
|
+
spinner.fail("Kunne ikke injisere i Webflow");
|
|
1712
|
+
console.log();
|
|
1713
|
+
if (error.statusCode === 400) {
|
|
1714
|
+
console.log(chalk11.red(" Webflow er ikke konfigurert for dette nettstedet."));
|
|
1715
|
+
console.log(chalk11.dim(" Sett opp Webflow-tilkobling i Cure App forst."));
|
|
1716
|
+
} else {
|
|
1717
|
+
console.log(chalk11.red(` Feil: ${error.message}`));
|
|
1718
|
+
}
|
|
1719
|
+
console.log();
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
async function webflowRemoveCommand() {
|
|
1723
|
+
showCompactBanner();
|
|
1724
|
+
const config = loadConfig();
|
|
1725
|
+
if (!config) return;
|
|
1726
|
+
const api = createApiClient(config);
|
|
1727
|
+
const { confirm } = await prompt([
|
|
1728
|
+
{
|
|
1729
|
+
type: "confirm",
|
|
1730
|
+
name: "confirm",
|
|
1731
|
+
message: "Fjerne Cure Kode-skriptet fra Webflow?",
|
|
1732
|
+
initial: false
|
|
1733
|
+
}
|
|
1734
|
+
]);
|
|
1735
|
+
if (!confirm) {
|
|
1736
|
+
console.log(chalk11.dim(" Avbrutt."));
|
|
1737
|
+
console.log();
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
const spinner = ora7("Fjerner skript fra Webflow...").start();
|
|
1741
|
+
try {
|
|
1742
|
+
const result = await api.removeWebflowCustomCode(config.siteId);
|
|
1743
|
+
spinner.succeed("Skript fjernet fra Webflow");
|
|
1744
|
+
console.log();
|
|
1745
|
+
console.log(chalk11.dim(` ${result.message}`));
|
|
1746
|
+
console.log();
|
|
1747
|
+
console.log(chalk11.yellow(" OBS: Du ma publisere Webflow-nettstedet for at endringene skal forsvinne."));
|
|
1748
|
+
console.log();
|
|
1749
|
+
} catch (error) {
|
|
1750
|
+
spinner.fail("Kunne ikke fjerne skript");
|
|
1751
|
+
console.log();
|
|
1752
|
+
console.log(chalk11.red(` Feil: ${error.message}`));
|
|
1753
|
+
console.log();
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
async function webflowStatusCommand() {
|
|
1757
|
+
showCompactBanner();
|
|
1758
|
+
const config = loadConfig();
|
|
1759
|
+
if (!config) return;
|
|
1760
|
+
const api = createApiClient(config);
|
|
1761
|
+
const spinner = ora7("Henter Webflow-status...").start();
|
|
1762
|
+
try {
|
|
1763
|
+
const status = await api.getWebflowCustomCodeStatus(config.siteId);
|
|
1764
|
+
if (status.injected) {
|
|
1765
|
+
spinner.succeed("Cure Kode er aktiv i Webflow");
|
|
1766
|
+
console.log();
|
|
1767
|
+
console.log(chalk11.dim(" Skript-URL: ") + chalk11.cyan(status.scriptUrl));
|
|
1768
|
+
console.log(chalk11.dim(" Plassering: ") + (status.location === "header" ? "<head>" : "<body>"));
|
|
1769
|
+
console.log(chalk11.dim(" Injisert: ") + new Date(status.injectedAt).toLocaleString("nb-NO"));
|
|
1770
|
+
console.log(chalk11.dim(" Andre skript: ") + `${status.totalScripts - 1} til`);
|
|
1771
|
+
} else {
|
|
1772
|
+
spinner.info("Cure Kode er ikke injisert i Webflow");
|
|
1773
|
+
console.log();
|
|
1774
|
+
console.log(chalk11.dim(" Skript-URL: ") + chalk11.cyan(status.scriptUrl));
|
|
1775
|
+
console.log(chalk11.dim(" Bruk ") + chalk11.cyan("kode webflow inject") + chalk11.dim(" for a legge den til."));
|
|
1776
|
+
}
|
|
1777
|
+
console.log();
|
|
1778
|
+
} catch (error) {
|
|
1779
|
+
spinner.fail("Kunne ikke hente status");
|
|
1780
|
+
console.log();
|
|
1781
|
+
if (error.statusCode === 400) {
|
|
1782
|
+
console.log(chalk11.red(" Webflow er ikke konfigurert for dette nettstedet."));
|
|
1783
|
+
} else {
|
|
1784
|
+
console.log(chalk11.red(` Feil: ${error.message}`));
|
|
1785
|
+
}
|
|
1786
|
+
console.log();
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1608
1790
|
// src/cli.ts
|
|
1609
1791
|
var program = new Command();
|
|
1610
1792
|
program.name("kode").description("CLI for Cure Kode - manage JS/CSS scripts for Webflow sites").version(CLI_VERSION);
|
|
@@ -1626,6 +1808,9 @@ program.command("sync").description("Bidirectional sync - pull and push changes
|
|
|
1626
1808
|
program.command("diff <script>").description("Show differences between local and remote script").action((script) => {
|
|
1627
1809
|
diffCommand(script);
|
|
1628
1810
|
});
|
|
1811
|
+
program.command("delete <script>").description("Delete a script from Cure Kode CDN").option("-f, --force", "Confirm deletion").action((script, options) => {
|
|
1812
|
+
deleteCommand(script, options);
|
|
1813
|
+
});
|
|
1629
1814
|
program.command("watch").description("Watch for changes and auto-push").option("-d, --deploy", "Auto-deploy after each push").action((options) => {
|
|
1630
1815
|
watchCommand(options);
|
|
1631
1816
|
});
|
|
@@ -1678,6 +1863,19 @@ program.command("production <action>").description("Enable or disable production
|
|
|
1678
1863
|
program.command("update-claude-md").alias("ucm").description("Add or update Cure Kode section in CLAUDE.md").action(() => {
|
|
1679
1864
|
updateClaudeMdCommand();
|
|
1680
1865
|
});
|
|
1866
|
+
program.command("sync-config").description("Sync project MCP servers and regenerate documentation").action(() => {
|
|
1867
|
+
syncConfigCommand();
|
|
1868
|
+
});
|
|
1869
|
+
var webflowCmd = program.command("webflow").description("Manage Webflow Custom Code integration");
|
|
1870
|
+
webflowCmd.command("inject").description("Inject Cure Kode init.js into Webflow <head>").option("-l, --location <location>", "Script location: header or footer", "header").action((options) => {
|
|
1871
|
+
webflowInjectCommand(options);
|
|
1872
|
+
});
|
|
1873
|
+
webflowCmd.command("remove").description("Remove Cure Kode init.js from Webflow").action(() => {
|
|
1874
|
+
webflowRemoveCommand();
|
|
1875
|
+
});
|
|
1876
|
+
webflowCmd.command("status", { isDefault: true }).description("Show current Webflow injection status").action(() => {
|
|
1877
|
+
webflowStatusCommand();
|
|
1878
|
+
});
|
|
1681
1879
|
program.command("doctor").description("Diagnose configuration and environment issues").action(() => {
|
|
1682
1880
|
doctorCommand();
|
|
1683
1881
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ interface ProjectConfig {
|
|
|
9
9
|
apiUrl?: string;
|
|
10
10
|
scriptsDir?: string;
|
|
11
11
|
environment?: 'staging' | 'production';
|
|
12
|
+
projectId?: string;
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* Find project config by walking up directory tree
|
|
@@ -239,6 +240,26 @@ declare class KodeApiClient {
|
|
|
239
240
|
acquiredAt?: string;
|
|
240
241
|
duration_ms?: number;
|
|
241
242
|
}>;
|
|
243
|
+
getWebflowCustomCodeStatus(siteId: string): Promise<{
|
|
244
|
+
injected: boolean;
|
|
245
|
+
scriptId: string | null;
|
|
246
|
+
scriptUrl: string;
|
|
247
|
+
location: string | null;
|
|
248
|
+
version: string | null;
|
|
249
|
+
totalScripts: number;
|
|
250
|
+
injectedAt: string | null;
|
|
251
|
+
}>;
|
|
252
|
+
injectWebflowCustomCode(siteId: string, location?: 'header' | 'footer'): Promise<{
|
|
253
|
+
success: boolean;
|
|
254
|
+
scriptId: string;
|
|
255
|
+
scriptUrl: string;
|
|
256
|
+
location: string;
|
|
257
|
+
message: string;
|
|
258
|
+
}>;
|
|
259
|
+
removeWebflowCustomCode(siteId: string): Promise<{
|
|
260
|
+
success: boolean;
|
|
261
|
+
message: string;
|
|
262
|
+
}>;
|
|
242
263
|
}
|
|
243
264
|
/**
|
|
244
265
|
* Create API client from project config
|
|
@@ -325,6 +346,15 @@ interface ContextOptions {
|
|
|
325
346
|
*/
|
|
326
347
|
declare function contextCommand(options: ContextOptions): Promise<void>;
|
|
327
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Sync project MCP servers and regenerate documentation.
|
|
351
|
+
*
|
|
352
|
+
* Re-fetches project MCP servers from the Cure app and merges them into
|
|
353
|
+
* the local .mcp.json. Preserves non-project servers (cure-kode, webflow,
|
|
354
|
+
* playwright) and updates project ones.
|
|
355
|
+
*/
|
|
356
|
+
declare function syncConfigCommand(): Promise<void>;
|
|
357
|
+
|
|
328
358
|
/**
|
|
329
359
|
* Kode Context - Dynamic project state for AI agents
|
|
330
360
|
*/
|
|
@@ -409,4 +439,4 @@ declare function generateInitialContext(config: ProjectConfig, scripts: CdnScrip
|
|
|
409
439
|
*/
|
|
410
440
|
declare function generateClaudeMd(siteName: string, scriptsDir?: string, siteSlug?: string): string;
|
|
411
441
|
|
|
412
|
-
export { type CdnDeployment, type CdnPage, type CdnScript, type CdnSite, KodeApiClient, KodeApiError, type KodeContext, type KodeScriptContext, type KodeSession, type ParsedHtmlResult, type ProjectConfig, addSession, appendNote, contextCommand, createApiClient, deployCommand, findProjectRoot, generateClaudeMd, generateInitialContext, getApiKey, getApiUrl, getContextPath, getProjectConfig, getScriptsDir, htmlCommand, initCommand, parseContext, pullCommand, pushCommand, readContext, saveProjectConfig, serializeContext, setGlobalConfig, statusCommand, updateScriptPurpose, watchCommand, writeContext };
|
|
442
|
+
export { type CdnDeployment, type CdnPage, type CdnScript, type CdnSite, KodeApiClient, KodeApiError, type KodeContext, type KodeScriptContext, type KodeSession, type ParsedHtmlResult, type ProjectConfig, addSession, appendNote, contextCommand, createApiClient, deployCommand, findProjectRoot, generateClaudeMd, generateInitialContext, getApiKey, getApiUrl, getContextPath, getProjectConfig, getScriptsDir, htmlCommand, initCommand, parseContext, pullCommand, pushCommand, readContext, saveProjectConfig, serializeContext, setGlobalConfig, statusCommand, syncConfigCommand, updateScriptPurpose, watchCommand, writeContext };
|
package/dist/index.js
CHANGED
|
@@ -24,10 +24,11 @@ import {
|
|
|
24
24
|
serializeContext,
|
|
25
25
|
setGlobalConfig,
|
|
26
26
|
statusCommand,
|
|
27
|
+
syncConfigCommand,
|
|
27
28
|
updateScriptPurpose,
|
|
28
29
|
watchCommand,
|
|
29
30
|
writeContext
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-E7DFDYOS.js";
|
|
31
32
|
export {
|
|
32
33
|
KodeApiClient,
|
|
33
34
|
KodeApiError,
|
|
@@ -54,6 +55,7 @@ export {
|
|
|
54
55
|
serializeContext,
|
|
55
56
|
setGlobalConfig,
|
|
56
57
|
statusCommand,
|
|
58
|
+
syncConfigCommand,
|
|
57
59
|
updateScriptPurpose,
|
|
58
60
|
watchCommand,
|
|
59
61
|
writeContext
|