@vc-shell/vc-app-skill 2.0.0-alpha.31 → 2.0.0-alpha.33

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 (41) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +1 -1
  3. package/runtime/VERSION +1 -1
  4. package/runtime/agents/migration-agent.md +83 -0
  5. package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
  6. package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +111 -0
  7. package/runtime/knowledge/docs/core/composables/useBladeForm/useBladeForm.docs.md +167 -0
  8. package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +305 -0
  9. package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +83 -0
  10. package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +116 -0
  11. package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +1 -1
  12. package/runtime/knowledge/docs/ui/components/atoms/vc-card/vc-card.docs.md +4 -0
  13. package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +4 -0
  14. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +5 -0
  15. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +5 -0
  16. package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +5 -0
  17. package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +7 -0
  18. package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +5 -0
  19. package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +5 -0
  20. package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +5 -0
  21. package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +7 -0
  22. package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +7 -0
  23. package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +7 -0
  24. package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +7 -0
  25. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +5 -0
  26. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md +5 -0
  27. package/runtime/knowledge/docs/ui/components/molecules/vc-rating/vc-rating.docs.md +5 -0
  28. package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +7 -0
  29. package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +5 -0
  30. package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +5 -0
  31. package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +7 -0
  32. package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +30 -0
  33. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +28 -0
  34. package/runtime/knowledge/migration-prompts/blade-form-migration.md +246 -0
  35. package/runtime/knowledge/migration-prompts/blade-props-migration.md +195 -0
  36. package/runtime/knowledge/migration-prompts/notifications-migration.md +218 -0
  37. package/runtime/knowledge/migration-prompts/nswag-migration.md +248 -0
  38. package/runtime/knowledge/migration-prompts/widgets-migration.md +157 -0
  39. package/runtime/vc-app.md +126 -0
  40. package/runtime/knowledge/docs/core/constants/constants.docs.md +0 -185
  41. /package/runtime/knowledge/docs/shell/{pages → auth}/ChangePasswordPage/change-password-page.docs.md +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ # [2.0.0-alpha.33](https://github.com/VirtoCommerce/vc-shell/compare/v2.0.0-alpha.32...v2.0.0-alpha.33) (2026-04-14)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **vc-app-skill:** add VC_SHELL_MIGRATE_CLI env override for local testing ([010d2f2](https://github.com/VirtoCommerce/vc-shell/commit/010d2f2ecb29d31d9134406bcd18e46e5883208b))
7
+ * **vc-app-skill:** resolve migrate CLI from project node_modules before npx fallback ([82a8156](https://github.com/VirtoCommerce/vc-shell/commit/82a81563f7fdb94a94a7b8a80796ecffc671a39c))
8
+ * **vc-app-skill:** resolve migrate CLI locally in dev mode, fallback to npx ([89888a0](https://github.com/VirtoCommerce/vc-shell/commit/89888a06cc0b4a1519f46f070ee06ebb0d82fd09))
9
+
10
+
11
+ ### Features
12
+
13
+ * **vc-app-skill:** add /vc-app migrate command with full migration pipeline ([35a8b11](https://github.com/VirtoCommerce/vc-shell/commit/35a8b119457b14f6f4626caf133476222afd6663))
14
+ * **vc-app-skill:** add migration prompt knowledge base (nswag, widgets, form, blade-props, notifications) ([a0b0eb2](https://github.com/VirtoCommerce/vc-shell/commit/a0b0eb2a96521916a72bdbf787961c1c96f96f6d))
15
+ * **vc-app-skill:** add migration-agent subagent prompt ([29ac155](https://github.com/VirtoCommerce/vc-shell/commit/29ac1550c8e3c9b71d5dbc2ade7ea86b4d40213f))
16
+ # [2.0.0-alpha.32](https://github.com/VirtoCommerce/vc-shell/compare/v2.0.0-alpha.31...v2.0.0-alpha.32) (2026-04-02)
17
+
18
+ **Note:** Version bump only for package @vc-shell/vc-app-skill
19
+
1
20
  # [2.0.0-alpha.31](https://github.com/VirtoCommerce/vc-shell/compare/v2.0.0-alpha.30...v2.0.0-alpha.31) (2026-04-01)
2
21
 
3
22
  **Note:** Version bump only for package @vc-shell/vc-app-skill
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vc-shell/vc-app-skill",
3
- "version": "2.0.0-alpha.31",
3
+ "version": "2.0.0-alpha.33",
4
4
  "description": "AI coding skill for scaffolding and generating VirtoCommerce Shell applications. Works with Claude Code, OpenCode, Gemini, Codex, Cursor.",
5
5
  "bin": "./bin/install.cjs",
6
6
  "files": [
package/runtime/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0-alpha.31
1
+ 2.0.0-alpha.33
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: migration-agent
3
+ description: Performs AI-powered manual migrations on files identified by MIGRATION_REPORT.md, using transformation rules from migration prompts.
4
+ ---
5
+
6
+ ## Input Contract
7
+
8
+ ```json
9
+ {
10
+ "required": {
11
+ "cwd": "string — absolute path to project root",
12
+ "reportPath": "string — path to MIGRATION_REPORT.md",
13
+ "topics": "array — migration topics to process, each with: { name, affectedFiles, migrationPromptPath, patternPath? }"
14
+ }
15
+ }
16
+ ```
17
+
18
+ ## Knowledge Loading
19
+
20
+ For each topic in `topics`:
21
+ 1. Read the migration prompt from `migrationPromptPath` — these contain specific transformation rules with BEFORE/AFTER examples
22
+ 2. If `patternPath` is provided, read the pattern file — this shows what correct target code looks like
23
+
24
+ Do NOT read all prompts upfront. Load each topic's knowledge just before processing that topic.
25
+
26
+ ## Processing Strategy
27
+
28
+ ### Topic Order
29
+
30
+ Process topics in this order (dependencies first):
31
+ 1. `notifications-migration` — may create new files and restructure directories
32
+ 2. `nswag-migration` — type-level changes that affect all other code
33
+ 3. `widgets-migration` — creates new composable files referenced by blades
34
+ 4. `blade-form-migration` — depends on correct types from nswag
35
+ 5. `blade-props-migration` — final cleanup of reusable components
36
+
37
+ Skip topics not present in the `topics` input.
38
+
39
+ ### Per-File Strategy
40
+
41
+ For each affected file in the current topic:
42
+
43
+ 1. **Read the file** completely
44
+ 2. **Apply transformation rules** from the loaded migration prompt — follow the BEFORE/AFTER patterns exactly
45
+ 3. **Create new files if required** by the prompt (e.g. `widgets/useXxxWidgets.ts` for widget migration)
46
+ 4. **Write the modified file**
47
+ 5. **Type-check:** Run `cd {cwd} && npx vue-tsc --noEmit 2>&1 | head -30` to check for errors
48
+ 6. **If errors in this file:** Read error messages, fix, re-check. Max 3 attempts.
49
+ 7. **If fixed or clean:** Commit: `fix(migrate): {topic name} — {filename}`
50
+ 8. **If still broken after 3 attempts:** Revert the file (`git checkout -- {filepath}`), report as "needs manual intervention", continue to next file
51
+
52
+ ### Important Rules
53
+
54
+ 1. **Only modify files listed in the topic's `affectedFiles`** — do not touch other files unless creating new files required by the migration prompt (e.g. widget composables)
55
+ 2. **Follow transformation rules exactly** — each migration prompt has specific BEFORE/AFTER patterns. Apply them mechanically.
56
+ 3. **Do not add features or refactor** — only transform existing code to the new API
57
+ 4. **Preserve all business logic** — the behavior must stay identical after migration
58
+ 5. **Commit after each successfully migrated file** — atomic commits for easy rollback
59
+ 6. **Do not modify `api_client/` directory** — generated code, not consumer code
60
+ 7. **Do not modify `node_modules/`**
61
+
62
+ ## Output
63
+
64
+ When all topics are processed, report:
65
+
66
+ ```
67
+ ## Migration Agent Report
68
+
69
+ ### Completed
70
+ - {topic}: {N} files migrated
71
+ - src/path/to/file.vue ✅
72
+ - src/path/to/other.ts ✅
73
+
74
+ ### Failed (needs manual intervention)
75
+ - {topic}: {M} files failed
76
+ - src/path/to/problem.vue — {error description}
77
+
78
+ ### New Files Created
79
+ - src/modules/xxx/widgets/useXxxWidgets.ts
80
+
81
+ ### Remaining TypeScript Errors
82
+ {output of final vue-tsc --noEmit, if any}
83
+ ```
@@ -1 +1 @@
1
- Synced from framework at commit 2f71da38b on 2026-04-01T16:03:16.012Z
1
+ Synced from framework at commit b399787ff on 2026-04-14T15:15:27.844Z
@@ -0,0 +1,111 @@
1
+ # useBladeContext (defineBladeContext / injectBladeContext)
2
+
3
+ Exposes blade-level data to descendant widgets, extensions, and nested components via Vue's provide/inject mechanism. This pair of functions eliminates the need for prop drilling when child widgets or extension points need access to the parent blade's entity data, loading flags, or other shared state.
4
+
5
+ The pattern follows a "define once, inject anywhere" approach: the blade component calls `defineBladeContext` during setup, and any descendant (no matter how deeply nested) can call `injectBladeContext` to read that data reactively.
6
+
7
+ ## When to Use
8
+
9
+ - Share blade state (current entity, loading flags, disabled state) with child widgets without prop drilling
10
+ - Access parent blade data from an extension or widget component
11
+ - Expose selective fields to widgets (e.g., only the entity ID) via a computed getter
12
+ - When NOT to use: for cross-blade communication between sibling blades (use `useBlade` / blade messaging instead)
13
+
14
+ ## Basic Usage
15
+
16
+ ```typescript
17
+ // In a blade's <script setup>
18
+ import { defineBladeContext, injectBladeContext } from '@vc-shell/framework';
19
+
20
+ // Provide context — refs/computeds are auto-unwrapped for consumers
21
+ defineBladeContext({ item, disabled, loading });
22
+
23
+ // Or with a computed for selective exposure
24
+ defineBladeContext(computed(() => ({ id: item.value?.id })));
25
+ ```
26
+
27
+ ```typescript
28
+ // In a widget or nested component
29
+ import { injectBladeContext } from '@vc-shell/framework';
30
+
31
+ const ctx = injectBladeContext();
32
+ // Refs are already unwrapped — access values directly, no .value needed
33
+ const entityId = computed(() => ctx.value.id as string);
34
+ const item = computed(() => ctx.value.item as { id: string; name: string });
35
+ ```
36
+
37
+ ## API
38
+
39
+ ### defineBladeContext
40
+
41
+ | Parameter | Type | Required | Description |
42
+ |---|---|---|---|
43
+ | `data` | `MaybeRefOrGetter<Record<string, unknown>>` | Yes | Plain object, ref, or getter to expose |
44
+
45
+ Returns `void`. Must be called in the blade's `<script setup>`.
46
+
47
+ ### injectBladeContext
48
+
49
+ Takes no parameters. Returns `ComputedRef<Record<string, unknown>>`.
50
+
51
+ Throws `InjectionError` if no ancestor blade has called `defineBladeContext`.
52
+
53
+ ## Recipe: Widget Consuming Blade Context
54
+
55
+ A typical pattern is a sidebar widget that needs to load related data based on the current blade entity. The widget does not receive any props from the blade -- it reads the entity ID from the blade context:
56
+
57
+ ```vue
58
+ <script setup lang="ts">
59
+ // widgets/RelatedOrdersWidget.vue
60
+ import { computed, watch } from "vue";
61
+ import { injectBladeContext } from "@vc-shell/framework";
62
+
63
+ const ctx = injectBladeContext();
64
+ const customerId = computed(() => ctx.value.id as string | undefined);
65
+
66
+ // Reload orders whenever the customer changes
67
+ watch(customerId, async (id) => {
68
+ if (id) {
69
+ await loadOrders(id);
70
+ }
71
+ });
72
+ </script>
73
+ ```
74
+
75
+ ```vue
76
+ <script setup lang="ts">
77
+ // blades/CustomerDetailBlade.vue
78
+ import { ref, computed } from "vue";
79
+ import { defineBladeContext } from "@vc-shell/framework";
80
+
81
+ const customer = ref({ id: "cust-1", name: "Acme Corp" });
82
+ const loading = ref(false);
83
+
84
+ // Expose the customer data to all descendant widgets
85
+ defineBladeContext(computed(() => ({
86
+ id: customer.value?.id,
87
+ name: customer.value?.name,
88
+ loading: loading.value,
89
+ })));
90
+ </script>
91
+ ```
92
+
93
+ ## Details
94
+
95
+ - **Automatic ref unwrapping**: `defineBladeContext` shallow-unwraps all ref/computed values in the provided object. Consumers get plain values directly (`ctx.value.item` instead of `ctx.value.item.value`). This works reactively — when the source ref changes, the context updates automatically.
96
+ - **Reactivity**: The provided context is always wrapped in a `computed`, so consumers receive a `ComputedRef` regardless of whether the provider passed a plain object, a ref, or a getter. Changes propagate automatically.
97
+ - **Injection key**: Uses `BladeContextKey` from `framework/injection-keys.ts`. This is a framework-level Symbol, so there is no risk of key collision with application code.
98
+ - **Error handling**: `injectBladeContext` throws an `InjectionError` with a descriptive message if called outside a blade component tree. This fails fast during development rather than silently returning `undefined`.
99
+ - **Scope**: The context is scoped to the Vue component subtree. Each blade in the stack has its own context, so nested blades do not leak data upward or sideways.
100
+
101
+ ## Tips
102
+
103
+ - Prefer exposing a computed getter rather than the full reactive object when only a subset of fields is needed. This minimizes unnecessary re-renders in consuming widgets.
104
+ - The context value is untyped (`Record<string, unknown>`). Use type assertions or a typed wrapper in your module if you need type safety (e.g., `ctx.value.id as string`).
105
+ - If a blade does not call `defineBladeContext`, any descendant calling `injectBladeContext` will throw. Make sure all blades that host widgets define their context.
106
+
107
+ ## Related
108
+
109
+ - `BladeContextKey` in `framework/injection-keys.ts`
110
+ - `useBladeWidgets` -- widgets that consume blade context
111
+ - `useBladeStack` -- manages the blade navigation stack
@@ -0,0 +1,167 @@
1
+ # useBladeForm
2
+
3
+ Unified form state management for blades. Replaces manual combination of `useForm` + `useModificationTracker` + `useBeforeUnload` + `onBeforeClose` with a single composable.
4
+
5
+ ## Import
6
+
7
+ ```ts
8
+ import { useBladeForm } from "@vc-shell/framework";
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ ```ts
14
+ const { item, loadItem, saveItem } = useItemData();
15
+
16
+ const form = useBladeForm({ data: item });
17
+
18
+ onMounted(async () => {
19
+ await loadItem({ id: param.value });
20
+ form.setBaseline(); // snapshot current data as pristine
21
+ });
22
+
23
+ // Toolbar
24
+ const toolbar = ref<IBladeToolbar[]>([
25
+ {
26
+ id: "save",
27
+ title: "Save",
28
+ icon: "lucide-save",
29
+ disabled: computed(() => !form.canSave.value),
30
+ async clickHandler() {
31
+ await saveItem(item.value);
32
+ form.setBaseline(); // snapshot after save
33
+ callParent("reload");
34
+ },
35
+ },
36
+ ]);
37
+ ```
38
+
39
+ ## API
40
+
41
+ ### Options
42
+
43
+ | Option | Type | Default | Description |
44
+ |--------|------|---------|-------------|
45
+ | `data` | `Ref<T>` | required | Reactive data object for the form |
46
+ | `canSaveOverride` | `ComputedRef<boolean>` | — | Additional condition for canSave |
47
+ | `autoBeforeClose` | `boolean \| ComputedRef<boolean>` | `true` | Close guard behavior |
48
+ | `autoBeforeUnload` | `boolean` | `true` | Browser tab close guard |
49
+ | `closeConfirmMessage` | `MaybeRefOrGetter<string>` | — | Custom unsaved changes message |
50
+ | `onRevert` | `() => void \| Promise<void>` | — | Custom revert handler |
51
+
52
+ ### Returns
53
+
54
+ | Property | Type | Description |
55
+ |----------|------|-------------|
56
+ | `setBaseline()` | `() => void` | Snapshot current data as pristine. Call after load and after save |
57
+ | `markReady()` | `() => void` | Mark form ready without resetting pristine snapshot. Computes modification state from current data vs setup-time snapshot |
58
+ | `revert()` | `() => void \| Promise<void>` | Revert data to pristine (or call onRevert) |
59
+ | `canSave` | `ComputedRef<boolean>` | `isReady && valid && modified && canSaveOverride` |
60
+ | `isModified` | `ComputedRef<boolean>` | Data differs from pristine (false until setBaseline) |
61
+ | `isReady` | `ComputedRef<boolean>` | setBaseline() called at least once |
62
+ | `formMeta` | vee-validate meta | Form validation state |
63
+ | `setFieldError` | function | Set field error programmatically |
64
+ | `errorBag` | Ref | All field errors |
65
+
66
+ ## Lifecycle
67
+
68
+ ### Standard (edit existing entity)
69
+ ```
70
+ Mount → Load data → setBaseline() → User edits → Save → setBaseline()
71
+ └→ Cancel → revert()
72
+ ```
73
+
74
+ ### Pre-filled (create from template)
75
+ ```
76
+ Mount → Pre-fill data → markReady() → canSave = true immediately
77
+ └→ Save → setBaseline()
78
+ ```
79
+
80
+ ## VcBlade Integration
81
+
82
+ `useBladeForm` auto-provides form state to `VcBlade` via inject. No need to pass `:modified` prop:
83
+
84
+ ```vue
85
+ <!-- Before -->
86
+ <VcBlade :modified="isModified" :toolbar-items="toolbar">
87
+
88
+ <!-- After -->
89
+ <VcBlade :toolbar-items="toolbar">
90
+ ```
91
+
92
+ ## Advanced: Readonly Blade
93
+
94
+ ```ts
95
+ const disabled = computed(() => !!param.value && !item.value?.canBeModified);
96
+
97
+ const form = useBladeForm({
98
+ data: item,
99
+ canSaveOverride: computed(() => !disabled.value),
100
+ autoBeforeClose: computed(() => !disabled.value), // no prompt when readonly
101
+ });
102
+ ```
103
+
104
+ ## Advanced: Custom Revert
105
+
106
+ ```ts
107
+ const form = useBladeForm({
108
+ data: item,
109
+ onRevert: () => loadItem({ id: param.value }), // reload from server
110
+ });
111
+ ```
112
+
113
+ ## Advanced: Pre-filled Entity (markReady)
114
+
115
+ When creating a new entity that is pre-populated from a parent (e.g. new offer from a product), the form should be immediately saveable. Use `markReady()` instead of `setBaseline()`:
116
+
117
+ ```ts
118
+ const form = useBladeForm({ data: item });
119
+
120
+ onMounted(async () => {
121
+ // Populate base fields
122
+ item.value.sku = generateSku();
123
+ await addEmptyInventory();
124
+
125
+ const hasTemplate = !param.value && !!options.value?.templateId;
126
+
127
+ if (hasTemplate) {
128
+ // Fill from template — data diverges from the setup-time snapshot
129
+ await fillFromTemplate(options.value.templateId);
130
+ // Mark ready: compares current data to setup-time snapshot → isModified = true
131
+ form.markReady();
132
+ } else {
133
+ // Standard load — current state becomes the pristine baseline
134
+ await loadItem({ id: param.value });
135
+ form.setBaseline();
136
+ }
137
+ });
138
+ ```
139
+
140
+ ### setBaseline vs markReady
141
+
142
+ | | `setBaseline()` | `markReady()` |
143
+ |--|-----------------|---------------|
144
+ | Sets `isReady` | yes | yes |
145
+ | Updates pristine snapshot | yes (current data → pristine) | no (keeps setup-time snapshot) |
146
+ | `trackerIsModified` after call | `false` | computed: `data !== pristineSnapshot` |
147
+ | Use case | Load / Save — "this is the clean state" | Pre-fill — "form is ready, changes are intentional" |
148
+
149
+ ### How it works
150
+
151
+ At composable creation, `useBladeForm` takes a snapshot of `data` (the **setup-time snapshot**). When `markReady()` is called:
152
+
153
+ 1. `isReady` → `true` (gates `canSave` and the deep watcher)
154
+ 2. `trackerIsModified` = `!semanticEqual(data, setupTimeSnapshot)` — since data was mutated during `onMounted`, this evaluates to `true`
155
+ 3. Subsequent edits are tracked normally by the deep watcher
156
+
157
+ After save, call `setBaseline()` as usual to capture the saved state as the new pristine snapshot.
158
+
159
+ ## Constraints
160
+
161
+ - **Must be called from component `setup()`** (or `<script setup>`). Do NOT call from shared data-composables.
162
+ - Validation rules stay in template (`<Field rules="...">`).
163
+ - `setBaseline()` must be called after data is loaded — before that, `canSave` and `isModified` are `false`.
164
+
165
+ ## Migration
166
+
167
+ See `MIGRATION_GUIDE.md` for step-by-step instructions on migrating existing modules.