latitude-mcp-server 2.2.6 → 2.2.7

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/api.d.ts CHANGED
@@ -65,6 +65,24 @@ export declare function computeDiff(incoming: Array<{
65
65
  content: string;
66
66
  }>, existing: Document[]): DocumentChange[];
67
67
  export declare function runDocument(path: string, parameters?: Record<string, unknown>, versionUuid?: string): Promise<RunResult>;
68
+ export interface ValidationIssue {
69
+ type: 'error' | 'warning';
70
+ code: string;
71
+ message: string;
72
+ rootCause: string;
73
+ suggestion: string;
74
+ location?: {
75
+ line: number;
76
+ column: number;
77
+ };
78
+ codeFrame?: string;
79
+ }
80
+ /**
81
+ * Pre-validate PromptL content using the official promptl-ai library.
82
+ * Returns detailed, actionable error messages with code frames.
83
+ * EXPORTED for use by tools.ts to pre-validate before pushing.
84
+ */
85
+ export declare function validatePromptLContent(content: string, path: string): Promise<ValidationIssue[]>;
68
86
  /**
69
87
  * Deploy changes to LIVE version using the proper workflow:
70
88
  * 1. Create a draft version
package/dist/api.js CHANGED
@@ -27,6 +27,7 @@ exports.pushChanges = pushChanges;
27
27
  exports.hashContent = hashContent;
28
28
  exports.computeDiff = computeDiff;
29
29
  exports.runDocument = runDocument;
30
+ exports.validatePromptLContent = validatePromptLContent;
30
31
  exports.deployToLive = deployToLive;
31
32
  exports.getPromptNames = getPromptNames;
32
33
  const logger_util_js_1 = require("./utils/logger.util.js");
@@ -446,6 +447,7 @@ const ERROR_SUGGESTIONS = {
446
447
  /**
447
448
  * Pre-validate PromptL content using the official promptl-ai library.
448
449
  * Returns detailed, actionable error messages with code frames.
450
+ * EXPORTED for use by tools.ts to pre-validate before pushing.
449
451
  */
450
452
  async function validatePromptLContent(content, path) {
451
453
  const issues = [];
package/dist/tools.js CHANGED
@@ -106,6 +106,55 @@ function formatAvailablePrompts(names) {
106
106
  const formatted = names.map(n => `\`${n}\``).join(', ');
107
107
  return `\n\n**Available prompts (${names.length}):** ${formatted}`;
108
108
  }
109
+ /**
110
+ * Validate all prompts BEFORE pushing.
111
+ * If ANY prompt fails validation, returns all errors and NOTHING is pushed.
112
+ */
113
+ async function validateAllPrompts(prompts) {
114
+ const errors = [];
115
+ for (const prompt of prompts) {
116
+ const issues = await (0, api_js_1.validatePromptLContent)(prompt.content, prompt.name);
117
+ const errorIssues = issues.filter(i => i.type === 'error');
118
+ if (errorIssues.length > 0) {
119
+ errors.push({ name: prompt.name, issues: errorIssues });
120
+ }
121
+ }
122
+ return {
123
+ valid: errors.length === 0,
124
+ errors,
125
+ };
126
+ }
127
+ /**
128
+ * Format validation errors into a detailed MCP-friendly error message.
129
+ */
130
+ function formatValidationErrors(errors) {
131
+ const lines = [
132
+ `## ❌ Validation Failed - No Changes Made\n`,
133
+ `**${errors.length} prompt(s) have errors.** Fix all errors before pushing.\n`,
134
+ ];
135
+ for (const { name, issues } of errors) {
136
+ for (const issue of issues) {
137
+ lines.push(`### ${name}`);
138
+ lines.push(`**Error Code:** \`${issue.code}\``);
139
+ lines.push(`**Error:** ${issue.message}`);
140
+ lines.push(`**Root Cause:** ${issue.rootCause}`);
141
+ if (issue.location) {
142
+ lines.push(`**Location:** Line ${issue.location.line}, Column ${issue.location.column}`);
143
+ }
144
+ if (issue.codeFrame) {
145
+ lines.push(`**Code Context:**\n\`\`\`\n${issue.codeFrame}\n\`\`\``);
146
+ }
147
+ lines.push(`**Fix:** ${issue.suggestion}`);
148
+ lines.push('');
149
+ }
150
+ }
151
+ lines.push(`---`);
152
+ lines.push(`**Action Required:** Fix the errors above, then retry.`);
153
+ return {
154
+ content: [{ type: 'text', text: lines.join('\n') }],
155
+ isError: true,
156
+ };
157
+ }
109
158
  // ============================================================================
110
159
  // Tool Handlers
111
160
  // ============================================================================
@@ -194,6 +243,15 @@ async function handlePushPrompts(args) {
194
243
  if (prompts.length === 0) {
195
244
  return formatError(new Error('No prompts provided. Use either prompts array or filePaths.'));
196
245
  }
246
+ // PRE-VALIDATE ALL PROMPTS BEFORE PUSHING
247
+ // If ANY prompt fails validation, return errors and push NOTHING
248
+ logger.info(`Validating ${prompts.length} prompt(s) before push...`);
249
+ const validation = await validateAllPrompts(prompts);
250
+ if (!validation.valid) {
251
+ logger.warn(`Validation failed for ${validation.errors.length} prompt(s)`);
252
+ return formatValidationErrors(validation.errors);
253
+ }
254
+ logger.info(`All ${prompts.length} prompt(s) passed validation`);
197
255
  // Get existing prompts for diff computation
198
256
  const existingDocs = await (0, api_js_1.listDocuments)('live');
199
257
  // Compute diff - this determines what needs to be added, modified, or deleted
@@ -279,6 +337,15 @@ async function handleAppendPrompts(args) {
279
337
  if (prompts.length === 0) {
280
338
  return formatError(new Error('No prompts provided. Use either prompts array or filePaths.'));
281
339
  }
340
+ // PRE-VALIDATE ALL PROMPTS BEFORE APPENDING
341
+ // If ANY prompt fails validation, return errors and append NOTHING
342
+ logger.info(`Validating ${prompts.length} prompt(s) before append...`);
343
+ const validation = await validateAllPrompts(prompts);
344
+ if (!validation.valid) {
345
+ logger.warn(`Validation failed for ${validation.errors.length} prompt(s)`);
346
+ return formatValidationErrors(validation.errors);
347
+ }
348
+ logger.info(`All ${prompts.length} prompt(s) passed validation`);
282
349
  // Get existing prompts
283
350
  const existingDocs = await (0, api_js_1.listDocuments)('live');
284
351
  const existingMap = new Map(existingDocs.map((d) => [d.path, d]));
@@ -454,6 +521,15 @@ async function handleReplacePrompt(args) {
454
521
  if (!content) {
455
522
  return formatError(new Error('Prompt content is required. Provide either `content` or `filePath`.'));
456
523
  }
524
+ // PRE-VALIDATE PROMPT BEFORE REPLACING
525
+ // If validation fails, return error and replace NOTHING
526
+ logger.info(`Validating prompt "${name}" before replace...`);
527
+ const validation = await validateAllPrompts([{ name, content }]);
528
+ if (!validation.valid) {
529
+ logger.warn(`Validation failed for prompt "${name}"`);
530
+ return formatValidationErrors(validation.errors);
531
+ }
532
+ logger.info(`Prompt "${name}" passed validation`);
457
533
  // Check if prompt exists
458
534
  const existingDocs = await (0, api_js_1.listDocuments)('live');
459
535
  const exists = existingDocs.some((d) => d.path === name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latitude-mcp-server",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "description": "Simplified MCP server for Latitude.so prompt management - 8 focused tools for push, pull, run, and manage prompts",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",