@curenorway/kode-cli 1.14.0 → 1.15.1
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 +22 -0
- package/dist/{chunk-I7TVOZJR.js → chunk-E7DFDYOS.js} +262 -8
- package/dist/cli.js +197 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@ Command-line tool for managing JavaScript and CSS scripts for Webflow sites via
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
+
- **Webflow Auto-Inject** - Automatically injects init.js into Webflow `<head>` via Custom Code API during init
|
|
7
8
|
- **Pull/Push scripts** - Sync scripts between local files and remote CDN with conflict detection
|
|
8
9
|
- **Sync awareness** - Staleness indicators show when local state is out of date
|
|
9
10
|
- **Deploy dry-run** - Preview what will be deployed before executing
|
|
@@ -61,6 +62,8 @@ Creates:
|
|
|
61
62
|
- `CLAUDE.md` - Reference to KODE.md (prepended, never overwrites existing content)
|
|
62
63
|
- `.mcp.json` - MCP server configuration (cure-kode, webflow, playwright)
|
|
63
64
|
|
|
65
|
+
Automatically registers and injects init.js into the Webflow site's `<head>` via the Custom Code API. If injection fails, it falls back to showing the manual embed code.
|
|
66
|
+
|
|
64
67
|
### `kode pull`
|
|
65
68
|
|
|
66
69
|
Download scripts from remote to your local scripts directory.
|
|
@@ -215,6 +218,25 @@ kode sync # Sync both directions
|
|
|
215
218
|
kode sync --dry-run # Preview what would change
|
|
216
219
|
```
|
|
217
220
|
|
|
221
|
+
### `kode webflow`
|
|
222
|
+
|
|
223
|
+
Manage the Webflow Custom Code integration. During `kode init`, the init.js script is automatically injected into Webflow's `<head>` via the Custom Code API. These commands let you manage it afterwards.
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
kode webflow status # Check if init.js is injected (default)
|
|
227
|
+
kode webflow inject # Inject init.js into Webflow <head>
|
|
228
|
+
kode webflow inject --location footer # Inject into footer instead
|
|
229
|
+
kode webflow remove # Remove init.js from Webflow
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**How it works:**
|
|
233
|
+
1. Registers init.js as a hosted script with Webflow
|
|
234
|
+
2. Applies it to the site's `<head>` via the Custom Code API
|
|
235
|
+
3. Preserves any other scripts already managed by the API
|
|
236
|
+
4. Does not affect manually-added code in the Webflow Designer
|
|
237
|
+
|
|
238
|
+
**Note:** After inject/remove, you must **publish** the Webflow site for changes to take effect.
|
|
239
|
+
|
|
218
240
|
## Configuration
|
|
219
241
|
|
|
220
242
|
### Project Config (`.cure-kode/config.json`)
|
|
@@ -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";
|
|
@@ -1451,6 +1451,12 @@ function showBanner() {
|
|
|
1451
1451
|
console.log(chalk.dim(" JS/CSS delivery for Webflow sites"));
|
|
1452
1452
|
console.log();
|
|
1453
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
|
+
}
|
|
1454
1460
|
async function initCommand(options) {
|
|
1455
1461
|
const cwd = process.cwd();
|
|
1456
1462
|
showBanner();
|
|
@@ -1543,13 +1549,34 @@ async function initCommand(options) {
|
|
|
1543
1549
|
}
|
|
1544
1550
|
console.log(chalk.dim(" Webflow: ") + chalk.green("\u2713 Konfigurert"));
|
|
1545
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
|
+
}
|
|
1546
1572
|
const config = {
|
|
1547
1573
|
siteId: site.id,
|
|
1548
1574
|
siteSlug: site.slug,
|
|
1549
1575
|
siteName: site.name,
|
|
1550
1576
|
apiKey,
|
|
1551
1577
|
scriptsDir: DEFAULT_SCRIPTS_DIR,
|
|
1552
|
-
environment: "staging"
|
|
1578
|
+
environment: "staging",
|
|
1579
|
+
...projectCtx?.project && { projectId: projectCtx.project.id }
|
|
1553
1580
|
};
|
|
1554
1581
|
spinner.start("Oppretter prosjektstruktur...");
|
|
1555
1582
|
saveProjectConfig(config, cwd);
|
|
@@ -1591,8 +1618,42 @@ config.json
|
|
|
1591
1618
|
command: "npx",
|
|
1592
1619
|
args: ["-y", "@playwright/mcp@^0.0.21"]
|
|
1593
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
|
+
}
|
|
1594
1647
|
writeFileSync4(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + "\n");
|
|
1595
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
|
+
}
|
|
1596
1657
|
spinner.start("Genererer AI-dokumentasjon...");
|
|
1597
1658
|
let scripts = [];
|
|
1598
1659
|
let pages = [];
|
|
@@ -1660,11 +1721,39 @@ config.json
|
|
|
1660
1721
|
console.log(chalk.dim(` \u2514\u2500\u2500 ${DEFAULT_SCRIPTS_DIR}/`));
|
|
1661
1722
|
console.log(chalk.dim(" \u2514\u2500\u2500 (skriptene dine her)"));
|
|
1662
1723
|
console.log();
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
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
|
+
}
|
|
1668
1757
|
console.log(chalk.bold(" Neste steg:"));
|
|
1669
1758
|
console.log();
|
|
1670
1759
|
console.log(chalk.cyan(" 1. kode pull ") + chalk.dim("Last ned eksisterende skript"));
|
|
@@ -1959,6 +2048,21 @@ var KodeApiClient = class {
|
|
|
1959
2048
|
body: JSON.stringify({ siteId })
|
|
1960
2049
|
});
|
|
1961
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
|
+
}
|
|
1962
2066
|
};
|
|
1963
2067
|
function createApiClient(config) {
|
|
1964
2068
|
return new KodeApiClient(config);
|
|
@@ -3631,6 +3735,154 @@ async function contextCommand(options) {
|
|
|
3631
3735
|
console.log(chalk8.dim("Use --edit to open in editor, --refresh to update from server"));
|
|
3632
3736
|
}
|
|
3633
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
|
+
|
|
3634
3886
|
export {
|
|
3635
3887
|
findProjectRoot,
|
|
3636
3888
|
getProjectConfig,
|
|
@@ -3654,6 +3906,7 @@ export {
|
|
|
3654
3906
|
pagesToInfoFormat,
|
|
3655
3907
|
updateClaudeMd,
|
|
3656
3908
|
CLI_VERSION,
|
|
3909
|
+
showCompactBanner,
|
|
3657
3910
|
initCommand,
|
|
3658
3911
|
KodeApiError,
|
|
3659
3912
|
KodeApiClient,
|
|
@@ -3667,5 +3920,6 @@ export {
|
|
|
3667
3920
|
listCachedPages,
|
|
3668
3921
|
htmlCommand,
|
|
3669
3922
|
statusCommand,
|
|
3670
|
-
contextCommand
|
|
3923
|
+
contextCommand,
|
|
3924
|
+
syncConfigCommand
|
|
3671
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";
|
|
@@ -1607,6 +1609,184 @@ function printResults(results) {
|
|
|
1607
1609
|
console.log();
|
|
1608
1610
|
}
|
|
1609
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
|
+
|
|
1610
1790
|
// src/cli.ts
|
|
1611
1791
|
var program = new Command();
|
|
1612
1792
|
program.name("kode").description("CLI for Cure Kode - manage JS/CSS scripts for Webflow sites").version(CLI_VERSION);
|
|
@@ -1628,6 +1808,9 @@ program.command("sync").description("Bidirectional sync - pull and push changes
|
|
|
1628
1808
|
program.command("diff <script>").description("Show differences between local and remote script").action((script) => {
|
|
1629
1809
|
diffCommand(script);
|
|
1630
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
|
+
});
|
|
1631
1814
|
program.command("watch").description("Watch for changes and auto-push").option("-d, --deploy", "Auto-deploy after each push").action((options) => {
|
|
1632
1815
|
watchCommand(options);
|
|
1633
1816
|
});
|
|
@@ -1680,6 +1863,19 @@ program.command("production <action>").description("Enable or disable production
|
|
|
1680
1863
|
program.command("update-claude-md").alias("ucm").description("Add or update Cure Kode section in CLAUDE.md").action(() => {
|
|
1681
1864
|
updateClaudeMdCommand();
|
|
1682
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
|
+
});
|
|
1683
1879
|
program.command("doctor").description("Diagnose configuration and environment issues").action(() => {
|
|
1684
1880
|
doctorCommand();
|
|
1685
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
|