@curenorway/kode-cli 1.3.7 → 1.4.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-OGDEQRXS.js → chunk-OW3XKTBO.js} +69 -98
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -10,6 +10,7 @@ var globalConfig = new Conf({
|
|
|
10
10
|
});
|
|
11
11
|
var PROJECT_CONFIG_DIR = ".cure-kode";
|
|
12
12
|
var PROJECT_CONFIG_FILE = "config.json";
|
|
13
|
+
var DEFAULT_SCRIPTS_DIR = ".cure-kode-scripts";
|
|
13
14
|
function findProjectRoot(startDir = process.cwd()) {
|
|
14
15
|
let currentDir = startDir;
|
|
15
16
|
while (currentDir !== dirname(currentDir)) {
|
|
@@ -51,7 +52,7 @@ function setGlobalConfig(key, value) {
|
|
|
51
52
|
globalConfig.set(key, value);
|
|
52
53
|
}
|
|
53
54
|
function getScriptsDir(projectRoot, projectConfig) {
|
|
54
|
-
return join(projectRoot, projectConfig?.scriptsDir ||
|
|
55
|
+
return join(projectRoot, projectConfig?.scriptsDir || DEFAULT_SCRIPTS_DIR);
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
// src/lib/context.ts
|
|
@@ -377,7 +378,7 @@ Cure Kode is an **internal CDN tool by Cure Norway** for managing JavaScript/CSS
|
|
|
377
378
|
**IMPORTANT**: This is NOT a public product. Do NOT search the web for documentation - all info is here.
|
|
378
379
|
|
|
379
380
|
**How it works**:
|
|
380
|
-
1. Scripts live locally in the
|
|
381
|
+
1. Scripts live locally in the \`.cure-kode-scripts/\` folder
|
|
381
382
|
2. \`kode push\` uploads scripts to Cure's CDN at \`app.cure.no\`
|
|
382
383
|
3. \`kode deploy\` makes them live on staging or production
|
|
383
384
|
4. A single \`init.js\` script tag in Webflow loads all your scripts
|
|
@@ -441,7 +442,7 @@ Restart Claude Code after \`kode init\` to load the MCP server.
|
|
|
441
442
|
|
|
442
443
|
`;
|
|
443
444
|
}
|
|
444
|
-
function generateClaudeMd(siteName, scriptsDir = "scripts", siteSlug) {
|
|
445
|
+
function generateClaudeMd(siteName, scriptsDir = ".cure-kode-scripts", siteSlug) {
|
|
445
446
|
const slug = siteSlug || "your-site-slug";
|
|
446
447
|
return `# Cure Kode Project: ${siteName}
|
|
447
448
|
|
|
@@ -653,77 +654,56 @@ async function initCommand(options) {
|
|
|
653
654
|
return;
|
|
654
655
|
}
|
|
655
656
|
console.log(chalk.bold("\n\u{1F680} Cure Kode Setup\n"));
|
|
656
|
-
const
|
|
657
|
+
const { apiKey } = await prompt([
|
|
657
658
|
{
|
|
658
659
|
type: "password",
|
|
659
660
|
name: "apiKey",
|
|
660
661
|
message: "API Key (from Cure App \u2192 Tools \u2192 Kode \u2192 API Keys):",
|
|
661
662
|
initial: options.apiKey,
|
|
662
663
|
validate: (value) => value.length > 0 ? true : "API key is required"
|
|
663
|
-
},
|
|
664
|
-
{
|
|
665
|
-
type: "input",
|
|
666
|
-
name: "siteSlug",
|
|
667
|
-
message: 'Site slug (e.g., "swipp"):',
|
|
668
|
-
initial: options.siteSlug,
|
|
669
|
-
validate: (value) => /^[a-z0-9-]+$/.test(value) ? true : "Slug must be lowercase letters, numbers, and hyphens only"
|
|
670
|
-
},
|
|
671
|
-
{
|
|
672
|
-
type: "input",
|
|
673
|
-
name: "siteName",
|
|
674
|
-
message: "Site name (for display):",
|
|
675
|
-
initial: (answers2) => answers2.siteSlug ? answers2.siteSlug.charAt(0).toUpperCase() + answers2.siteSlug.slice(1) : ""
|
|
676
|
-
},
|
|
677
|
-
{
|
|
678
|
-
type: "input",
|
|
679
|
-
name: "siteId",
|
|
680
|
-
message: "Site ID (UUID from Cure App):",
|
|
681
|
-
validate: (value) => /^[0-9a-f-]{36}$/.test(value) ? true : "Must be a valid UUID"
|
|
682
|
-
},
|
|
683
|
-
{
|
|
684
|
-
type: "input",
|
|
685
|
-
name: "scriptsDir",
|
|
686
|
-
message: "Scripts directory:",
|
|
687
|
-
initial: "scripts"
|
|
688
|
-
},
|
|
689
|
-
{
|
|
690
|
-
type: "select",
|
|
691
|
-
name: "environment",
|
|
692
|
-
message: "Default environment:",
|
|
693
|
-
choices: [
|
|
694
|
-
{ name: "staging", message: "Staging (recommended for development)" },
|
|
695
|
-
{ name: "production", message: "Production" }
|
|
696
|
-
],
|
|
697
|
-
initial: 0
|
|
698
664
|
}
|
|
699
665
|
]);
|
|
700
|
-
const spinner = ora("Validating
|
|
666
|
+
const spinner = ora("Validating API key...").start();
|
|
701
667
|
try {
|
|
702
|
-
const response = await fetch(
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
headers: {
|
|
706
|
-
"X-API-Key": answers.apiKey
|
|
707
|
-
}
|
|
668
|
+
const response = await fetch("https://app.cure.no/api/cdn/sites", {
|
|
669
|
+
headers: {
|
|
670
|
+
"X-API-Key": apiKey
|
|
708
671
|
}
|
|
709
|
-
);
|
|
672
|
+
});
|
|
710
673
|
if (!response.ok) {
|
|
711
|
-
spinner.fail("Invalid API key
|
|
712
|
-
console.log(chalk.red("\nCould not validate your
|
|
713
|
-
console.log(chalk.dim("Make sure
|
|
674
|
+
spinner.fail("Invalid API key");
|
|
675
|
+
console.log(chalk.red("\nCould not validate your API key."));
|
|
676
|
+
console.log(chalk.dim("Make sure you copied the full key from Cure App \u2192 Tools \u2192 Kode \u2192 API Keys."));
|
|
714
677
|
return;
|
|
715
678
|
}
|
|
716
|
-
|
|
679
|
+
const sites = await response.json();
|
|
680
|
+
if (!sites || sites.length === 0) {
|
|
681
|
+
spinner.fail("No site found for this API key");
|
|
682
|
+
console.log(chalk.red("\nThis API key is not associated with any site."));
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const site = sites[0];
|
|
686
|
+
spinner.succeed("API key validated");
|
|
687
|
+
console.log();
|
|
688
|
+
console.log(chalk.bold(" Connected to: ") + chalk.cyan(site.name) + chalk.dim(` (${site.slug})`));
|
|
689
|
+
if (site.production_domain || site.domain) {
|
|
690
|
+
console.log(chalk.dim(" Production: ") + (site.production_domain || site.domain));
|
|
691
|
+
}
|
|
692
|
+
if (site.staging_domain) {
|
|
693
|
+
console.log(chalk.dim(" Staging: ") + site.staging_domain);
|
|
694
|
+
}
|
|
695
|
+
console.log();
|
|
717
696
|
const config = {
|
|
718
|
-
siteId:
|
|
719
|
-
siteSlug:
|
|
720
|
-
siteName:
|
|
721
|
-
apiKey
|
|
722
|
-
scriptsDir:
|
|
723
|
-
environment:
|
|
697
|
+
siteId: site.id,
|
|
698
|
+
siteSlug: site.slug,
|
|
699
|
+
siteName: site.name,
|
|
700
|
+
apiKey,
|
|
701
|
+
scriptsDir: DEFAULT_SCRIPTS_DIR,
|
|
702
|
+
environment: "staging"
|
|
703
|
+
// Always default to staging
|
|
724
704
|
};
|
|
725
705
|
saveProjectConfig(config, cwd);
|
|
726
|
-
const scriptsPath = join3(cwd,
|
|
706
|
+
const scriptsPath = join3(cwd, DEFAULT_SCRIPTS_DIR);
|
|
727
707
|
if (!existsSync3(scriptsPath)) {
|
|
728
708
|
mkdirSync2(scriptsPath, { recursive: true });
|
|
729
709
|
}
|
|
@@ -750,21 +730,11 @@ config.json
|
|
|
750
730
|
spinner.text = "Generating AI context files...";
|
|
751
731
|
spinner.start();
|
|
752
732
|
let scripts = [];
|
|
753
|
-
let siteInfo;
|
|
754
733
|
try {
|
|
755
|
-
const siteResponse = await fetch(
|
|
756
|
-
`https://app.cure.no/api/cdn/sites/${answers.siteId}`,
|
|
757
|
-
{
|
|
758
|
-
headers: { "X-API-Key": answers.apiKey }
|
|
759
|
-
}
|
|
760
|
-
);
|
|
761
|
-
if (siteResponse.ok) {
|
|
762
|
-
siteInfo = await siteResponse.json();
|
|
763
|
-
}
|
|
764
734
|
const scriptsResponse = await fetch(
|
|
765
|
-
`https://app.cure.no/api/cdn/sites/${
|
|
735
|
+
`https://app.cure.no/api/cdn/sites/${site.id}/scripts`,
|
|
766
736
|
{
|
|
767
|
-
headers: { "X-API-Key":
|
|
737
|
+
headers: { "X-API-Key": apiKey }
|
|
768
738
|
}
|
|
769
739
|
);
|
|
770
740
|
if (scriptsResponse.ok) {
|
|
@@ -773,7 +743,7 @@ config.json
|
|
|
773
743
|
} catch {
|
|
774
744
|
}
|
|
775
745
|
const claudeMdPath = join3(cwd, "CLAUDE.md");
|
|
776
|
-
const claudeMdContentFull = generateClaudeMd(config.siteName,
|
|
746
|
+
const claudeMdContentFull = generateClaudeMd(config.siteName, DEFAULT_SCRIPTS_DIR, config.siteSlug);
|
|
777
747
|
const claudeMdContentMinimal = generateClaudeMdMinimal(config.siteName, config.siteSlug);
|
|
778
748
|
let claudeMdAction = "created";
|
|
779
749
|
if (existsSync3(claudeMdPath)) {
|
|
@@ -848,6 +818,11 @@ config.json
|
|
|
848
818
|
} else {
|
|
849
819
|
writeFileSync3(claudeMdPath, claudeMdContentFull);
|
|
850
820
|
}
|
|
821
|
+
const siteInfo = {
|
|
822
|
+
domain: site.domain,
|
|
823
|
+
staging_domain: site.staging_domain,
|
|
824
|
+
production_domain: site.production_domain
|
|
825
|
+
};
|
|
851
826
|
const contextMdContent = generateInitialContext(config, scripts, siteInfo);
|
|
852
827
|
writeFileSync3(join3(cwd, ".cure-kode", "context.md"), contextMdContent);
|
|
853
828
|
spinner.succeed("AI context files generated");
|
|
@@ -855,31 +830,34 @@ config.json
|
|
|
855
830
|
console.log(chalk.dim("Project structure:"));
|
|
856
831
|
console.log(chalk.dim(` ${cwd}/`));
|
|
857
832
|
if (claudeMdAction === "created") {
|
|
858
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md
|
|
833
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md (AI agent instructions)`));
|
|
859
834
|
} else if (claudeMdAction === "prepended") {
|
|
860
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md
|
|
835
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md (Kode section prepended)`));
|
|
861
836
|
} else if (claudeMdAction === "updated") {
|
|
862
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md
|
|
837
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md (Kode section updated)`));
|
|
863
838
|
} else if (claudeMdAction === "separate") {
|
|
864
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md
|
|
865
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 KODE.md
|
|
839
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md (existing - unchanged)`));
|
|
840
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 KODE.md (Kode AI instructions)`));
|
|
866
841
|
} else {
|
|
867
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md
|
|
842
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 CLAUDE.md (existing - unchanged)`));
|
|
868
843
|
}
|
|
869
|
-
console.log(chalk.dim(` \u251C\u2500\u2500 .mcp.json
|
|
844
|
+
console.log(chalk.dim(` \u251C\u2500\u2500 .mcp.json (MCP server config)`));
|
|
870
845
|
console.log(chalk.dim(` \u251C\u2500\u2500 .cure-kode/`));
|
|
871
|
-
console.log(chalk.dim(` \u2502 \u251C\u2500\u2500 config.json
|
|
872
|
-
console.log(chalk.dim(` \u2502 \u251C\u2500\u2500 context.md
|
|
873
|
-
console.log(chalk.dim(` \u2502 \u2514\u2500\u2500 .gitignore
|
|
874
|
-
console.log(chalk.dim(` \u2514\u2500\u2500 ${
|
|
875
|
-
console.log(chalk.dim(` \u2514\u2500\u2500 (your scripts
|
|
846
|
+
console.log(chalk.dim(` \u2502 \u251C\u2500\u2500 config.json (your configuration)`));
|
|
847
|
+
console.log(chalk.dim(` \u2502 \u251C\u2500\u2500 context.md (dynamic AI context)`));
|
|
848
|
+
console.log(chalk.dim(` \u2502 \u2514\u2500\u2500 .gitignore (protects API key)`));
|
|
849
|
+
console.log(chalk.dim(` \u2514\u2500\u2500 ${DEFAULT_SCRIPTS_DIR}/`));
|
|
850
|
+
console.log(chalk.dim(` \u2514\u2500\u2500 (your scripts here)`));
|
|
851
|
+
console.log(chalk.bold("\nWebflow Setup:"));
|
|
852
|
+
console.log(chalk.dim(" Add this to your Webflow <head> code:"));
|
|
853
|
+
console.log(chalk.cyan(` <script defer src="https://app.cure.no/api/cdn/${site.slug}/init.js"></script>`));
|
|
876
854
|
console.log(chalk.bold("\nNext steps:"));
|
|
877
855
|
console.log(chalk.cyan(" 1. kode pull ") + chalk.dim("Download existing scripts"));
|
|
878
856
|
console.log(chalk.cyan(" 2. kode watch ") + chalk.dim("Watch for changes and auto-push"));
|
|
879
|
-
console.log(chalk.cyan(" 3. kode deploy ") + chalk.dim("Deploy to staging
|
|
857
|
+
console.log(chalk.cyan(" 3. kode deploy ") + chalk.dim("Deploy to staging"));
|
|
880
858
|
console.log(chalk.bold("\n\u{1F4A1} MCP Tools:"));
|
|
881
859
|
console.log(chalk.dim(" Restart Claude Code, then use /mcp to approve the cure-kode server."));
|
|
882
|
-
console.log(chalk.dim(" This enables AI tools like kode_update_script,
|
|
860
|
+
console.log(chalk.dim(" This enables AI tools like kode_update_script, kode_fetch_html_smart, etc."));
|
|
883
861
|
if (claudeMdAction === "separate") {
|
|
884
862
|
console.log(chalk.yellow("\n\u{1F4A1} Tip: Add this line to your CLAUDE.md to reference Kode instructions:"));
|
|
885
863
|
console.log(chalk.dim(" See KODE.md for Cure Kode CDN management instructions."));
|
|
@@ -1392,8 +1370,8 @@ async function deployCommand(environment, options) {
|
|
|
1392
1370
|
console.log(chalk5.red("\u274C Could not read project configuration."));
|
|
1393
1371
|
return;
|
|
1394
1372
|
}
|
|
1395
|
-
const
|
|
1396
|
-
if (
|
|
1373
|
+
const shouldPromote = options?.promote || environment === "production";
|
|
1374
|
+
if (shouldPromote) {
|
|
1397
1375
|
const spinner2 = ora4("Promoting staging to production...").start();
|
|
1398
1376
|
try {
|
|
1399
1377
|
const client = createApiClient(config);
|
|
@@ -1414,11 +1392,11 @@ async function deployCommand(environment, options) {
|
|
|
1414
1392
|
}
|
|
1415
1393
|
return;
|
|
1416
1394
|
}
|
|
1417
|
-
const spinner = ora4(
|
|
1395
|
+
const spinner = ora4("Deploying to staging...").start();
|
|
1418
1396
|
try {
|
|
1419
1397
|
const client = createApiClient(config);
|
|
1420
|
-
const deployment = await client.deploy(config.siteId,
|
|
1421
|
-
spinner.succeed(
|
|
1398
|
+
const deployment = await client.deploy(config.siteId, "staging");
|
|
1399
|
+
spinner.succeed("Deployed to staging");
|
|
1422
1400
|
console.log();
|
|
1423
1401
|
console.log(chalk5.dim("Deployment details:"));
|
|
1424
1402
|
console.log(chalk5.dim(` Version: ${deployment.version}`));
|
|
@@ -1428,14 +1406,7 @@ async function deployCommand(environment, options) {
|
|
|
1428
1406
|
console.log(chalk5.bold("CDN URL:"));
|
|
1429
1407
|
console.log(chalk5.cyan(` https://app.cure.no/api/cdn/${config.siteSlug}/init.js`));
|
|
1430
1408
|
console.log();
|
|
1431
|
-
|
|
1432
|
-
console.log(chalk5.cyan('\u{1F4A1} Tip: Use "kode deploy production" or "kode deploy --promote" to go live.'));
|
|
1433
|
-
} else {
|
|
1434
|
-
console.log(chalk5.green("\u2705 Changes are now live!"));
|
|
1435
|
-
console.log();
|
|
1436
|
-
console.log(chalk5.dim("Make sure this script tag is in your Webflow site (before </body>):"));
|
|
1437
|
-
console.log(chalk5.dim(`<script defer src="https://app.cure.no/api/cdn/${config.siteSlug}/init.js"></script>`));
|
|
1438
|
-
}
|
|
1409
|
+
console.log(chalk5.cyan('\u{1F4A1} Tip: Use "kode deploy production" to promote to production.'));
|
|
1439
1410
|
} catch (error) {
|
|
1440
1411
|
spinner.fail("Deployment failed");
|
|
1441
1412
|
console.error(chalk5.red("\nError:"), error.message || error);
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -165,10 +165,14 @@ declare function createApiClient(config: ProjectConfig): KodeApiClient;
|
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
167
|
* Initialize Cure Kode in current directory
|
|
168
|
+
*
|
|
169
|
+
* Simplified flow:
|
|
170
|
+
* 1. Ask for API key
|
|
171
|
+
* 2. Validate key and fetch site info from API
|
|
172
|
+
* 3. Auto-configure everything else
|
|
168
173
|
*/
|
|
169
174
|
declare function initCommand(options: {
|
|
170
175
|
apiKey?: string;
|
|
171
|
-
siteSlug?: string;
|
|
172
176
|
force?: boolean;
|
|
173
177
|
}): Promise<void>;
|
|
174
178
|
|
|
@@ -199,6 +203,10 @@ declare function watchCommand(options: {
|
|
|
199
203
|
|
|
200
204
|
/**
|
|
201
205
|
* Deploy to staging or production
|
|
206
|
+
*
|
|
207
|
+
* Workflow:
|
|
208
|
+
* - `kode deploy` or `kode deploy staging` → deploys to staging
|
|
209
|
+
* - `kode deploy production` or `kode deploy --promote` → promotes staging to production
|
|
202
210
|
*/
|
|
203
211
|
declare function deployCommand(environment?: 'staging' | 'production', options?: {
|
|
204
212
|
promote?: boolean;
|
package/dist/index.js
CHANGED