@curenorway/kode-cli 1.12.0 → 1.13.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 CHANGED
@@ -4,12 +4,14 @@ Command-line tool for managing JavaScript and CSS scripts for Webflow sites via
4
4
 
5
5
  ## Features
6
6
 
7
- - **Pull/Push scripts** - Sync scripts between local files and remote CDN
7
+ - **Pull/Push scripts** - Sync scripts between local files and remote CDN with conflict detection
8
+ - **Sync awareness** - Staleness indicators show when local state is out of date
9
+ - **Deploy dry-run** - Preview what will be deployed before executing
10
+ - **Doctor command** - Diagnose configuration issues and check for CLI updates
8
11
  - **Watch mode** - Auto-sync on file changes with retry on failure
9
12
  - **Staging/Production** - Separate environments with explicit production enable
10
13
  - **Rollback** - Quick recovery to previous deployments
11
- - **AI Context** - Generate and manage context for AI agents
12
- - **Page Context Caching** - Save page structures for AI development
14
+ - **AI-ready** - Auto-generates KODE.md documentation for AI agents
13
15
  - **MCP Integration** - Works with Cure Kode MCP for AI agents
14
16
 
15
17
  ## Installation
@@ -53,9 +55,10 @@ kode init
53
55
 
54
56
  Creates:
55
57
  - `.cure-kode/config.json` - Site configuration and API key
58
+ - `.cure-kode/KODE.md` - Auto-generated documentation (scripts, pages, commands)
56
59
  - `.cure-kode/context.md` - AI context file
57
60
  - `.cure-kode-scripts/` - Scripts directory
58
- - `CLAUDE.md` - AI agent instructions (with metadata documentation)
61
+ - `CLAUDE.md` - Reference to KODE.md (prepended, never overwrites existing content)
59
62
  - `.mcp.json` - MCP server configuration (cure-kode, webflow, playwright)
60
63
 
61
64
  ### `kode pull`
@@ -104,9 +107,9 @@ Deploy scripts to staging or production.
104
107
 
105
108
  ```bash
106
109
  kode deploy # Deploy to staging (default)
110
+ kode deploy --dry-run # Preview deployment without executing
107
111
  kode deploy --promote # Promote staging to production
108
112
  kode deploy --force # Force release stale deploy lock
109
- kode deploy -n "Release v2" # Deploy with notes
110
113
  ```
111
114
 
112
115
  **Note:** Production must be enabled before promoting. See `kode production`.
@@ -165,7 +168,7 @@ kode context --json # Output as JSON
165
168
 
166
169
  ### `kode status`
167
170
 
168
- Show current project status.
171
+ Show current project status with staleness indicators.
169
172
 
170
173
  ```bash
171
174
  kode status
@@ -174,9 +177,44 @@ kode status
174
177
  Shows:
175
178
  - Site info and CDN URL
176
179
  - Production enabled state
177
- - Script sync status
180
+ - Script sync status with staleness warnings
181
+ - Per-script indicators: modified locally, server updated, conflicts
178
182
  - Deployment versions
179
183
 
184
+ ### `kode doctor`
185
+
186
+ Diagnose configuration and environment issues.
187
+
188
+ ```bash
189
+ kode doctor
190
+ ```
191
+
192
+ Checks:
193
+ - Project configuration and API key validity
194
+ - Network connectivity and API access
195
+ - MCP server configuration
196
+ - KODE.md and CLAUDE.md setup
197
+ - Security (.gitignore for API key)
198
+ - Sync state staleness
199
+ - CLI version and available updates
200
+
201
+ ### `kode diff <script>`
202
+
203
+ Show differences between local and remote script versions.
204
+
205
+ ```bash
206
+ kode diff my-script # Compare local vs remote
207
+ ```
208
+
209
+ ### `kode sync`
210
+
211
+ Bidirectional sync with conflict detection.
212
+
213
+ ```bash
214
+ kode sync # Sync both directions
215
+ kode sync --dry-run # Preview what would change
216
+ ```
217
+
180
218
  ## Configuration
181
219
 
182
220
  ### Project Config (`.cure-kode/config.json`)
@@ -206,15 +244,17 @@ Default: `.cure-kode-scripts/` (avoids conflicts with AI-generated `scripts/` fo
206
244
  ```
207
245
  your-project/
208
246
  ├── .cure-kode/
209
- │ ├── config.json # Project configuration
247
+ │ ├── config.json # Project configuration (gitignored)
248
+ │ ├── scripts.json # Sync state for conflict detection
249
+ │ ├── KODE.md # Auto-generated documentation
210
250
  │ ├── context.md # AI context (notes, discoveries)
211
251
  │ └── pages/ # Cached page contexts
212
252
  ├── .cure-kode-scripts/ # Your scripts directory
213
- │ ├── init.js
214
- │ ├── tracking.js
253
+ │ ├── main.js
254
+ │ ├── form-handler.js
215
255
  │ └── styles.css
216
256
  ├── .mcp.json # MCP server configuration
217
- └── CLAUDE.md # AI agent instructions
257
+ └── CLAUDE.md # Reference to KODE.md (your content preserved)
218
258
  ```
219
259
 
220
260
  ## Workflow Examples
@@ -1201,7 +1201,7 @@ Option C: Full rollback
1201
1201
  }
1202
1202
 
1203
1203
  // src/version.ts
1204
- var CLI_VERSION = "1.12.0";
1204
+ var CLI_VERSION = "1.12.1";
1205
1205
 
1206
1206
  // src/commands/init.ts
1207
1207
  import chalk from "chalk";
@@ -1288,6 +1288,29 @@ Page-specific scripts only load when URL matches these patterns:
1288
1288
  `;
1289
1289
  }
1290
1290
  md += `
1291
+ `;
1292
+ }
1293
+ const pageSpecificScripts = scripts.filter(
1294
+ (s) => s.scope === "page-specific" && s.pageAssignments && s.pageAssignments.length > 0
1295
+ );
1296
+ if (pageSpecificScripts.length > 0) {
1297
+ md += `---
1298
+
1299
+ ## Script \u2192 Page Assignments
1300
+
1301
+ | Script | Pages |
1302
+ |--------|-------|
1303
+ `;
1304
+ for (const script of pageSpecificScripts) {
1305
+ const pageList = script.pageAssignments.map((pa) => {
1306
+ const page = pages.find((p) => p.slug === pa.pageSlug);
1307
+ const patterns = page ? ` (\`${page.patterns.join("`, `")}\`)` : "";
1308
+ return `\`${pa.pageSlug}\`${patterns}`;
1309
+ }).join(", ");
1310
+ md += `| \`${script.slug}\` | ${pageList} |
1311
+ `;
1312
+ }
1313
+ md += `
1291
1314
  `;
1292
1315
  }
1293
1316
  md += `---
@@ -1383,15 +1406,22 @@ function updateKodeDocs(projectRoot, siteName, siteSlug, scripts, pages) {
1383
1406
  const claudeMd = ensureClaudeMdReference(projectRoot);
1384
1407
  return { kodeMd, claudeMd };
1385
1408
  }
1386
- function scriptsToDocsFormat(scripts) {
1387
- return scripts.map((s) => ({
1388
- slug: s.slug,
1389
- name: s.name,
1390
- type: s.type,
1391
- scope: s.scope,
1392
- autoLoad: s.auto_load,
1393
- purpose: s.metadata?.purpose || s.description
1394
- }));
1409
+ function scriptsToDocsFormat(scripts, pages) {
1410
+ return scripts.map((s) => {
1411
+ const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
1412
+ const page = pages?.find((pg) => pg.id === p.page_id);
1413
+ return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
1414
+ }).filter((p) => p !== null);
1415
+ return {
1416
+ slug: s.slug,
1417
+ name: s.name,
1418
+ type: s.type,
1419
+ scope: s.scope,
1420
+ autoLoad: s.auto_load,
1421
+ purpose: s.metadata?.purpose || s.description,
1422
+ pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0
1423
+ };
1424
+ });
1395
1425
  }
1396
1426
  function pagesToInfoFormat(pages) {
1397
1427
  return pages.filter((p) => p.is_active).map((p) => ({
@@ -1584,7 +1614,7 @@ config.json
1584
1614
  cwd,
1585
1615
  config.siteName,
1586
1616
  config.siteSlug,
1587
- scriptsToDocsFormat(scripts),
1617
+ scriptsToDocsFormat(scripts, pages),
1588
1618
  pagesToInfoFormat(pages)
1589
1619
  );
1590
1620
  const siteInfo = {
@@ -2034,10 +2064,19 @@ Fant ikke skript "${options.script}".`));
2034
2064
  if (skipped > 0) {
2035
2065
  console.log(chalk2.dim(`Hoppet over ${skipped} skript`));
2036
2066
  }
2067
+ let pages = [];
2068
+ try {
2069
+ pages = await client.listPages(config.siteId);
2070
+ } catch {
2071
+ }
2037
2072
  const now = (/* @__PURE__ */ new Date()).toISOString();
2038
2073
  const metadata = scripts.map((s) => {
2039
2074
  const filePath = join5(scriptsDir, `${s.slug}.${s.type === "javascript" ? "js" : "css"}`);
2040
2075
  const localContent = existsSync5(filePath) ? readFileSync5(filePath, "utf-8") : s.content;
2076
+ const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
2077
+ const page = pages.find((pg) => pg.id === p.page_id);
2078
+ return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
2079
+ }).filter((p) => p !== null);
2041
2080
  return {
2042
2081
  id: s.id,
2043
2082
  slug: s.slug,
@@ -2047,6 +2086,7 @@ Fant ikke skript "${options.script}".`));
2047
2086
  autoLoad: s.auto_load,
2048
2087
  version: s.current_version,
2049
2088
  loadOrder: s.load_order,
2089
+ pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
2050
2090
  lastPulledVersion: s.current_version,
2051
2091
  lastPulledAt: now,
2052
2092
  contentHash: hashContent(localContent)
@@ -2054,12 +2094,11 @@ Fant ikke skript "${options.script}".`));
2054
2094
  });
2055
2095
  writeFileSync5(metadataPath, JSON.stringify(metadata, null, 2));
2056
2096
  try {
2057
- const pages = await client.listPages(config.siteId);
2058
2097
  const result = updateClaudeMd(
2059
2098
  projectRoot,
2060
2099
  config.siteName,
2061
2100
  config.siteSlug,
2062
- scriptsToDocsFormat(scripts),
2101
+ scriptsToDocsFormat(scripts, pages),
2063
2102
  pagesToInfoFormat(pages)
2064
2103
  );
2065
2104
  if (result.kodeMd.created) {
@@ -2233,12 +2272,21 @@ ${conflicts} skript med konflikter (bruk --force for \xE5 overskrive)`));
2233
2272
  ${emptyScriptCount} tomme skript lastet opp`));
2234
2273
  console.log(chalk3.dim("Tomme skript har ingen effekt ved deploy."));
2235
2274
  }
2275
+ let pages = [];
2276
+ try {
2277
+ pages = await client.listPages(config.siteId);
2278
+ } catch {
2279
+ }
2236
2280
  const updatedScripts = await client.listScripts(config.siteId);
2237
2281
  const now = (/* @__PURE__ */ new Date()).toISOString();
2238
2282
  const updatedMetadata = updatedScripts.map((s) => {
2239
2283
  const ext = s.type === "javascript" ? "js" : "css";
2240
2284
  const filePath = join6(scriptsDir, `${s.slug}.${ext}`);
2241
2285
  const localContent = existsSync6(filePath) ? readFileSync6(filePath, "utf-8") : s.content;
2286
+ const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
2287
+ const page = pages.find((pg) => pg.id === p.page_id);
2288
+ return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
2289
+ }).filter((p) => p !== null);
2242
2290
  return {
2243
2291
  id: s.id,
2244
2292
  slug: s.slug,
@@ -2248,6 +2296,7 @@ ${emptyScriptCount} tomme skript lastet opp`));
2248
2296
  autoLoad: s.auto_load,
2249
2297
  version: s.current_version,
2250
2298
  loadOrder: s.load_order,
2299
+ pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
2251
2300
  lastPulledVersion: s.current_version,
2252
2301
  lastPulledAt: now,
2253
2302
  contentHash: hashContent2(localContent)
@@ -2255,12 +2304,11 @@ ${emptyScriptCount} tomme skript lastet opp`));
2255
2304
  });
2256
2305
  writeFileSync6(metadataPath, JSON.stringify(updatedMetadata, null, 2));
2257
2306
  try {
2258
- const pages = await client.listPages(config.siteId);
2259
2307
  const result = updateClaudeMd(
2260
2308
  projectRoot,
2261
2309
  config.siteName,
2262
2310
  config.siteSlug,
2263
- scriptsToDocsFormat(updatedScripts),
2311
+ scriptsToDocsFormat(updatedScripts, pages),
2264
2312
  pagesToInfoFormat(pages)
2265
2313
  );
2266
2314
  if (result.kodeMd.created) {
package/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  updateClaudeMd,
22
22
  updateKodeDocs,
23
23
  watchCommand
24
- } from "./chunk-XU4YS3JQ.js";
24
+ } from "./chunk-C2BM7IJ6.js";
25
25
 
26
26
  // src/cli.ts
27
27
  import { Command } from "commander";
@@ -65,7 +65,7 @@ async function upgradeCommand() {
65
65
  projectRoot,
66
66
  config.siteName,
67
67
  config.siteSlug,
68
- scriptsToDocsFormat(scripts),
68
+ scriptsToDocsFormat(scripts, pages),
69
69
  pagesToInfoFormat(pages)
70
70
  );
71
71
  if (result.kodeMd.created) {
@@ -845,7 +845,7 @@ async function updateClaudeMdCommand() {
845
845
  projectRoot,
846
846
  config.siteName,
847
847
  config.siteSlug,
848
- scriptsToDocsFormat(scripts),
848
+ scriptsToDocsFormat(scripts, pages),
849
849
  pagesToInfoFormat(pages)
850
850
  );
851
851
  if (result.kodeMd.created) {
@@ -1077,11 +1077,20 @@ async function syncCommand(options) {
1077
1077
  console.log(chalk7.dim(' Bruk "kode pull --force <script>" for \xE5 overskrive lokalt'));
1078
1078
  }
1079
1079
  const updatedScripts = await client.listScripts(config.siteId);
1080
+ let pages = [];
1081
+ try {
1082
+ pages = await client.listPages(config.siteId);
1083
+ } catch {
1084
+ }
1080
1085
  const now = (/* @__PURE__ */ new Date()).toISOString();
1081
1086
  const updatedMetadata = updatedScripts.map((s) => {
1082
1087
  const ext = s.type === "javascript" ? "js" : "css";
1083
1088
  const filePath = join2(scriptsDir, `${s.slug}.${ext}`);
1084
1089
  const localContent = existsSync2(filePath) ? readFileSync2(filePath, "utf-8") : s.content;
1090
+ const pageAssignments = (s.pages || []).filter((p) => p.is_enabled).map((p) => {
1091
+ const page = pages.find((pg) => pg.id === p.page_id);
1092
+ return page ? { pageId: page.id, pageSlug: page.slug, pageName: page.name } : null;
1093
+ }).filter((p) => p !== null);
1085
1094
  return {
1086
1095
  id: s.id,
1087
1096
  slug: s.slug,
@@ -1091,6 +1100,7 @@ async function syncCommand(options) {
1091
1100
  autoLoad: s.auto_load,
1092
1101
  version: s.current_version,
1093
1102
  loadOrder: s.load_order,
1103
+ pageAssignments: pageAssignments.length > 0 ? pageAssignments : void 0,
1094
1104
  lastPulledVersion: s.current_version,
1095
1105
  lastPulledAt: now,
1096
1106
  contentHash: hashContent(localContent)
package/dist/index.d.ts CHANGED
@@ -66,6 +66,10 @@ interface CdnScript {
66
66
  current_version: number;
67
67
  is_active: boolean;
68
68
  load_order: number;
69
+ pages?: Array<{
70
+ page_id: string;
71
+ is_enabled: boolean;
72
+ }>;
69
73
  }
70
74
  interface CdnPage {
71
75
  id: string;
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  updateScriptPurpose,
28
28
  watchCommand,
29
29
  writeContext
30
- } from "./chunk-XU4YS3JQ.js";
30
+ } from "./chunk-C2BM7IJ6.js";
31
31
  export {
32
32
  KodeApiClient,
33
33
  KodeApiError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curenorway/kode-cli",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "CLI for Cure Kode CDN - manage, deploy, and sync JS/CSS scripts for Webflow sites with AI agent support",
5
5
  "type": "module",
6
6
  "bin": {