bps-kit 1.2.2 → 1.3.1

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.
Files changed (51) hide show
  1. package/.bps-kit.json +4 -4
  2. package/README.md +3 -0
  3. package/implementation_plan.md.resolved +37 -0
  4. package/package.json +2 -2
  5. package/templates/agents-template/ARCHITECTURE.md +21 -9
  6. package/templates/agents-template/agents/automation-specialist.md +157 -0
  7. package/templates/agents-template/rules/GEMINI.md +2 -10
  8. package/templates/agents-template/workflows/automate.md +153 -0
  9. package/templates/skills_normal/n8n-code-javascript/BUILTIN_FUNCTIONS.md +764 -0
  10. package/templates/skills_normal/n8n-code-javascript/COMMON_PATTERNS.md +1110 -0
  11. package/templates/skills_normal/n8n-code-javascript/DATA_ACCESS.md +782 -0
  12. package/templates/skills_normal/n8n-code-javascript/ERROR_PATTERNS.md +763 -0
  13. package/templates/skills_normal/n8n-code-javascript/README.md +350 -0
  14. package/templates/skills_normal/n8n-code-javascript/SKILL.md +699 -0
  15. package/templates/skills_normal/n8n-code-python/COMMON_PATTERNS.md +794 -0
  16. package/templates/skills_normal/n8n-code-python/DATA_ACCESS.md +702 -0
  17. package/templates/skills_normal/n8n-code-python/ERROR_PATTERNS.md +601 -0
  18. package/templates/skills_normal/n8n-code-python/README.md +386 -0
  19. package/templates/skills_normal/n8n-code-python/SKILL.md +748 -0
  20. package/templates/skills_normal/n8n-code-python/STANDARD_LIBRARY.md +974 -0
  21. package/templates/skills_normal/n8n-expression-syntax/COMMON_MISTAKES.md +393 -0
  22. package/templates/skills_normal/n8n-expression-syntax/EXAMPLES.md +483 -0
  23. package/templates/skills_normal/n8n-expression-syntax/README.md +93 -0
  24. package/templates/skills_normal/n8n-expression-syntax/SKILL.md +516 -0
  25. package/templates/skills_normal/n8n-mcp-tools-expert/README.md +99 -0
  26. package/templates/skills_normal/n8n-mcp-tools-expert/SEARCH_GUIDE.md +374 -0
  27. package/templates/skills_normal/n8n-mcp-tools-expert/SKILL.md +642 -0
  28. package/templates/skills_normal/n8n-mcp-tools-expert/VALIDATION_GUIDE.md +442 -0
  29. package/templates/skills_normal/n8n-mcp-tools-expert/WORKFLOW_GUIDE.md +618 -0
  30. package/templates/skills_normal/n8n-node-configuration/DEPENDENCIES.md +789 -0
  31. package/templates/skills_normal/n8n-node-configuration/OPERATION_PATTERNS.md +913 -0
  32. package/templates/skills_normal/n8n-node-configuration/README.md +364 -0
  33. package/templates/skills_normal/n8n-node-configuration/SKILL.md +785 -0
  34. package/templates/skills_normal/n8n-validation-expert/ERROR_CATALOG.md +943 -0
  35. package/templates/skills_normal/n8n-validation-expert/FALSE_POSITIVES.md +720 -0
  36. package/templates/skills_normal/n8n-validation-expert/README.md +290 -0
  37. package/templates/skills_normal/n8n-validation-expert/SKILL.md +689 -0
  38. package/templates/skills_normal/n8n-workflow-patterns/README.md +251 -0
  39. package/templates/skills_normal/n8n-workflow-patterns/SKILL.md +411 -0
  40. package/templates/skills_normal/n8n-workflow-patterns/ai_agent_workflow.md +784 -0
  41. package/templates/skills_normal/n8n-workflow-patterns/database_operations.md +785 -0
  42. package/templates/skills_normal/n8n-workflow-patterns/http_api_integration.md +734 -0
  43. package/templates/skills_normal/n8n-workflow-patterns/scheduled_tasks.md +773 -0
  44. package/templates/skills_normal/n8n-workflow-patterns/webhook_processing.md +545 -0
  45. package/templates/vault/n8n-code-javascript/SKILL.md +10 -10
  46. package/templates/vault/n8n-code-python/SKILL.md +11 -11
  47. package/templates/vault/n8n-expression-syntax/SKILL.md +4 -4
  48. package/templates/vault/n8n-mcp-tools-expert/SKILL.md +9 -9
  49. package/templates/vault/n8n-node-configuration/SKILL.md +2 -2
  50. package/templates/vault/n8n-validation-expert/SKILL.md +3 -3
  51. package/templates/vault/n8n-workflow-patterns/SKILL.md +11 -11
@@ -0,0 +1,601 @@
1
+ # Error Patterns - Python Code Node
2
+
3
+ Common Python Code node errors and how to fix them.
4
+
5
+ ---
6
+
7
+ ## Error Overview
8
+
9
+ **Top 5 Python Code Node Errors**:
10
+
11
+ 1. **ModuleNotFoundError** - Trying to import external libraries (Python-specific)
12
+ 2. **Empty Code / Missing Return** - No code or return statement
13
+ 3. **KeyError** - Dictionary access without .get()
14
+ 4. **IndexError** - List access without bounds checking
15
+ 5. **Incorrect Return Format** - Wrong data structure returned
16
+
17
+ These 5 errors cover the majority of Python Code node failures.
18
+
19
+ ---
20
+
21
+ ## Error #1: ModuleNotFoundError (MOST CRITICAL)
22
+
23
+ **Frequency**: Very common in Python Code nodes
24
+
25
+ **What it is**: Attempting to import external libraries that aren't available.
26
+
27
+ ### The Problem
28
+
29
+ ```python
30
+ # ❌ WRONG: External libraries not available
31
+ import requests # ModuleNotFoundError: No module named 'requests'
32
+ import pandas # ModuleNotFoundError: No module named 'pandas'
33
+ import numpy # ModuleNotFoundError: No module named 'numpy'
34
+ import bs4 # ModuleNotFoundError: No module named 'bs4'
35
+ import pymongo # ModuleNotFoundError: No module named 'pymongo'
36
+ import psycopg2 # ModuleNotFoundError: No module named 'psycopg2'
37
+
38
+ # This code will FAIL - these libraries are not installed!
39
+ response = requests.get("https://api.example.com/data")
40
+ ```
41
+
42
+ ### The Solution
43
+
44
+ **Option 1: Use JavaScript Instead** (Recommended for 95% of cases)
45
+
46
+ ```javascript
47
+ // ✅ JavaScript Code node with $helpers.httpRequest()
48
+ const response = await $helpers.httpRequest({
49
+ method: 'GET',
50
+ url: 'https://api.example.com/data'
51
+ });
52
+
53
+ return [{json: response}];
54
+ ```
55
+
56
+ **Option 2: Use n8n HTTP Request Node**
57
+
58
+ ```python
59
+ # ✅ Add HTTP Request node BEFORE Python Code node
60
+ # Access the response in Python Code node
61
+
62
+ response = _input.first()["json"]
63
+
64
+ return [{
65
+ "json": {
66
+ "status": response.get("status"),
67
+ "data": response.get("body"),
68
+ "processed": True
69
+ }
70
+ }]
71
+ ```
72
+
73
+ **Option 3: Use Standard Library Only**
74
+
75
+ ```python
76
+ # ✅ Use urllib from standard library (limited functionality)
77
+ from urllib.request import urlopen
78
+ from urllib.parse import urlencode
79
+ import json
80
+
81
+ # Simple GET request (no headers, no auth)
82
+ url = "https://api.example.com/data"
83
+ with urlopen(url) as response:
84
+ data = json.loads(response.read())
85
+
86
+ return [{"json": data}]
87
+ ```
88
+
89
+ ### Common Library Replacements
90
+
91
+ | Need | ❌ External Library | ✅ Alternative |
92
+ |------|-------------------|----------------|
93
+ | HTTP requests | `requests` | Use HTTP Request node or JavaScript |
94
+ | Data analysis | `pandas` | Use Python list comprehensions |
95
+ | Database | `psycopg2`, `pymongo` | Use n8n database nodes |
96
+ | Web scraping | `beautifulsoup4` | Use HTML Extract node |
97
+ | Excel | `openpyxl` | Use Spreadsheet File node |
98
+ | Image processing | `pillow` | Use external API or node |
99
+
100
+ ### Available Standard Library Modules
101
+
102
+ ```python
103
+ # ✅ THESE WORK - Standard library only
104
+ import json # JSON parsing
105
+ import datetime # Date/time operations
106
+ import re # Regular expressions
107
+ import base64 # Base64 encoding
108
+ import hashlib # Hashing (MD5, SHA256)
109
+ import urllib.parse # URL parsing and encoding
110
+ import math # Math functions
111
+ import random # Random numbers
112
+ import statistics # Statistical functions
113
+ import collections # defaultdict, Counter, etc.
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Error #2: Empty Code / Missing Return
119
+
120
+ **Frequency**: Common across all Code nodes
121
+
122
+ **What it is**: Code node has no code or no return statement.
123
+
124
+ ### The Problem
125
+
126
+ ```python
127
+ # ❌ WRONG: Empty code
128
+ # (nothing here)
129
+
130
+ # ❌ WRONG: Code but no return
131
+ items = _input.all()
132
+ processed = [item for item in items if item["json"].get("active")]
133
+ # Forgot to return!
134
+
135
+ # ❌ WRONG: Return in wrong scope
136
+ if _input.all():
137
+ return [{"json": {"result": "success"}}]
138
+ # Return is inside if block - may not execute!
139
+ ```
140
+
141
+ ### The Solution
142
+
143
+ ```python
144
+ # ✅ CORRECT: Always return
145
+ all_items = _input.all()
146
+
147
+ if not all_items:
148
+ # Return empty array or error
149
+ return [{"json": {"error": "No items"}}]
150
+
151
+ # Process items
152
+ processed = [item for item in all_items if item["json"].get("active")]
153
+
154
+ # Always return at the end
155
+ return processed if processed else [{"json": {"message": "No active items"}}]
156
+ ```
157
+
158
+ ### Best Practice
159
+
160
+ ```python
161
+ # ✅ GOOD: Return at end of function (unconditional)
162
+ def process_items():
163
+ items = _input.all()
164
+
165
+ if not items:
166
+ return [{"json": {"error": "Empty input"}}]
167
+
168
+ # Process
169
+ result = []
170
+ for item in items:
171
+ result.append({"json": item["json"]})
172
+
173
+ return result
174
+
175
+ # Call function and return result
176
+ return process_items()
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Error #3: KeyError
182
+
183
+ **Frequency**: Very common in Python Code nodes
184
+
185
+ **What it is**: Accessing dictionary key that doesn't exist.
186
+
187
+ ### The Problem
188
+
189
+ ```python
190
+ # ❌ WRONG: Direct key access
191
+ item = _input.first()["json"]
192
+
193
+ name = item["name"] # KeyError if "name" doesn't exist!
194
+ email = item["email"] # KeyError if "email" doesn't exist!
195
+ age = item["age"] # KeyError if "age" doesn't exist!
196
+
197
+ return [{
198
+ "json": {
199
+ "name": name,
200
+ "email": email,
201
+ "age": age
202
+ }
203
+ }]
204
+ ```
205
+
206
+ ### Error Message
207
+
208
+ ```
209
+ KeyError: 'name'
210
+ ```
211
+
212
+ ### The Solution
213
+
214
+ ```python
215
+ # ✅ CORRECT: Use .get() with defaults
216
+ item = _input.first()["json"]
217
+
218
+ name = item.get("name", "Unknown")
219
+ email = item.get("email", "no-email@example.com")
220
+ age = item.get("age", 0)
221
+
222
+ return [{
223
+ "json": {
224
+ "name": name,
225
+ "email": email,
226
+ "age": age
227
+ }
228
+ }]
229
+ ```
230
+
231
+ ### Nested Dictionary Access
232
+
233
+ ```python
234
+ # ❌ WRONG: Nested key access
235
+ webhook = _input.first()["json"]
236
+ name = webhook["body"]["user"]["name"] # Multiple KeyErrors possible!
237
+
238
+ # ✅ CORRECT: Safe nested access
239
+ webhook = _input.first()["json"]
240
+ body = webhook.get("body", {})
241
+ user = body.get("user", {})
242
+ name = user.get("name", "Unknown")
243
+
244
+ # ✅ ALSO CORRECT: Chained .get()
245
+ name = (
246
+ webhook
247
+ .get("body", {})
248
+ .get("user", {})
249
+ .get("name", "Unknown")
250
+ )
251
+
252
+ return [{"json": {"name": name}}]
253
+ ```
254
+
255
+ ### Webhook Body Access (Critical!)
256
+
257
+ ```python
258
+ # ❌ WRONG: Forgetting webhook data is under "body"
259
+ webhook = _input.first()["json"]
260
+ name = webhook["name"] # KeyError!
261
+ email = webhook["email"] # KeyError!
262
+
263
+ # ✅ CORRECT: Access via ["body"]
264
+ webhook = _input.first()["json"]
265
+ body = webhook.get("body", {})
266
+ name = body.get("name", "Unknown")
267
+ email = body.get("email", "no-email")
268
+
269
+ return [{
270
+ "json": {
271
+ "name": name,
272
+ "email": email
273
+ }
274
+ }]
275
+ ```
276
+
277
+ ---
278
+
279
+ ## Error #4: IndexError
280
+
281
+ **Frequency**: Common when processing arrays/lists
282
+
283
+ **What it is**: Accessing list index that doesn't exist.
284
+
285
+ ### The Problem
286
+
287
+ ```python
288
+ # ❌ WRONG: Assuming items exist
289
+ all_items = _input.all()
290
+ first_item = all_items[0] # IndexError if list is empty!
291
+ second_item = all_items[1] # IndexError if only 1 item!
292
+
293
+ return [{
294
+ "json": {
295
+ "first": first_item["json"],
296
+ "second": second_item["json"]
297
+ }
298
+ }]
299
+ ```
300
+
301
+ ### Error Message
302
+
303
+ ```
304
+ IndexError: list index out of range
305
+ ```
306
+
307
+ ### The Solution
308
+
309
+ ```python
310
+ # ✅ CORRECT: Check length first
311
+ all_items = _input.all()
312
+
313
+ if len(all_items) >= 2:
314
+ first_item = all_items[0]["json"]
315
+ second_item = all_items[1]["json"]
316
+
317
+ return [{
318
+ "json": {
319
+ "first": first_item,
320
+ "second": second_item
321
+ }
322
+ }]
323
+ else:
324
+ return [{
325
+ "json": {
326
+ "error": f"Expected 2+ items, got {len(all_items)}"
327
+ }
328
+ }]
329
+ ```
330
+
331
+ ### Safe First Item Access
332
+
333
+ ```python
334
+ # ✅ CORRECT: Use _input.first() instead of [0]
335
+ # This is safer than manual indexing
336
+ first_item = _input.first()["json"]
337
+
338
+ return [{"json": first_item}]
339
+
340
+ # ✅ ALSO CORRECT: Check before accessing
341
+ all_items = _input.all()
342
+ if all_items:
343
+ first_item = all_items[0]["json"]
344
+ else:
345
+ first_item = {}
346
+
347
+ return [{"json": first_item}]
348
+ ```
349
+
350
+ ### Slice Instead of Index
351
+
352
+ ```python
353
+ # ✅ CORRECT: Use slicing (never raises IndexError)
354
+ all_items = _input.all()
355
+
356
+ # Get first 5 items (won't fail if fewer than 5)
357
+ first_five = all_items[:5]
358
+
359
+ # Get items after first (won't fail if empty)
360
+ rest = all_items[1:]
361
+
362
+ return [{"json": item["json"]} for item in first_five]
363
+ ```
364
+
365
+ ---
366
+
367
+ ## Error #5: Incorrect Return Format
368
+
369
+ **Frequency**: Common for new users
370
+
371
+ **What it is**: Returning data in wrong format (n8n expects array of objects with "json" key).
372
+
373
+ ### The Problem
374
+
375
+ ```python
376
+ # ❌ WRONG: Returning plain dictionary
377
+ return {"name": "Alice", "age": 30}
378
+
379
+ # ❌ WRONG: Returning array without "json" wrapper
380
+ return [{"name": "Alice"}, {"name": "Bob"}]
381
+
382
+ # ❌ WRONG: Returning None
383
+ return None
384
+
385
+ # ❌ WRONG: Returning string
386
+ return "success"
387
+
388
+ # ❌ WRONG: Returning single item (not array)
389
+ return {"json": {"name": "Alice"}}
390
+ ```
391
+
392
+ ### The Solution
393
+
394
+ ```python
395
+ # ✅ CORRECT: Array of objects with "json" key
396
+ return [{"json": {"name": "Alice", "age": 30}}]
397
+
398
+ # ✅ CORRECT: Multiple items
399
+ return [
400
+ {"json": {"name": "Alice"}},
401
+ {"json": {"name": "Bob"}}
402
+ ]
403
+
404
+ # ✅ CORRECT: Transform items
405
+ all_items = _input.all()
406
+ return [
407
+ {"json": item["json"]}
408
+ for item in all_items
409
+ ]
410
+
411
+ # ✅ CORRECT: Empty array (valid)
412
+ return []
413
+
414
+ # ✅ CORRECT: Single item still needs array wrapper
415
+ return [{"json": {"result": "success"}}]
416
+ ```
417
+
418
+ ### Common Scenarios
419
+
420
+ **Scenario 1: Aggregation (Return Single Result)**
421
+
422
+ ```python
423
+ # Calculate total
424
+ all_items = _input.all()
425
+ total = sum(item["json"].get("amount", 0) for item in all_items)
426
+
427
+ # ✅ CORRECT: Wrap in array with "json"
428
+ return [{
429
+ "json": {
430
+ "total": total,
431
+ "count": len(all_items)
432
+ }
433
+ }]
434
+ ```
435
+
436
+ **Scenario 2: Filtering (Return Multiple Results)**
437
+
438
+ ```python
439
+ # Filter active items
440
+ all_items = _input.all()
441
+ active = [item for item in all_items if item["json"].get("active")]
442
+
443
+ # ✅ CORRECT: Already in correct format
444
+ return active
445
+
446
+ # ✅ ALSO CORRECT: If transforming
447
+ return [
448
+ {"json": {**item["json"], "filtered": True}}
449
+ for item in active
450
+ ]
451
+ ```
452
+
453
+ **Scenario 3: No Results**
454
+
455
+ ```python
456
+ # ✅ CORRECT: Return empty array
457
+ return []
458
+
459
+ # ✅ ALSO CORRECT: Return error message
460
+ return [{"json": {"error": "No results found"}}]
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Bonus Error: AttributeError
466
+
467
+ **What it is**: Using _input.item in wrong mode.
468
+
469
+ ### The Problem
470
+
471
+ ```python
472
+ # ❌ WRONG: Using _input.item in "All Items" mode
473
+ current = _input.item # None in "All Items" mode
474
+ data = current["json"] # AttributeError: 'NoneType' object has no attribute '__getitem__'
475
+ ```
476
+
477
+ ### The Solution
478
+
479
+ ```python
480
+ # ✅ CORRECT: Check mode or use appropriate method
481
+ # In "All Items" mode, use:
482
+ all_items = _input.all()
483
+
484
+ # In "Each Item" mode, use:
485
+ current_item = _input.item
486
+
487
+ # ✅ SAFE: Check if item exists
488
+ current = _input.item
489
+ if current:
490
+ data = current["json"]
491
+ return [{"json": data}]
492
+ else:
493
+ # Running in "All Items" mode
494
+ return _input.all()
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Error Prevention Checklist
500
+
501
+ Before running your Python Code node, verify:
502
+
503
+ - [ ] **No external imports**: Only standard library (json, datetime, re, etc.)
504
+ - [ ] **Code returns data**: Every code path ends with `return`
505
+ - [ ] **Correct format**: Returns `[{"json": {...}}]` (array with "json" key)
506
+ - [ ] **Safe dictionary access**: Uses `.get()` instead of `[]` for dictionaries
507
+ - [ ] **Safe list access**: Checks length before indexing or uses slicing
508
+ - [ ] **Webhook body access**: Accesses webhook data via `_json["body"]`
509
+ - [ ] **No None returns**: Returns empty array `[]` instead of `None`
510
+ - [ ] **Mode awareness**: Uses `_input.all()`, `_input.first()`, or `_input.item` appropriately
511
+
512
+ ---
513
+
514
+ ## Quick Fix Reference
515
+
516
+ | Error | Quick Fix |
517
+ |-------|-----------|
518
+ | `ModuleNotFoundError` | Use JavaScript or HTTP Request node instead |
519
+ | `KeyError: 'field'` | Change `data["field"]` to `data.get("field", default)` |
520
+ | `IndexError: list index out of range` | Check `if len(items) > 0:` before `items[0]` |
521
+ | Empty output | Add `return [{"json": {...}}]` at end |
522
+ | `AttributeError: 'NoneType'` | Check mode setting or verify `_input.item` exists |
523
+ | Wrong format error | Wrap result: `return [{"json": result}]` |
524
+ | Webhook KeyError | Access via `_json.get("body", {})` |
525
+
526
+ ---
527
+
528
+ ## Testing Your Code
529
+
530
+ ### Test Pattern 1: Handle Empty Input
531
+
532
+ ```python
533
+ # ✅ Always test with empty input
534
+ all_items = _input.all()
535
+
536
+ if not all_items:
537
+ return [{"json": {"message": "No items to process"}}]
538
+
539
+ # Continue with processing
540
+ # ...
541
+ ```
542
+
543
+ ### Test Pattern 2: Test with Missing Fields
544
+
545
+ ```python
546
+ # ✅ Use .get() with defaults
547
+ item = _input.first()["json"]
548
+
549
+ # These won't fail even if fields missing
550
+ name = item.get("name", "Unknown")
551
+ email = item.get("email", "no-email")
552
+ age = item.get("age", 0)
553
+
554
+ return [{"json": {"name": name, "email": email, "age": age}}]
555
+ ```
556
+
557
+ ### Test Pattern 3: Test Both Modes
558
+
559
+ ```python
560
+ # ✅ Code that works in both modes
561
+ try:
562
+ # Try "Each Item" mode first
563
+ current = _input.item
564
+ if current:
565
+ return [{"json": current["json"]}]
566
+ except:
567
+ pass
568
+
569
+ # Fall back to "All Items" mode
570
+ all_items = _input.all()
571
+ return all_items if all_items else [{"json": {"message": "No data"}}]
572
+ ```
573
+
574
+ ---
575
+
576
+ ## Summary
577
+
578
+ **Top 5 Errors to Avoid**:
579
+ 1. **ModuleNotFoundError** - Use JavaScript or n8n nodes instead
580
+ 2. **Missing return** - Always end with `return [{"json": {...}}]`
581
+ 3. **KeyError** - Use `.get()` for dictionary access
582
+ 4. **IndexError** - Check length before indexing
583
+ 5. **Wrong format** - Return `[{"json": {...}}]`, not plain objects
584
+
585
+ **Golden Rules**:
586
+ - NO external libraries (use JavaScript instead)
587
+ - ALWAYS use `.get()` for dictionaries
588
+ - ALWAYS return `[{"json": {...}}]` format
589
+ - CHECK lengths before list access
590
+ - ACCESS webhook data via `["body"]`
591
+
592
+ **Remember**:
593
+ - JavaScript is recommended for 95% of use cases
594
+ - Python has limitations (no requests, pandas, numpy)
595
+ - Use n8n nodes for complex operations
596
+
597
+ **See Also**:
598
+ - [SKILL.md](SKILL.md) - Python Code overview
599
+ - [DATA_ACCESS.md](DATA_ACCESS.md) - Data access patterns
600
+ - [STANDARD_LIBRARY.md](STANDARD_LIBRARY.md) - Available modules
601
+ - [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - Production patterns