x-ipe 1.0.23__py3-none-any.whl → 1.0.25__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 (146) hide show
  1. x_ipe/app.py +32 -1
  2. x_ipe/handlers/terminal_handlers.py +6 -0
  3. x_ipe/handlers/voice_handlers.py +5 -0
  4. x_ipe/resources/copilot-instructions.md +19 -6
  5. x_ipe/resources/skills/lesson-learned/SKILL.md +208 -0
  6. x_ipe/resources/skills/lesson-learned/references/examples.md +238 -0
  7. x_ipe/resources/skills/project-quality-board-management/SKILL.md +135 -298
  8. x_ipe/resources/skills/project-quality-board-management/references/evaluation-principles.md +213 -0
  9. x_ipe/resources/skills/project-quality-board-management/references/evaluation-procedures.md +214 -0
  10. x_ipe/resources/skills/project-quality-board-management/templates/quality-report.md +70 -18
  11. x_ipe/resources/skills/task-execution-guideline/SKILL.md +2 -2
  12. x_ipe/resources/skills/task-execution-guideline/templates/task-record.yaml +1 -1
  13. x_ipe/resources/skills/task-type-code-implementation/SKILL.md +72 -270
  14. x_ipe/resources/skills/task-type-code-implementation/references/implementation-guidelines.md +432 -0
  15. x_ipe/resources/skills/task-type-code-refactor-v2/SKILL.md +127 -353
  16. x_ipe/resources/skills/task-type-code-refactor-v2/references/refactoring-techniques.md +373 -0
  17. x_ipe/resources/skills/task-type-feature-breakdown/SKILL.md +31 -243
  18. x_ipe/resources/skills/task-type-feature-breakdown/references/breakdown-guidelines.md +330 -0
  19. x_ipe/resources/skills/task-type-feature-refinement/SKILL.md +27 -180
  20. x_ipe/resources/skills/task-type-feature-refinement/references/specification-writing-guide.md +267 -0
  21. x_ipe/resources/skills/task-type-idea-mockup/SKILL.md +38 -276
  22. x_ipe/resources/skills/task-type-idea-mockup/references/mockup-guidelines.md +299 -0
  23. x_ipe/resources/skills/task-type-idea-to-architecture/SKILL.md +20 -218
  24. x_ipe/resources/skills/task-type-idea-to-architecture/references/architecture-patterns.md +342 -0
  25. x_ipe/resources/skills/task-type-ideation/SKILL.md +10 -266
  26. x_ipe/resources/skills/task-type-ideation/references/folder-naming-guide.md +55 -0
  27. x_ipe/resources/skills/task-type-ideation/references/tool-usage-guide.md +236 -0
  28. x_ipe/resources/skills/task-type-ideation-v2/SKILL.md +488 -0
  29. x_ipe/resources/skills/task-type-ideation-v2/references/examples.md +377 -0
  30. x_ipe/resources/skills/task-type-ideation-v2/references/folder-naming-guide.md +74 -0
  31. x_ipe/resources/skills/task-type-ideation-v2/references/tool-usage-guide.md +145 -0
  32. x_ipe/resources/skills/task-type-ideation-v2/references/visualization-guide.md +160 -0
  33. x_ipe/resources/skills/task-type-ideation-v2/templates/idea-summary.md +86 -0
  34. x_ipe/resources/skills/task-type-refactoring-analysis/SKILL.md +83 -145
  35. x_ipe/resources/skills/task-type-refactoring-analysis/references/output-schema.md +172 -0
  36. x_ipe/resources/skills/task-type-technical-design/SKILL.md +28 -214
  37. x_ipe/resources/skills/task-type-technical-design/references/design-templates.md +422 -0
  38. x_ipe/resources/skills/task-type-test-generation/SKILL.md +47 -332
  39. x_ipe/resources/skills/task-type-test-generation/references/test-patterns.md +368 -0
  40. x_ipe/resources/skills/tool-tracing-creator/SKILL.md +312 -0
  41. x_ipe/resources/skills/tool-tracing-creator/references/examples.md +324 -0
  42. x_ipe/resources/skills/tool-tracing-instrumentation/SKILL.md +373 -0
  43. x_ipe/resources/skills/tool-tracing-instrumentation/references/examples.md +264 -0
  44. x_ipe/resources/skills/x-ipe-skill-creator-v3/SKILL.md +486 -0
  45. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/10. example-gate-conditions.md +73 -0
  46. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/11. reference-quality-standards.md +127 -0
  47. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/2. reference-section-order.md +127 -0
  48. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/3. example-step-based-code-review.md +84 -0
  49. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/4. example-step-based-feature-implementation.md +113 -0
  50. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/5. example-function-based-validation.md +73 -0
  51. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/6. example-function-based-analysis.md +94 -0
  52. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/7. example-task-io-code-implementation.md +36 -0
  53. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/8. example-structured-summary.md +43 -0
  54. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/9. example-dor-dod.md +77 -0
  55. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/examples.md +429 -0
  56. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/skill-general-guidelines-v2.md +611 -0
  57. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-meta.md +153 -0
  58. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-based.md +324 -0
  59. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-category.md +109 -0
  60. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-tool.md +205 -0
  61. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-meta.md +334 -0
  62. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-task-based.md +279 -0
  63. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-tool.md +175 -0
  64. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-workflow-orchestration.md +329 -0
  65. x_ipe/resources/skills/x-ipe-task-based-ideation/SKILL.md +487 -0
  66. x_ipe/resources/skills/x-ipe-task-based-ideation/references/examples.md +377 -0
  67. x_ipe/resources/skills/x-ipe-task-based-ideation/references/folder-naming-guide.md +74 -0
  68. x_ipe/resources/skills/x-ipe-task-based-ideation/references/tool-usage-guide.md +145 -0
  69. x_ipe/resources/skills/x-ipe-task-based-ideation/references/visualization-guide.md +160 -0
  70. x_ipe/resources/skills/x-ipe-task-based-ideation/templates/idea-summary.md +86 -0
  71. x_ipe/routes/__init__.py +2 -0
  72. x_ipe/routes/ideas_routes.py +289 -0
  73. x_ipe/routes/kb_routes.py +80 -0
  74. x_ipe/routes/main_routes.py +18 -0
  75. x_ipe/routes/project_routes.py +7 -0
  76. x_ipe/routes/proxy_routes.py +10 -2
  77. x_ipe/routes/quality_evaluation_routes.py +193 -0
  78. x_ipe/routes/settings_routes.py +6 -0
  79. x_ipe/routes/tools_routes.py +6 -0
  80. x_ipe/routes/tracing_routes.py +232 -0
  81. x_ipe/routes/uiux_feedback_routes.py +50 -0
  82. x_ipe/services/__init__.py +5 -0
  83. x_ipe/services/config_service.py +6 -0
  84. x_ipe/services/file_service.py +20 -0
  85. x_ipe/services/homepage_service.py +160 -0
  86. x_ipe/services/ideas_service.py +535 -2
  87. x_ipe/services/kb_service.py +378 -0
  88. x_ipe/services/proxy_service.py +37 -7
  89. x_ipe/services/settings_service.py +13 -0
  90. x_ipe/services/skills_service.py +4 -0
  91. x_ipe/services/terminal_service.py +24 -0
  92. x_ipe/services/themes_service.py +4 -0
  93. x_ipe/services/tools_config_service.py +4 -0
  94. x_ipe/services/tracing_service.py +333 -0
  95. x_ipe/services/uiux_feedback_service.py +148 -1
  96. x_ipe/services/voice_input_service_v2.py +11 -0
  97. x_ipe/static/css/base.css +7 -0
  98. x_ipe/static/css/homepage-infinity.css +330 -0
  99. x_ipe/static/css/kb-core.css +301 -0
  100. x_ipe/static/css/quality-evaluation.css +345 -0
  101. x_ipe/static/css/sidebar.css +14 -4
  102. x_ipe/static/css/terminal.css +23 -0
  103. x_ipe/static/css/tracing-dashboard.css +796 -0
  104. x_ipe/static/css/uiux-feedback.css +7 -1
  105. x_ipe/static/css/workplace.css +636 -0
  106. x_ipe/static/img/homepage-infinity-loop.png +0 -0
  107. x_ipe/static/js/features/confirm-dialog.js +169 -0
  108. x_ipe/static/js/features/folder-view.js +742 -0
  109. x_ipe/static/js/features/homepage-infinity.js +314 -0
  110. x_ipe/static/js/features/kb-core.js +371 -0
  111. x_ipe/static/js/features/quality-evaluation.js +387 -0
  112. x_ipe/static/js/features/sidebar.js +255 -12
  113. x_ipe/static/js/features/tracing-dashboard.js +855 -0
  114. x_ipe/static/js/features/tracing-graph.js +1031 -0
  115. x_ipe/static/js/features/tree-drag.js +227 -0
  116. x_ipe/static/js/features/tree-search.js +228 -0
  117. x_ipe/static/js/features/workplace.js +661 -33
  118. x_ipe/static/js/init.js +76 -0
  119. x_ipe/static/js/terminal-v2.js +45 -14
  120. x_ipe/static/js/terminal.js +50 -49
  121. x_ipe/static/js/uiux-feedback.js +75 -16
  122. x_ipe/templates/base.html +24 -0
  123. x_ipe/templates/index.html +10 -1
  124. x_ipe/templates/knowledge-base.html +110 -0
  125. x_ipe/templates/workplace.html +4 -0
  126. x_ipe/tracing/__init__.py +37 -0
  127. x_ipe/tracing/buffer.py +135 -0
  128. x_ipe/tracing/context.py +125 -0
  129. x_ipe/tracing/decorator.py +288 -0
  130. x_ipe/tracing/middleware.py +197 -0
  131. x_ipe/tracing/parser.py +235 -0
  132. x_ipe/tracing/redactor.py +111 -0
  133. x_ipe/tracing/writer.py +122 -0
  134. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/METADATA +2 -2
  135. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/RECORD +138 -65
  136. x_ipe/app.py.bak +0 -1333
  137. x_ipe/resources/skills/x-ipe-skill-creator/SKILL.md +0 -329
  138. x_ipe/resources/skills/x-ipe-skill-creator/references/output-patterns.md +0 -169
  139. x_ipe/resources/skills/x-ipe-skill-creator/references/skill-structure.md +0 -162
  140. x_ipe/resources/skills/x-ipe-skill-creator/references/workflows.md +0 -110
  141. x_ipe/resources/skills/x-ipe-skill-creator/templates/references/examples.md +0 -113
  142. x_ipe/resources/skills/x-ipe-skill-creator/templates/skill-category-skill.md +0 -296
  143. x_ipe/resources/skills/x-ipe-skill-creator/templates/task-type-skill.md +0 -269
  144. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/WHEEL +0 -0
  145. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/entry_points.txt +0 -0
  146. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,235 @@
1
+ """
2
+ FEATURE-023-C: Trace Viewer & DAG Visualization
3
+
4
+ TraceLogParser for parsing trace log files into visualization-ready graph structures.
5
+
6
+ Handles the log format:
7
+ [TRACE-START] trace_id | API | timestamp
8
+ [INFO] → start_function: name | input_json
9
+ [INFO] ← return_function: name | output_json | duration
10
+ [ERROR] ← exception: name | error | duration
11
+ [TRACE-END] trace_id | total_duration | status
12
+ """
13
+ import re
14
+ from pathlib import Path
15
+ from typing import Dict, List, Any, Optional
16
+
17
+
18
+ class TraceLogParser:
19
+ """
20
+ Parse trace log files into graph structure for visualization.
21
+
22
+ Usage:
23
+ parser = TraceLogParser()
24
+ result = parser.parse(Path("trace.log"))
25
+ # result = {"trace_id": "...", "nodes": [...], "edges": [...]}
26
+ """
27
+
28
+ # Regex patterns for parsing log lines
29
+ TRACE_START_PATTERN = re.compile(
30
+ r'\[TRACE-START\]\s*([^\|]+)\s*\|\s*([^\|]+)\s*\|\s*(.+)'
31
+ )
32
+ TRACE_END_PATTERN = re.compile(
33
+ r'\[TRACE-END\]\s*([^\|]+)\s*\|\s*(\d+)ms\s*\|\s*(\w+)'
34
+ )
35
+ FUNCTION_START_PATTERN = re.compile(
36
+ r'\[(INFO|DEBUG)\]\s*→\s*start_function:\s*([^\|]+)\s*\|\s*(.+)'
37
+ )
38
+ FUNCTION_RETURN_PATTERN = re.compile(
39
+ r'\[(INFO|DEBUG)\]\s*←\s*return_function:\s*([^\|]+)\s*\|\s*([^\|]+)\s*\|\s*(\d+)ms'
40
+ )
41
+ EXCEPTION_PATTERN = re.compile(
42
+ r'\[(ERROR|INFO|DEBUG)\]\s*←\s*exception:\s*([^\|]+)\s*\|\s*([^|]+):\s*([^\|]+)\s*\|\s*(\d+)ms'
43
+ )
44
+ STACK_LINE_PATTERN = re.compile(
45
+ r'\s+at\s+(\w+)\s+\(([^:]+):?(\d+)?\)'
46
+ )
47
+
48
+ def parse(self, filepath: Path) -> Dict[str, Any]:
49
+ """
50
+ Parse trace log file into visualization-ready structure.
51
+
52
+ Args:
53
+ filepath: Path to the trace log file
54
+
55
+ Returns:
56
+ Dictionary with trace data:
57
+ {
58
+ "trace_id": str,
59
+ "api": str,
60
+ "timestamp": str,
61
+ "total_time_ms": int,
62
+ "status": str ("success" or "error"),
63
+ "nodes": [
64
+ {
65
+ "id": str,
66
+ "label": str,
67
+ "timing": str,
68
+ "status": str,
69
+ "level": str,
70
+ "input": str,
71
+ "output": str,
72
+ "error": dict or None
73
+ }
74
+ ],
75
+ "edges": [
76
+ {"source": str, "target": str}
77
+ ]
78
+ }
79
+ """
80
+ result = {
81
+ "trace_id": "",
82
+ "api": "",
83
+ "timestamp": "",
84
+ "total_time_ms": 0,
85
+ "status": "success",
86
+ "nodes": [],
87
+ "edges": []
88
+ }
89
+
90
+ if not filepath.exists():
91
+ return result
92
+
93
+ content = filepath.read_text()
94
+ if not content.strip():
95
+ return result
96
+
97
+ lines = content.splitlines()
98
+ nodes = []
99
+ edges = []
100
+ call_stack = [] # Stack of node indices for tracking parent-child
101
+ node_counter = 0
102
+ current_error_node = None
103
+ stack_lines = []
104
+
105
+ for raw_line in lines:
106
+ # Keep original line for stack trace matching
107
+ line = raw_line.strip()
108
+
109
+ # Check for stack trace lines (indented with 'at')
110
+ stack_match = self.STACK_LINE_PATTERN.match(raw_line)
111
+ if stack_match and current_error_node is not None:
112
+ func, file_path, line_num = stack_match.groups()
113
+ stack_lines.append({
114
+ "func": func,
115
+ "file": file_path,
116
+ "line": int(line_num) if line_num else None
117
+ })
118
+ continue
119
+
120
+ # If we were collecting stack and hit non-stack line, finalize
121
+ if stack_lines and current_error_node is not None:
122
+ nodes[current_error_node]["error"]["stack"] = stack_lines
123
+ stack_lines = []
124
+ current_error_node = None
125
+
126
+ # TRACE-START
127
+ start_match = self.TRACE_START_PATTERN.match(line)
128
+ if start_match:
129
+ trace_id, api, timestamp = start_match.groups()
130
+ result["trace_id"] = trace_id.strip()
131
+ result["api"] = api.strip()
132
+ result["timestamp"] = timestamp.strip()
133
+
134
+ # Create root API node
135
+ nodes.append({
136
+ "id": f"node-{node_counter}",
137
+ "label": api.strip(),
138
+ "timing": "",
139
+ "status": "success",
140
+ "level": "API",
141
+ "input": "{}",
142
+ "output": "{}",
143
+ "error": None
144
+ })
145
+ call_stack.append(node_counter)
146
+ node_counter += 1
147
+ continue
148
+
149
+ # TRACE-END
150
+ end_match = self.TRACE_END_PATTERN.match(line)
151
+ if end_match:
152
+ _, total_ms, status = end_match.groups()
153
+ result["total_time_ms"] = int(total_ms)
154
+ result["status"] = status.lower()
155
+
156
+ # Update root node timing
157
+ if nodes:
158
+ nodes[0]["timing"] = f"{total_ms}ms"
159
+ if status.upper() == "ERROR":
160
+ nodes[0]["status"] = "error"
161
+ continue
162
+
163
+ # Function start
164
+ func_start_match = self.FUNCTION_START_PATTERN.match(line)
165
+ if func_start_match:
166
+ level, func_name, input_json = func_start_match.groups()
167
+ func_name = func_name.strip()
168
+
169
+ # Create function node
170
+ new_node = {
171
+ "id": f"node-{node_counter}",
172
+ "label": func_name,
173
+ "timing": "",
174
+ "status": "success",
175
+ "level": level,
176
+ "input": input_json.strip(),
177
+ "output": "{}",
178
+ "error": None
179
+ }
180
+ nodes.append(new_node)
181
+
182
+ # Create edge from parent
183
+ if call_stack:
184
+ parent_id = call_stack[-1]
185
+ edges.append({
186
+ "source": f"node-{parent_id}",
187
+ "target": f"node-{node_counter}"
188
+ })
189
+
190
+ call_stack.append(node_counter)
191
+ node_counter += 1
192
+ continue
193
+
194
+ # Function return
195
+ func_return_match = self.FUNCTION_RETURN_PATTERN.match(line)
196
+ if func_return_match:
197
+ level, func_name, output_json, duration = func_return_match.groups()
198
+ func_name = func_name.strip()
199
+
200
+ # Pop from stack and update node
201
+ if call_stack:
202
+ current_id = call_stack.pop()
203
+ if current_id < len(nodes):
204
+ nodes[current_id]["output"] = output_json.strip()
205
+ nodes[current_id]["timing"] = f"{duration}ms"
206
+ continue
207
+
208
+ # Exception
209
+ exception_match = self.EXCEPTION_PATTERN.match(line)
210
+ if exception_match:
211
+ level, func_name, error_type, error_msg, duration = exception_match.groups()
212
+ func_name = func_name.strip()
213
+
214
+ # Pop from stack and update node with error
215
+ if call_stack:
216
+ current_id = call_stack.pop()
217
+ if current_id < len(nodes):
218
+ nodes[current_id]["status"] = "error"
219
+ nodes[current_id]["timing"] = f"{duration}ms"
220
+ nodes[current_id]["error"] = {
221
+ "type": error_type.strip(),
222
+ "message": error_msg.strip(),
223
+ "stack": []
224
+ }
225
+ current_error_node = current_id
226
+ continue
227
+
228
+ # Finalize any remaining stack lines
229
+ if stack_lines and current_error_node is not None:
230
+ nodes[current_error_node]["error"]["stack"] = stack_lines
231
+
232
+ result["nodes"] = nodes
233
+ result["edges"] = edges
234
+
235
+ return result
@@ -0,0 +1,111 @@
1
+ """
2
+ FEATURE-023: Application Action Tracing - Core
3
+
4
+ Redactor module for sensitive data redaction in trace logs.
5
+
6
+ This module provides automatic redaction of sensitive data before logging,
7
+ including passwords, tokens, API keys, and credit card numbers.
8
+ """
9
+ import re
10
+ from typing import Any, Dict, List, Set, Optional
11
+
12
+ REDACTED = "[REDACTED]"
13
+
14
+ # Sensitive key patterns (case-insensitive matching)
15
+ SENSITIVE_KEY_PATTERNS = {
16
+ "password",
17
+ "secret",
18
+ "token",
19
+ "api_key",
20
+ "apikey",
21
+ "authorization",
22
+ "auth",
23
+ "credential",
24
+ "private_key",
25
+ "privatekey",
26
+ }
27
+
28
+ # Value patterns
29
+ CREDIT_CARD_PATTERN = re.compile(r"^\d{16}$")
30
+ JWT_PREFIX = "eyJ"
31
+
32
+
33
+ class Redactor:
34
+ """
35
+ Sensitive data redactor for trace logs.
36
+
37
+ Automatically redacts:
38
+ - Fields containing sensitive key patterns (password, secret, token, etc.)
39
+ - Credit card numbers (16-digit patterns)
40
+ - JWT tokens (values starting with 'eyJ')
41
+ - Custom fields specified via constructor
42
+
43
+ Usage:
44
+ redactor = Redactor(custom_fields=["ssn", "dob"])
45
+ safe_data = redactor.redact({"password": "secret", "name": "John"})
46
+ # Result: {"password": "[REDACTED]", "name": "John"}
47
+ """
48
+
49
+ def __init__(self, custom_fields: Optional[List[str]] = None):
50
+ """
51
+ Initialize Redactor with optional custom fields.
52
+
53
+ Args:
54
+ custom_fields: Additional field names to redact (case-insensitive)
55
+ """
56
+ self.custom_fields: Set[str] = set(
57
+ f.lower() for f in (custom_fields or [])
58
+ )
59
+
60
+ def redact(self, data: Any) -> Any:
61
+ """
62
+ Recursively redact sensitive data.
63
+
64
+ Args:
65
+ data: Data to redact (dict, list, or primitive)
66
+
67
+ Returns:
68
+ Data with sensitive values replaced with '[REDACTED]'
69
+ """
70
+ if isinstance(data, dict):
71
+ return {k: self._redact_value(k, v) for k, v in data.items()}
72
+ elif isinstance(data, list):
73
+ return [self.redact(item) for item in data]
74
+ elif isinstance(data, tuple):
75
+ return tuple(self.redact(item) for item in data)
76
+ return data
77
+
78
+ def _redact_value(self, key: str, value: Any) -> Any:
79
+ """
80
+ Redact a single value based on key name and value patterns.
81
+
82
+ Args:
83
+ key: Field name
84
+ value: Field value
85
+
86
+ Returns:
87
+ Redacted value or original value if not sensitive
88
+ """
89
+ key_lower = key.lower()
90
+
91
+ # Check field name against sensitive patterns
92
+ for pattern in SENSITIVE_KEY_PATTERNS:
93
+ if pattern in key_lower:
94
+ return REDACTED
95
+
96
+ # Check custom fields
97
+ if key_lower in self.custom_fields:
98
+ return REDACTED
99
+
100
+ # Check value patterns for strings
101
+ if isinstance(value, str):
102
+ # Credit card pattern (16 digits)
103
+ if CREDIT_CARD_PATTERN.match(value):
104
+ return REDACTED
105
+
106
+ # JWT pattern (starts with eyJ)
107
+ if value.startswith(JWT_PREFIX):
108
+ return REDACTED
109
+
110
+ # Recurse for nested structures
111
+ return self.redact(value)
@@ -0,0 +1,122 @@
1
+ """
2
+ FEATURE-023: Application Action Tracing - Core
3
+
4
+ TraceLogWriter for writing trace buffers to log files.
5
+
6
+ Handles file naming, directory creation, permission setting,
7
+ and cleanup of old log files.
8
+ """
9
+ import os
10
+ import re
11
+ from datetime import datetime, timezone
12
+ from pathlib import Path
13
+ from typing import Optional
14
+
15
+ from .buffer import TraceBuffer
16
+
17
+
18
+ class TraceLogWriter:
19
+ """
20
+ Writer for trace log files.
21
+
22
+ Writes trace buffers to structured log files with proper naming,
23
+ permissions, and cleanup of old files.
24
+
25
+ Usage:
26
+ writer = TraceLogWriter("instance/traces/")
27
+ filepath = writer.write(buffer, "SUCCESS")
28
+ deleted = writer.cleanup(retention_hours=24)
29
+ """
30
+
31
+ def __init__(self, log_path: str = "instance/traces/"):
32
+ """
33
+ Initialize TraceLogWriter.
34
+
35
+ Args:
36
+ log_path: Directory path for log files
37
+ """
38
+ self.log_path = Path(log_path)
39
+
40
+ def write(self, buffer: TraceBuffer, status: str = "SUCCESS") -> Optional[str]:
41
+ """
42
+ Write trace buffer to log file.
43
+
44
+ Creates the log directory if it doesn't exist.
45
+ Sets file permissions to 600 (owner read/write only).
46
+
47
+ Args:
48
+ buffer: TraceBuffer to write
49
+ status: Final status (SUCCESS, ERROR)
50
+
51
+ Returns:
52
+ Path to created log file, or None if write failed
53
+ """
54
+ try:
55
+ # Ensure directory exists
56
+ self.log_path.mkdir(parents=True, exist_ok=True)
57
+
58
+ # Calculate total duration
59
+ total_ms = (datetime.now(timezone.utc) - buffer.started_at).total_seconds() * 1000
60
+ content = buffer.to_log_string(status, total_ms)
61
+
62
+ # Generate filename
63
+ timestamp = buffer.started_at.strftime("%Y%m%d-%H%M%S")
64
+ api_name = self._sanitize_api_name(buffer.root_api)
65
+ filename = f"{timestamp}-{api_name}-{buffer.trace_id}.log"
66
+ filepath = self.log_path / filename
67
+
68
+ # Write file
69
+ with open(filepath, 'w', encoding='utf-8') as f:
70
+ f.write(content)
71
+
72
+ # Set permissions (owner read/write only)
73
+ os.chmod(filepath, 0o600)
74
+
75
+ return str(filepath)
76
+
77
+ except Exception as e:
78
+ print(f"[TRACING] Failed to write log: {e}")
79
+ return None
80
+
81
+ def cleanup(self, retention_hours: int = 24) -> int:
82
+ """
83
+ Delete log files older than retention period.
84
+
85
+ Args:
86
+ retention_hours: Hours to retain log files
87
+
88
+ Returns:
89
+ Number of files deleted
90
+ """
91
+ if not self.log_path.exists():
92
+ return 0
93
+
94
+ deleted = 0
95
+ cutoff = datetime.now(timezone.utc).timestamp() - (retention_hours * 3600)
96
+
97
+ for filepath in self.log_path.glob("*.log"):
98
+ try:
99
+ if filepath.stat().st_mtime < cutoff:
100
+ filepath.unlink()
101
+ deleted += 1
102
+ except OSError:
103
+ continue
104
+
105
+ return deleted
106
+
107
+ def _sanitize_api_name(self, api: str) -> str:
108
+ """
109
+ Convert API string to safe filename component.
110
+
111
+ Args:
112
+ api: API string (e.g., "POST /api/orders")
113
+
114
+ Returns:
115
+ Sanitized string (e.g., "post--api-orders")
116
+ """
117
+ # Replace spaces and slashes with hyphens
118
+ sanitized = api.lower().replace(" ", "-").replace("/", "-")
119
+ # Remove multiple consecutive hyphens
120
+ sanitized = re.sub(r'-+', '-', sanitized)
121
+ # Strip leading/trailing hyphens
122
+ return sanitized.strip("-")
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: x-ipe
3
- Version: 1.0.23
4
- Summary: X-IPE: AI-powered development framework
3
+ Version: 1.0.25
4
+ Summary: An AI native integrated project environment for end to end business value delivery
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
7
7
  Requires-Dist: beautifulsoup4>=4.14.3