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
@@ -15,17 +15,20 @@ from pathlib import Path
15
15
  from flask import Blueprint, render_template, jsonify, request, current_app, send_file
16
16
 
17
17
  from x_ipe.services import ProjectService, ContentService
18
+ from x_ipe.tracing import x_ipe_tracing
18
19
 
19
20
  main_bp = Blueprint('main', __name__)
20
21
 
21
22
 
22
23
  @main_bp.route('/')
24
+ @x_ipe_tracing()
23
25
  def index():
24
26
  """Serve main page with sidebar navigation"""
25
27
  return render_template('index.html')
26
28
 
27
29
 
28
30
  @main_bp.route('/uiux-feedbacks')
31
+ @x_ipe_tracing()
29
32
  def uiux_feedbacks():
30
33
  """
31
34
  GET /uiux-feedbacks
@@ -36,6 +39,7 @@ def uiux_feedbacks():
36
39
 
37
40
 
38
41
  @main_bp.route('/workplace')
42
+ @x_ipe_tracing()
39
43
  def workplace():
40
44
  """
41
45
  GET /workplace
@@ -46,7 +50,19 @@ def workplace():
46
50
  return render_template('workplace.html')
47
51
 
48
52
 
53
+ @main_bp.route('/knowledge-base')
54
+ @x_ipe_tracing()
55
+ def knowledge_base():
56
+ """
57
+ GET /knowledge-base
58
+
59
+ FEATURE-025-A: Knowledge Base page
60
+ """
61
+ return render_template('knowledge-base.html')
62
+
63
+
49
64
  @main_bp.route('/api/project/structure')
65
+ @x_ipe_tracing()
50
66
  def get_project_structure():
51
67
  """
52
68
  GET /api/project/structure
@@ -68,6 +84,7 @@ def get_project_structure():
68
84
 
69
85
 
70
86
  @main_bp.route('/api/file/content')
87
+ @x_ipe_tracing()
71
88
  def get_file_content():
72
89
  """
73
90
  GET /api/file/content?path=<relative_path>&raw=<true/false>
@@ -148,6 +165,7 @@ def get_file_content():
148
165
 
149
166
 
150
167
  @main_bp.route('/api/file/save', methods=['POST'])
168
+ @x_ipe_tracing()
151
169
  def save_file():
152
170
  """
153
171
  POST /api/file/save
@@ -13,6 +13,8 @@ Provides:
13
13
  import os
14
14
  from flask import Blueprint, jsonify, request, current_app
15
15
 
16
+ from x_ipe.tracing import x_ipe_tracing
17
+
16
18
  project_bp = Blueprint('project', __name__)
17
19
 
18
20
 
@@ -22,6 +24,7 @@ def get_project_folders_service():
22
24
 
23
25
 
24
26
  @project_bp.route('/api/projects', methods=['GET'])
27
+ @x_ipe_tracing()
25
28
  def get_projects():
26
29
  """
27
30
  GET /api/projects
@@ -43,6 +46,7 @@ def get_projects():
43
46
 
44
47
 
45
48
  @project_bp.route('/api/projects', methods=['POST'])
49
+ @x_ipe_tracing()
46
50
  def add_project():
47
51
  """
48
52
  POST /api/projects
@@ -78,6 +82,7 @@ def add_project():
78
82
 
79
83
 
80
84
  @project_bp.route('/api/projects/<int:project_id>', methods=['PUT'])
85
+ @x_ipe_tracing()
81
86
  def update_project(project_id):
82
87
  """
83
88
  PUT /api/projects/<id>
@@ -113,6 +118,7 @@ def update_project(project_id):
113
118
 
114
119
 
115
120
  @project_bp.route('/api/projects/<int:project_id>', methods=['DELETE'])
121
+ @x_ipe_tracing()
116
122
  def delete_project(project_id):
117
123
  """
118
124
  DELETE /api/projects/<id>
@@ -137,6 +143,7 @@ def delete_project(project_id):
137
143
 
138
144
 
139
145
  @project_bp.route('/api/projects/switch', methods=['POST'])
146
+ @x_ipe_tracing()
140
147
  def switch_project():
141
148
  """
142
149
  POST /api/projects/switch
@@ -8,11 +8,13 @@ Provides localhost URL proxying endpoint.
8
8
  from flask import Blueprint, jsonify, request, Response
9
9
 
10
10
  from x_ipe.services import ProxyService
11
+ from x_ipe.tracing import x_ipe_tracing
11
12
 
12
13
  proxy_bp = Blueprint('proxy', __name__)
13
14
 
14
15
 
15
16
  @proxy_bp.route('/api/proxy', methods=['GET'])
17
+ @x_ipe_tracing()
16
18
  def proxy_url():
17
19
  """
18
20
  GET /api/proxy?url=<encoded_url>
@@ -46,15 +48,21 @@ def proxy_url():
46
48
  result = service.fetch_and_rewrite(url)
47
49
 
48
50
  if result.success:
51
+ # TASK-235: Handle binary content (fonts, images, etc.)
52
+ if result.binary_content is not None:
53
+ return Response(
54
+ result.binary_content,
55
+ mimetype=result.content_type.split(';')[0].strip()
56
+ )
49
57
  # For HTML, return JSON (used by frontend to set iframe.srcdoc)
50
- if 'text/html' in result.content_type:
58
+ elif 'text/html' in result.content_type:
51
59
  return jsonify({
52
60
  'success': True,
53
61
  'html': result.html,
54
62
  'content_type': result.content_type
55
63
  })
56
64
  else:
57
- # For non-HTML (JS, CSS, images, etc.), return raw content
65
+ # For non-HTML text (JS, CSS, etc.), return raw content
58
66
  return Response(
59
67
  result.html, # Contains raw content for non-HTML
60
68
  mimetype=result.content_type.split(';')[0].strip()
@@ -0,0 +1,193 @@
1
+ """
2
+ FEATURE-024: Project Quality Evaluation UI
3
+
4
+ API routes for quality evaluation file management.
5
+
6
+ Provides REST endpoints for:
7
+ - GET /api/quality-evaluation/status - Get folder status and versions
8
+ - GET /api/quality-evaluation/content - Get markdown content for a version
9
+ """
10
+ from flask import Blueprint, request, jsonify, current_app
11
+ from pathlib import Path
12
+ import re
13
+ from datetime import datetime
14
+
15
+ from x_ipe.tracing import x_ipe_tracing
16
+
17
+
18
+ quality_evaluation_bp = Blueprint('quality_evaluation', __name__, url_prefix='/api/quality-evaluation')
19
+
20
+
21
+ QUALITY_EVAL_FOLDER = 'x-ipe-docs/quality-evaluation'
22
+ EVAL_FILE_PREFIX = 'project-quality-evaluation'
23
+
24
+
25
+ def get_project_root() -> Path:
26
+ """Get project root from app config."""
27
+ return Path(current_app.config.get('PROJECT_ROOT', '.'))
28
+
29
+
30
+ @x_ipe_tracing(level="INFO")
31
+ def get_evaluation_folder() -> Path:
32
+ """Get the quality evaluation folder path."""
33
+ return get_project_root() / QUALITY_EVAL_FOLDER
34
+
35
+
36
+ @x_ipe_tracing(level="INFO")
37
+ def parse_version_from_filename(filename: str) -> str:
38
+ """Extract version number from filename.
39
+
40
+ Examples:
41
+ project-quality-evaluation.md -> v5 (current)
42
+ project-quality-evaluation-v4.md -> v4
43
+ """
44
+ if filename == f'{EVAL_FILE_PREFIX}.md':
45
+ return 'current'
46
+ match = re.match(rf'{EVAL_FILE_PREFIX}-v(\d+)\.md', filename)
47
+ if match:
48
+ return f'v{match.group(1)}'
49
+ return None
50
+
51
+
52
+ @x_ipe_tracing(level="INFO")
53
+ def get_file_date(file_path: Path) -> str:
54
+ """Get formatted modification date for a file."""
55
+ try:
56
+ mtime = file_path.stat().st_mtime
57
+ dt = datetime.fromtimestamp(mtime)
58
+ return dt.strftime('%b %d')
59
+ except Exception:
60
+ return ''
61
+
62
+
63
+ @x_ipe_tracing(level="INFO")
64
+ def scan_versions(folder: Path) -> list:
65
+ """Scan folder for evaluation versions.
66
+
67
+ Returns list of version dicts sorted by version number (newest first).
68
+ Latest (current) file is always first.
69
+ """
70
+ if not folder.exists():
71
+ return []
72
+
73
+ versions = []
74
+ current_file = folder / f'{EVAL_FILE_PREFIX}.md'
75
+
76
+ # Check for current (latest) file first
77
+ if current_file.exists():
78
+ # Count existing versioned files to determine current version number
79
+ versioned_files = list(folder.glob(f'{EVAL_FILE_PREFIX}-v*.md'))
80
+ max_version = 0
81
+ for vf in versioned_files:
82
+ match = re.match(rf'{EVAL_FILE_PREFIX}-v(\d+)\.md', vf.name)
83
+ if match:
84
+ max_version = max(max_version, int(match.group(1)))
85
+
86
+ current_version = max_version + 1
87
+ versions.append({
88
+ 'version': f'v{current_version}',
89
+ 'filename': current_file.name,
90
+ 'date': get_file_date(current_file),
91
+ 'is_current': True
92
+ })
93
+
94
+ # Scan for versioned files
95
+ versioned_files = sorted(
96
+ folder.glob(f'{EVAL_FILE_PREFIX}-v*.md'),
97
+ key=lambda f: int(re.search(r'-v(\d+)\.md', f.name).group(1)),
98
+ reverse=True
99
+ )
100
+
101
+ for vf in versioned_files:
102
+ match = re.match(rf'{EVAL_FILE_PREFIX}-v(\d+)\.md', vf.name)
103
+ if match:
104
+ versions.append({
105
+ 'version': f'v{match.group(1)}',
106
+ 'filename': vf.name,
107
+ 'date': get_file_date(vf),
108
+ 'is_current': False
109
+ })
110
+
111
+ # Limit to 5 most recent versions
112
+ return versions[:5]
113
+
114
+
115
+ @quality_evaluation_bp.route('/status', methods=['GET'])
116
+ @x_ipe_tracing(level="INFO")
117
+ def get_status():
118
+ """
119
+ GET /api/quality-evaluation/status
120
+
121
+ Get folder status and available versions.
122
+
123
+ Response:
124
+ {
125
+ "exists": true,
126
+ "folder_path": "x-ipe-docs/quality-evaluation",
127
+ "versions": [
128
+ {"version": "v5", "filename": "project-quality-evaluation.md", "date": "Feb 1", "is_current": true},
129
+ {"version": "v4", "filename": "project-quality-evaluation-v4.md", "date": "Jan 31", "is_current": false}
130
+ ]
131
+ }
132
+ """
133
+ folder = get_evaluation_folder()
134
+ versions = scan_versions(folder)
135
+
136
+ return jsonify({
137
+ 'exists': len(versions) > 0,
138
+ 'folder_path': QUALITY_EVAL_FOLDER,
139
+ 'versions': versions
140
+ })
141
+
142
+
143
+ @quality_evaluation_bp.route('/content', methods=['GET'])
144
+ @x_ipe_tracing(level="INFO")
145
+ def get_content():
146
+ """
147
+ GET /api/quality-evaluation/content
148
+
149
+ Get markdown content for a specific version.
150
+
151
+ Query Parameters:
152
+ version (optional): Version to retrieve (e.g., "v4"). Default: latest.
153
+
154
+ Response:
155
+ {
156
+ "content": "# Project Quality Evaluation...",
157
+ "version": "v5",
158
+ "filename": "project-quality-evaluation.md",
159
+ "path": "x-ipe-docs/quality-evaluation/project-quality-evaluation.md"
160
+ }
161
+ """
162
+ folder = get_evaluation_folder()
163
+ requested_version = request.args.get('version')
164
+
165
+ versions = scan_versions(folder)
166
+ if not versions:
167
+ return jsonify({'error': 'No evaluation file found'}), 404
168
+
169
+ # Find the requested version or use latest
170
+ target_version = None
171
+ if requested_version:
172
+ for v in versions:
173
+ if v['version'] == requested_version:
174
+ target_version = v
175
+ break
176
+ if not target_version:
177
+ return jsonify({'error': f'Version {requested_version} not found'}), 404
178
+ else:
179
+ target_version = versions[0] # Latest
180
+
181
+ # Read the file content
182
+ file_path = folder / target_version['filename']
183
+ try:
184
+ content = file_path.read_text(encoding='utf-8')
185
+ except Exception as e:
186
+ return jsonify({'error': f'Failed to read file: {str(e)}'}), 500
187
+
188
+ return jsonify({
189
+ 'content': content,
190
+ 'version': target_version['version'],
191
+ 'filename': target_version['filename'],
192
+ 'path': f"{QUALITY_EVAL_FOLDER}/{target_version['filename']}"
193
+ })
@@ -12,6 +12,8 @@ Provides:
12
12
  import os
13
13
  from flask import Blueprint, render_template, jsonify, request, current_app
14
14
 
15
+ from x_ipe.tracing import x_ipe_tracing
16
+
15
17
  settings_bp = Blueprint('settings', __name__)
16
18
 
17
19
 
@@ -21,6 +23,7 @@ def get_settings_service():
21
23
 
22
24
 
23
25
  @settings_bp.route('/settings')
26
+ @x_ipe_tracing()
24
27
  def settings_page():
25
28
  """
26
29
  GET /settings
@@ -33,6 +36,7 @@ def settings_page():
33
36
 
34
37
 
35
38
  @settings_bp.route('/api/settings', methods=['GET'])
39
+ @x_ipe_tracing()
36
40
  def get_settings():
37
41
  """
38
42
  GET /api/settings
@@ -50,6 +54,7 @@ def get_settings():
50
54
 
51
55
 
52
56
  @settings_bp.route('/api/settings', methods=['POST'])
57
+ @x_ipe_tracing()
53
58
  def save_settings():
54
59
  """
55
60
  POST /api/settings
@@ -96,6 +101,7 @@ def save_settings():
96
101
 
97
102
 
98
103
  @settings_bp.route('/api/config', methods=['GET'])
104
+ @x_ipe_tracing()
99
105
  def get_config():
100
106
  """
101
107
  GET /api/config
@@ -14,6 +14,7 @@ import json
14
14
  from flask import Blueprint, jsonify, request, current_app
15
15
 
16
16
  from x_ipe.services import ToolsConfigService, ThemesService
17
+ from x_ipe.tracing import x_ipe_tracing
17
18
 
18
19
  tools_bp = Blueprint('tools', __name__)
19
20
 
@@ -31,6 +32,7 @@ def _get_themes_service():
31
32
 
32
33
 
33
34
  @tools_bp.route('/api/config/tools', methods=['GET'])
35
+ @x_ipe_tracing()
34
36
  def get_tools_config():
35
37
  """
36
38
  GET /api/config/tools
@@ -56,6 +58,7 @@ def get_tools_config():
56
58
 
57
59
 
58
60
  @tools_bp.route('/api/config/tools', methods=['POST'])
61
+ @x_ipe_tracing()
59
62
  def save_tools_config():
60
63
  """
61
64
  POST /api/config/tools
@@ -93,6 +96,7 @@ def save_tools_config():
93
96
 
94
97
 
95
98
  @tools_bp.route('/api/config/copilot-prompt', methods=['GET'])
99
+ @x_ipe_tracing()
96
100
  def get_copilot_prompt_config():
97
101
  """
98
102
  GET /api/config/copilot-prompt
@@ -130,6 +134,7 @@ def get_copilot_prompt_config():
130
134
  # ============================================================
131
135
 
132
136
  @tools_bp.route('/api/themes', methods=['GET'])
137
+ @x_ipe_tracing()
133
138
  def list_themes():
134
139
  """
135
140
  GET /api/themes
@@ -163,6 +168,7 @@ def list_themes():
163
168
 
164
169
 
165
170
  @tools_bp.route('/api/themes/<name>', methods=['GET'])
171
+ @x_ipe_tracing()
166
172
  def get_theme_detail(name):
167
173
  """
168
174
  GET /api/themes/<name>
@@ -0,0 +1,232 @@
1
+ """
2
+ FEATURE-023: Application Action Tracing - Core
3
+
4
+ Tracing API routes for controlling tracing and viewing logs.
5
+
6
+ Provides REST endpoints for:
7
+ - GET /api/tracing/status - Get tracing configuration
8
+ - POST /api/tracing/start - Start tracing for duration
9
+ - POST /api/tracing/stop - Stop tracing immediately
10
+ - GET /api/tracing/logs - List trace log files
11
+ - DELETE /api/tracing/logs - Delete all trace logs
12
+ """
13
+ from flask import Blueprint, request, jsonify, current_app
14
+ from pathlib import Path
15
+
16
+ from x_ipe.services.tracing_service import TracingService
17
+ from x_ipe.tracing import x_ipe_tracing
18
+
19
+
20
+ tracing_bp = Blueprint('tracing', __name__, url_prefix='/api/tracing')
21
+
22
+
23
+ def get_service() -> TracingService:
24
+ """Get TracingService instance for current app."""
25
+ project_root = current_app.config.get('PROJECT_ROOT', '.')
26
+ return TracingService(project_root)
27
+
28
+
29
+ @tracing_bp.route('/status', methods=['GET'])
30
+ @x_ipe_tracing()
31
+ def get_status():
32
+ """
33
+ GET /api/tracing/status
34
+
35
+ Get current tracing configuration and status.
36
+
37
+ Response:
38
+ {
39
+ "enabled": false,
40
+ "stop_at": "2026-02-01T03:30:00Z",
41
+ "log_path": "instance/traces/",
42
+ "retention_hours": 24,
43
+ "ignored_apis": [],
44
+ "active": true
45
+ }
46
+ """
47
+ service = get_service()
48
+ config = service.get_config()
49
+ config["active"] = service.is_active()
50
+ return jsonify(config)
51
+
52
+
53
+ @tracing_bp.route('/start', methods=['POST'])
54
+ @x_ipe_tracing()
55
+ def start_tracing():
56
+ """
57
+ POST /api/tracing/start
58
+
59
+ Start tracing for specified duration.
60
+
61
+ Request:
62
+ {
63
+ "duration_minutes": 3 | 15 | 30
64
+ }
65
+
66
+ Response:
67
+ {
68
+ "success": true,
69
+ "stop_at": "2026-02-01T03:33:00Z"
70
+ }
71
+
72
+ Errors:
73
+ 400 - Invalid duration (must be 3, 15, or 30)
74
+ """
75
+ data = request.get_json() or {}
76
+ duration = data.get('duration_minutes', 3)
77
+
78
+ try:
79
+ service = get_service()
80
+ result = service.start(duration)
81
+ return jsonify(result)
82
+ except ValueError as e:
83
+ return jsonify({"error": str(e)}), 400
84
+
85
+
86
+ @tracing_bp.route('/stop', methods=['POST'])
87
+ @x_ipe_tracing()
88
+ def stop_tracing():
89
+ """
90
+ POST /api/tracing/stop
91
+
92
+ Stop tracing immediately.
93
+
94
+ Response:
95
+ {
96
+ "success": true
97
+ }
98
+ """
99
+ service = get_service()
100
+ result = service.stop()
101
+ return jsonify(result)
102
+
103
+
104
+ @tracing_bp.route('/logs', methods=['GET'])
105
+ @x_ipe_tracing()
106
+ def list_logs():
107
+ """
108
+ GET /api/tracing/logs
109
+
110
+ List all trace log files.
111
+
112
+ Response:
113
+ [
114
+ {
115
+ "trace_id": "abc-123",
116
+ "filename": "20260201-033000-post-api-orders-abc-123.log",
117
+ "size": 1234,
118
+ "timestamp": "2026-02-01T03:30:00"
119
+ }
120
+ ]
121
+ """
122
+ service = get_service()
123
+ logs = service.list_logs()
124
+ return jsonify(logs)
125
+
126
+
127
+ @tracing_bp.route('/logs', methods=['DELETE'])
128
+ @x_ipe_tracing()
129
+ def delete_logs():
130
+ """
131
+ DELETE /api/tracing/logs
132
+
133
+ Delete all trace log files.
134
+
135
+ Response:
136
+ {
137
+ "deleted": 5
138
+ }
139
+ """
140
+ service = get_service()
141
+ deleted = service.delete_all_logs()
142
+ return jsonify({"deleted": deleted})
143
+
144
+
145
+ @tracing_bp.route('/logs/<trace_id>', methods=['GET'])
146
+ @x_ipe_tracing()
147
+ def get_trace(trace_id):
148
+ """
149
+ GET /api/tracing/logs/<trace_id>
150
+
151
+ Get parsed trace data for DAG visualization.
152
+
153
+ Response:
154
+ {
155
+ "trace_id": "abc-123",
156
+ "api": "POST /api/orders",
157
+ "timestamp": "2026-02-01T03:30:00",
158
+ "total_time_ms": 245,
159
+ "status": "success",
160
+ "nodes": [
161
+ {
162
+ "id": "node-0",
163
+ "label": "POST /api/orders",
164
+ "timing": "245ms",
165
+ "status": "success",
166
+ "level": "API",
167
+ "input": "{}",
168
+ "output": "{}",
169
+ "error": null
170
+ }
171
+ ],
172
+ "edges": [
173
+ {"source": "node-0", "target": "node-1"}
174
+ ],
175
+ "filename": "20260201-post-api-orders-abc123.log"
176
+ }
177
+
178
+ Errors:
179
+ 404 - Trace not found
180
+ """
181
+ service = get_service()
182
+ result = service.get_trace(trace_id)
183
+
184
+ if result is None:
185
+ return jsonify({"error": f"Trace not found: {trace_id}"}), 404
186
+
187
+ return jsonify(result)
188
+
189
+
190
+ @tracing_bp.route('/ignored', methods=['GET'])
191
+ @x_ipe_tracing()
192
+ def get_ignored_apis():
193
+ """
194
+ GET /api/tracing/ignored
195
+
196
+ Get list of ignored API patterns.
197
+
198
+ Response:
199
+ {
200
+ "patterns": ["/api/health/*", "/api/status"]
201
+ }
202
+ """
203
+ service = get_service()
204
+ config = service.get_config()
205
+ return jsonify({"patterns": config.get("ignored_apis", [])})
206
+
207
+
208
+ @tracing_bp.route('/ignored', methods=['POST'])
209
+ @x_ipe_tracing()
210
+ def update_ignored_apis():
211
+ """
212
+ POST /api/tracing/ignored
213
+
214
+ Update list of ignored API patterns.
215
+
216
+ Request:
217
+ {
218
+ "patterns": ["/api/health/*", "/api/status"]
219
+ }
220
+
221
+ Response:
222
+ {
223
+ "success": true
224
+ }
225
+ """
226
+ data = request.get_json() or {}
227
+ patterns = data.get('patterns', [])
228
+
229
+ service = get_service()
230
+ service.update_ignored_apis(patterns)
231
+
232
+ return jsonify({"success": True})