@fishawack/lab-env 4.45.0-beta.2 → 4.45.0-beta.3
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.
- package/CHANGELOG.md +15 -0
- package/_Ai/lab-env-@.md +402 -0
- package/_Ai/mcp-@.md +15 -0
- package/_Ai/sass-@.md +350 -0
- package/_Ai/ui-framework-3.md +422 -0
- package/_Ai/workspace-@.md +11 -0
- package/cli.js +9 -1
- package/commands/workspace.js +124 -0
- package/globals.js +14 -8
- package/package.json +1 -1
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.vue"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Element Plus UI Framework Integration Instructions for GitHub Copilot
|
|
6
|
+
|
|
7
|
+
## Project Overview
|
|
8
|
+
|
|
9
|
+
Element Plus serves as the primary UI component framework, integrated with Vue.js 3 through a structured plugin system. Element Plus provides robust form components, navigation elements, and interactive UI components that are globally registered and customized through SASS overrides. The integration follows a clear separation between JavaScript component registration and SASS styling, maintaining optimal build performance and consistent theming.
|
|
10
|
+
|
|
11
|
+
Element Plus components are selectively imported and registered globally, with custom styling applied through dedicated SASS override files that layer on top of the built-in Element Plus theme-chalk styles.
|
|
12
|
+
|
|
13
|
+
## Integration Architecture
|
|
14
|
+
|
|
15
|
+
### Project Structure Variations
|
|
16
|
+
|
|
17
|
+
**Important**: Build file locations vary by project configuration. Common patterns include:
|
|
18
|
+
|
|
19
|
+
- `resources/` directory
|
|
20
|
+
- `_Build/` directory (most common)
|
|
21
|
+
- Custom directory structures as defined in project setup
|
|
22
|
+
|
|
23
|
+
Always check your project's specific directory structure. File paths in these examples use `[build-dir]` placeholder but should be adapted to your project's build directory.
|
|
24
|
+
|
|
25
|
+
### JavaScript Registration (`[build-dir]/js/libs/elements.js`)
|
|
26
|
+
|
|
27
|
+
Element Plus components are registered through a dedicated Vue plugin:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import {
|
|
31
|
+
ElCheckbox,
|
|
32
|
+
ElSelect,
|
|
33
|
+
ElOption,
|
|
34
|
+
ElInfiniteScroll,
|
|
35
|
+
ElPopover,
|
|
36
|
+
ElMenu,
|
|
37
|
+
ElSubMenu,
|
|
38
|
+
ElMenuItem,
|
|
39
|
+
} from "element-plus";
|
|
40
|
+
|
|
41
|
+
export default {
|
|
42
|
+
install(Vue) {
|
|
43
|
+
Vue.component(ElCheckbox.name, ElCheckbox);
|
|
44
|
+
Vue.component(ElSelect.name, ElSelect);
|
|
45
|
+
Vue.component(ElOption.name, ElOption);
|
|
46
|
+
Vue.component(ElPopover.name, ElPopover);
|
|
47
|
+
Vue.component(ElMenu.name, ElMenu);
|
|
48
|
+
Vue.component(ElSubMenu.name, ElSubMenu);
|
|
49
|
+
Vue.component(ElMenuItem.name, ElMenuItem);
|
|
50
|
+
|
|
51
|
+
Vue.use(ElInfiniteScroll);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Plugin Integration (`[build-dir]/js/script.js`)
|
|
57
|
+
|
|
58
|
+
The Element Plus plugin is registered in the main Vue application:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
import elements from "./libs/elements";
|
|
62
|
+
|
|
63
|
+
const vue = createApp({
|
|
64
|
+
// App configuration
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
vue.use(elements);
|
|
68
|
+
vue.mount("#app");
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### SASS Integration (`[build-dir]/sass/vendor.scss`)
|
|
72
|
+
|
|
73
|
+
Element Plus styles are imported selectively in the vendor SASS file:
|
|
74
|
+
|
|
75
|
+
```scss
|
|
76
|
+
/* purgecss start ignore */
|
|
77
|
+
@import "element-plus/theme-chalk/base";
|
|
78
|
+
|
|
79
|
+
@import "element-plus/theme-chalk/el-input";
|
|
80
|
+
@import "element-plus/theme-chalk/el-tag";
|
|
81
|
+
@import "element-plus/theme-chalk/el-checkbox";
|
|
82
|
+
@import "element-plus/theme-chalk/el-scrollbar";
|
|
83
|
+
@import "element-plus/theme-chalk/el-select";
|
|
84
|
+
@import "element-plus/theme-chalk/el-option";
|
|
85
|
+
@import "element-plus/theme-chalk/el-option-group";
|
|
86
|
+
@import "element-plus/theme-chalk/el-popover";
|
|
87
|
+
@import "element-plus/theme-chalk/el-popper";
|
|
88
|
+
@import "element-plus/theme-chalk/el-dropdown";
|
|
89
|
+
@import "element-plus/theme-chalk/el-menu";
|
|
90
|
+
/* purgecss end ignore */
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Component Selection and Documentation
|
|
94
|
+
|
|
95
|
+
### Element Plus Documentation
|
|
96
|
+
|
|
97
|
+
Reference the official Element Plus documentation for component options and slots:
|
|
98
|
+
|
|
99
|
+
- **Documentation**: https://element-plus.org/en-US/component/overview.html
|
|
100
|
+
- **Version**: Always assume latest version
|
|
101
|
+
- **Evaluation Process**: Browse the component library and select components based on project needs
|
|
102
|
+
|
|
103
|
+
### Common Components by Category
|
|
104
|
+
|
|
105
|
+
#### Form Components (Most Frequently Used):
|
|
106
|
+
|
|
107
|
+
- `ElCheckbox` - Checkbox inputs with group support
|
|
108
|
+
- `ElSelect` / `ElOption` - Dropdown select components
|
|
109
|
+
- `ElInput` - Text input fields
|
|
110
|
+
- `ElTag` - Tag/chip components for selections
|
|
111
|
+
|
|
112
|
+
#### Navigation Components:
|
|
113
|
+
|
|
114
|
+
- `ElMenu` / `ElSubMenu` / `ElMenuItem` - Navigation menu systems
|
|
115
|
+
- `ElDropdown` - Dropdown menu actions
|
|
116
|
+
|
|
117
|
+
#### Overlay Components:
|
|
118
|
+
|
|
119
|
+
- `ElPopover` - Tooltip and popover overlays
|
|
120
|
+
- `ElPopper` - Positioning engine for overlays
|
|
121
|
+
|
|
122
|
+
#### Utility Components:
|
|
123
|
+
|
|
124
|
+
- `ElScrollbar` - Custom scrollbar styling
|
|
125
|
+
- `ElInfiniteScroll` - Infinite scroll directive
|
|
126
|
+
|
|
127
|
+
## Adding New Element Plus Components
|
|
128
|
+
|
|
129
|
+
### Step 1: JavaScript Registration
|
|
130
|
+
|
|
131
|
+
Add the component import and registration to `[build-dir]/js/libs/elements.js`:
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
import {
|
|
135
|
+
// Existing imports
|
|
136
|
+
ElButton, // New component
|
|
137
|
+
} from "element-plus";
|
|
138
|
+
|
|
139
|
+
export default {
|
|
140
|
+
install(Vue) {
|
|
141
|
+
// Existing registrations
|
|
142
|
+
Vue.component(ElButton.name, ElButton); // New registration
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Step 2: SASS Import
|
|
148
|
+
|
|
149
|
+
Add the corresponding SASS import to `[build-dir]/sass/vendor.scss`:
|
|
150
|
+
|
|
151
|
+
```scss
|
|
152
|
+
/* purgecss start ignore */
|
|
153
|
+
@import "element-plus/theme-chalk/base";
|
|
154
|
+
|
|
155
|
+
// Existing imports
|
|
156
|
+
@import "element-plus/theme-chalk/el-button"; // New import
|
|
157
|
+
|
|
158
|
+
/* purgecss end ignore */
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Step 3: Custom Styling (Optional)
|
|
162
|
+
|
|
163
|
+
For component-specific styling overrides, add styles to `[build-dir]/sass/components/_element.scss` or create individual override files for larger projects:
|
|
164
|
+
|
|
165
|
+
**Single File Approach:**
|
|
166
|
+
|
|
167
|
+
```scss
|
|
168
|
+
// [build-dir]/sass/components/_element.scss
|
|
169
|
+
.el-button {
|
|
170
|
+
border-radius: 4px;
|
|
171
|
+
font-weight: $fontWeightMedium;
|
|
172
|
+
|
|
173
|
+
&--primary {
|
|
174
|
+
background-color: $color1;
|
|
175
|
+
border-color: $color1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Individual File Approach (Larger Projects):**
|
|
181
|
+
|
|
182
|
+
```scss
|
|
183
|
+
// [build-dir]/sass/components/_el-button.scss
|
|
184
|
+
.el-button {
|
|
185
|
+
border-radius: 4px;
|
|
186
|
+
font-weight: $fontWeightMedium;
|
|
187
|
+
|
|
188
|
+
&--primary {
|
|
189
|
+
background-color: $color1;
|
|
190
|
+
border-color: $color1;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
&--secondary {
|
|
194
|
+
background-color: transparent;
|
|
195
|
+
border-color: $color2;
|
|
196
|
+
color: $color2;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Then import in `[build-dir]/sass/general.scss`:
|
|
202
|
+
|
|
203
|
+
```scss
|
|
204
|
+
@import "./components/_el-button.scss";
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Vue Template Usage
|
|
208
|
+
|
|
209
|
+
### Basic Component Usage
|
|
210
|
+
|
|
211
|
+
Once registered globally, Element Plus components are available in all Vue templates:
|
|
212
|
+
|
|
213
|
+
```vue
|
|
214
|
+
<template>
|
|
215
|
+
<div class="form-container">
|
|
216
|
+
<!-- Select dropdown -->
|
|
217
|
+
<el-select
|
|
218
|
+
v-model="selectedValue"
|
|
219
|
+
placeholder="Select an option"
|
|
220
|
+
class="form__select"
|
|
221
|
+
>
|
|
222
|
+
<el-option
|
|
223
|
+
v-for="item in options"
|
|
224
|
+
:key="item.value"
|
|
225
|
+
:label="item.label"
|
|
226
|
+
:value="item.value"
|
|
227
|
+
/>
|
|
228
|
+
</el-select>
|
|
229
|
+
|
|
230
|
+
<!-- Checkbox -->
|
|
231
|
+
<el-checkbox v-model="isChecked" class="form__checkbox">
|
|
232
|
+
Enable notifications
|
|
233
|
+
</el-checkbox>
|
|
234
|
+
|
|
235
|
+
<!-- Menu navigation -->
|
|
236
|
+
<el-menu mode="horizontal" class="navigation">
|
|
237
|
+
<el-menu-item index="1">Dashboard</el-menu-item>
|
|
238
|
+
<el-sub-menu index="2">
|
|
239
|
+
<template #title>Reports</template>
|
|
240
|
+
<el-menu-item index="2-1">Analytics</el-menu-item>
|
|
241
|
+
<el-menu-item index="2-2">Performance</el-menu-item>
|
|
242
|
+
</el-sub-menu>
|
|
243
|
+
</el-menu>
|
|
244
|
+
|
|
245
|
+
<!-- Popover tooltip -->
|
|
246
|
+
<el-popover
|
|
247
|
+
placement="top"
|
|
248
|
+
title="Help Information"
|
|
249
|
+
:width="200"
|
|
250
|
+
trigger="hover"
|
|
251
|
+
content="This provides additional context about the feature."
|
|
252
|
+
>
|
|
253
|
+
<template #reference>
|
|
254
|
+
<el-button>Hover for info</el-button>
|
|
255
|
+
</template>
|
|
256
|
+
</el-popover>
|
|
257
|
+
</div>
|
|
258
|
+
</template>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Custom Class Integration
|
|
262
|
+
|
|
263
|
+
Combine Element Plus components with project BEM classes and lab-ui utilities:
|
|
264
|
+
|
|
265
|
+
```vue
|
|
266
|
+
<template>
|
|
267
|
+
<div class="user-form user-form--compact">
|
|
268
|
+
<div class="user-form__field">
|
|
269
|
+
<el-select
|
|
270
|
+
v-model="user.role"
|
|
271
|
+
class="user-form__select form__group--seamless"
|
|
272
|
+
placeholder="Select role"
|
|
273
|
+
>
|
|
274
|
+
<el-option label="Admin" value="admin" />
|
|
275
|
+
<el-option label="User" value="user" />
|
|
276
|
+
</el-select>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<div class="user-form__actions flex justify-end mt-2">
|
|
280
|
+
<el-button
|
|
281
|
+
type="primary"
|
|
282
|
+
class="user-form__submit"
|
|
283
|
+
@click="handleSubmit"
|
|
284
|
+
>
|
|
285
|
+
Save User
|
|
286
|
+
</el-button>
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
</template>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Styling Integration
|
|
293
|
+
|
|
294
|
+
### Theme Integration
|
|
295
|
+
|
|
296
|
+
Element Plus uses CSS variables for theming, but the typical approach is to layer custom SASS variables and overrides:
|
|
297
|
+
|
|
298
|
+
```scss
|
|
299
|
+
// Override Element Plus component styles
|
|
300
|
+
.el-input__inner {
|
|
301
|
+
border: none !important;
|
|
302
|
+
box-shadow: none !important;
|
|
303
|
+
min-height: 48px;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.el-select {
|
|
307
|
+
.el-input__inner {
|
|
308
|
+
padding: $spacing * 0.5;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Custom form variants using project variables
|
|
313
|
+
.form__group--seamless {
|
|
314
|
+
.el-input__wrapper {
|
|
315
|
+
--el-select-input-focus-border-color: none;
|
|
316
|
+
--el-border-color: none;
|
|
317
|
+
--el-input-border-color: none;
|
|
318
|
+
--el-input-hover-border-color: none;
|
|
319
|
+
--el-select-border-color-hover: none;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.el-input__inner {
|
|
323
|
+
padding: 0;
|
|
324
|
+
height: auto !important;
|
|
325
|
+
min-height: auto !important;
|
|
326
|
+
line-height: 1;
|
|
327
|
+
min-width: auto !important;
|
|
328
|
+
width: 95px !important;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Color System Integration
|
|
334
|
+
|
|
335
|
+
Use project color variables to maintain consistency with lab-ui:
|
|
336
|
+
|
|
337
|
+
```scss
|
|
338
|
+
.el-button--primary {
|
|
339
|
+
background-color: $color1;
|
|
340
|
+
border-color: $color1;
|
|
341
|
+
|
|
342
|
+
&:hover {
|
|
343
|
+
background-color: $color2;
|
|
344
|
+
border-color: $color2;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.el-popover__title {
|
|
349
|
+
margin-bottom: $spacing * 0.5;
|
|
350
|
+
color: $color8;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.el-popover.el-popper {
|
|
354
|
+
color: $fontColor;
|
|
355
|
+
padding: $spacing;
|
|
356
|
+
word-break: break-word;
|
|
357
|
+
text-align: left;
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Development Workflow
|
|
362
|
+
|
|
363
|
+
### Adding New Components
|
|
364
|
+
|
|
365
|
+
1. **Research Component**: Visit https://element-plus.org/en-US/component/overview.html
|
|
366
|
+
2. **Evaluate Options**: Review props, slots, and events available
|
|
367
|
+
3. **Register JavaScript**: Add import and registration to `elements.js`
|
|
368
|
+
4. **Import SASS**: Add theme-chalk import to `vendor.scss`
|
|
369
|
+
5. **Test Integration**: Verify component works in Vue templates
|
|
370
|
+
6. **Add Custom Styles**: Create overrides in `_element.scss` or individual files
|
|
371
|
+
7. **Document Usage**: Update component documentation if needed
|
|
372
|
+
|
|
373
|
+
### Performance Considerations
|
|
374
|
+
|
|
375
|
+
- **Selective Imports**: Only import components that are actually used
|
|
376
|
+
- **PurgeCSS Protection**: Element Plus styles are wrapped in `/* purgecss start ignore */`
|
|
377
|
+
- **Build Optimization**: Vendor SASS file is cached for faster rebuilds
|
|
378
|
+
- **Tree Shaking**: Unused Element Plus components are automatically excluded
|
|
379
|
+
|
|
380
|
+
### File Organization
|
|
381
|
+
|
|
382
|
+
**Small to Medium Projects:**
|
|
383
|
+
|
|
384
|
+
- Single override file: `[build-dir]/sass/components/_element.scss`
|
|
385
|
+
- All Element Plus customizations in one location
|
|
386
|
+
|
|
387
|
+
**Large Projects:**
|
|
388
|
+
|
|
389
|
+
- Individual override files: `[build-dir]/sass/components/_el-[component].scss`
|
|
390
|
+
- Better organization and maintainability
|
|
391
|
+
- Easier to track component-specific changes
|
|
392
|
+
|
|
393
|
+
## Best Practices
|
|
394
|
+
|
|
395
|
+
### Component Registration
|
|
396
|
+
|
|
397
|
+
- Always register components globally for consistency
|
|
398
|
+
- Use the component's default name (`ElButton.name`)
|
|
399
|
+
- Group related components together in imports
|
|
400
|
+
|
|
401
|
+
### Styling Approach
|
|
402
|
+
|
|
403
|
+
- Layer custom styles over Element Plus defaults
|
|
404
|
+
- Use project SASS variables for consistent theming
|
|
405
|
+
- Prefer CSS custom properties for dynamic theming
|
|
406
|
+
- Avoid `!important` unless necessary for specificity
|
|
407
|
+
|
|
408
|
+
### Vue Template Usage
|
|
409
|
+
|
|
410
|
+
- Combine Element Plus classes with project BEM classes
|
|
411
|
+
- Use semantic prop names and clear component structure
|
|
412
|
+
- Leverage slots for flexible content composition
|
|
413
|
+
- Test responsive behavior across breakpoints
|
|
414
|
+
|
|
415
|
+
### Maintenance
|
|
416
|
+
|
|
417
|
+
- Keep Element Plus version updated to latest
|
|
418
|
+
- Review breaking changes in Element Plus updates
|
|
419
|
+
- Test custom overrides after version updates
|
|
420
|
+
- Document any component-specific customizations
|
|
421
|
+
|
|
422
|
+
Remember: Element Plus provides the foundation UI components, while project-specific styling and behavior are layered on top through the structured SASS architecture and custom component classes.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# GitHub Copilot Instructions for this workspace
|
|
6
|
+
|
|
7
|
+
Backends are typically named with the pattern \*-api.
|
|
8
|
+
|
|
9
|
+
Frontends are typically named with the pattern \*-fe. or with no suffix.
|
|
10
|
+
|
|
11
|
+
Ensure you cd into the correct directory before running any terminal commands.
|
package/cli.js
CHANGED
|
@@ -36,7 +36,15 @@ const args = hideBin(process.argv);
|
|
|
36
36
|
// Platform command mapping
|
|
37
37
|
const platformCommands = {
|
|
38
38
|
// Base commands available to all platforms
|
|
39
|
-
base: [
|
|
39
|
+
base: [
|
|
40
|
+
"start",
|
|
41
|
+
"setup",
|
|
42
|
+
"connect",
|
|
43
|
+
"execute",
|
|
44
|
+
"nuke",
|
|
45
|
+
"lint",
|
|
46
|
+
"workspace",
|
|
47
|
+
],
|
|
40
48
|
|
|
41
49
|
// Web development commands (for frameworks that build frontend assets)
|
|
42
50
|
webDev: [
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const _ = require("../globals.js");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const glob = require("glob");
|
|
5
|
+
const { execSync } = require("child_process");
|
|
6
|
+
|
|
7
|
+
// Helper functions
|
|
8
|
+
const exitWithError = (message) => {
|
|
9
|
+
console.error(`Error: ${message}`);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const createSymlink = (sourcePath, targetPath) => {
|
|
14
|
+
if (fs.existsSync(targetPath)) fs.unlinkSync(targetPath);
|
|
15
|
+
fs.symlinkSync(
|
|
16
|
+
path.relative(path.dirname(targetPath), sourcePath),
|
|
17
|
+
targetPath,
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const generateWorkspaceName = (projects, customName) => {
|
|
22
|
+
if (customName) return `workspace-${customName}`;
|
|
23
|
+
|
|
24
|
+
const firstProject = projects[0];
|
|
25
|
+
const parts = firstProject.split("-");
|
|
26
|
+
const baseName =
|
|
27
|
+
parts.length >= 2 ? parts.slice(0, -1).join("-") : firstProject;
|
|
28
|
+
return `workspace-${baseName}`;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
module.exports = [
|
|
32
|
+
"workspace <projects..>",
|
|
33
|
+
"creates workspace directory with project symlinks and AI instruction files",
|
|
34
|
+
(yargs) => {
|
|
35
|
+
yargs
|
|
36
|
+
.positional("projects", {
|
|
37
|
+
describe: "project directory names to include in workspace",
|
|
38
|
+
type: "array",
|
|
39
|
+
demandOption: true,
|
|
40
|
+
})
|
|
41
|
+
.option("name", {
|
|
42
|
+
alias: "n",
|
|
43
|
+
describe:
|
|
44
|
+
"custom workspace name (will be prefixed with 'workspace-')",
|
|
45
|
+
type: "string",
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
(argv) => {
|
|
49
|
+
const { projects, name } = argv;
|
|
50
|
+
const cwd = process.cwd();
|
|
51
|
+
|
|
52
|
+
// Validation
|
|
53
|
+
if (!projects?.length)
|
|
54
|
+
exitWithError("At least one project name is required");
|
|
55
|
+
|
|
56
|
+
const missingProjects = projects.filter(
|
|
57
|
+
(project) => !fs.existsSync(path.join(cwd, project)),
|
|
58
|
+
);
|
|
59
|
+
if (missingProjects.length)
|
|
60
|
+
exitWithError(
|
|
61
|
+
`Project directories not found: ${missingProjects.join(", ")}`,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Setup workspace
|
|
65
|
+
const workspaceName = generateWorkspaceName(projects, name);
|
|
66
|
+
const workspaceDir = path.join(cwd, workspaceName);
|
|
67
|
+
|
|
68
|
+
if (fs.existsSync(workspaceDir))
|
|
69
|
+
exitWithError(
|
|
70
|
+
`Workspace directory '${workspaceName}' already exists`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
fs.mkdirSync(workspaceDir);
|
|
74
|
+
console.log(`Created workspace directory: ${workspaceName}`);
|
|
75
|
+
|
|
76
|
+
// Create project symlinks
|
|
77
|
+
projects.forEach((project) => {
|
|
78
|
+
createSymlink(
|
|
79
|
+
path.join(cwd, project),
|
|
80
|
+
path.join(workspaceDir, project),
|
|
81
|
+
);
|
|
82
|
+
console.log(`Linked project: ${project}`);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Setup AI instructions
|
|
86
|
+
const instructionsDir = path.join(
|
|
87
|
+
workspaceDir,
|
|
88
|
+
".github",
|
|
89
|
+
"instructions",
|
|
90
|
+
);
|
|
91
|
+
fs.mkdirSync(instructionsDir, { recursive: true });
|
|
92
|
+
|
|
93
|
+
const instructionFiles = projects.flatMap((project) =>
|
|
94
|
+
glob.sync(`${project}/.github/instructions/*.md`, { cwd }),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
instructionFiles.forEach((filePath) => {
|
|
98
|
+
const fileName = path.basename(filePath);
|
|
99
|
+
createSymlink(
|
|
100
|
+
path.join(cwd, filePath),
|
|
101
|
+
path.join(instructionsDir, fileName),
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
console.log(
|
|
106
|
+
instructionFiles.length
|
|
107
|
+
? `Linked ${instructionFiles.length} instruction file(s) to workspace`
|
|
108
|
+
: "No AI instruction files found in projects",
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
_.copyAIInstructionsFile("workspace-@", workspaceDir);
|
|
112
|
+
_.copyAIInstructionsFile("mcp-@", workspaceDir);
|
|
113
|
+
|
|
114
|
+
// Open in VS Code
|
|
115
|
+
try {
|
|
116
|
+
execSync("code .", { cwd: workspaceDir, stdio: "ignore" });
|
|
117
|
+
console.log(`\nOpened workspace in VS Code: ${workspaceName}`);
|
|
118
|
+
} catch {
|
|
119
|
+
// Silently ignore VS Code errors
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(`\nWorkspace setup complete: ${workspaceName}`);
|
|
123
|
+
},
|
|
124
|
+
];
|
package/globals.js
CHANGED
|
@@ -215,7 +215,8 @@ if (composer && composer.require && composer.require["laravel/framework"]) {
|
|
|
215
215
|
args[0] !== "new" &&
|
|
216
216
|
args[0] !== "key" &&
|
|
217
217
|
args[0] !== "dekey" &&
|
|
218
|
-
args[0] !== "lint"
|
|
218
|
+
args[0] !== "lint" &&
|
|
219
|
+
args[0] !== "workspace"
|
|
219
220
|
) {
|
|
220
221
|
if (!args.find((d) => d === "--force")) {
|
|
221
222
|
console.log(
|
|
@@ -264,7 +265,8 @@ if (composer && composer.require && composer.require["laravel/framework"]) {
|
|
|
264
265
|
args[0] !== "new" &&
|
|
265
266
|
args[0] !== "key" &&
|
|
266
267
|
args[0] !== "dekey" &&
|
|
267
|
-
args[0] !== "lint"
|
|
268
|
+
args[0] !== "lint" &&
|
|
269
|
+
args[0] !== "workspace"
|
|
268
270
|
) {
|
|
269
271
|
if (!args.find((d) => d === "--force")) {
|
|
270
272
|
console.log(
|
|
@@ -338,7 +340,8 @@ if (process.env.FW_NEXT) {
|
|
|
338
340
|
args[0] !== "new" &&
|
|
339
341
|
args[0] !== "key" &&
|
|
340
342
|
args[0] !== "dekey" &&
|
|
341
|
-
args[0] !== "lint"
|
|
343
|
+
args[0] !== "lint" &&
|
|
344
|
+
args[0] !== "workspace"
|
|
342
345
|
) {
|
|
343
346
|
if (
|
|
344
347
|
!args.find((d) => d === "--force") &&
|
|
@@ -570,9 +573,9 @@ if (!existsSync(path.join(cwd, "stylelint.config.js"))) {
|
|
|
570
573
|
);
|
|
571
574
|
}
|
|
572
575
|
|
|
573
|
-
function copyAIInstructionsFile(source) {
|
|
576
|
+
function copyAIInstructionsFile(source, projectDir = cwd) {
|
|
574
577
|
// Create directory if it doesn't exist
|
|
575
|
-
const destDir = path.join(
|
|
578
|
+
const destDir = path.join(projectDir, ".github/instructions");
|
|
576
579
|
if (!existsSync(destDir)) {
|
|
577
580
|
mkdirSync(destDir, { recursive: true });
|
|
578
581
|
}
|
|
@@ -606,11 +609,12 @@ if (
|
|
|
606
609
|
semver.satisfies(semver.coerce(pkg.dependencies["vue"]), "3.x")
|
|
607
610
|
) {
|
|
608
611
|
copyAIInstructionsFile("vue-3");
|
|
612
|
+
copyAIInstructionsFile("ui-framework-3");
|
|
609
613
|
}
|
|
610
614
|
|
|
611
615
|
if (version) {
|
|
612
|
-
copyAIInstructionsFile("sass
|
|
613
|
-
copyAIInstructionsFile("lab-env
|
|
616
|
+
copyAIInstructionsFile("sass-@");
|
|
617
|
+
copyAIInstructionsFile("lab-env-@");
|
|
614
618
|
copyAIInstructionsFile("webdriverio-capture-v9");
|
|
615
619
|
}
|
|
616
620
|
|
|
@@ -666,7 +670,8 @@ if (
|
|
|
666
670
|
args[0] !== "new" &&
|
|
667
671
|
args[0] !== "key" &&
|
|
668
672
|
args[0] !== "dekey" &&
|
|
669
|
-
args[0] !== "lint"
|
|
673
|
+
args[0] !== "lint" &&
|
|
674
|
+
args[0] !== "workspace"
|
|
670
675
|
) {
|
|
671
676
|
if (!args.find((d) => d === "--force")) {
|
|
672
677
|
// Stop here if diagnosis either unset or outdated
|
|
@@ -827,4 +832,5 @@ module.exports = {
|
|
|
827
832
|
opts,
|
|
828
833
|
);
|
|
829
834
|
},
|
|
835
|
+
copyAIInstructionsFile,
|
|
830
836
|
};
|