@curenorway/kode-mcp 1.1.0 → 1.3.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/index.js +568 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -105,6 +105,16 @@ var KodeApiClient = class {
|
|
|
105
105
|
async getDeploymentStatus(siteId) {
|
|
106
106
|
return this.request(`/api/cdn/sites/${siteId}/deployments/status`);
|
|
107
107
|
}
|
|
108
|
+
// v2.3: Production enabled toggle
|
|
109
|
+
async setProductionEnabled(siteId, enabled, productionDomain) {
|
|
110
|
+
return this.request(`/api/cdn/sites/${siteId}/production`, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
body: JSON.stringify({
|
|
113
|
+
enabled,
|
|
114
|
+
productionDomain
|
|
115
|
+
})
|
|
116
|
+
});
|
|
117
|
+
}
|
|
108
118
|
// HTML operations
|
|
109
119
|
async fetchHtml(siteId, url) {
|
|
110
120
|
return this.request("/api/cdn/fetch-html", {
|
|
@@ -121,6 +131,16 @@ var KodeApiClient = class {
|
|
|
121
131
|
return false;
|
|
122
132
|
}
|
|
123
133
|
}
|
|
134
|
+
// Metadata operations
|
|
135
|
+
async analyzeScript(scriptId, options = {}) {
|
|
136
|
+
return this.request(`/api/cdn/scripts/${scriptId}/analyze`, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
body: JSON.stringify(options)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async getScriptMetadata(scriptId) {
|
|
142
|
+
return this.request(`/api/cdn/scripts/${scriptId}/metadata`);
|
|
143
|
+
}
|
|
124
144
|
};
|
|
125
145
|
|
|
126
146
|
// src/config.ts
|
|
@@ -252,13 +272,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
252
272
|
},
|
|
253
273
|
{
|
|
254
274
|
name: "kode_get_script",
|
|
255
|
-
description: "Get
|
|
275
|
+
description: "Get a script by its slug or ID. By default returns full content. Use includeContent:false to get just metadata (saves context tokens for large scripts).",
|
|
256
276
|
inputSchema: {
|
|
257
277
|
type: "object",
|
|
258
278
|
properties: {
|
|
259
279
|
slug: {
|
|
260
280
|
type: "string",
|
|
261
281
|
description: 'Script slug (e.g., "init", "tracking") or script ID (UUID)'
|
|
282
|
+
},
|
|
283
|
+
includeContent: {
|
|
284
|
+
type: "boolean",
|
|
285
|
+
description: "Include full script content. Default: true. Set to false to get just metadata (name, type, scope, version, size) - useful for large scripts."
|
|
286
|
+
},
|
|
287
|
+
contentPreview: {
|
|
288
|
+
type: "number",
|
|
289
|
+
description: "If set, include only the first N characters of content. Useful for previewing large scripts without loading everything."
|
|
262
290
|
}
|
|
263
291
|
},
|
|
264
292
|
required: ["slug"]
|
|
@@ -266,7 +294,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
266
294
|
},
|
|
267
295
|
{
|
|
268
296
|
name: "kode_create_script",
|
|
269
|
-
description: "Create a new script
|
|
297
|
+
description: "Create a new script entry (metadata only). After creating, write the script file locally to .cure-kode-scripts/{name}.js and use kode_push to upload content. This keeps script content out of MCP context.",
|
|
270
298
|
inputSchema: {
|
|
271
299
|
type: "object",
|
|
272
300
|
properties: {
|
|
@@ -279,10 +307,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
279
307
|
enum: ["javascript", "css"],
|
|
280
308
|
description: "Script type"
|
|
281
309
|
},
|
|
282
|
-
content: {
|
|
283
|
-
type: "string",
|
|
284
|
-
description: "Script content (JavaScript or CSS code)"
|
|
285
|
-
},
|
|
286
310
|
scope: {
|
|
287
311
|
type: "string",
|
|
288
312
|
enum: ["global", "page-specific"],
|
|
@@ -290,15 +314,37 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
290
314
|
},
|
|
291
315
|
autoLoad: {
|
|
292
316
|
type: "boolean",
|
|
293
|
-
description: "Whether to auto-load the script. Default: true for global scripts, false for page-specific.
|
|
317
|
+
description: "Whether to auto-load the script. Default: true for global scripts, false for page-specific."
|
|
318
|
+
},
|
|
319
|
+
purpose: {
|
|
320
|
+
type: "string",
|
|
321
|
+
description: "Brief description of what the script does (for metadata)"
|
|
294
322
|
}
|
|
295
323
|
},
|
|
296
|
-
required: ["name", "type"
|
|
324
|
+
required: ["name", "type"]
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "kode_push",
|
|
329
|
+
description: "Push local script files to Cure Kode. Reads files from .cure-kode-scripts/ folder and uploads to API. This is the proper way to sync code - never send script content through other MCP tools.",
|
|
330
|
+
inputSchema: {
|
|
331
|
+
type: "object",
|
|
332
|
+
properties: {
|
|
333
|
+
scriptSlug: {
|
|
334
|
+
type: "string",
|
|
335
|
+
description: 'Specific script slug to push (e.g., "map"). If omitted, pushes all changed scripts.'
|
|
336
|
+
},
|
|
337
|
+
force: {
|
|
338
|
+
type: "boolean",
|
|
339
|
+
description: "Force push even if content appears unchanged. Default: false"
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
required: []
|
|
297
343
|
}
|
|
298
344
|
},
|
|
299
345
|
{
|
|
300
346
|
name: "kode_update_script",
|
|
301
|
-
description: "Update
|
|
347
|
+
description: "Update script settings (NOT content). For content changes, edit the local file in .cure-kode-scripts/ and use kode_push. This tool is for metadata, scope, and autoLoad changes only.",
|
|
302
348
|
inputSchema: {
|
|
303
349
|
type: "object",
|
|
304
350
|
properties: {
|
|
@@ -306,10 +352,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
306
352
|
type: "string",
|
|
307
353
|
description: "Script slug or ID to update"
|
|
308
354
|
},
|
|
309
|
-
content: {
|
|
310
|
-
type: "string",
|
|
311
|
-
description: "New script content"
|
|
312
|
-
},
|
|
313
355
|
autoLoad: {
|
|
314
356
|
type: "boolean",
|
|
315
357
|
description: "Whether to auto-load the script. Set to true to load automatically, false for manual loading via CK.loadScript()."
|
|
@@ -319,9 +361,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
319
361
|
enum: ["global", "page-specific"],
|
|
320
362
|
description: "Change script scope. Note: changing to page-specific requires assigning to pages."
|
|
321
363
|
},
|
|
322
|
-
|
|
364
|
+
purpose: {
|
|
323
365
|
type: "string",
|
|
324
|
-
description: "
|
|
366
|
+
description: "Update the script purpose description (shown in Chrome Extension)"
|
|
367
|
+
},
|
|
368
|
+
regenerateSummary: {
|
|
369
|
+
type: "boolean",
|
|
370
|
+
description: "Re-analyze the script content and regenerate the AI summary. Useful after significant changes."
|
|
325
371
|
}
|
|
326
372
|
},
|
|
327
373
|
required: ["slug"]
|
|
@@ -371,7 +417,30 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
371
417
|
},
|
|
372
418
|
{
|
|
373
419
|
name: "kode_status",
|
|
374
|
-
description: "Get the current deployment status
|
|
420
|
+
description: "Get the current deployment status including production enabled state, staging and production environments.",
|
|
421
|
+
inputSchema: {
|
|
422
|
+
type: "object",
|
|
423
|
+
properties: {},
|
|
424
|
+
required: []
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: "kode_production_enable",
|
|
429
|
+
description: "Enable production environment for this site. Required before promoting to production. Sites start in staging-only mode by default.",
|
|
430
|
+
inputSchema: {
|
|
431
|
+
type: "object",
|
|
432
|
+
properties: {
|
|
433
|
+
productionDomain: {
|
|
434
|
+
type: "string",
|
|
435
|
+
description: 'Production domain (e.g., "example.com"). Optional - can be set later.'
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
required: []
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
name: "kode_production_disable",
|
|
443
|
+
description: "Disable production environment for this site. Production requests will return an empty script. Useful during development when only staging should be active.",
|
|
375
444
|
inputSchema: {
|
|
376
445
|
type: "object",
|
|
377
446
|
properties: {},
|
|
@@ -450,6 +519,38 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
450
519
|
required: []
|
|
451
520
|
}
|
|
452
521
|
},
|
|
522
|
+
{
|
|
523
|
+
name: "kode_analyze_script",
|
|
524
|
+
description: "Analyze a script's content and auto-generate metadata. Detects DOM selectors, event triggers, dependencies (GSAP, Swiper, etc.), and behavior patterns. Optionally saves the analysis to the script.",
|
|
525
|
+
inputSchema: {
|
|
526
|
+
type: "object",
|
|
527
|
+
properties: {
|
|
528
|
+
slug: {
|
|
529
|
+
type: "string",
|
|
530
|
+
description: "Script slug or ID to analyze"
|
|
531
|
+
},
|
|
532
|
+
saveToScript: {
|
|
533
|
+
type: "boolean",
|
|
534
|
+
description: "Save the generated metadata to the script. Default: false (preview only)"
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
required: ["slug"]
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
name: "kode_get_script_metadata",
|
|
542
|
+
description: "Get the metadata for a script, including detected DOM targets, triggers, dependencies, and AI summary. Useful for Chrome Extension visibility.",
|
|
543
|
+
inputSchema: {
|
|
544
|
+
type: "object",
|
|
545
|
+
properties: {
|
|
546
|
+
slug: {
|
|
547
|
+
type: "string",
|
|
548
|
+
description: "Script slug or ID to get metadata for"
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
required: ["slug"]
|
|
552
|
+
}
|
|
553
|
+
},
|
|
453
554
|
{
|
|
454
555
|
name: "kode_read_context",
|
|
455
556
|
description: "Read the project context file (.cure-kode/context.md). Contains current scripts, notes, and session history. ALWAYS call this before starting work on a Kode project.",
|
|
@@ -597,7 +698,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
597
698
|
};
|
|
598
699
|
}
|
|
599
700
|
case "kode_get_script": {
|
|
600
|
-
const { slug } = args;
|
|
701
|
+
const { slug, includeContent = true, contentPreview } = args;
|
|
601
702
|
const scripts = await client.listScripts(siteId);
|
|
602
703
|
const script = scripts.find((s) => s.slug === slug || s.id === slug);
|
|
603
704
|
if (!script) {
|
|
@@ -606,6 +707,44 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
606
707
|
isError: true
|
|
607
708
|
};
|
|
608
709
|
}
|
|
710
|
+
const contentLength = script.content?.length || 0;
|
|
711
|
+
const estimatedTokens = Math.ceil(contentLength / 4);
|
|
712
|
+
if (!includeContent && !contentPreview) {
|
|
713
|
+
return {
|
|
714
|
+
content: [
|
|
715
|
+
{
|
|
716
|
+
type: "text",
|
|
717
|
+
text: `Script: ${script.name}
|
|
718
|
+
Slug: ${script.slug}
|
|
719
|
+
Type: ${script.type}
|
|
720
|
+
Scope: ${script.scope}
|
|
721
|
+
Version: ${script.current_version}
|
|
722
|
+
Auto-load: ${script.auto_load ? "yes" : "no"}
|
|
723
|
+
Size: ${contentLength} chars (~${estimatedTokens} tokens)
|
|
724
|
+
|
|
725
|
+
Use includeContent:true or contentPreview:N to fetch content.`
|
|
726
|
+
}
|
|
727
|
+
]
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
if (contentPreview && contentPreview > 0) {
|
|
731
|
+
const preview = script.content?.slice(0, contentPreview) || "";
|
|
732
|
+
const isTruncated = contentLength > contentPreview;
|
|
733
|
+
return {
|
|
734
|
+
content: [
|
|
735
|
+
{
|
|
736
|
+
type: "text",
|
|
737
|
+
text: `// Script: ${script.name} (${script.type})
|
|
738
|
+
// Version: ${script.current_version}
|
|
739
|
+
// Scope: ${script.scope}
|
|
740
|
+
// Size: ${contentLength} chars (~${estimatedTokens} tokens)${isTruncated ? `
|
|
741
|
+
// Showing first ${contentPreview} chars` : ""}
|
|
742
|
+
|
|
743
|
+
${preview}${isTruncated ? "\n\n// ... (truncated) - use includeContent:true for full content" : ""}`
|
|
744
|
+
}
|
|
745
|
+
]
|
|
746
|
+
};
|
|
747
|
+
}
|
|
609
748
|
return {
|
|
610
749
|
content: [
|
|
611
750
|
{
|
|
@@ -613,6 +752,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
613
752
|
text: `// Script: ${script.name} (${script.type})
|
|
614
753
|
// Version: ${script.current_version}
|
|
615
754
|
// Scope: ${script.scope}
|
|
755
|
+
// Size: ${contentLength} chars (~${estimatedTokens} tokens)
|
|
616
756
|
|
|
617
757
|
${script.content}`
|
|
618
758
|
}
|
|
@@ -620,35 +760,155 @@ ${script.content}`
|
|
|
620
760
|
};
|
|
621
761
|
}
|
|
622
762
|
case "kode_create_script": {
|
|
623
|
-
const { name: scriptName, type,
|
|
763
|
+
const { name: scriptName, type, scope, autoLoad, purpose } = args;
|
|
624
764
|
const scriptScope = scope || "global";
|
|
625
765
|
const script = await client.createScript(siteId, {
|
|
626
766
|
name: scriptName,
|
|
627
767
|
slug: scriptName,
|
|
628
768
|
type,
|
|
629
|
-
content,
|
|
769
|
+
content: "",
|
|
770
|
+
// Empty - content comes from local files via kode_push
|
|
630
771
|
scope: scriptScope,
|
|
631
|
-
autoLoad
|
|
632
|
-
|
|
772
|
+
autoLoad,
|
|
773
|
+
metadata: purpose ? { purpose } : void 0
|
|
633
774
|
});
|
|
634
|
-
const
|
|
775
|
+
const scriptsDir = getScriptsDir();
|
|
776
|
+
const ext = type === "javascript" ? "js" : "css";
|
|
777
|
+
const localPath = scriptsDir ? `${scriptsDir}/${scriptName}.${ext}` : `.cure-kode-scripts/${scriptName}.${ext}`;
|
|
778
|
+
let responseText = `Created script "${script.name}" (${script.type})`;
|
|
779
|
+
responseText += `
|
|
780
|
+
Slug: ${script.slug}`;
|
|
781
|
+
responseText += `
|
|
782
|
+
Scope: ${script.scope}`;
|
|
783
|
+
responseText += `
|
|
784
|
+
Auto-load: ${script.auto_load ? "yes" : "no"}`;
|
|
785
|
+
if (purpose) responseText += `
|
|
786
|
+
Purpose: ${purpose}`;
|
|
787
|
+
responseText += `
|
|
788
|
+
|
|
789
|
+
Next steps:`;
|
|
790
|
+
responseText += `
|
|
791
|
+
1. Create file: ${localPath}`;
|
|
792
|
+
responseText += `
|
|
793
|
+
2. Write your ${type} code`;
|
|
794
|
+
responseText += `
|
|
795
|
+
3. Run kode_push to upload content`;
|
|
796
|
+
responseText += `
|
|
797
|
+
4. Run kode_deploy to make it live`;
|
|
635
798
|
return {
|
|
636
799
|
content: [
|
|
637
800
|
{
|
|
638
801
|
type: "text",
|
|
639
|
-
text:
|
|
640
|
-
Slug: ${script.slug}
|
|
641
|
-
Scope: ${script.scope}
|
|
642
|
-
Auto-load: ${autoLoadStatus}
|
|
643
|
-
Version: ${script.current_version}
|
|
644
|
-
|
|
645
|
-
Note: Run kode_deploy to make it live.`
|
|
802
|
+
text: responseText
|
|
646
803
|
}
|
|
647
804
|
]
|
|
648
805
|
};
|
|
649
806
|
}
|
|
807
|
+
case "kode_push": {
|
|
808
|
+
const { scriptSlug, force } = args;
|
|
809
|
+
const scriptsDir = getScriptsDir();
|
|
810
|
+
if (!scriptsDir || !fs2.existsSync(scriptsDir)) {
|
|
811
|
+
return {
|
|
812
|
+
content: [{
|
|
813
|
+
type: "text",
|
|
814
|
+
text: 'No .cure-kode-scripts/ folder found. Run "kode init" first or create the folder manually.'
|
|
815
|
+
}],
|
|
816
|
+
isError: true
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
const remoteScripts = await client.listScripts(siteId);
|
|
820
|
+
const localFiles = fs2.readdirSync(scriptsDir).filter((f) => f.endsWith(".js") || f.endsWith(".css"));
|
|
821
|
+
if (scriptSlug) {
|
|
822
|
+
const ext = remoteScripts.find((s) => s.slug === scriptSlug)?.type === "css" ? "css" : "js";
|
|
823
|
+
const fileName = `${scriptSlug}.${ext}`;
|
|
824
|
+
const filePath = path2.join(scriptsDir, fileName);
|
|
825
|
+
if (!fs2.existsSync(filePath)) {
|
|
826
|
+
return {
|
|
827
|
+
content: [{
|
|
828
|
+
type: "text",
|
|
829
|
+
text: `File not found: ${filePath}
|
|
830
|
+
|
|
831
|
+
Available files: ${localFiles.join(", ") || "(none)"}`
|
|
832
|
+
}],
|
|
833
|
+
isError: true
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
837
|
+
const remote = remoteScripts.find((s) => s.slug === scriptSlug);
|
|
838
|
+
if (!remote) {
|
|
839
|
+
return {
|
|
840
|
+
content: [{
|
|
841
|
+
type: "text",
|
|
842
|
+
text: `Script "${scriptSlug}" not found on server. Create it first with kode_create_script.`
|
|
843
|
+
}],
|
|
844
|
+
isError: true
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
if (!force && remote.content === content) {
|
|
848
|
+
return {
|
|
849
|
+
content: [{
|
|
850
|
+
type: "text",
|
|
851
|
+
text: `Script "${scriptSlug}" is already up to date (${content.length} chars). Use force: true to push anyway.`
|
|
852
|
+
}]
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
const updated = await client.updateScript(remote.id, {
|
|
856
|
+
content,
|
|
857
|
+
changeSummary: "Pushed via MCP"
|
|
858
|
+
});
|
|
859
|
+
return {
|
|
860
|
+
content: [{
|
|
861
|
+
type: "text",
|
|
862
|
+
text: `Pushed "${scriptSlug}": ${content.length} chars \u2192 v${updated.current_version}
|
|
863
|
+
|
|
864
|
+
Run kode_deploy to make changes live.`
|
|
865
|
+
}]
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
const results = [];
|
|
869
|
+
let pushedCount = 0;
|
|
870
|
+
let skippedCount = 0;
|
|
871
|
+
for (const file of localFiles) {
|
|
872
|
+
const slug = file.replace(/\.(js|css)$/, "");
|
|
873
|
+
const filePath = path2.join(scriptsDir, file);
|
|
874
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
875
|
+
const remote = remoteScripts.find((s) => s.slug === slug);
|
|
876
|
+
if (!remote) {
|
|
877
|
+
results.push(`\u26A0\uFE0F ${slug}: not on server (create with kode_create_script first)`);
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
if (!force && remote.content === content) {
|
|
881
|
+
skippedCount++;
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
try {
|
|
885
|
+
const updated = await client.updateScript(remote.id, {
|
|
886
|
+
content,
|
|
887
|
+
changeSummary: "Pushed via MCP"
|
|
888
|
+
});
|
|
889
|
+
results.push(`\u2713 ${slug}: ${content.length} chars \u2192 v${updated.current_version}`);
|
|
890
|
+
pushedCount++;
|
|
891
|
+
} catch (err) {
|
|
892
|
+
results.push(`\u2717 ${slug}: ${err instanceof Error ? err.message : "failed"}`);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
let responseText = `Push complete: ${pushedCount} updated, ${skippedCount} unchanged`;
|
|
896
|
+
if (results.length > 0) {
|
|
897
|
+
responseText += `
|
|
898
|
+
|
|
899
|
+
${results.join("\n")}`;
|
|
900
|
+
}
|
|
901
|
+
if (pushedCount > 0) {
|
|
902
|
+
responseText += `
|
|
903
|
+
|
|
904
|
+
Run kode_deploy to make changes live.`;
|
|
905
|
+
}
|
|
906
|
+
return {
|
|
907
|
+
content: [{ type: "text", text: responseText }]
|
|
908
|
+
};
|
|
909
|
+
}
|
|
650
910
|
case "kode_update_script": {
|
|
651
|
-
const { slug,
|
|
911
|
+
const { slug, autoLoad, scope, purpose, regenerateSummary } = args;
|
|
652
912
|
const scripts = await client.listScripts(siteId);
|
|
653
913
|
const script = scripts.find((s) => s.slug === slug || s.id === slug);
|
|
654
914
|
if (!script) {
|
|
@@ -657,24 +917,32 @@ Note: Run kode_deploy to make it live.`
|
|
|
657
917
|
isError: true
|
|
658
918
|
};
|
|
659
919
|
}
|
|
660
|
-
const updateData = {
|
|
661
|
-
|
|
920
|
+
const updateData = {
|
|
921
|
+
changeSummary: "Updated settings via MCP"
|
|
922
|
+
};
|
|
662
923
|
if (autoLoad !== void 0) updateData.autoLoad = autoLoad;
|
|
663
924
|
if (scope !== void 0) updateData.scope = scope;
|
|
664
|
-
updateData.
|
|
925
|
+
if (purpose !== void 0) updateData.metadata = { purpose };
|
|
926
|
+
if (regenerateSummary !== void 0) updateData.regenerateSummary = regenerateSummary;
|
|
665
927
|
const updated = await client.updateScript(script.id, updateData);
|
|
666
928
|
const changes = [];
|
|
667
|
-
if (
|
|
668
|
-
if (autoLoad !== void 0) changes.push(`auto_load \u2192 ${autoLoad}`);
|
|
929
|
+
if (autoLoad !== void 0) changes.push(`autoLoad \u2192 ${autoLoad}`);
|
|
669
930
|
if (scope !== void 0) changes.push(`scope \u2192 ${scope}`);
|
|
931
|
+
if (purpose !== void 0) changes.push(`purpose updated`);
|
|
932
|
+
if (regenerateSummary) changes.push("AI summary regenerated");
|
|
933
|
+
let responseText = `Updated script "${updated.name}"`;
|
|
934
|
+
if (changes.length > 0) {
|
|
935
|
+
responseText += `
|
|
936
|
+
Changes: ${changes.join(", ")}`;
|
|
937
|
+
}
|
|
938
|
+
responseText += `
|
|
939
|
+
|
|
940
|
+
To update content: edit local file and run kode_push`;
|
|
670
941
|
return {
|
|
671
942
|
content: [
|
|
672
943
|
{
|
|
673
944
|
type: "text",
|
|
674
|
-
text:
|
|
675
|
-
Changes: ${changes.join(", ")}
|
|
676
|
-
|
|
677
|
-
Note: Run kode_deploy to make changes live.`
|
|
945
|
+
text: responseText
|
|
678
946
|
}
|
|
679
947
|
]
|
|
680
948
|
};
|
|
@@ -705,19 +973,54 @@ Note: Run kode_deploy to make changes live.`
|
|
|
705
973
|
environment: environment || "staging",
|
|
706
974
|
notes: notes || "Deployed via MCP"
|
|
707
975
|
});
|
|
976
|
+
let responseText = `Deployment ${deployment.version} to ${deployment.environment}: ${deployment.status}`;
|
|
977
|
+
responseText += `
|
|
978
|
+
Started: ${deployment.started_at}`;
|
|
979
|
+
if (deployment.completed_at) {
|
|
980
|
+
responseText += `
|
|
981
|
+
Completed: ${deployment.completed_at}`;
|
|
982
|
+
}
|
|
983
|
+
const scriptSizes = deployment.stats?.scriptSizes;
|
|
984
|
+
if (scriptSizes && scriptSizes.length > 0) {
|
|
985
|
+
responseText += `
|
|
986
|
+
|
|
987
|
+
Scripts deployed (${scriptSizes.length}):`;
|
|
988
|
+
for (const s of scriptSizes) {
|
|
989
|
+
const flags = [
|
|
990
|
+
s.scope === "global" ? "G" : "P",
|
|
991
|
+
s.autoLoad ? "\u26A1" : "\u25CB"
|
|
992
|
+
].join("");
|
|
993
|
+
responseText += `
|
|
994
|
+
${s.slug} [${flags}]: ${s.contentSize} chars`;
|
|
995
|
+
if (s.contentSize === 0) {
|
|
996
|
+
responseText += " \u26A0\uFE0F EMPTY";
|
|
997
|
+
} else if (s.contentSize < 50 && s.scope === "global") {
|
|
998
|
+
responseText += " \u26A0\uFE0F very small";
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
708
1002
|
return {
|
|
709
1003
|
content: [
|
|
710
1004
|
{
|
|
711
1005
|
type: "text",
|
|
712
|
-
text:
|
|
713
|
-
Started: ${deployment.started_at}${deployment.completed_at ? `
|
|
714
|
-
Completed: ${deployment.completed_at}` : ""}`
|
|
1006
|
+
text: responseText
|
|
715
1007
|
}
|
|
716
1008
|
]
|
|
717
1009
|
};
|
|
718
1010
|
}
|
|
719
1011
|
case "kode_promote": {
|
|
720
1012
|
const status = await client.getDeploymentStatus(siteId);
|
|
1013
|
+
if (!status.productionEnabled) {
|
|
1014
|
+
return {
|
|
1015
|
+
content: [
|
|
1016
|
+
{
|
|
1017
|
+
type: "text",
|
|
1018
|
+
text: "Cannot promote: Production is not enabled for this site.\n\nRun kode_production_enable first to activate the production environment."
|
|
1019
|
+
}
|
|
1020
|
+
],
|
|
1021
|
+
isError: true
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
721
1024
|
if (!status.canPromote) {
|
|
722
1025
|
return {
|
|
723
1026
|
content: [
|
|
@@ -740,12 +1043,46 @@ Status: ${deployment.status}`
|
|
|
740
1043
|
]
|
|
741
1044
|
};
|
|
742
1045
|
}
|
|
1046
|
+
case "kode_production_enable": {
|
|
1047
|
+
const { productionDomain } = args;
|
|
1048
|
+
const result = await client.setProductionEnabled(siteId, true, productionDomain);
|
|
1049
|
+
let text = "Production environment enabled!\n\n";
|
|
1050
|
+
if (result.productionDomain) {
|
|
1051
|
+
text += `Domain: ${result.productionDomain}
|
|
1052
|
+
`;
|
|
1053
|
+
}
|
|
1054
|
+
text += "\nNext steps:\n";
|
|
1055
|
+
text += "1. Deploy to staging: kode_deploy\n";
|
|
1056
|
+
text += "2. Promote to production: kode_promote";
|
|
1057
|
+
return {
|
|
1058
|
+
content: [{ type: "text", text }]
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
case "kode_production_disable": {
|
|
1062
|
+
await client.setProductionEnabled(siteId, false);
|
|
1063
|
+
return {
|
|
1064
|
+
content: [
|
|
1065
|
+
{
|
|
1066
|
+
type: "text",
|
|
1067
|
+
text: "Production environment disabled.\n\nOnly staging is now active. Production domain requests will receive an empty script with a warning."
|
|
1068
|
+
}
|
|
1069
|
+
]
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
743
1072
|
case "kode_status": {
|
|
744
1073
|
const status = await client.getDeploymentStatus(siteId);
|
|
745
1074
|
const config = getConfig();
|
|
746
1075
|
let text = `Site: ${config?.siteName || "Unknown"}
|
|
747
1076
|
|
|
748
1077
|
`;
|
|
1078
|
+
const productionEnabled = status.productionEnabled ?? false;
|
|
1079
|
+
text += `PRODUCTION STATUS: ${productionEnabled ? "\u2713 Enabled" : "\u25CB Disabled (staging only)"}
|
|
1080
|
+
`;
|
|
1081
|
+
if (productionEnabled && status.productionDomain) {
|
|
1082
|
+
text += ` Domain: ${status.productionDomain}
|
|
1083
|
+
`;
|
|
1084
|
+
}
|
|
1085
|
+
text += "\n";
|
|
749
1086
|
text += `STAGING:
|
|
750
1087
|
`;
|
|
751
1088
|
if (status.staging.lastSuccessful) {
|
|
@@ -760,17 +1097,25 @@ Status: ${deployment.status}`
|
|
|
760
1097
|
text += `
|
|
761
1098
|
PRODUCTION:
|
|
762
1099
|
`;
|
|
763
|
-
if (
|
|
1100
|
+
if (!productionEnabled) {
|
|
1101
|
+
text += ` (Disabled - use kode_production_enable to activate)
|
|
1102
|
+
`;
|
|
1103
|
+
} else if (status.production.lastSuccessful) {
|
|
764
1104
|
text += ` Version: ${status.production.lastSuccessful.version}
|
|
765
1105
|
`;
|
|
766
1106
|
text += ` Deployed: ${status.production.lastSuccessful.completed_at}
|
|
767
1107
|
`;
|
|
768
1108
|
} else {
|
|
769
|
-
text += `
|
|
1109
|
+
text += ` Enabled, not yet deployed
|
|
770
1110
|
`;
|
|
771
1111
|
}
|
|
772
|
-
|
|
1112
|
+
if (productionEnabled) {
|
|
1113
|
+
text += `
|
|
773
1114
|
Can promote staging to production: ${status.canPromote ? "Yes" : "No"}`;
|
|
1115
|
+
} else {
|
|
1116
|
+
text += `
|
|
1117
|
+
Enable production first (kode_production_enable) before promoting.`;
|
|
1118
|
+
}
|
|
774
1119
|
return {
|
|
775
1120
|
content: [{ type: "text", text }]
|
|
776
1121
|
};
|
|
@@ -955,6 +1300,184 @@ Embed code:
|
|
|
955
1300
|
content: [{ type: "text", text }]
|
|
956
1301
|
};
|
|
957
1302
|
}
|
|
1303
|
+
case "kode_analyze_script": {
|
|
1304
|
+
const { slug, saveToScript } = args;
|
|
1305
|
+
const scripts = await client.listScripts(siteId);
|
|
1306
|
+
const script = scripts.find((s) => s.slug === slug || s.id === slug);
|
|
1307
|
+
if (!script) {
|
|
1308
|
+
return {
|
|
1309
|
+
content: [{ type: "text", text: `Script "${slug}" not found` }],
|
|
1310
|
+
isError: true
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
try {
|
|
1314
|
+
const result = await client.analyzeScript(script.id, { saveToScript });
|
|
1315
|
+
let text = `Script Analysis: ${script.name}
|
|
1316
|
+
|
|
1317
|
+
`;
|
|
1318
|
+
text += `Purpose: ${result.metadata.purpose || "(not detected)"}
|
|
1319
|
+
|
|
1320
|
+
`;
|
|
1321
|
+
if (result.metadata.triggers.length > 0) {
|
|
1322
|
+
text += `Triggers:
|
|
1323
|
+
`;
|
|
1324
|
+
for (const t of result.metadata.triggers) {
|
|
1325
|
+
text += ` - ${t.event}${t.selector ? ` on ${t.selector}` : ""}
|
|
1326
|
+
`;
|
|
1327
|
+
}
|
|
1328
|
+
text += "\n";
|
|
1329
|
+
}
|
|
1330
|
+
if (result.metadata.domTargets.length > 0) {
|
|
1331
|
+
text += `DOM Targets:
|
|
1332
|
+
`;
|
|
1333
|
+
for (const d of result.metadata.domTargets) {
|
|
1334
|
+
text += ` - ${d.selector} (${d.action})
|
|
1335
|
+
`;
|
|
1336
|
+
}
|
|
1337
|
+
text += "\n";
|
|
1338
|
+
}
|
|
1339
|
+
if (result.metadata.dependencies.length > 0) {
|
|
1340
|
+
text += `Dependencies:
|
|
1341
|
+
`;
|
|
1342
|
+
for (const dep of result.metadata.dependencies) {
|
|
1343
|
+
text += ` - ${dep.name}${dep.required ? " (required)" : ""}
|
|
1344
|
+
`;
|
|
1345
|
+
}
|
|
1346
|
+
text += "\n";
|
|
1347
|
+
}
|
|
1348
|
+
text += `Flags:
|
|
1349
|
+
`;
|
|
1350
|
+
text += ` - Modifies DOM: ${result.metadata.modifiesDom ? "Yes" : "No"}
|
|
1351
|
+
`;
|
|
1352
|
+
text += ` - Event listeners: ${result.metadata.addsEventListeners ? "Yes" : "No"}
|
|
1353
|
+
`;
|
|
1354
|
+
if (result.metadata.usesExternalApis) text += ` - Uses external APIs: Yes
|
|
1355
|
+
`;
|
|
1356
|
+
if (result.metadata.usesLocalStorage) text += ` - Uses localStorage: Yes
|
|
1357
|
+
`;
|
|
1358
|
+
if (result.metadata.usesCookies) text += ` - Uses cookies: Yes
|
|
1359
|
+
`;
|
|
1360
|
+
if (result.warnings.length > 0) {
|
|
1361
|
+
text += `
|
|
1362
|
+
Warnings:
|
|
1363
|
+
`;
|
|
1364
|
+
for (const w of result.warnings) {
|
|
1365
|
+
text += ` \u26A0\uFE0F ${w}
|
|
1366
|
+
`;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
if (result.suggestions.length > 0) {
|
|
1370
|
+
text += `
|
|
1371
|
+
Suggestions:
|
|
1372
|
+
`;
|
|
1373
|
+
for (const s of result.suggestions) {
|
|
1374
|
+
text += ` \u{1F4A1} ${s}
|
|
1375
|
+
`;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
if (saveToScript) {
|
|
1379
|
+
text += `
|
|
1380
|
+
\u2713 Metadata saved to script. Run kode_deploy to update CDN.`;
|
|
1381
|
+
} else {
|
|
1382
|
+
text += `
|
|
1383
|
+
Use saveToScript: true to save this metadata to the script.`;
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
content: [{ type: "text", text }]
|
|
1387
|
+
};
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1390
|
+
return {
|
|
1391
|
+
content: [{ type: "text", text: `Failed to analyze script: ${message}` }],
|
|
1392
|
+
isError: true
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
case "kode_get_script_metadata": {
|
|
1397
|
+
const { slug } = args;
|
|
1398
|
+
const scripts = await client.listScripts(siteId);
|
|
1399
|
+
const script = scripts.find((s) => s.slug === slug || s.id === slug);
|
|
1400
|
+
if (!script) {
|
|
1401
|
+
return {
|
|
1402
|
+
content: [{ type: "text", text: `Script "${slug}" not found` }],
|
|
1403
|
+
isError: true
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
try {
|
|
1407
|
+
const result = await client.getScriptMetadata(script.id);
|
|
1408
|
+
if (!result.metadata) {
|
|
1409
|
+
return {
|
|
1410
|
+
content: [{
|
|
1411
|
+
type: "text",
|
|
1412
|
+
text: `Script "${script.name}" has no metadata.
|
|
1413
|
+
|
|
1414
|
+
Use kode_analyze_script to generate metadata, or provide metadata when creating/updating the script.`
|
|
1415
|
+
}]
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
let text = `Metadata for: ${script.name}
|
|
1419
|
+
|
|
1420
|
+
`;
|
|
1421
|
+
if (result.metadata.purpose) {
|
|
1422
|
+
text += `Purpose: ${result.metadata.purpose}
|
|
1423
|
+
|
|
1424
|
+
`;
|
|
1425
|
+
}
|
|
1426
|
+
if (result.aiSummary) {
|
|
1427
|
+
text += `AI Summary: ${result.aiSummary}
|
|
1428
|
+
|
|
1429
|
+
`;
|
|
1430
|
+
}
|
|
1431
|
+
if (result.metadata.triggers.length > 0) {
|
|
1432
|
+
text += `Triggers:
|
|
1433
|
+
`;
|
|
1434
|
+
for (const t of result.metadata.triggers) {
|
|
1435
|
+
text += ` - ${t.event}${t.selector ? ` on ${t.selector}` : ""}
|
|
1436
|
+
`;
|
|
1437
|
+
}
|
|
1438
|
+
text += "\n";
|
|
1439
|
+
}
|
|
1440
|
+
if (result.metadata.domTargets.length > 0) {
|
|
1441
|
+
text += `DOM Targets:
|
|
1442
|
+
`;
|
|
1443
|
+
for (const d of result.metadata.domTargets) {
|
|
1444
|
+
text += ` - ${d.selector} (${d.action})
|
|
1445
|
+
`;
|
|
1446
|
+
}
|
|
1447
|
+
text += "\n";
|
|
1448
|
+
}
|
|
1449
|
+
if (result.metadata.dependencies.length > 0) {
|
|
1450
|
+
text += `Dependencies:
|
|
1451
|
+
`;
|
|
1452
|
+
for (const dep of result.metadata.dependencies) {
|
|
1453
|
+
text += ` - ${dep.name}${dep.required ? " (required)" : ""}
|
|
1454
|
+
`;
|
|
1455
|
+
}
|
|
1456
|
+
text += "\n";
|
|
1457
|
+
}
|
|
1458
|
+
text += `Flags:
|
|
1459
|
+
`;
|
|
1460
|
+
text += ` - AI Generated: ${result.aiGenerated ? "Yes" : "No"}
|
|
1461
|
+
`;
|
|
1462
|
+
text += ` - Modifies DOM: ${result.metadata.modifiesDom ? "Yes" : "No"}
|
|
1463
|
+
`;
|
|
1464
|
+
text += ` - Event listeners: ${result.metadata.addsEventListeners ? "Yes" : "No"}
|
|
1465
|
+
`;
|
|
1466
|
+
if (result.lastAnalyzed) {
|
|
1467
|
+
text += `
|
|
1468
|
+
Last analyzed: ${result.lastAnalyzed}`;
|
|
1469
|
+
}
|
|
1470
|
+
return {
|
|
1471
|
+
content: [{ type: "text", text }]
|
|
1472
|
+
};
|
|
1473
|
+
} catch (error) {
|
|
1474
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1475
|
+
return {
|
|
1476
|
+
content: [{ type: "text", text: `Failed to get metadata: ${message}` }],
|
|
1477
|
+
isError: true
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
958
1481
|
case "kode_read_context": {
|
|
959
1482
|
const contextPath = getContextPath();
|
|
960
1483
|
if (!contextPath) {
|