@polymorphism-tech/morph-spec 4.3.4 → 4.3.6

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 (164) hide show
  1. package/.morph/.morphversion +5 -0
  2. package/.morph/config/agents.json +948 -0
  3. package/.morph/config/config.json +9 -9
  4. package/.morph/project/context/README.md +17 -0
  5. package/.morph/project/context/detection-log.md +16 -0
  6. package/.morph/project/standards/inferred.md +59 -0
  7. package/.morph/standards/ai-agents/blazor-ui.md +364 -0
  8. package/.morph/standards/ai-agents/production.md +415 -0
  9. package/.morph/standards/ai-agents/setup.md +418 -0
  10. package/.morph/standards/ai-agents/team-orchestration.md +479 -0
  11. package/.morph/standards/ai-agents/workflows.md +354 -0
  12. package/.morph/standards/architecture/ddd/aggregates.md +120 -0
  13. package/.morph/standards/architecture/ddd/entities.md +99 -0
  14. package/.morph/standards/architecture/ddd/value-objects.md +124 -0
  15. package/.morph/standards/backend/api/minimal-api.md +494 -0
  16. package/.morph/standards/backend/api/rest.md +492 -0
  17. package/.morph/standards/backend/api/validation.md +88 -0
  18. package/.morph/standards/backend/authentication/passkeys.md +428 -0
  19. package/.morph/standards/backend/database/ef-core.md +199 -0
  20. package/.morph/standards/backend/database/migrations.md +393 -0
  21. package/.morph/standards/backend/database/postgresql/database.md +352 -0
  22. package/.morph/standards/backend/database/repository-patterns.md +528 -0
  23. package/.morph/standards/backend/database/vector-search-rag.md +541 -0
  24. package/.morph/standards/backend/dotnet/async.md +366 -0
  25. package/.morph/standards/backend/dotnet/core.md +117 -0
  26. package/.morph/standards/backend/dotnet/di.md +439 -0
  27. package/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
  28. package/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
  29. package/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
  30. package/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
  31. package/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
  32. package/.morph/standards/context/analytics.md +96 -0
  33. package/.morph/standards/context/bundles.md +110 -0
  34. package/.morph/standards/context/priming.md +78 -0
  35. package/.morph/standards/core/architecture.md +185 -0
  36. package/.morph/standards/core/coding.md +214 -0
  37. package/.morph/standards/core/git-branching-strategy.md +403 -0
  38. package/.morph/standards/core/git.md +185 -0
  39. package/.morph/standards/core/testing.md +295 -0
  40. package/.morph/standards/data/nosql/blob-storage.md +102 -0
  41. package/.morph/standards/data/nosql/cache/redis.md +97 -0
  42. package/.morph/standards/data/nosql/cosmos-db.md +118 -0
  43. package/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
  44. package/.morph/standards/data/vector-search/rag-chunking.md +104 -0
  45. package/.morph/standards/frontend/blazor/design-checklist.md +222 -0
  46. package/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
  47. package/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
  48. package/.morph/standards/frontend/blazor/html-conversion.md +184 -0
  49. package/.morph/standards/frontend/blazor/lifecycle.md +195 -0
  50. package/.morph/standards/frontend/blazor/pitfalls.md +198 -0
  51. package/.morph/standards/frontend/blazor/state.md +191 -0
  52. package/.morph/standards/frontend/design-system/animations.md +151 -0
  53. package/.morph/standards/frontend/design-system/naming.md +64 -0
  54. package/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
  55. package/.morph/standards/infrastructure/azure/azure.md +624 -0
  56. package/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
  57. package/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
  58. package/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
  59. package/.morph/standards/infrastructure/azure/services/functions.md +486 -0
  60. package/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
  61. package/.morph/standards/infrastructure/azure/services/storage.md +407 -0
  62. package/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
  63. package/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
  64. package/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
  65. package/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
  66. package/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
  67. package/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
  68. package/.morph/standards/integration/api/graphql.md +91 -0
  69. package/.morph/standards/integration/api/grpc.md +114 -0
  70. package/.morph/standards/integration/api/rest-design.md +95 -0
  71. package/.morph/standards/integration/event-driven/cqrs.md +101 -0
  72. package/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
  73. package/.morph/standards/integration/event-driven/service-bus.md +95 -0
  74. package/.morph/standards/observability/logging.md +131 -0
  75. package/.morph/standards/observability/metrics.md +121 -0
  76. package/.morph/standards/observability/monitoring.md +114 -0
  77. package/.morph/standards/observability/tracing.md +132 -0
  78. package/.morph/standards/workflows/parallel-execution.md +112 -0
  79. package/.morph/standards/workflows/thread-management.md +113 -0
  80. package/.morph/templates/.idea/morph-templates.xml +92 -0
  81. package/.morph/templates/.vscode/morph-templates.code-snippets +186 -0
  82. package/.morph/templates/IDE-SNIPPETS.md +266 -0
  83. package/.morph/templates/README.md +814 -0
  84. package/.morph/templates/REGISTRY.json +1677 -0
  85. package/.morph/templates/code/dotnet/backend/repository.cs +141 -0
  86. package/.morph/templates/code/dotnet/backend/service.cs +139 -0
  87. package/.morph/templates/code/dotnet/contracts/Commands.cs +74 -0
  88. package/.morph/templates/code/dotnet/contracts/Entities.cs +25 -0
  89. package/.morph/templates/code/dotnet/contracts/Queries.cs +74 -0
  90. package/.morph/templates/code/dotnet/contracts/README.md +74 -0
  91. package/.morph/templates/code/dotnet/contracts/api-contracts.cs +173 -0
  92. package/.morph/templates/code/dotnet/contracts/contracts.cs +217 -0
  93. package/.morph/templates/code/dotnet/database/migration.cs +83 -0
  94. package/.morph/templates/code/dotnet/frontend/component.razor +239 -0
  95. package/.morph/templates/code/dotnet/jobs/agent.cs +163 -0
  96. package/.morph/templates/code/dotnet/jobs/job.cs +171 -0
  97. package/.morph/templates/code/dotnet/test.cs +239 -0
  98. package/.morph/templates/code/sql/rls-policy.sql +57 -0
  99. package/.morph/templates/code/sql/supabase-migration.sql +100 -0
  100. package/.morph/templates/code/sql/supabase-migration.template.sql +113 -0
  101. package/.morph/templates/code/typescript/contracts.ts +168 -0
  102. package/.morph/templates/context/CONTEXT-FEATURE.md +276 -0
  103. package/.morph/templates/context/CONTEXT.md +181 -0
  104. package/.morph/templates/docs/proposal.md +182 -0
  105. package/.morph/templates/docs/spec.md +149 -0
  106. package/.morph/templates/examples/design-system-examples.md +357 -0
  107. package/.morph/templates/examples/spec-examples.md +90 -0
  108. package/.morph/templates/feature/decisions.md +187 -0
  109. package/.morph/templates/feature/recap.md +146 -0
  110. package/.morph/templates/feature/tasks.md +199 -0
  111. package/.morph/templates/infrastructure/azure/Dockerfile.example +82 -0
  112. package/.morph/templates/infrastructure/azure/README.md +286 -0
  113. package/.morph/templates/infrastructure/azure/app-insights.bicep +63 -0
  114. package/.morph/templates/infrastructure/azure/app-service.bicep +164 -0
  115. package/.morph/templates/infrastructure/azure/container-app-env.bicep +49 -0
  116. package/.morph/templates/infrastructure/azure/container-app.bicep +156 -0
  117. package/.morph/templates/infrastructure/azure/deploy-checklist.md +426 -0
  118. package/.morph/templates/infrastructure/azure/deploy.ps1 +229 -0
  119. package/.morph/templates/infrastructure/azure/deploy.sh +208 -0
  120. package/.morph/templates/infrastructure/azure/key-vault.bicep +91 -0
  121. package/.morph/templates/infrastructure/azure/main.bicep +189 -0
  122. package/.morph/templates/infrastructure/azure/parameters.dev.json +29 -0
  123. package/.morph/templates/infrastructure/azure/parameters.prod.json +29 -0
  124. package/.morph/templates/infrastructure/azure/parameters.staging.json +29 -0
  125. package/.morph/templates/infrastructure/azure/sql-database.bicep +103 -0
  126. package/.morph/templates/infrastructure/azure/storage.bicep +106 -0
  127. package/.morph/templates/infrastructure/docker/Dockerfile.template +58 -0
  128. package/.morph/templates/infrastructure/docker/docker-compose.template.yml +67 -0
  129. package/.morph/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
  130. package/.morph/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
  131. package/.morph/templates/infrastructure/docker/easypanel.template.json +54 -0
  132. package/.morph/templates/infrastructure/github/README.md +593 -0
  133. package/.morph/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
  134. package/.morph/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
  135. package/.morph/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
  136. package/.morph/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
  137. package/.morph/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
  138. package/.morph/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
  139. package/.morph/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
  140. package/.morph/templates/integrations/asaas-client.cs +387 -0
  141. package/.morph/templates/integrations/asaas-webhook.cs +351 -0
  142. package/.morph/templates/integrations/azure-identity-config.cs +288 -0
  143. package/.morph/templates/integrations/clerk-config.cs +258 -0
  144. package/.morph/templates/meta-prompts/fusion/fusion-agent.md +76 -0
  145. package/.morph/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
  146. package/.morph/templates/meta-prompts/hops/hop-retry.md +78 -0
  147. package/.morph/templates/meta-prompts/hops/hop-validation.md +97 -0
  148. package/.morph/templates/meta-prompts/hops/hop-wrapper.md +36 -0
  149. package/.morph/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
  150. package/.morph/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
  151. package/.morph/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
  152. package/.morph/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
  153. package/.morph/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
  154. package/.morph/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
  155. package/.morph/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
  156. package/.morph/templates/saas/subscription.cs +347 -0
  157. package/.morph/templates/saas/tenant.cs +338 -0
  158. package/.morph/templates/state.template.json +17 -0
  159. package/.morph/templates/ui/FluentDesignTheme.cs +149 -0
  160. package/.morph/templates/ui/MudTheme.cs +281 -0
  161. package/.morph/templates/ui/design-system.css +226 -0
  162. package/bin/morph-spec.js +1 -1
  163. package/package.json +1 -1
  164. package/src/commands/project/update.js +185 -46
@@ -9,9 +9,11 @@ import { logger } from '../../utils/logger.js';
9
9
  import {
10
10
  getContentDir,
11
11
  copyDirectory,
12
+ copyFile,
12
13
  pathExists,
13
14
  ensureDir,
14
15
  createDirectoryLink,
16
+ createSymlink,
15
17
  readJson,
16
18
  writeJson
17
19
  } from '../../utils/file-copier.js';
@@ -26,6 +28,79 @@ import { installClaudeHooks } from '../../utils/hooks-installer.js';
26
28
  import { AutoContextOrchestrator } from '../../core/orchestrator.js';
27
29
  import { detectClaudeCode } from '../../llm/environment-detector.js';
28
30
 
31
+ /**
32
+ * Backup user's config.json before cleaning
33
+ * @param {string} morphPath - Path to .morph directory
34
+ * @returns {Promise<object|null>} Backup of config.json or null
35
+ */
36
+ async function backupUserConfig(morphPath) {
37
+ try {
38
+ const configPath = join(morphPath, 'config', 'config.json');
39
+ if (await pathExists(configPath)) {
40
+ const config = await readJson(configPath);
41
+ return config;
42
+ }
43
+ } catch (error) {
44
+ // If backup fails, return null and continue
45
+ }
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * Clean framework directories but preserve .morph/project/
51
+ * @param {string} morphPath - Path to .morph directory
52
+ * @param {string} targetPath - Project root path
53
+ */
54
+ async function cleanFrameworkDirs(morphPath, targetPath) {
55
+ const dirsToClean = [
56
+ join(morphPath, 'templates'),
57
+ join(morphPath, 'standards'),
58
+ join(morphPath, 'config'),
59
+ join(targetPath, '.claude')
60
+ ];
61
+
62
+ for (const dir of dirsToClean) {
63
+ try {
64
+ if (await pathExists(dir)) {
65
+ await fs.remove(dir);
66
+ }
67
+ } catch (error) {
68
+ // Continue even if cleanup fails for one directory
69
+ }
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Restore user's config.json after reinstallation
75
+ * @param {string} morphPath - Path to .morph directory
76
+ * @param {string} targetPath - Project root path
77
+ * @param {object|null} configBackup - Backup of config.json
78
+ * @param {string} currentVersion - Current CLI version
79
+ */
80
+ async function restoreUserConfig(morphPath, targetPath, configBackup, currentVersion) {
81
+ const configDir = join(morphPath, 'config');
82
+ await ensureDir(configDir);
83
+ const configPath = join(configDir, 'config.json');
84
+
85
+ if (configBackup) {
86
+ // Preserve user data but update framework version
87
+ configBackup.frameworkVersion = currentVersion;
88
+ await writeJson(configPath, configBackup);
89
+ } else {
90
+ // Create basic config if none existed
91
+ const dirName = targetPath.split(/[\\/]/).pop();
92
+ const defaultConfig = {
93
+ framework: 'global',
94
+ frameworkVersion: currentVersion,
95
+ project: {
96
+ name: dirName,
97
+ architecture: 'unknown'
98
+ }
99
+ };
100
+ await writeJson(configPath, defaultConfig);
101
+ }
102
+ }
103
+
29
104
  export async function updateCommand(options) {
30
105
  const targetPath = process.cwd();
31
106
  const contentDir = getContentDir();
@@ -34,10 +109,17 @@ export async function updateCommand(options) {
34
109
  logger.header('MORPH-SPEC Update');
35
110
 
36
111
  // Check if MORPH is initialized
112
+ let needsInitialization = false;
37
113
  if (!(await pathExists(morphPath))) {
38
- logger.error('MORPH not initialized in this directory.');
39
- logger.dim('Run "morph-spec init" first.');
40
- process.exit(1);
114
+ logger.warn('MORPH not fully initialized. Creating basic structure...');
115
+ needsInitialization = true;
116
+
117
+ // Create basic .morph structure
118
+ await ensureDir(join(morphPath, 'project', 'context'));
119
+ await ensureDir(join(morphPath, 'project', 'standards'));
120
+ await ensureDir(join(morphPath, 'project', 'outputs'));
121
+ await ensureDir(join(morphPath, 'config'));
122
+ logger.dim(' ✓ Created .morph directory structure');
41
123
  }
42
124
 
43
125
  // Check CLI version
@@ -93,6 +175,18 @@ export async function updateCommand(options) {
93
175
  const updateSpinner = ora('Updating MORPH-SPEC...').start();
94
176
 
95
177
  try {
178
+ // Backup user config before cleaning
179
+ updateSpinner.text = 'Backing up user configuration...';
180
+ const configBackup = await backupUserConfig(morphPath);
181
+ if (configBackup) {
182
+ logger.dim(' ✓ User config backed up');
183
+ }
184
+
185
+ // Clean framework directories (preserve .morph/project/)
186
+ updateSpinner.text = 'Cleaning old framework files...';
187
+ await cleanFrameworkDirs(morphPath, targetPath);
188
+ logger.dim(' ✓ Old framework files removed');
189
+
96
190
  const updateTemplates = !options.standards || options.templates;
97
191
  const updateStandards = !options.templates || options.standards;
98
192
 
@@ -112,54 +206,94 @@ export async function updateCommand(options) {
112
206
  await copyDirectory(standardsSrc, standardsDest);
113
207
  }
114
208
 
115
- // Update agents.json (sourced from framework root .morph/config/ — canonical single source of truth)
209
+ // Update agents.json (sourced from framework/ — canonical single source of truth)
116
210
  updateSpinner.text = 'Updating agents configuration...';
117
- const agentsSrc = join(__dirname, '..', '..', '..', '.morph', 'config', 'agents.json');
211
+ const agentsSrc = join(__dirname, '..', '..', '..', 'framework', 'agents.json');
118
212
  const agentsDest = join(morphPath, 'config', 'agents.json');
119
213
  if (await pathExists(agentsSrc)) {
120
- await copyDirectory(agentsSrc, agentsDest);
214
+ await copyFile(agentsSrc, agentsDest);
215
+ }
216
+
217
+ // Update azure-pricing files
218
+ updateSpinner.text = 'Updating Azure pricing data...';
219
+ const configDir = join(morphPath, 'config');
220
+ const pricingSrc = join(contentDir, '.morph', 'config', 'azure-pricing.json');
221
+ const pricingDest = join(configDir, 'azure-pricing.json');
222
+ if (await pathExists(pricingSrc)) {
223
+ await copyFile(pricingSrc, pricingDest);
224
+ }
225
+ const pricingSchemaSrc = join(contentDir, '.morph', 'config', 'azure-pricing.schema.json');
226
+ const pricingSchemaDest = join(configDir, 'azure-pricing.schema.json');
227
+ if (await pathExists(pricingSchemaSrc)) {
228
+ await copyFile(pricingSchemaSrc, pricingSchemaDest);
121
229
  }
122
230
 
123
231
  // Update .claude commands and skills
124
- // Source: framework root .claude/ (canonical for all stacks)
125
- updateSpinner.text = 'Updating Claude commands and skills...';
126
- const claudeSrc = join(__dirname, '..', '..', '..', '.claude');
232
+ // Source: framework/ (canonical for all stacks)
233
+ updateSpinner.text = 'Setting up Claude Code integration...';
234
+ const frameworkDir = join(__dirname, '..', '..', '..', 'framework');
127
235
  const claudeDest = join(targetPath, '.claude');
128
- let claudeUpdated = false;
129
- if (await pathExists(claudeSrc)) {
130
- // Copy commands (always copy, these are small)
131
- const commandsSrc = join(claudeSrc, 'commands');
132
- const commandsDest = join(claudeDest, 'commands');
133
- if (await pathExists(commandsSrc)) {
134
- await copyDirectory(commandsSrc, commandsDest);
135
- claudeUpdated = true;
136
-
137
- // Clean up stale command files moved to skills/workflows/ in v2.4+
138
- const staleCommands = [
139
- 'morph-setup.md', 'morph-uiux.md', 'morph-design.md',
140
- 'morph-clarify.md', 'morph-tasks.md'
141
- ];
142
- for (const file of staleCommands) {
143
- const stalePath = join(commandsDest, file);
144
- if (await pathExists(stalePath)) {
145
- await fs.remove(stalePath);
146
- }
147
- }
148
- } else {
149
- logger.warn(' ⚠ .claude/commands/ source missing — commands not updated');
150
- }
151
236
 
152
- // Update skills using directory links per category
153
- const skillsSrc = join(claudeSrc, 'skills');
237
+ let symlinkCount = 0;
238
+ let copyCount = 0;
239
+ let commandsCopied = false;
240
+
241
+ // Copy commands directory (slash commands): framework/commands/ → .claude/commands/
242
+ const commandsSrc = join(frameworkDir, 'commands');
243
+ const commandsDest = join(claudeDest, 'commands');
244
+ if (await pathExists(commandsSrc)) {
245
+ await copyDirectory(commandsSrc, commandsDest);
246
+ commandsCopied = true;
247
+ } else {
248
+ logger.warn(' ⚠ framework/commands/ source missing — commands not updated');
249
+ }
250
+
251
+ // Create directory links for skill categories (or copy if linking fails)
252
+ // Source: framework/skills/ → .claude/skills/
253
+ {
254
+ const skillsSrc = join(frameworkDir, 'skills');
154
255
  const skillsDest = join(claudeDest, 'skills');
256
+
155
257
  if (await pathExists(skillsSrc)) {
156
258
  await ensureDir(skillsDest);
259
+
157
260
  const entries = await fs.readdir(skillsSrc, { withFileTypes: true });
261
+
262
+ let linkedCategories = 0;
263
+ let copiedCategories = 0;
264
+ let totalSkillFiles = 0;
265
+
266
+ // Link category directories (specialists/, infra/, checklists/, etc.)
158
267
  for (const entry of entries) {
159
268
  if (entry.isDirectory()) {
160
- await createDirectoryLink(join(skillsSrc, entry.name), join(skillsDest, entry.name));
269
+ const categorySrc = join(skillsSrc, entry.name);
270
+ const categoryDest = join(skillsDest, entry.name);
271
+
272
+ // Count .md files for reporting
273
+ const categoryEntries = await fs.readdir(categorySrc, { withFileTypes: true });
274
+ const mdFiles = categoryEntries.filter(e => e.isFile() && e.name.endsWith('.md'));
275
+ totalSkillFiles += mdFiles.length;
276
+
277
+ const result = await createDirectoryLink(categorySrc, categoryDest);
278
+ if (result === 'copy') {
279
+ copiedCategories++;
280
+ } else {
281
+ linkedCategories++;
282
+ }
283
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
284
+ // Handle .md files in skills root
285
+ totalSkillFiles++;
286
+ const result = await createSymlink(join(skillsSrc, entry.name), join(skillsDest, entry.name), 'file');
287
+ if (result === 'symlink') {
288
+ linkedCategories++;
289
+ } else {
290
+ copiedCategories++;
291
+ }
161
292
  }
162
293
  }
294
+
295
+ symlinkCount = linkedCategories > 0 ? totalSkillFiles : 0;
296
+ copyCount = linkedCategories === 0 ? totalSkillFiles : 0;
163
297
  }
164
298
  }
165
299
 
@@ -173,20 +307,15 @@ export async function updateCommand(options) {
173
307
  const claudeMdDest = join(targetPath, 'CLAUDE.md');
174
308
  await copyDirectory(claudeMdSrc, claudeMdDest);
175
309
 
310
+ // Restore user config after framework reinstallation
311
+ updateSpinner.text = 'Restoring user configuration...';
312
+ await restoreUserConfig(morphPath, targetPath, configBackup, cliCheck.current);
313
+ logger.dim(' ✓ User config restored with updated framework version');
314
+
176
315
  // Update .morphversion
177
316
  updateSpinner.text = 'Saving version info...';
178
317
  await saveProjectMorphVersion(targetPath, cliCheck.current);
179
318
 
180
- // Update config.json frameworkVersion (BUG #9 fix)
181
- const configPath = join(morphPath, 'config', 'config.json');
182
- if (await pathExists(configPath)) {
183
- try {
184
- const config = await readJson(configPath);
185
- config.frameworkVersion = cliCheck.current;
186
- await writeJson(configPath, config);
187
- } catch { /* preserve existing config if read/write fails */ }
188
- }
189
-
190
319
  updateSpinner.succeed('MORPH-SPEC updated successfully!');
191
320
  logger.blank();
192
321
 
@@ -204,7 +333,17 @@ export async function updateCommand(options) {
204
333
  if (updateTemplates) logger.dim(' ✓ .morph/templates/');
205
334
  if (updateStandards) logger.dim(' ✓ .morph/standards/');
206
335
  logger.dim(' ✓ .morph/config/agents.json');
207
- if (claudeUpdated) logger.dim(' ✓ .claude/commands/ and .claude/skills/');
336
+ logger.dim(' ✓ .morph/config/azure-pricing.json');
337
+ if (commandsCopied) logger.dim(' ✓ .claude/commands/');
338
+
339
+ if (symlinkCount > 0) {
340
+ const linkType = process.platform === 'win32' ? 'junction-linked' : 'symlinked';
341
+ logger.dim(` ✓ .claude/skills/ (${symlinkCount} ${linkType})`);
342
+ } else if (copyCount > 0) {
343
+ logger.dim(` ✓ .claude/skills/ (${copyCount} copied)`);
344
+ logger.warn(` ⚠ Directory links not supported (copied instead). Skills won't auto-update.`);
345
+ }
346
+
208
347
  logger.dim(' ✓ .claude/settings.local.json (agent-teams hooks)');
209
348
  logger.dim(' ✓ CLAUDE.md');
210
349
  logger.blank();