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.
- x_ipe/app.py +32 -1
- x_ipe/handlers/terminal_handlers.py +6 -0
- x_ipe/handlers/voice_handlers.py +5 -0
- x_ipe/resources/copilot-instructions.md +19 -6
- x_ipe/resources/skills/lesson-learned/SKILL.md +208 -0
- x_ipe/resources/skills/lesson-learned/references/examples.md +238 -0
- x_ipe/resources/skills/project-quality-board-management/SKILL.md +135 -298
- x_ipe/resources/skills/project-quality-board-management/references/evaluation-principles.md +213 -0
- x_ipe/resources/skills/project-quality-board-management/references/evaluation-procedures.md +214 -0
- x_ipe/resources/skills/project-quality-board-management/templates/quality-report.md +70 -18
- x_ipe/resources/skills/task-execution-guideline/SKILL.md +2 -2
- x_ipe/resources/skills/task-execution-guideline/templates/task-record.yaml +1 -1
- x_ipe/resources/skills/task-type-code-implementation/SKILL.md +72 -270
- x_ipe/resources/skills/task-type-code-implementation/references/implementation-guidelines.md +432 -0
- x_ipe/resources/skills/task-type-code-refactor-v2/SKILL.md +127 -353
- x_ipe/resources/skills/task-type-code-refactor-v2/references/refactoring-techniques.md +373 -0
- x_ipe/resources/skills/task-type-feature-breakdown/SKILL.md +31 -243
- x_ipe/resources/skills/task-type-feature-breakdown/references/breakdown-guidelines.md +330 -0
- x_ipe/resources/skills/task-type-feature-refinement/SKILL.md +27 -180
- x_ipe/resources/skills/task-type-feature-refinement/references/specification-writing-guide.md +267 -0
- x_ipe/resources/skills/task-type-idea-mockup/SKILL.md +38 -276
- x_ipe/resources/skills/task-type-idea-mockup/references/mockup-guidelines.md +299 -0
- x_ipe/resources/skills/task-type-idea-to-architecture/SKILL.md +20 -218
- x_ipe/resources/skills/task-type-idea-to-architecture/references/architecture-patterns.md +342 -0
- x_ipe/resources/skills/task-type-ideation/SKILL.md +10 -266
- x_ipe/resources/skills/task-type-ideation/references/folder-naming-guide.md +55 -0
- x_ipe/resources/skills/task-type-ideation/references/tool-usage-guide.md +236 -0
- x_ipe/resources/skills/task-type-ideation-v2/SKILL.md +488 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/examples.md +377 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/folder-naming-guide.md +74 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/tool-usage-guide.md +145 -0
- x_ipe/resources/skills/task-type-ideation-v2/references/visualization-guide.md +160 -0
- x_ipe/resources/skills/task-type-ideation-v2/templates/idea-summary.md +86 -0
- x_ipe/resources/skills/task-type-refactoring-analysis/SKILL.md +83 -145
- x_ipe/resources/skills/task-type-refactoring-analysis/references/output-schema.md +172 -0
- x_ipe/resources/skills/task-type-technical-design/SKILL.md +28 -214
- x_ipe/resources/skills/task-type-technical-design/references/design-templates.md +422 -0
- x_ipe/resources/skills/task-type-test-generation/SKILL.md +47 -332
- x_ipe/resources/skills/task-type-test-generation/references/test-patterns.md +368 -0
- x_ipe/resources/skills/tool-tracing-creator/SKILL.md +312 -0
- x_ipe/resources/skills/tool-tracing-creator/references/examples.md +324 -0
- x_ipe/resources/skills/tool-tracing-instrumentation/SKILL.md +373 -0
- x_ipe/resources/skills/tool-tracing-instrumentation/references/examples.md +264 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/SKILL.md +486 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/10. example-gate-conditions.md +73 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/11. reference-quality-standards.md +127 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/2. reference-section-order.md +127 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/3. example-step-based-code-review.md +84 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/4. example-step-based-feature-implementation.md +113 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/5. example-function-based-validation.md +73 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/6. example-function-based-analysis.md +94 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/7. example-task-io-code-implementation.md +36 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/8. example-structured-summary.md +43 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/9. example-dor-dod.md +77 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/examples.md +429 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/references/skill-general-guidelines-v2.md +611 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-meta.md +153 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-based.md +324 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-category.md +109 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-tool.md +205 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-meta.md +334 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-task-based.md +279 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-tool.md +175 -0
- x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-workflow-orchestration.md +329 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/SKILL.md +487 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/examples.md +377 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/folder-naming-guide.md +74 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/tool-usage-guide.md +145 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/references/visualization-guide.md +160 -0
- x_ipe/resources/skills/x-ipe-task-based-ideation/templates/idea-summary.md +86 -0
- x_ipe/routes/__init__.py +2 -0
- x_ipe/routes/ideas_routes.py +289 -0
- x_ipe/routes/kb_routes.py +80 -0
- x_ipe/routes/main_routes.py +18 -0
- x_ipe/routes/project_routes.py +7 -0
- x_ipe/routes/proxy_routes.py +10 -2
- x_ipe/routes/quality_evaluation_routes.py +193 -0
- x_ipe/routes/settings_routes.py +6 -0
- x_ipe/routes/tools_routes.py +6 -0
- x_ipe/routes/tracing_routes.py +232 -0
- x_ipe/routes/uiux_feedback_routes.py +50 -0
- x_ipe/services/__init__.py +5 -0
- x_ipe/services/config_service.py +6 -0
- x_ipe/services/file_service.py +20 -0
- x_ipe/services/homepage_service.py +160 -0
- x_ipe/services/ideas_service.py +535 -2
- x_ipe/services/kb_service.py +378 -0
- x_ipe/services/proxy_service.py +37 -7
- x_ipe/services/settings_service.py +13 -0
- x_ipe/services/skills_service.py +4 -0
- x_ipe/services/terminal_service.py +24 -0
- x_ipe/services/themes_service.py +4 -0
- x_ipe/services/tools_config_service.py +4 -0
- x_ipe/services/tracing_service.py +333 -0
- x_ipe/services/uiux_feedback_service.py +148 -1
- x_ipe/services/voice_input_service_v2.py +11 -0
- x_ipe/static/css/base.css +7 -0
- x_ipe/static/css/homepage-infinity.css +330 -0
- x_ipe/static/css/kb-core.css +301 -0
- x_ipe/static/css/quality-evaluation.css +345 -0
- x_ipe/static/css/sidebar.css +14 -4
- x_ipe/static/css/terminal.css +23 -0
- x_ipe/static/css/tracing-dashboard.css +796 -0
- x_ipe/static/css/uiux-feedback.css +7 -1
- x_ipe/static/css/workplace.css +636 -0
- x_ipe/static/img/homepage-infinity-loop.png +0 -0
- x_ipe/static/js/features/confirm-dialog.js +169 -0
- x_ipe/static/js/features/folder-view.js +742 -0
- x_ipe/static/js/features/homepage-infinity.js +314 -0
- x_ipe/static/js/features/kb-core.js +371 -0
- x_ipe/static/js/features/quality-evaluation.js +387 -0
- x_ipe/static/js/features/sidebar.js +255 -12
- x_ipe/static/js/features/tracing-dashboard.js +855 -0
- x_ipe/static/js/features/tracing-graph.js +1031 -0
- x_ipe/static/js/features/tree-drag.js +227 -0
- x_ipe/static/js/features/tree-search.js +228 -0
- x_ipe/static/js/features/workplace.js +661 -33
- x_ipe/static/js/init.js +76 -0
- x_ipe/static/js/terminal-v2.js +45 -14
- x_ipe/static/js/terminal.js +50 -49
- x_ipe/static/js/uiux-feedback.js +75 -16
- x_ipe/templates/base.html +24 -0
- x_ipe/templates/index.html +10 -1
- x_ipe/templates/knowledge-base.html +110 -0
- x_ipe/templates/workplace.html +4 -0
- x_ipe/tracing/__init__.py +37 -0
- x_ipe/tracing/buffer.py +135 -0
- x_ipe/tracing/context.py +125 -0
- x_ipe/tracing/decorator.py +288 -0
- x_ipe/tracing/middleware.py +197 -0
- x_ipe/tracing/parser.py +235 -0
- x_ipe/tracing/redactor.py +111 -0
- x_ipe/tracing/writer.py +122 -0
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/METADATA +2 -2
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/RECORD +138 -65
- x_ipe/app.py.bak +0 -1333
- x_ipe/resources/skills/x-ipe-skill-creator/SKILL.md +0 -329
- x_ipe/resources/skills/x-ipe-skill-creator/references/output-patterns.md +0 -169
- x_ipe/resources/skills/x-ipe-skill-creator/references/skill-structure.md +0 -162
- x_ipe/resources/skills/x-ipe-skill-creator/references/workflows.md +0 -110
- x_ipe/resources/skills/x-ipe-skill-creator/templates/references/examples.md +0 -113
- x_ipe/resources/skills/x-ipe-skill-creator/templates/skill-category-skill.md +0 -296
- x_ipe/resources/skills/x-ipe-skill-creator/templates/task-type-skill.md +0 -269
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/WHEEL +0 -0
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/entry_points.txt +0 -0
- {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/licenses/LICENSE +0 -0
x_ipe/routes/main_routes.py
CHANGED
|
@@ -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
|
x_ipe/routes/project_routes.py
CHANGED
|
@@ -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
|
x_ipe/routes/proxy_routes.py
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
+
})
|
x_ipe/routes/settings_routes.py
CHANGED
|
@@ -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
|
x_ipe/routes/tools_routes.py
CHANGED
|
@@ -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})
|