x-ipe 1.0.17__py3-none-any.whl → 1.0.19__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/cli/main.py +39 -0
- x_ipe/core/scaffold.py +143 -0
- x_ipe/resources/planning/features.md +53 -0
- x_ipe/resources/planning/task-board.md +77 -0
- x_ipe/resources/themes/theme-default/component-visualization.html +738 -0
- x_ipe/resources/themes/theme-default/design-system.md +302 -0
- x_ipe/static/3rdparty/html2canvas.min.js +20 -0
- x_ipe/static/css/uiux-feedback.css +35 -0
- x_ipe/static/js/features/workplace.js +43 -0
- x_ipe/static/js/terminal-v2.js +27 -8
- x_ipe/static/js/terminal.js +2 -2
- x_ipe/static/js/uiux-feedback.js +276 -21
- x_ipe/templates/base.html +1 -1
- {x_ipe-1.0.17.dist-info → x_ipe-1.0.19.dist-info}/METADATA +2 -1
- {x_ipe-1.0.17.dist-info → x_ipe-1.0.19.dist-info}/RECORD +18 -13
- {x_ipe-1.0.17.dist-info → x_ipe-1.0.19.dist-info}/WHEEL +0 -0
- {x_ipe-1.0.17.dist-info → x_ipe-1.0.19.dist-info}/entry_points.txt +0 -0
- {x_ipe-1.0.17.dist-info → x_ipe-1.0.19.dist-info}/licenses/LICENSE +0 -0
x_ipe/cli/main.py
CHANGED
|
@@ -211,6 +211,12 @@ def init(ctx: click.Context, force: bool, dry_run: bool, no_skills: bool) -> Non
|
|
|
211
211
|
# Copy config files (copilot-prompt.json, tools.json, .env.example)
|
|
212
212
|
scaffold.copy_config_files()
|
|
213
213
|
|
|
214
|
+
# Copy planning templates (features.md, task-board.md)
|
|
215
|
+
scaffold.copy_planning_templates()
|
|
216
|
+
|
|
217
|
+
# Copy default theme
|
|
218
|
+
scaffold.copy_themes()
|
|
219
|
+
|
|
214
220
|
# Create config file
|
|
215
221
|
scaffold.create_config_file()
|
|
216
222
|
|
|
@@ -218,6 +224,39 @@ def init(ctx: click.Context, force: bool, dry_run: bool, no_skills: bool) -> Non
|
|
|
218
224
|
if (project_root / ".git").exists():
|
|
219
225
|
scaffold.update_gitignore()
|
|
220
226
|
|
|
227
|
+
# MCP config merge with user confirmation
|
|
228
|
+
mcp_servers = scaffold.get_project_mcp_servers()
|
|
229
|
+
if mcp_servers and not dry_run:
|
|
230
|
+
click.echo("\n" + "-" * 40)
|
|
231
|
+
click.echo("MCP Server Configuration")
|
|
232
|
+
click.echo("-" * 40)
|
|
233
|
+
|
|
234
|
+
# Show available servers
|
|
235
|
+
click.echo(f"\nFound {len(mcp_servers)} MCP server(s) in project config:")
|
|
236
|
+
for name in mcp_servers:
|
|
237
|
+
click.echo(f" • {name}")
|
|
238
|
+
|
|
239
|
+
# Confirm each server
|
|
240
|
+
servers_to_merge = []
|
|
241
|
+
for name in mcp_servers:
|
|
242
|
+
if click.confirm(f"\nAdd '{name}' to global MCP config?", default=True):
|
|
243
|
+
servers_to_merge.append(name)
|
|
244
|
+
|
|
245
|
+
if servers_to_merge:
|
|
246
|
+
# Confirm target path
|
|
247
|
+
default_path = Path.home() / ".copilot" / "mcp-config.json"
|
|
248
|
+
target_path = click.prompt(
|
|
249
|
+
"\nTarget MCP config path",
|
|
250
|
+
default=str(default_path),
|
|
251
|
+
type=click.Path(dir_okay=False, path_type=Path)
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
scaffold.merge_mcp_config(
|
|
255
|
+
servers_to_merge=servers_to_merge,
|
|
256
|
+
target_path=target_path
|
|
257
|
+
)
|
|
258
|
+
click.echo(f"\n✓ Merged {len(servers_to_merge)} MCP server(s) to {target_path}")
|
|
259
|
+
|
|
221
260
|
# Show summary
|
|
222
261
|
created, skipped = scaffold.get_summary()
|
|
223
262
|
|
x_ipe/core/scaffold.py
CHANGED
|
@@ -3,6 +3,7 @@ from pathlib import Path
|
|
|
3
3
|
from typing import List, Tuple, Optional
|
|
4
4
|
import shutil
|
|
5
5
|
import os
|
|
6
|
+
import json
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class ScaffoldManager:
|
|
@@ -14,6 +15,7 @@ class ScaffoldManager:
|
|
|
14
15
|
"x-ipe-docs/features",
|
|
15
16
|
"x-ipe-docs/ideas",
|
|
16
17
|
"x-ipe-docs/config",
|
|
18
|
+
"x-ipe-docs/themes",
|
|
17
19
|
]
|
|
18
20
|
|
|
19
21
|
GITIGNORE_ENTRIES = [
|
|
@@ -143,6 +145,90 @@ class ScaffoldManager:
|
|
|
143
145
|
shutil.copy2(source, target)
|
|
144
146
|
self.created.append(target)
|
|
145
147
|
|
|
148
|
+
def get_project_mcp_servers(self) -> dict:
|
|
149
|
+
"""Get MCP servers from project's .github/copilot/mcp-config.json.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dict of server_name -> server_config, or empty dict if not found.
|
|
153
|
+
"""
|
|
154
|
+
project_mcp = self.project_root / ".github" / "copilot" / "mcp-config.json"
|
|
155
|
+
if not project_mcp.exists():
|
|
156
|
+
return {}
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
project_config = json.loads(project_mcp.read_text())
|
|
160
|
+
return project_config.get("mcpServers", {})
|
|
161
|
+
except (json.JSONDecodeError, IOError):
|
|
162
|
+
return {}
|
|
163
|
+
|
|
164
|
+
def merge_mcp_config(
|
|
165
|
+
self,
|
|
166
|
+
servers_to_merge: Optional[List[str]] = None,
|
|
167
|
+
target_path: Optional[Path] = None
|
|
168
|
+
) -> None:
|
|
169
|
+
"""Merge project's MCP servers into global config.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
servers_to_merge: List of server names to merge. If None, merges all.
|
|
173
|
+
target_path: Path to target mcp-config.json. Defaults to ~/.copilot/mcp-config.json.
|
|
174
|
+
|
|
175
|
+
This allows project-specific MCP servers to be available globally.
|
|
176
|
+
Deep-merges mcpServers objects, with project servers added to global config.
|
|
177
|
+
Existing global servers are preserved unless --force is used for conflicts.
|
|
178
|
+
"""
|
|
179
|
+
project_servers = self.get_project_mcp_servers()
|
|
180
|
+
if not project_servers:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# Filter to requested servers if specified
|
|
184
|
+
if servers_to_merge is not None:
|
|
185
|
+
project_servers = {k: v for k, v in project_servers.items() if k in servers_to_merge}
|
|
186
|
+
if not project_servers:
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
# Target: configurable or default to ~/.copilot/mcp-config.json
|
|
190
|
+
if target_path is None:
|
|
191
|
+
global_copilot_dir = Path.home() / ".copilot"
|
|
192
|
+
global_mcp = global_copilot_dir / "mcp-config.json"
|
|
193
|
+
else:
|
|
194
|
+
global_mcp = Path(target_path)
|
|
195
|
+
global_copilot_dir = global_mcp.parent
|
|
196
|
+
|
|
197
|
+
if self.dry_run:
|
|
198
|
+
self.created.append(global_mcp)
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
# Load or create global config
|
|
202
|
+
global_config = {"mcpServers": {}}
|
|
203
|
+
if global_mcp.exists():
|
|
204
|
+
try:
|
|
205
|
+
global_config = json.loads(global_mcp.read_text())
|
|
206
|
+
if "mcpServers" not in global_config:
|
|
207
|
+
global_config["mcpServers"] = {}
|
|
208
|
+
except (json.JSONDecodeError, IOError):
|
|
209
|
+
global_config = {"mcpServers": {}}
|
|
210
|
+
|
|
211
|
+
# Merge: add project servers to global
|
|
212
|
+
merged_count = 0
|
|
213
|
+
skipped_count = 0
|
|
214
|
+
for server_name, server_config in project_servers.items():
|
|
215
|
+
if server_name in global_config["mcpServers"]:
|
|
216
|
+
if self.force:
|
|
217
|
+
global_config["mcpServers"][server_name] = server_config
|
|
218
|
+
merged_count += 1
|
|
219
|
+
else:
|
|
220
|
+
skipped_count += 1
|
|
221
|
+
else:
|
|
222
|
+
global_config["mcpServers"][server_name] = server_config
|
|
223
|
+
merged_count += 1
|
|
224
|
+
|
|
225
|
+
if merged_count > 0:
|
|
226
|
+
global_copilot_dir.mkdir(parents=True, exist_ok=True)
|
|
227
|
+
global_mcp.write_text(json.dumps(global_config, indent=2) + "\n")
|
|
228
|
+
self.created.append(global_mcp)
|
|
229
|
+
elif skipped_count > 0:
|
|
230
|
+
self.skipped.append(global_mcp)
|
|
231
|
+
|
|
146
232
|
def copy_config_files(self) -> None:
|
|
147
233
|
"""Copy config files (copilot-prompt.json, tools.json, .env.example) to x-ipe-docs/config/."""
|
|
148
234
|
config_source = self._get_resource_path("config")
|
|
@@ -170,6 +256,60 @@ class ScaffoldManager:
|
|
|
170
256
|
shutil.copy2(source_file, target_file)
|
|
171
257
|
self.created.append(target_file)
|
|
172
258
|
|
|
259
|
+
def copy_planning_templates(self) -> None:
|
|
260
|
+
"""Copy planning templates (features.md, task-board.md) to x-ipe-docs/planning/."""
|
|
261
|
+
planning_source = self._get_resource_path("planning")
|
|
262
|
+
if planning_source is None or not planning_source.exists():
|
|
263
|
+
return
|
|
264
|
+
|
|
265
|
+
target_dir = self.project_root / "x-ipe-docs" / "planning"
|
|
266
|
+
|
|
267
|
+
# Copy each planning file individually (don't overwrite existing)
|
|
268
|
+
planning_files = ["features.md", "task-board.md"]
|
|
269
|
+
for filename in planning_files:
|
|
270
|
+
source_file = planning_source / filename
|
|
271
|
+
target_file = target_dir / filename
|
|
272
|
+
|
|
273
|
+
if not source_file.exists():
|
|
274
|
+
continue
|
|
275
|
+
|
|
276
|
+
if target_file.exists():
|
|
277
|
+
if not self.force:
|
|
278
|
+
self.skipped.append(target_file)
|
|
279
|
+
continue
|
|
280
|
+
|
|
281
|
+
if not self.dry_run:
|
|
282
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
283
|
+
shutil.copy2(source_file, target_file)
|
|
284
|
+
self.created.append(target_file)
|
|
285
|
+
|
|
286
|
+
def copy_themes(self) -> None:
|
|
287
|
+
"""Copy default theme to x-ipe-docs/themes/."""
|
|
288
|
+
themes_source = self._get_resource_path("themes")
|
|
289
|
+
if themes_source is None or not themes_source.exists():
|
|
290
|
+
return
|
|
291
|
+
|
|
292
|
+
target_dir = self.project_root / "x-ipe-docs" / "themes"
|
|
293
|
+
|
|
294
|
+
# Copy entire theme-default folder
|
|
295
|
+
theme_source = themes_source / "theme-default"
|
|
296
|
+
theme_target = target_dir / "theme-default"
|
|
297
|
+
|
|
298
|
+
if not theme_source.exists():
|
|
299
|
+
return
|
|
300
|
+
|
|
301
|
+
if theme_target.exists():
|
|
302
|
+
if not self.force:
|
|
303
|
+
self.skipped.append(theme_target)
|
|
304
|
+
return
|
|
305
|
+
|
|
306
|
+
if not self.dry_run:
|
|
307
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
308
|
+
if theme_target.exists() and self.force:
|
|
309
|
+
shutil.rmtree(theme_target)
|
|
310
|
+
shutil.copytree(theme_source, theme_target, dirs_exist_ok=True)
|
|
311
|
+
self.created.append(theme_target)
|
|
312
|
+
|
|
173
313
|
def create_config_file(self, config_content: Optional[str] = None) -> None:
|
|
174
314
|
"""Create .x-ipe.yaml with defaults.
|
|
175
315
|
|
|
@@ -243,8 +383,11 @@ server:
|
|
|
243
383
|
self.copy_skills()
|
|
244
384
|
self.copy_copilot_instructions()
|
|
245
385
|
self.copy_config_files()
|
|
386
|
+
self.copy_planning_templates()
|
|
387
|
+
self.copy_themes()
|
|
246
388
|
self.create_config_file()
|
|
247
389
|
self.update_gitignore()
|
|
390
|
+
self.merge_mcp_config()
|
|
248
391
|
return self.get_summary()
|
|
249
392
|
|
|
250
393
|
def get_summary(self) -> Tuple[List[Path], List[Path]]:
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Feature Board
|
|
2
|
+
|
|
3
|
+
> Last Updated: {DATE}
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This board tracks all features across the project lifecycle.
|
|
8
|
+
|
|
9
|
+
**Status Definitions:**
|
|
10
|
+
- **Planned** - Feature identified, awaiting refinement
|
|
11
|
+
- **Refined** - Specification complete, ready for design
|
|
12
|
+
- **Designed** - Technical design complete, ready for implementation
|
|
13
|
+
- **Implemented** - Code complete, ready for testing
|
|
14
|
+
- **Tested** - Tests complete, ready for deployment
|
|
15
|
+
- **Completed** - Feature fully deployed and verified
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Feature Tracking
|
|
20
|
+
|
|
21
|
+
| Feature ID | Feature Title | Version | Status | Specification Link | Created | Last Updated |
|
|
22
|
+
|------------|---------------|---------|--------|-------------------|---------|--------------|
|
|
23
|
+
| _No features yet_ | | | | | | |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Status Details
|
|
28
|
+
|
|
29
|
+
### Planned (0)
|
|
30
|
+
- None
|
|
31
|
+
|
|
32
|
+
### Refined (0)
|
|
33
|
+
- None
|
|
34
|
+
|
|
35
|
+
### Designed (0)
|
|
36
|
+
- None
|
|
37
|
+
|
|
38
|
+
### Implemented (0)
|
|
39
|
+
- None
|
|
40
|
+
|
|
41
|
+
### Tested (0)
|
|
42
|
+
- None
|
|
43
|
+
|
|
44
|
+
### Completed (0)
|
|
45
|
+
- None
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Feature Details
|
|
50
|
+
|
|
51
|
+
_Features will appear here after creation_
|
|
52
|
+
|
|
53
|
+
---
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Task Board
|
|
2
|
+
|
|
3
|
+
> Task Board Management - Task Tracking
|
|
4
|
+
|
|
5
|
+
## Global Settings
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
auto_proceed: false # Set to true for automatic task chaining
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Active Tasks
|
|
14
|
+
|
|
15
|
+
| Task ID | Task Type | Description | Role | Status | Last Updated | Output Links | Next Task |
|
|
16
|
+
|---------|-----------|-------------|------|--------|--------------|--------------|----------|
|
|
17
|
+
| | | | | | | | |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Completed Tasks
|
|
22
|
+
|
|
23
|
+
| Task ID | Task Type | Description | Role | Last Updated | Output Links | Notes |
|
|
24
|
+
|---------|-----------|-------------|------|--------------|--------------|-------|
|
|
25
|
+
| | | | | | | |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Cancelled Tasks
|
|
30
|
+
|
|
31
|
+
| Task ID | Task Type | Description | Reason | Last Updated | Output Links |
|
|
32
|
+
|---------|-----------|-------------|--------|--------------|--------------|
|
|
33
|
+
| | | | | | |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Status Legend
|
|
38
|
+
|
|
39
|
+
| Status | Symbol | Description |
|
|
40
|
+
|--------|--------|-------------|
|
|
41
|
+
| pending | ⏳ | Waiting to start |
|
|
42
|
+
| in_progress | 🔄 | Working |
|
|
43
|
+
| blocked | 🚫 | Waiting for dependency |
|
|
44
|
+
| deferred | ⏸️ | Paused by human |
|
|
45
|
+
| completed | ✅ | Done |
|
|
46
|
+
| cancelled | ❌ | Stopped |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Task Type Quick Reference
|
|
51
|
+
|
|
52
|
+
| Task Type | Skill | Default Next |
|
|
53
|
+
|-----------|-------|--------------|
|
|
54
|
+
| Requirement Gathering | task-type-requirement-gathering | Feature Breakdown |
|
|
55
|
+
| Feature Breakdown | task-type-feature-breakdown | Technical Design |
|
|
56
|
+
| Technical Design | task-type-technical-design | Test Generation |
|
|
57
|
+
| Test Generation | task-type-test-generation | Code Implementation |
|
|
58
|
+
| Code Implementation | task-type-code-implementation | Human Playground |
|
|
59
|
+
| Human Playground | task-type-human-playground | Feature Closing |
|
|
60
|
+
| Feature Closing | task-type-feature-closing | - |
|
|
61
|
+
| Code Refactor | task-type-code-refactor | - |
|
|
62
|
+
| Project Initialization | task-type-project-init | Dev Environment Setup |
|
|
63
|
+
| Dev Environment Setup | task-type-dev-environment | - |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Quick Stats
|
|
68
|
+
|
|
69
|
+
- **Total Active:** 0
|
|
70
|
+
- **In Progress:** 0
|
|
71
|
+
- **Pending:** 0
|
|
72
|
+
- **Pending Review:** 0
|
|
73
|
+
- **Blocked:** 0
|
|
74
|
+
- **Deferred:** 0
|
|
75
|
+
- **Completed:** 0
|
|
76
|
+
|
|
77
|
+
---
|