latitude-mcp-server 3.2.1 → 3.2.3
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/PROMPT_GUIDE.md +314 -97
- package/dist/api.d.ts +9 -0
- package/dist/api.js +26 -8
- package/dist/tools.js +6 -3
- package/package.json +1 -1
package/PROMPT_GUIDE.md
CHANGED
|
@@ -3,107 +3,200 @@ description: Complete guide for LLMs to autonomously manage, test, and optimize
|
|
|
3
3
|
auto_execution_mode: 3
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# LATITUDE MCP SERVER - LLM GUIDE
|
|
6
|
+
# LATITUDE MCP SERVER - LLM AUTONOMOUS GUIDE
|
|
7
7
|
|
|
8
|
-
> "
|
|
8
|
+
> "File-first workflow: Pull → Edit → Push → Test → Iterate"
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## GOLDEN RULE: FILE PATHS ONLY
|
|
11
11
|
|
|
12
12
|
```
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
3. add_prompt → Push with validation (overwrites if exists)
|
|
16
|
-
4. run_prompt → Test with parameters
|
|
17
|
-
5. Iterate → Analyze output → improve → re-push → re-test
|
|
13
|
+
❌ NEVER: Write prompt content directly in tool calls
|
|
14
|
+
✅ ALWAYS: Create .promptl files, use filePaths parameter
|
|
18
15
|
```
|
|
19
16
|
|
|
20
|
-
**
|
|
17
|
+
**Why?** Files are versionable, editable, reviewable. Inline content is messy and hard to iterate.
|
|
21
18
|
|
|
22
19
|
---
|
|
23
20
|
|
|
24
21
|
## THE 7 TOOLS
|
|
25
22
|
|
|
26
|
-
| Tool |
|
|
27
|
-
|
|
28
|
-
| `list_prompts` |
|
|
29
|
-
| `get_prompt` | Read
|
|
30
|
-
| `run_prompt` | Execute
|
|
31
|
-
| `pull_prompts` |
|
|
32
|
-
| `add_prompt` |
|
|
33
|
-
| `push_prompts` |
|
|
34
|
-
| `docs` |
|
|
23
|
+
| Tool | Purpose | Key Param |
|
|
24
|
+
|------|---------|-----------|
|
|
25
|
+
| `list_prompts` | See what exists | — |
|
|
26
|
+
| `get_prompt` | Read prompt content | `name` |
|
|
27
|
+
| `run_prompt` | Execute with params | `name`, `parameters` |
|
|
28
|
+
| `pull_prompts` | Download all → `./prompts/` | `outputDir?` |
|
|
29
|
+
| `add_prompt` | Add/update (never deletes) | `filePaths` ✅ |
|
|
30
|
+
| `push_prompts` | Replace ALL (FULL SYNC) | `filePaths` ✅ |
|
|
31
|
+
| `docs` | Learn PromptL | `action`, `query`/`topic` |
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## FILE-FIRST WORKFLOW
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
### Step 1: Pull
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{ "tool": "pull_prompts" }
|
|
39
41
|
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
Creates `./prompts/*.promptl`
|
|
43
|
+
|
|
44
|
+
### Step 2: Create/Edit File
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Create new file
|
|
48
|
+
echo '---
|
|
49
|
+
provider: openai
|
|
50
|
+
model: gpt-4o
|
|
51
|
+
temperature: 0.2
|
|
52
|
+
---
|
|
53
|
+
<user>Extract email from: {{ text }}</user>' > ./prompts/email-extractor.promptl
|
|
43
54
|
```
|
|
44
55
|
|
|
45
|
-
|
|
56
|
+
### Step 3: Push via File Path
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"tool": "add_prompt",
|
|
61
|
+
"filePaths": ["./prompts/email-extractor.promptl"],
|
|
62
|
+
"versionName": "feat/add-email-extractor"
|
|
63
|
+
}
|
|
46
64
|
```
|
|
47
|
-
|
|
65
|
+
|
|
66
|
+
### Step 4: Test
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"tool": "run_prompt",
|
|
71
|
+
"name": "email-extractor",
|
|
72
|
+
"parameters": { "text": "Contact john@example.com" }
|
|
73
|
+
}
|
|
48
74
|
```
|
|
49
75
|
|
|
76
|
+
### Step 5: Iterate
|
|
77
|
+
|
|
78
|
+
Edit file → `add_prompt` again → `run_prompt` → repeat until quality is perfect
|
|
79
|
+
|
|
50
80
|
---
|
|
51
81
|
|
|
52
|
-
##
|
|
82
|
+
## 📚 LEARN PROMPTL WITH `docs` TOOL
|
|
53
83
|
|
|
54
|
-
###
|
|
84
|
+
### How to Use
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{ "tool": "docs", "action": "help" } // Overview of all 52 topics
|
|
88
|
+
{ "tool": "docs", "action": "find", "query": "json schema" } // Search
|
|
89
|
+
{ "tool": "docs", "action": "get", "topic": "config-json-output" } // Get specific
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Learning Menu: "To build X, call Y"
|
|
93
|
+
|
|
94
|
+
| I want to... | Call this |
|
|
95
|
+
|--------------|-----------|
|
|
96
|
+
| **Understand PromptL basics** | `docs(action: "get", topic: "overview")` |
|
|
97
|
+
| **Learn file structure** | `docs(action: "get", topic: "structure")` |
|
|
98
|
+
| **Use variables** | `docs(action: "get", topic: "variables")` |
|
|
99
|
+
| **Add conditionals (if/else)** | `docs(action: "get", topic: "conditionals")` |
|
|
100
|
+
| **Loop through items** | `docs(action: "get", topic: "loops")` |
|
|
101
|
+
|
|
102
|
+
| I want to... | Call this |
|
|
103
|
+
|--------------|-----------|
|
|
104
|
+
| **Configure provider/model** | `docs(action: "get", topic: "config-basics")` |
|
|
105
|
+
| **Get JSON output (schema)** | `docs(action: "get", topic: "config-json-output")` |
|
|
106
|
+
| **Set temperature/tokens** | `docs(action: "get", topic: "config-generation")` |
|
|
107
|
+
| **Use OpenAI models** | `docs(action: "get", topic: "providers-openai")` |
|
|
108
|
+
| **Use Anthropic models** | `docs(action: "get", topic: "providers-anthropic")` |
|
|
109
|
+
|
|
110
|
+
| I want to... | Call this |
|
|
111
|
+
|--------------|-----------|
|
|
112
|
+
| **Write system/user/assistant** | `docs(action: "get", topic: "messages-roles")` |
|
|
113
|
+
| **Use images (multimodal)** | `docs(action: "get", topic: "messages-multimodal")` |
|
|
114
|
+
|
|
115
|
+
| I want to... | Call this |
|
|
116
|
+
|--------------|-----------|
|
|
117
|
+
| **Add few-shot examples** | `docs(action: "get", topic: "technique-few-shot")` |
|
|
118
|
+
| **Chain of thought reasoning** | `docs(action: "get", topic: "technique-cot")` |
|
|
119
|
+
| **Build agents with tools** | `docs(action: "get", topic: "agents")` |
|
|
120
|
+
| **Define custom tools** | `docs(action: "get", topic: "tools-custom")` |
|
|
121
|
+
| **Multi-step chains** | `docs(action: "get", topic: "chains")` |
|
|
122
|
+
|
|
123
|
+
| I want to build... | Call this |
|
|
124
|
+
|--------------------|-----------|
|
|
125
|
+
| **Data extraction** | `docs(action: "get", topic: "recipe-extraction")` |
|
|
126
|
+
| **Classification** | `docs(action: "get", topic: "recipe-classification")` |
|
|
127
|
+
| **Chatbot** | `docs(action: "get", topic: "recipe-chatbot")` |
|
|
128
|
+
| **RAG system** | `docs(action: "get", topic: "recipe-rag")` |
|
|
129
|
+
| **Content moderation** | `docs(action: "get", topic: "recipe-moderation")` |
|
|
130
|
+
|
|
131
|
+
### Quick Search Examples
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
// Don't know exact topic? Search!
|
|
135
|
+
{ "tool": "docs", "action": "find", "query": "extract structured data" }
|
|
136
|
+
{ "tool": "docs", "action": "find", "query": "few shot examples" }
|
|
137
|
+
{ "tool": "docs", "action": "find", "query": "agent autonomous" }
|
|
138
|
+
{ "tool": "docs", "action": "find", "query": "loop array items" }
|
|
139
|
+
{ "tool": "docs", "action": "find", "query": "temperature settings" }
|
|
140
|
+
```
|
|
55
141
|
|
|
56
|
-
```javascript
|
|
57
|
-
// 1. Create prompt
|
|
58
|
-
add_prompt({
|
|
59
|
-
prompts: [{
|
|
60
|
-
name: "email-extractor",
|
|
61
|
-
content: `---
|
|
62
|
-
provider: openai
|
|
63
|
-
model: gpt-4o
|
|
64
|
-
temperature: 0.2
|
|
65
|
-
schema:
|
|
66
|
-
type: object
|
|
67
|
-
properties:
|
|
68
|
-
email: { type: string }
|
|
69
|
-
required: [email]
|
|
70
142
|
---
|
|
71
|
-
<user>Extract from: {{ text }}</user>`
|
|
72
|
-
}],
|
|
73
|
-
versionName: "feat/email-extractor-v1"
|
|
74
|
-
})
|
|
75
143
|
|
|
76
|
-
|
|
77
|
-
run_prompt({
|
|
78
|
-
name: "email-extractor",
|
|
79
|
-
parameters: { text: "Contact john@example.com" }
|
|
80
|
-
})
|
|
144
|
+
## 🎯 DYNAMIC TOOL DESCRIPTIONS
|
|
81
145
|
|
|
82
|
-
|
|
83
|
-
add_prompt({
|
|
84
|
-
prompts: [{
|
|
85
|
-
name: "email-extractor",
|
|
86
|
-
content: "... improved version ..."
|
|
87
|
-
}],
|
|
88
|
-
versionName: "fix/improve-accuracy"
|
|
89
|
-
})
|
|
146
|
+
**No need to call `list_prompts` first!**
|
|
90
147
|
|
|
91
|
-
|
|
148
|
+
`run_prompt` description shows:
|
|
92
149
|
```
|
|
150
|
+
Available prompts (10):
|
|
151
|
+
- email-extractor (params: text)
|
|
152
|
+
- sentiment (params: input, language)
|
|
153
|
+
- cover-letter (params: job_details, patterns, company)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`add_prompt` description shows:
|
|
157
|
+
```
|
|
158
|
+
Available prompts (10): email-extractor, sentiment, cover-letter, ...
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Check tool description → know what exists + what params needed**
|
|
162
|
+
|
|
163
|
+
---
|
|
93
164
|
|
|
94
|
-
|
|
165
|
+
## AUTONOMOUS ITERATION LOOP
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
1. Learn pattern → docs(action: "find", query: "...")
|
|
169
|
+
2. Create file → ./prompts/my-prompt.promptl
|
|
170
|
+
3. Push → add_prompt(filePaths: [...], versionName: "v1")
|
|
171
|
+
4. Test → run_prompt(name: "...", parameters: {...})
|
|
172
|
+
5. Analyze output → Good? Done. Bad? Continue.
|
|
173
|
+
6. Edit file → Improve based on output analysis
|
|
174
|
+
7. Re-push → add_prompt(filePaths: [...], versionName: "v2")
|
|
175
|
+
8. Re-test → run_prompt again
|
|
176
|
+
9. Repeat 5-8 → Until quality threshold met
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## BULK TESTING WITH MCP INSPECTOR
|
|
95
182
|
|
|
96
183
|
```bash
|
|
97
|
-
# Test
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
184
|
+
# Test single prompt
|
|
185
|
+
npx @modelcontextprotocol/inspector \
|
|
186
|
+
-e LATITUDE_API_KEY=$KEY -e LATITUDE_PROJECT_ID=$ID \
|
|
187
|
+
--cli npx -y latitude-mcp-server@3.2.1 \
|
|
188
|
+
--method tools/call \
|
|
189
|
+
--tool-name run_prompt \
|
|
190
|
+
--tool-arg name=email-extractor \
|
|
191
|
+
--tool-arg 'parameters={"text":"john@example.com"}'
|
|
192
|
+
|
|
193
|
+
# Test multiple prompts in loop
|
|
194
|
+
for p in email-extractor sentiment classifier; do
|
|
195
|
+
echo "=== $p ===" && npx @modelcontextprotocol/inspector \
|
|
196
|
+
-e LATITUDE_API_KEY=$KEY -e LATITUDE_PROJECT_ID=$ID \
|
|
197
|
+
--cli npx -y latitude-mcp-server@3.2.1 \
|
|
198
|
+
--method tools/call --tool-name run_prompt \
|
|
199
|
+
--tool-arg name=$p --tool-arg 'parameters={"text":"test"}'
|
|
107
200
|
done
|
|
108
201
|
|
|
109
202
|
# Analyze outputs → update weak prompts → re-test
|
|
@@ -113,15 +206,27 @@ done
|
|
|
113
206
|
|
|
114
207
|
## VERSION NAMING
|
|
115
208
|
|
|
116
|
-
```javascript
|
|
117
|
-
// Git-style naming (optional)
|
|
118
|
-
versionName: "feat/add-email-extractor"
|
|
119
|
-
versionName: "fix/typo-in-system-message"
|
|
120
|
-
versionName: "refactor/simplify-logic"
|
|
121
|
-
versionName: "perf/reduce-tokens"
|
|
122
|
-
|
|
123
|
-
// If omitted → auto-generates timestamp
|
|
124
209
|
```
|
|
210
|
+
feat/add-email-extractor # New feature
|
|
211
|
+
fix/improve-accuracy # Bug fix
|
|
212
|
+
refactor/simplify-prompt # Cleanup
|
|
213
|
+
perf/reduce-tokens # Performance
|
|
214
|
+
test/add-examples # Testing
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Omit → auto-generates timestamp
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## SYNC BEHAVIOR
|
|
222
|
+
|
|
223
|
+
| Tool | Behavior |
|
|
224
|
+
|------|----------|
|
|
225
|
+
| `add_prompt` | ADDITIVE - adds/updates, never deletes |
|
|
226
|
+
| `push_prompts` | FULL SYNC - replaces ALL, deletes extras |
|
|
227
|
+
| `pull_prompts` | FULL SYNC - deletes local first |
|
|
228
|
+
|
|
229
|
+
**Use `add_prompt` for normal work. Use `push_prompts` only for reset/init.**
|
|
125
230
|
|
|
126
231
|
---
|
|
127
232
|
|
|
@@ -129,35 +234,147 @@ versionName: "perf/reduce-tokens"
|
|
|
129
234
|
|
|
130
235
|
All writes validate BEFORE API calls:
|
|
131
236
|
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
237
|
+
```
|
|
238
|
+
❌ Validation Failed
|
|
239
|
+
|
|
240
|
+
Error Code: `message-tag-inside-message`
|
|
241
|
+
Location: Line 4, Column 7
|
|
242
|
+
Code Context:
|
|
243
|
+
4: <user><assistant>Nested!</assistant></user>
|
|
244
|
+
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
245
|
+
Fix: Move nested tag outside parent.
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Fix file → re-push → validation passes**
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## PROMPTL QUICK REFERENCE
|
|
139
253
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
254
|
+
### Basic Structure
|
|
255
|
+
|
|
256
|
+
```yaml
|
|
257
|
+
---
|
|
258
|
+
provider: openai
|
|
259
|
+
model: gpt-4o
|
|
260
|
+
temperature: 0.2
|
|
261
|
+
---
|
|
262
|
+
<system>You are a helpful assistant.</system>
|
|
263
|
+
<user>{{ user_input }}</user>
|
|
143
264
|
```
|
|
144
265
|
|
|
266
|
+
### With Schema (JSON Output)
|
|
267
|
+
|
|
268
|
+
```yaml
|
|
145
269
|
---
|
|
270
|
+
provider: openai
|
|
271
|
+
model: gpt-4o
|
|
272
|
+
schema:
|
|
273
|
+
type: object
|
|
274
|
+
properties:
|
|
275
|
+
result: { type: string }
|
|
276
|
+
required: [result]
|
|
277
|
+
---
|
|
278
|
+
<user>{{ input }}</user>
|
|
279
|
+
```
|
|
146
280
|
|
|
147
|
-
|
|
281
|
+
### Few-Shot Examples
|
|
148
282
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
283
|
+
```yaml
|
|
284
|
+
---
|
|
285
|
+
provider: openai
|
|
286
|
+
model: gpt-4o
|
|
287
|
+
---
|
|
288
|
+
<user>Classify: Great product!</user>
|
|
289
|
+
<assistant>positive</assistant>
|
|
290
|
+
|
|
291
|
+
<user>Classify: Terrible experience</user>
|
|
292
|
+
<assistant>negative</assistant>
|
|
293
|
+
|
|
294
|
+
<user>Classify: {{ text }}</user>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Temperature Guide
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
0.0-0.2 Deterministic (extraction, classification)
|
|
301
|
+
0.3-0.5 Balanced (Q&A, analysis)
|
|
302
|
+
0.6-0.8 Creative (writing, brainstorming)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## COMPLETE EXAMPLE: BUILD EMAIL EXTRACTOR
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
# 1. Learn JSON schema pattern
|
|
311
|
+
docs(action: "get", topic: "config-json-output")
|
|
312
|
+
|
|
313
|
+
# 2. Create file
|
|
314
|
+
cat > ./prompts/email-extractor.promptl << 'EOF'
|
|
315
|
+
---
|
|
316
|
+
provider: openai
|
|
317
|
+
model: gpt-4o
|
|
318
|
+
temperature: 0.1
|
|
319
|
+
schema:
|
|
320
|
+
type: object
|
|
321
|
+
properties:
|
|
322
|
+
email: { type: string }
|
|
323
|
+
name: { type: [string, "null"] }
|
|
324
|
+
required: [email]
|
|
325
|
+
---
|
|
326
|
+
<system>
|
|
327
|
+
Extract email and name. Return null for name if not found.
|
|
328
|
+
</system>
|
|
329
|
+
<user>{{ text }}</user>
|
|
330
|
+
EOF
|
|
331
|
+
|
|
332
|
+
# 3. Push
|
|
333
|
+
add_prompt(filePaths: ["./prompts/email-extractor.promptl"], versionName: "v1")
|
|
334
|
+
|
|
335
|
+
# 4. Test
|
|
336
|
+
run_prompt(name: "email-extractor", parameters: { text: "John at john@example.com" })
|
|
337
|
+
|
|
338
|
+
# 5. Output not good? Edit file, re-push as v2, re-test
|
|
339
|
+
# 6. Repeat until perfect
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## ANTI-PATTERNS
|
|
345
|
+
|
|
346
|
+
| ❌ Don't | ✅ Do |
|
|
347
|
+
|----------|-------|
|
|
348
|
+
| Write content in tool call | Create .promptl file, use filePaths |
|
|
349
|
+
| Guess PromptL syntax | `docs(action: "find", query: "...")` |
|
|
350
|
+
| Call list_prompts first | Check run_prompt tool description |
|
|
351
|
+
| Use push_prompts casually | Use add_prompt (safer) |
|
|
352
|
+
| Skip testing | run_prompt after every change |
|
|
152
353
|
|
|
153
354
|
---
|
|
154
355
|
|
|
155
356
|
## QUICK COMMANDS
|
|
156
357
|
|
|
157
358
|
```
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
359
|
+
"What prompts exist?" → Check run_prompt description (dynamic)
|
|
360
|
+
"What params does X need?" → Check run_prompt description (dynamic)
|
|
361
|
+
"Learn about schemas" → docs(action: "get", topic: "config-json-output")
|
|
362
|
+
"Search for X" → docs(action: "find", query: "X")
|
|
363
|
+
"Add my file" → add_prompt(filePaths: ["./prompts/x.promptl"])
|
|
364
|
+
"Test prompt" → run_prompt(name: "x", parameters: {...})
|
|
365
|
+
"Pull all prompts" → pull_prompts
|
|
163
366
|
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## WISDOM
|
|
371
|
+
|
|
372
|
+
**File-First:** "Never write prompt content in tool calls. Always use filePaths."
|
|
373
|
+
|
|
374
|
+
**Learn-First:** "docs(find) → docs(get) → create file → push → test"
|
|
375
|
+
|
|
376
|
+
**Iterate:** "Edit file → add_prompt → run_prompt → analyze → repeat"
|
|
377
|
+
|
|
378
|
+
**Dynamic:** "Tool descriptions show prompts + params. No listing needed."
|
|
379
|
+
|
|
380
|
+
**Validate:** "Client-side validation catches errors before API calls."
|
package/dist/api.d.ts
CHANGED
|
@@ -46,9 +46,18 @@ interface PushResponse {
|
|
|
46
46
|
* This is the CLI-style push that sends all changes at once
|
|
47
47
|
*/
|
|
48
48
|
export declare function pushChanges(versionUuid: string, changes: DocumentChange[]): Promise<PushResponse>;
|
|
49
|
+
/**
|
|
50
|
+
* Normalize document path for consistent comparison.
|
|
51
|
+
* Handles leading/trailing slashes, whitespace, and ensures consistent format.
|
|
52
|
+
* API may return paths with or without leading slash - this normalizes them.
|
|
53
|
+
*/
|
|
54
|
+
export declare function normalizePath(path: string): string;
|
|
49
55
|
/**
|
|
50
56
|
* Compute diff between incoming prompts and existing prompts
|
|
51
57
|
* Returns only the changes that need to be made
|
|
58
|
+
*
|
|
59
|
+
* IMPORTANT: Uses normalized paths to handle API inconsistencies where
|
|
60
|
+
* paths may be returned with or without leading slashes.
|
|
52
61
|
*/
|
|
53
62
|
export declare function computeDiff(incoming: Array<{
|
|
54
63
|
path: string;
|
package/dist/api.js
CHANGED
|
@@ -18,6 +18,7 @@ exports.getProjectId = getProjectId;
|
|
|
18
18
|
exports.listDocuments = listDocuments;
|
|
19
19
|
exports.getDocument = getDocument;
|
|
20
20
|
exports.pushChanges = pushChanges;
|
|
21
|
+
exports.normalizePath = normalizePath;
|
|
21
22
|
exports.computeDiff = computeDiff;
|
|
22
23
|
exports.runDocument = runDocument;
|
|
23
24
|
exports.validatePromptLContent = validatePromptLContent;
|
|
@@ -301,17 +302,34 @@ async function pushChanges(versionUuid, changes) {
|
|
|
301
302
|
body: { changes: apiChanges },
|
|
302
303
|
});
|
|
303
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Normalize document path for consistent comparison.
|
|
307
|
+
* Handles leading/trailing slashes, whitespace, and ensures consistent format.
|
|
308
|
+
* API may return paths with or without leading slash - this normalizes them.
|
|
309
|
+
*/
|
|
310
|
+
function normalizePath(path) {
|
|
311
|
+
return path
|
|
312
|
+
.trim()
|
|
313
|
+
.replace(/^\/+/, '') // Remove leading slashes
|
|
314
|
+
.replace(/\/+$/, '') // Remove trailing slashes
|
|
315
|
+
.replace(/\/+/g, '/'); // Collapse multiple slashes
|
|
316
|
+
}
|
|
304
317
|
/**
|
|
305
318
|
* Compute diff between incoming prompts and existing prompts
|
|
306
319
|
* Returns only the changes that need to be made
|
|
320
|
+
*
|
|
321
|
+
* IMPORTANT: Uses normalized paths to handle API inconsistencies where
|
|
322
|
+
* paths may be returned with or without leading slashes.
|
|
307
323
|
*/
|
|
308
324
|
function computeDiff(incoming, existing) {
|
|
309
325
|
const changes = [];
|
|
310
|
-
|
|
311
|
-
const
|
|
326
|
+
// Build map with NORMALIZED paths as keys for reliable matching
|
|
327
|
+
const existingMap = new Map(existing.map((d) => [normalizePath(d.path), d]));
|
|
328
|
+
const incomingPaths = new Set(incoming.map((p) => normalizePath(p.path)));
|
|
312
329
|
// Check each incoming prompt
|
|
313
330
|
for (const prompt of incoming) {
|
|
314
|
-
const
|
|
331
|
+
const normalizedPath = normalizePath(prompt.path);
|
|
332
|
+
const existingDoc = existingMap.get(normalizedPath);
|
|
315
333
|
if (!existingDoc) {
|
|
316
334
|
// New prompt
|
|
317
335
|
changes.push({
|
|
@@ -321,9 +339,9 @@ function computeDiff(incoming, existing) {
|
|
|
321
339
|
});
|
|
322
340
|
}
|
|
323
341
|
else if (existingDoc.content !== prompt.content) {
|
|
324
|
-
// Modified prompt
|
|
342
|
+
// Modified prompt - use the EXISTING path to ensure API compatibility
|
|
325
343
|
changes.push({
|
|
326
|
-
path:
|
|
344
|
+
path: existingDoc.path,
|
|
327
345
|
content: prompt.content,
|
|
328
346
|
status: 'modified',
|
|
329
347
|
});
|
|
@@ -331,10 +349,10 @@ function computeDiff(incoming, existing) {
|
|
|
331
349
|
// If content is same, no change needed (don't include in changes)
|
|
332
350
|
}
|
|
333
351
|
// Check for deleted prompts (exist remotely but not in incoming)
|
|
334
|
-
for (const
|
|
335
|
-
if (!incomingPaths.has(
|
|
352
|
+
for (const [normalizedExistingPath, doc] of existingMap.entries()) {
|
|
353
|
+
if (!incomingPaths.has(normalizedExistingPath)) {
|
|
336
354
|
changes.push({
|
|
337
|
-
path,
|
|
355
|
+
path: doc.path,
|
|
338
356
|
content: '',
|
|
339
357
|
status: 'deleted',
|
|
340
358
|
});
|
package/dist/tools.js
CHANGED
|
@@ -417,16 +417,19 @@ async function handleAddPrompt(args) {
|
|
|
417
417
|
logger.info(`All ${prompts.length} prompt(s) passed validation`);
|
|
418
418
|
// Get existing prompts
|
|
419
419
|
const existingDocs = await (0, api_js_1.listDocuments)('live');
|
|
420
|
-
|
|
420
|
+
// Use NORMALIZED paths as keys for reliable matching (handles /path vs path inconsistencies)
|
|
421
|
+
const existingMap = new Map(existingDocs.map((d) => [(0, api_js_1.normalizePath)(d.path), d]));
|
|
421
422
|
// Build changes - ALWAYS overwrite if exists, add if new, NEVER delete
|
|
422
423
|
const changes = [];
|
|
423
424
|
for (const prompt of prompts) {
|
|
424
|
-
const
|
|
425
|
+
const normalizedName = (0, api_js_1.normalizePath)(prompt.name);
|
|
426
|
+
const existingDoc = existingMap.get(normalizedName);
|
|
425
427
|
if (existingDoc) {
|
|
426
428
|
// Only include if content is different
|
|
427
429
|
if (existingDoc.content !== prompt.content) {
|
|
430
|
+
// Use the EXISTING path from API to ensure compatibility
|
|
428
431
|
changes.push({
|
|
429
|
-
path:
|
|
432
|
+
path: existingDoc.path,
|
|
430
433
|
content: prompt.content,
|
|
431
434
|
status: 'modified',
|
|
432
435
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "latitude-mcp-server",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.3",
|
|
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",
|