onetool-mcp 1.0.0b1__py3-none-any.whl → 1.0.0rc2__py3-none-any.whl

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 (81) hide show
  1. onetool/cli.py +63 -4
  2. onetool_mcp-1.0.0rc2.dist-info/METADATA +266 -0
  3. onetool_mcp-1.0.0rc2.dist-info/RECORD +129 -0
  4. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/LICENSE.txt +1 -1
  5. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/NOTICE.txt +54 -64
  6. ot/__main__.py +6 -6
  7. ot/config/__init__.py +48 -46
  8. ot/config/global_templates/__init__.py +2 -2
  9. ot/config/{defaults → global_templates}/diagram-templates/api-flow.mmd +33 -33
  10. ot/config/{defaults → global_templates}/diagram-templates/c4-context.puml +30 -30
  11. ot/config/{defaults → global_templates}/diagram-templates/class-diagram.mmd +87 -87
  12. ot/config/{defaults → global_templates}/diagram-templates/feature-mindmap.mmd +70 -70
  13. ot/config/{defaults → global_templates}/diagram-templates/microservices.d2 +81 -81
  14. ot/config/{defaults → global_templates}/diagram-templates/project-gantt.mmd +37 -37
  15. ot/config/{defaults → global_templates}/diagram-templates/state-machine.mmd +42 -42
  16. ot/config/global_templates/diagram.yaml +167 -0
  17. ot/config/global_templates/onetool.yaml +3 -1
  18. ot/config/{defaults → global_templates}/prompts.yaml +102 -97
  19. ot/config/global_templates/security.yaml +31 -0
  20. ot/config/global_templates/servers.yaml +93 -12
  21. ot/config/global_templates/snippets.yaml +5 -26
  22. ot/config/{defaults → global_templates}/tool_templates/__init__.py +7 -7
  23. ot/config/loader.py +221 -105
  24. ot/config/mcp.py +5 -1
  25. ot/config/secrets.py +192 -190
  26. ot/decorators.py +116 -116
  27. ot/executor/__init__.py +35 -35
  28. ot/executor/base.py +16 -16
  29. ot/executor/fence_processor.py +83 -83
  30. ot/executor/linter.py +142 -142
  31. ot/executor/pep723.py +288 -288
  32. ot/executor/runner.py +20 -6
  33. ot/executor/simple.py +163 -163
  34. ot/executor/validator.py +603 -164
  35. ot/http_client.py +145 -145
  36. ot/logging/__init__.py +37 -37
  37. ot/logging/entry.py +213 -213
  38. ot/logging/format.py +191 -188
  39. ot/logging/span.py +349 -349
  40. ot/meta.py +236 -14
  41. ot/paths.py +32 -49
  42. ot/prompts.py +218 -218
  43. ot/proxy/manager.py +14 -2
  44. ot/registry/__init__.py +189 -189
  45. ot/registry/parser.py +269 -269
  46. ot/server.py +330 -315
  47. ot/shortcuts/__init__.py +15 -15
  48. ot/shortcuts/aliases.py +87 -87
  49. ot/shortcuts/snippets.py +258 -258
  50. ot/stats/__init__.py +35 -35
  51. ot/stats/html.py +2 -2
  52. ot/stats/reader.py +354 -354
  53. ot/stats/timing.py +57 -57
  54. ot/support.py +63 -63
  55. ot/tools.py +1 -1
  56. ot/utils/batch.py +161 -161
  57. ot/utils/cache.py +120 -120
  58. ot/utils/exceptions.py +23 -23
  59. ot/utils/factory.py +178 -179
  60. ot/utils/format.py +65 -65
  61. ot/utils/http.py +202 -202
  62. ot/utils/platform.py +45 -45
  63. ot/utils/truncate.py +69 -69
  64. ot_tools/__init__.py +4 -4
  65. ot_tools/_convert/__init__.py +12 -12
  66. ot_tools/_convert/pdf.py +254 -254
  67. ot_tools/diagram.yaml +167 -167
  68. ot_tools/scaffold.py +2 -2
  69. ot_tools/transform.py +124 -19
  70. ot_tools/web_fetch.py +94 -43
  71. onetool_mcp-1.0.0b1.dist-info/METADATA +0 -163
  72. onetool_mcp-1.0.0b1.dist-info/RECORD +0 -132
  73. ot/config/defaults/bench.yaml +0 -4
  74. ot/config/defaults/onetool.yaml +0 -25
  75. ot/config/defaults/servers.yaml +0 -7
  76. ot/config/defaults/snippets.yaml +0 -4
  77. ot_tools/firecrawl.py +0 -732
  78. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/WHEEL +0 -0
  79. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/entry_points.txt +0 -0
  80. /ot/config/{defaults → global_templates}/tool_templates/extension.py +0 -0
  81. /ot/config/{defaults → global_templates}/tool_templates/isolated.py +0 -0
ot/logging/format.py CHANGED
@@ -1,188 +1,191 @@
1
- """Output formatting for log entries.
2
-
3
- Provides truncation and credential sanitisation at OUTPUT time.
4
- Full values are preserved in LogEntry for programmatic access.
5
-
6
- Field-based truncation limits:
7
- | Pattern | Limit |
8
- |------------------------------------------------|-------|
9
- | path, filepath, source, dest, directory | 200 |
10
- | url | 120 |
11
- | query, topic | 100 |
12
- | pattern | 100 |
13
- | error | 300 |
14
- | default | 120 |
15
-
16
- Credential sanitisation:
17
- - URLs with credentials: postgres://user:pass@host -> postgres://***:***@host
18
- - Applied to fields containing 'url' or values starting with http(s)://
19
- """
20
-
21
- from __future__ import annotations
22
-
23
- import re
24
- from typing import Any
25
- from urllib.parse import urlparse, urlunparse
26
-
27
- # Field name patterns mapped to truncation limits
28
- FIELD_LIMITS: dict[str, int] = {
29
- "path": 200,
30
- "filepath": 200,
31
- "source": 200,
32
- "dest": 200,
33
- "directory": 200,
34
- "url": 120,
35
- "query": 100,
36
- "topic": 100,
37
- "pattern": 100,
38
- "error": 300,
39
- }
40
- DEFAULT_LIMIT = 120
41
-
42
- # URL credential pattern: scheme://user:pass@host
43
- URL_WITH_CREDS = re.compile(r"^([a-zA-Z][a-zA-Z0-9+.-]*://)([^:]+):([^@]+)@(.+)$")
44
-
45
-
46
- def _get_field_limit(field_name: str) -> int:
47
- """Get truncation limit for a field based on name patterns.
48
-
49
- Args:
50
- field_name: Name of the field (case-insensitive matching)
51
-
52
- Returns:
53
- Truncation limit in characters
54
- """
55
- lower_name = field_name.lower()
56
-
57
- # Check for pattern matches in field name
58
- for pattern, limit in FIELD_LIMITS.items():
59
- if pattern in lower_name:
60
- return limit
61
-
62
- return DEFAULT_LIMIT
63
-
64
-
65
- def sanitize_url(url: str) -> str:
66
- """Mask credentials in a URL.
67
-
68
- Args:
69
- url: URL string, potentially with embedded credentials
70
-
71
- Returns:
72
- URL with username:password masked as ***:***
73
-
74
- Example:
75
- postgres://user:password@host/db -> postgres://***:***@host/db
76
- """
77
- match = URL_WITH_CREDS.match(url)
78
- if match:
79
- scheme, _user, _password, rest = match.groups()
80
- return f"{scheme}***:***@{rest}"
81
-
82
- # Also handle parsed URLs without regex (for edge cases)
83
- try:
84
- parsed = urlparse(url)
85
- if parsed.username or parsed.password:
86
- # Reconstruct with masked credentials
87
- netloc = "***:***@" if parsed.password else "***@"
88
- netloc += parsed.hostname or ""
89
- if parsed.port:
90
- netloc += f":{parsed.port}"
91
- return urlunparse(
92
- (
93
- parsed.scheme,
94
- netloc,
95
- parsed.path,
96
- parsed.params,
97
- parsed.query,
98
- parsed.fragment,
99
- )
100
- )
101
- except Exception:
102
- pass # Return original if parsing fails
103
-
104
- return url
105
-
106
-
107
- def format_value(value: Any, field_name: str = "", max_length: int | None = None) -> Any:
108
- """Format a single value for output with truncation.
109
-
110
- Only string values are truncated. Other types pass through unchanged.
111
-
112
- Args:
113
- value: Value to format
114
- field_name: Field name for determining truncation limit
115
- max_length: Override truncation limit (None = use field-based limit)
116
-
117
- Returns:
118
- Formatted value (truncated string or original value)
119
- """
120
- if not isinstance(value, str):
121
- return value
122
-
123
- if max_length is None:
124
- max_length = _get_field_limit(field_name)
125
-
126
- if len(value) <= max_length:
127
- return value
128
-
129
- # Truncate with ellipsis
130
- return value[: max_length - 3] + "..."
131
-
132
-
133
- def sanitize_for_output(value: Any, field_name: str = "") -> Any:
134
- """Sanitize a value by masking credentials.
135
-
136
- Applies to:
137
- - Fields containing 'url' in name
138
- - String values starting with http:// or https://
139
-
140
- Args:
141
- value: Value to sanitize
142
- field_name: Field name for context
143
-
144
- Returns:
145
- Sanitized value
146
- """
147
- if not isinstance(value, str):
148
- return value
149
-
150
- lower_name = field_name.lower()
151
- lower_value = value.lower()
152
-
153
- # Apply URL sanitisation if field name contains 'url' or value is a URL
154
- if "url" in lower_name or lower_value.startswith(("http://", "https://")):
155
- return sanitize_url(value)
156
-
157
- return value
158
-
159
-
160
- def format_log_entry(
161
- entry_dict: dict[str, Any],
162
- verbose: bool = False,
163
- ) -> dict[str, Any]:
164
- """Format a log entry dict for output.
165
-
166
- Applies truncation and credential sanitisation to all fields.
167
- Full values are preserved in the original entry.
168
-
169
- Args:
170
- entry_dict: Log entry as dict (from LogEntry.to_dict())
171
- verbose: If True, skip truncation (still sanitizes credentials)
172
-
173
- Returns:
174
- New dict with formatted values
175
- """
176
- formatted: dict[str, Any] = {}
177
-
178
- for key, value in entry_dict.items():
179
- # Always sanitize credentials
180
- sanitized = sanitize_for_output(value, key)
181
-
182
- # Apply truncation unless verbose mode
183
- if verbose:
184
- formatted[key] = sanitized
185
- else:
186
- formatted[key] = format_value(sanitized, key)
187
-
188
- return formatted
1
+ """Output formatting for log entries.
2
+
3
+ Provides truncation and credential sanitisation at OUTPUT time.
4
+ Full values are preserved in LogEntry for programmatic access.
5
+
6
+ Field-based truncation limits:
7
+ | Pattern | Limit |
8
+ |------------------------------------------------|-------|
9
+ | path, filepath, source, dest, directory | 200 |
10
+ | command | 200 |
11
+ | url | 120 |
12
+ | query, topic | 100 |
13
+ | pattern, prompt | 100 |
14
+ | error | 300 |
15
+ | default | 120 |
16
+
17
+ Credential sanitisation:
18
+ - URLs with credentials: postgres://user:pass@host -> postgres://***:***@host
19
+ - Applied to fields containing 'url' or values starting with http(s)://
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import re
25
+ from typing import Any
26
+ from urllib.parse import urlparse, urlunparse
27
+
28
+ # Field name patterns mapped to truncation limits
29
+ FIELD_LIMITS: dict[str, int] = {
30
+ "path": 200,
31
+ "filepath": 200,
32
+ "source": 200,
33
+ "dest": 200,
34
+ "directory": 200,
35
+ "command": 200,
36
+ "url": 120,
37
+ "query": 100,
38
+ "topic": 100,
39
+ "pattern": 100,
40
+ "prompt": 100,
41
+ "error": 300,
42
+ }
43
+ DEFAULT_LIMIT = 120
44
+
45
+ # URL credential pattern: scheme://user:pass@host
46
+ URL_WITH_CREDS = re.compile(r"^([a-zA-Z][a-zA-Z0-9+.-]*://)([^:]+):([^@]+)@(.+)$")
47
+
48
+
49
+ def _get_field_limit(field_name: str) -> int:
50
+ """Get truncation limit for a field based on name patterns.
51
+
52
+ Args:
53
+ field_name: Name of the field (case-insensitive matching)
54
+
55
+ Returns:
56
+ Truncation limit in characters
57
+ """
58
+ lower_name = field_name.lower()
59
+
60
+ # Check for pattern matches in field name
61
+ for pattern, limit in FIELD_LIMITS.items():
62
+ if pattern in lower_name:
63
+ return limit
64
+
65
+ return DEFAULT_LIMIT
66
+
67
+
68
+ def sanitize_url(url: str) -> str:
69
+ """Mask credentials in a URL.
70
+
71
+ Args:
72
+ url: URL string, potentially with embedded credentials
73
+
74
+ Returns:
75
+ URL with username:password masked as ***:***
76
+
77
+ Example:
78
+ postgres://user:password@host/db -> postgres://***:***@host/db
79
+ """
80
+ match = URL_WITH_CREDS.match(url)
81
+ if match:
82
+ scheme, _user, _password, rest = match.groups()
83
+ return f"{scheme}***:***@{rest}"
84
+
85
+ # Also handle parsed URLs without regex (for edge cases)
86
+ try:
87
+ parsed = urlparse(url)
88
+ if parsed.username or parsed.password:
89
+ # Reconstruct with masked credentials
90
+ netloc = "***:***@" if parsed.password else "***@"
91
+ netloc += parsed.hostname or ""
92
+ if parsed.port:
93
+ netloc += f":{parsed.port}"
94
+ return urlunparse(
95
+ (
96
+ parsed.scheme,
97
+ netloc,
98
+ parsed.path,
99
+ parsed.params,
100
+ parsed.query,
101
+ parsed.fragment,
102
+ )
103
+ )
104
+ except Exception:
105
+ pass # Return original if parsing fails
106
+
107
+ return url
108
+
109
+
110
+ def format_value(value: Any, field_name: str = "", max_length: int | None = None) -> Any:
111
+ """Format a single value for output with truncation.
112
+
113
+ Only string values are truncated. Other types pass through unchanged.
114
+
115
+ Args:
116
+ value: Value to format
117
+ field_name: Field name for determining truncation limit
118
+ max_length: Override truncation limit (None = use field-based limit)
119
+
120
+ Returns:
121
+ Formatted value (truncated string or original value)
122
+ """
123
+ if not isinstance(value, str):
124
+ return value
125
+
126
+ if max_length is None:
127
+ max_length = _get_field_limit(field_name)
128
+
129
+ if len(value) <= max_length:
130
+ return value
131
+
132
+ # Truncate with ellipsis
133
+ return value[: max_length - 3] + "..."
134
+
135
+
136
+ def sanitize_for_output(value: Any, field_name: str = "") -> Any:
137
+ """Sanitize a value by masking credentials.
138
+
139
+ Applies to:
140
+ - Fields containing 'url' in name
141
+ - String values starting with http:// or https://
142
+
143
+ Args:
144
+ value: Value to sanitize
145
+ field_name: Field name for context
146
+
147
+ Returns:
148
+ Sanitized value
149
+ """
150
+ if not isinstance(value, str):
151
+ return value
152
+
153
+ lower_name = field_name.lower()
154
+ lower_value = value.lower()
155
+
156
+ # Apply URL sanitisation if field name contains 'url' or value is a URL
157
+ if "url" in lower_name or lower_value.startswith(("http://", "https://")):
158
+ return sanitize_url(value)
159
+
160
+ return value
161
+
162
+
163
+ def format_log_entry(
164
+ entry_dict: dict[str, Any],
165
+ verbose: bool = False,
166
+ ) -> dict[str, Any]:
167
+ """Format a log entry dict for output.
168
+
169
+ Applies truncation and credential sanitisation to all fields.
170
+ Full values are preserved in the original entry.
171
+
172
+ Args:
173
+ entry_dict: Log entry as dict (from LogEntry.to_dict())
174
+ verbose: If True, skip truncation (still sanitizes credentials)
175
+
176
+ Returns:
177
+ New dict with formatted values
178
+ """
179
+ formatted: dict[str, Any] = {}
180
+
181
+ for key, value in entry_dict.items():
182
+ # Always sanitize credentials
183
+ sanitized = sanitize_for_output(value, key)
184
+
185
+ # Apply truncation unless verbose mode
186
+ if verbose:
187
+ formatted[key] = sanitized
188
+ else:
189
+ formatted[key] = format_value(sanitized, key)
190
+
191
+ return formatted