@brookmind/ai-toolkit 1.1.7 → 1.2.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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -14
  3. package/dist/__tests__/index.test.d.ts +2 -0
  4. package/dist/__tests__/index.test.d.ts.map +1 -0
  5. package/dist/__tests__/index.test.js +214 -0
  6. package/dist/__tests__/index.test.js.map +1 -0
  7. package/dist/constants.d.ts +10 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +39 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +49 -332
  14. package/dist/index.js.map +1 -1
  15. package/dist/services/installers.d.ts +8 -0
  16. package/dist/services/installers.d.ts.map +1 -0
  17. package/dist/services/installers.js +79 -0
  18. package/dist/services/installers.js.map +1 -0
  19. package/dist/services/opencode.d.ts +3 -0
  20. package/dist/services/opencode.d.ts.map +1 -0
  21. package/dist/services/opencode.js +33 -0
  22. package/dist/services/opencode.js.map +1 -0
  23. package/dist/types.d.ts +10 -0
  24. package/dist/types.d.ts.map +1 -0
  25. package/dist/types.js +2 -0
  26. package/dist/types.js.map +1 -0
  27. package/dist/ui/categorize.d.ts +6 -0
  28. package/dist/ui/categorize.d.ts.map +1 -0
  29. package/dist/ui/categorize.js +69 -0
  30. package/dist/ui/categorize.js.map +1 -0
  31. package/dist/ui/choices.d.ts +6 -0
  32. package/dist/ui/choices.d.ts.map +1 -0
  33. package/dist/ui/choices.js +70 -0
  34. package/dist/ui/choices.js.map +1 -0
  35. package/dist/ui/display.d.ts +8 -0
  36. package/dist/ui/display.d.ts.map +1 -0
  37. package/dist/ui/display.js +84 -0
  38. package/dist/ui/display.js.map +1 -0
  39. package/dist/utils/fs.d.ts +5 -0
  40. package/dist/utils/fs.d.ts.map +1 -0
  41. package/dist/utils/fs.js +40 -0
  42. package/dist/utils/fs.js.map +1 -0
  43. package/dist/utils/terminal.d.ts +5 -0
  44. package/dist/utils/terminal.d.ts.map +1 -0
  45. package/dist/utils/terminal.js +18 -0
  46. package/dist/utils/terminal.js.map +1 -0
  47. package/package.json +27 -5
  48. package/agents/code-reviewer.md +0 -35
  49. package/agents/code-simplifier.md +0 -52
  50. package/commands/create-pr-description.md +0 -102
  51. package/commands/create-pr.md +0 -76
  52. package/commands/create-react-tests.md +0 -207
  53. package/mcps/context7/.mcp.json +0 -13
  54. package/mcps/expo-mcp/.mcp.json +0 -13
  55. package/mcps/figma-mcp/.mcp.json +0 -10
  56. package/skills/github-cli/SKILL.md +0 -125
  57. package/skills/pdf-processing-pro/FORMS.md +0 -610
  58. package/skills/pdf-processing-pro/OCR.md +0 -137
  59. package/skills/pdf-processing-pro/SKILL.md +0 -296
  60. package/skills/pdf-processing-pro/TABLES.md +0 -626
  61. package/skills/pdf-processing-pro/scripts/analyze_form.py +0 -307
  62. package/skills/react-best-practices/AGENTS.md +0 -915
  63. package/skills/react-best-practices/README.md +0 -127
  64. package/skills/react-best-practices/SKILL.md +0 -110
  65. package/skills/react-best-practices/metadata.json +0 -14
  66. package/skills/react-best-practices/rules/_sections.md +0 -41
  67. package/skills/react-best-practices/rules/_template.md +0 -28
  68. package/skills/react-best-practices/rules/advanced-event-handler-refs.md +0 -80
  69. package/skills/react-best-practices/rules/advanced-use-latest.md +0 -76
  70. package/skills/react-best-practices/rules/async-defer-await.md +0 -80
  71. package/skills/react-best-practices/rules/async-dependencies.md +0 -36
  72. package/skills/react-best-practices/rules/async-parallel.md +0 -28
  73. package/skills/react-best-practices/rules/async-suspense-boundaries.md +0 -100
  74. package/skills/react-best-practices/rules/bundle-barrel-imports.md +0 -42
  75. package/skills/react-best-practices/rules/bundle-conditional.md +0 -106
  76. package/skills/react-best-practices/rules/bundle-preload.md +0 -44
  77. package/skills/react-best-practices/rules/client-event-listeners.md +0 -131
  78. package/skills/react-best-practices/rules/client-swr-dedup.md +0 -133
  79. package/skills/react-best-practices/rules/js-batch-dom-css.md +0 -82
  80. package/skills/react-best-practices/rules/js-cache-function-results.md +0 -80
  81. package/skills/react-best-practices/rules/js-cache-property-access.md +0 -28
  82. package/skills/react-best-practices/rules/js-cache-storage.md +0 -70
  83. package/skills/react-best-practices/rules/js-combine-iterations.md +0 -32
  84. package/skills/react-best-practices/rules/js-early-exit.md +0 -50
  85. package/skills/react-best-practices/rules/js-hoist-regexp.md +0 -45
  86. package/skills/react-best-practices/rules/js-index-maps.md +0 -37
  87. package/skills/react-best-practices/rules/js-length-check-first.md +0 -49
  88. package/skills/react-best-practices/rules/js-min-max-loop.md +0 -82
  89. package/skills/react-best-practices/rules/js-set-map-lookups.md +0 -24
  90. package/skills/react-best-practices/rules/js-tosorted-immutable.md +0 -57
  91. package/skills/react-best-practices/rules/rendering-activity.md +0 -90
  92. package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  93. package/skills/react-best-practices/rules/rendering-conditional-render.md +0 -40
  94. package/skills/react-best-practices/rules/rendering-content-visibility.md +0 -38
  95. package/skills/react-best-practices/rules/rendering-hoist-jsx.md +0 -65
  96. package/skills/react-best-practices/rules/rendering-svg-precision.md +0 -28
  97. package/skills/react-best-practices/rules/rerender-defer-reads.md +0 -39
  98. package/skills/react-best-practices/rules/rerender-dependencies.md +0 -45
  99. package/skills/react-best-practices/rules/rerender-derived-state.md +0 -29
  100. package/skills/react-best-practices/rules/rerender-functional-setstate.md +0 -74
  101. package/skills/react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  102. package/skills/react-best-practices/rules/rerender-memo.md +0 -85
  103. package/skills/react-best-practices/rules/rerender-transitions.md +0 -40
  104. package/skills/skill-creator/LICENSE.txt +0 -202
  105. package/skills/skill-creator/SKILL.md +0 -209
  106. package/skills/skill-creator/scripts/init_skill.py +0 -303
  107. package/skills/skill-creator/scripts/package_skill.py +0 -110
  108. package/skills/skill-creator/scripts/quick_validate.py +0 -65
  109. package/skills/spring-boot-development/EXAMPLES.md +0 -2346
  110. package/skills/spring-boot-development/README.md +0 -595
  111. package/skills/spring-boot-development/SKILL.md +0 -1519
  112. package/themes/README.md +0 -68
  113. package/themes/claude-vivid.json +0 -72
@@ -1,307 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Analyze PDF form fields and structure.
4
-
5
- Usage:
6
- python analyze_form.py input.pdf [--output fields.json] [--verbose]
7
-
8
- Returns:
9
- JSON with all form fields, types, positions, and metadata
10
-
11
- Exit codes:
12
- 0 - Success
13
- 1 - File not found
14
- 2 - Invalid PDF
15
- 3 - Processing error
16
- """
17
-
18
- import sys
19
- import json
20
- import logging
21
- import argparse
22
- from pathlib import Path
23
- from typing import Dict, List, Optional, Any
24
-
25
- try:
26
- from pypdf import PdfReader
27
- except ImportError:
28
- print("Error: pypdf not installed. Run: pip install pypdf", file=sys.stderr)
29
- sys.exit(3)
30
-
31
- # Configure logging
32
- logging.basicConfig(
33
- level=logging.INFO,
34
- format='%(asctime)s - %(levelname)s - %(message)s'
35
- )
36
- logger = logging.getLogger(__name__)
37
-
38
-
39
- class FormField:
40
- """Represents a PDF form field."""
41
-
42
- def __init__(self, name: str, field_dict: Dict[str, Any]):
43
- self.name = name
44
- self.raw_data = field_dict
45
-
46
- @property
47
- def field_type(self) -> str:
48
- """Get field type."""
49
- ft = self.raw_data.get('/FT', '')
50
- type_map = {
51
- '/Tx': 'text',
52
- '/Btn': 'button', # checkbox or radio
53
- '/Ch': 'choice', # dropdown or list
54
- '/Sig': 'signature'
55
- }
56
- return type_map.get(ft, 'unknown')
57
-
58
- @property
59
- def value(self) -> Optional[str]:
60
- """Get current field value."""
61
- val = self.raw_data.get('/V')
62
- return str(val) if val else None
63
-
64
- @property
65
- def default_value(self) -> Optional[str]:
66
- """Get default field value."""
67
- dv = self.raw_data.get('/DV')
68
- return str(dv) if dv else None
69
-
70
- @property
71
- def is_required(self) -> bool:
72
- """Check if field is required."""
73
- flags = self.raw_data.get('/Ff', 0)
74
- # Bit 2 indicates required
75
- return bool(flags & 2)
76
-
77
- @property
78
- def is_readonly(self) -> bool:
79
- """Check if field is read-only."""
80
- flags = self.raw_data.get('/Ff', 0)
81
- # Bit 1 indicates read-only
82
- return bool(flags & 1)
83
-
84
- @property
85
- def options(self) -> List[str]:
86
- """Get options for choice fields."""
87
- if self.field_type != 'choice':
88
- return []
89
-
90
- opts = self.raw_data.get('/Opt', [])
91
- if isinstance(opts, list):
92
- return [str(opt) for opt in opts]
93
- return []
94
-
95
- @property
96
- def max_length(self) -> Optional[int]:
97
- """Get max length for text fields."""
98
- if self.field_type == 'text':
99
- return self.raw_data.get('/MaxLen')
100
- return None
101
-
102
- @property
103
- def rect(self) -> Optional[List[float]]:
104
- """Get field position and size [x0, y0, x1, y1]."""
105
- return self.raw_data.get('/Rect')
106
-
107
- def to_dict(self) -> Dict[str, Any]:
108
- """Convert to dictionary."""
109
- result = {
110
- 'name': self.name,
111
- 'type': self.field_type,
112
- 'required': self.is_required,
113
- 'readonly': self.is_readonly
114
- }
115
-
116
- if self.value is not None:
117
- result['value'] = self.value
118
-
119
- if self.default_value is not None:
120
- result['default_value'] = self.default_value
121
-
122
- if self.options:
123
- result['options'] = self.options
124
-
125
- if self.max_length is not None:
126
- result['max_length'] = self.max_length
127
-
128
- if self.rect:
129
- result['position'] = {
130
- 'x0': float(self.rect[0]),
131
- 'y0': float(self.rect[1]),
132
- 'x1': float(self.rect[2]),
133
- 'y1': float(self.rect[3]),
134
- 'width': float(self.rect[2] - self.rect[0]),
135
- 'height': float(self.rect[3] - self.rect[1])
136
- }
137
-
138
- return result
139
-
140
-
141
- class PDFFormAnalyzer:
142
- """Analyzes PDF forms and extracts field information."""
143
-
144
- def __init__(self, pdf_path: str):
145
- self.pdf_path = Path(pdf_path)
146
- self.reader: Optional[PdfReader] = None
147
- self._validate_file()
148
-
149
- def _validate_file(self) -> None:
150
- """Validate PDF file exists and is readable."""
151
- if not self.pdf_path.exists():
152
- logger.error(f"PDF not found: {self.pdf_path}")
153
- raise FileNotFoundError(f"PDF not found: {self.pdf_path}")
154
-
155
- if not self.pdf_path.is_file():
156
- logger.error(f"Not a file: {self.pdf_path}")
157
- raise ValueError(f"Not a file: {self.pdf_path}")
158
-
159
- if self.pdf_path.suffix.lower() != '.pdf':
160
- logger.error(f"Not a PDF file: {self.pdf_path}")
161
- raise ValueError(f"Not a PDF file: {self.pdf_path}")
162
-
163
- def analyze(self) -> Dict[str, Dict[str, Any]]:
164
- """
165
- Analyze PDF and extract all form fields.
166
-
167
- Returns:
168
- Dictionary mapping field names to field information
169
- """
170
- try:
171
- self.reader = PdfReader(str(self.pdf_path))
172
-
173
- if not self.reader.pages:
174
- logger.warning("PDF has no pages")
175
- return {}
176
-
177
- logger.info(f"Analyzing PDF with {len(self.reader.pages)} pages")
178
-
179
- # Get form fields
180
- raw_fields = self.reader.get_fields()
181
-
182
- if not raw_fields:
183
- logger.warning("PDF has no form fields")
184
- return {}
185
-
186
- logger.info(f"Found {len(raw_fields)} form fields")
187
-
188
- # Process fields
189
- fields = {}
190
- for field_name, field_dict in raw_fields.items():
191
- try:
192
- field = FormField(field_name, field_dict)
193
- fields[field_name] = field.to_dict()
194
- except Exception as e:
195
- logger.warning(f"Error processing field {field_name}: {e}")
196
- continue
197
-
198
- return fields
199
-
200
- except Exception as e:
201
- logger.error(f"Error analyzing PDF: {e}")
202
- raise
203
-
204
- def get_summary(self) -> Dict[str, Any]:
205
- """Get summary statistics."""
206
- fields = self.analyze()
207
-
208
- summary = {
209
- 'total_fields': len(fields),
210
- 'field_types': {},
211
- 'required_fields': [],
212
- 'readonly_fields': [],
213
- 'fields_with_values': []
214
- }
215
-
216
- for field_name, field_data in fields.items():
217
- # Count by type
218
- field_type = field_data['type']
219
- summary['field_types'][field_type] = summary['field_types'].get(field_type, 0) + 1
220
-
221
- # Required fields
222
- if field_data.get('required'):
223
- summary['required_fields'].append(field_name)
224
-
225
- # Read-only fields
226
- if field_data.get('readonly'):
227
- summary['readonly_fields'].append(field_name)
228
-
229
- # Fields with values
230
- if field_data.get('value'):
231
- summary['fields_with_values'].append(field_name)
232
-
233
- return summary
234
-
235
-
236
- def main():
237
- """Main entry point."""
238
- parser = argparse.ArgumentParser(
239
- description='Analyze PDF form fields',
240
- formatter_class=argparse.RawDescriptionHelpFormatter,
241
- epilog='''
242
- Examples:
243
- %(prog)s form.pdf
244
- %(prog)s form.pdf --output fields.json
245
- %(prog)s form.pdf --output fields.json --verbose
246
- %(prog)s form.pdf --summary
247
-
248
- Exit codes:
249
- 0 - Success
250
- 1 - File not found
251
- 2 - Invalid PDF
252
- 3 - Processing error
253
- '''
254
- )
255
-
256
- parser.add_argument('input', help='Input PDF file')
257
- parser.add_argument('--output', '-o', help='Output JSON file (default: stdout)')
258
- parser.add_argument('--summary', '-s', action='store_true', help='Show summary only')
259
- parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
260
-
261
- args = parser.parse_args()
262
-
263
- # Set log level
264
- if args.verbose:
265
- logger.setLevel(logging.DEBUG)
266
- else:
267
- logger.setLevel(logging.WARNING)
268
-
269
- try:
270
- # Analyze form
271
- analyzer = PDFFormAnalyzer(args.input)
272
-
273
- if args.summary:
274
- result = analyzer.get_summary()
275
- else:
276
- result = analyzer.analyze()
277
-
278
- # Output
279
- json_output = json.dumps(result, indent=2)
280
-
281
- if args.output:
282
- with open(args.output, 'w', encoding='utf-8') as f:
283
- f.write(json_output)
284
- logger.info(f"Saved to {args.output}")
285
- else:
286
- print(json_output)
287
-
288
- return 0
289
-
290
- except FileNotFoundError:
291
- logger.error(f"File not found: {args.input}")
292
- return 1
293
-
294
- except ValueError as e:
295
- logger.error(f"Invalid input: {e}")
296
- return 2
297
-
298
- except Exception as e:
299
- logger.error(f"Error: {e}")
300
- if args.verbose:
301
- import traceback
302
- traceback.print_exc()
303
- return 3
304
-
305
-
306
- if __name__ == '__main__':
307
- sys.exit(main())