@polymorphism-tech/morph-spec 4.8.19 → 4.9.0

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 (137) hide show
  1. package/CLAUDE.md +21 -0
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +15 -56
  4. package/bin/task-manager.js +115 -14
  5. package/bin/validate.js +67 -33
  6. package/claude-plugin.json +1 -1
  7. package/docs/CHEATSHEET.md +201 -203
  8. package/docs/QUICKSTART.md +2 -2
  9. package/framework/CLAUDE.md +21 -0
  10. package/framework/agents.json +698 -176
  11. package/framework/hooks/claude-code/post-tool-use/context-refresh.js +1 -1
  12. package/framework/hooks/claude-code/post-tool-use/dispatch.js +2 -2
  13. package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +155 -0
  14. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +1 -1
  15. package/framework/hooks/claude-code/session-start/inject-morph-context.js +71 -2
  16. package/framework/hooks/claude-code/statusline.py +76 -30
  17. package/framework/hooks/claude-code/user-prompt/set-terminal-title.js +14 -6
  18. package/framework/hooks/shared/activity-logger.js +0 -24
  19. package/framework/hooks/shared/phase-utils.js +3 -0
  20. package/framework/hooks/shared/skill-reminder-helpers.js +79 -0
  21. package/framework/hooks/shared/stale-task-reset.js +57 -0
  22. package/framework/hooks/shared/state-reader.js +2 -2
  23. package/framework/hooks/shared/worktree-helpers.js +53 -0
  24. package/framework/phases.json +40 -8
  25. package/framework/skills/level-0-meta/brainstorming/SKILL.md +1 -1
  26. package/framework/skills/level-0-meta/code-review/SKILL.md +1 -1
  27. package/framework/skills/level-0-meta/code-review-nextjs/SKILL.md +163 -163
  28. package/framework/skills/level-0-meta/frontend-review/SKILL.md +5 -5
  29. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +2 -2
  30. package/framework/skills/level-0-meta/morph-init/SKILL.md +5 -5
  31. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +4 -4
  32. package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +1 -1
  33. package/framework/skills/level-0-meta/post-implementation/SKILL.md +59 -12
  34. package/framework/skills/level-0-meta/simulation-checklist/SKILL.md +1 -1
  35. package/framework/skills/level-0-meta/terminal-title/SKILL.md +1 -1
  36. package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +1 -1
  37. package/framework/skills/level-0-meta/tool-usage-guide/references/tools-per-phase.md +6 -5
  38. package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +1 -1
  39. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +215 -189
  40. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +251 -251
  41. package/framework/skills/level-1-workflows/phase-design/SKILL.md +382 -365
  42. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +492 -450
  43. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +194 -190
  44. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +270 -270
  45. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +285 -285
  46. package/framework/standards/STANDARDS.json +640 -88
  47. package/framework/standards/infrastructure/vercel/vercel-database.md +106 -0
  48. package/framework/templates/REGISTRY.json +1825 -1909
  49. package/framework/templates/context/CONTEXT-FEATURE.md +276 -276
  50. package/framework/templates/docs/onboarding.md +1 -5
  51. package/package.json +2 -6
  52. package/src/commands/agents/dispatch-agents.js +55 -4
  53. package/src/commands/project/doctor.js +16 -47
  54. package/src/commands/project/init.js +1 -1
  55. package/src/commands/project/status.js +2 -2
  56. package/src/commands/project/update.js +381 -365
  57. package/src/commands/project/worktree.js +154 -0
  58. package/src/commands/state/advance-phase.js +120 -30
  59. package/src/commands/state/approve.js +2 -2
  60. package/src/commands/state/index.js +7 -8
  61. package/src/commands/state/phase-runner.js +1 -1
  62. package/src/commands/state/state.js +61 -6
  63. package/src/commands/tasks/task.js +78 -99
  64. package/src/commands/templates/template-render.js +93 -173
  65. package/src/commands/trust/trust.js +26 -21
  66. package/src/core/paths/output-schema.js +15 -0
  67. package/src/core/state/state-manager.js +28 -54
  68. package/src/core/workflows/workflow-detector.js +9 -87
  69. package/src/lib/phase-chain/phase-validator.js +330 -0
  70. package/src/lib/stack/stack-profile.js +88 -0
  71. package/src/lib/tasks/task-classifier.js +16 -0
  72. package/src/lib/tasks/test-runner.js +77 -0
  73. package/src/lib/trust/trust-manager.js +32 -144
  74. package/src/lib/validators/spec-validator.js +58 -4
  75. package/src/lib/validators/validation-runner.js +23 -11
  76. package/src/scripts/setup-infra.js +240 -224
  77. package/src/utils/agents-installer.js +2 -2
  78. package/src/utils/banner.js +1 -1
  79. package/src/utils/claude-settings-manager.js +1 -1
  80. package/src/utils/file-copier.js +1 -0
  81. package/src/utils/hooks-installer.js +258 -8
  82. package/framework/hooks/dev/check-sync-health.js +0 -117
  83. package/framework/hooks/dev/guard-version-numbers.js +0 -57
  84. package/framework/hooks/dev/sync-standards-registry.js +0 -60
  85. package/framework/hooks/dev/sync-template-registry.js +0 -60
  86. package/framework/hooks/dev/validate-skill-format.js +0 -70
  87. package/framework/hooks/dev/validate-standard-format.js +0 -73
  88. package/framework/templates/meta-prompts/hops/hop-retry.md +0 -78
  89. package/framework/templates/meta-prompts/hops/hop-validation.md +0 -97
  90. package/framework/templates/meta-prompts/hops/hop-wrapper.md +0 -36
  91. package/framework/workflows/configs/design-impl.json +0 -49
  92. package/framework/workflows/configs/express.json +0 -45
  93. package/framework/workflows/configs/fast-track.json +0 -42
  94. package/framework/workflows/configs/full-morph.json +0 -79
  95. package/framework/workflows/configs/fusion.json +0 -39
  96. package/framework/workflows/configs/long-running.json +0 -33
  97. package/framework/workflows/configs/spec-only.json +0 -43
  98. package/framework/workflows/configs/ui-refresh.json +0 -49
  99. package/framework/workflows/configs/zero-touch.json +0 -82
  100. package/src/commands/project/monitor.js +0 -295
  101. package/src/commands/project/tutorial.js +0 -115
  102. package/src/commands/state/validate-phase.js +0 -238
  103. package/src/commands/templates/generate-contracts.js +0 -445
  104. package/src/core/orchestrator.js +0 -171
  105. package/src/core/registry/command-registry.js +0 -28
  106. package/src/core/registry/index.js +0 -8
  107. package/src/core/registry/validator-registry.js +0 -204
  108. package/src/core/templates/template-validator.js +0 -296
  109. package/src/generator/config-generator.js +0 -206
  110. package/src/generator/templates/config.json.template +0 -40
  111. package/src/generator/templates/project.md.template +0 -67
  112. package/src/lib/agents/micro-agent-factory.js +0 -161
  113. package/src/lib/analysis/complexity-analyzer.js +0 -441
  114. package/src/lib/analysis/index.js +0 -7
  115. package/src/lib/analytics/analytics-engine.js +0 -345
  116. package/src/lib/checkpoints/checkpoint-hooks.js +0 -298
  117. package/src/lib/checkpoints/index.js +0 -7
  118. package/src/lib/context/context-bundler.js +0 -241
  119. package/src/lib/context/context-optimizer.js +0 -212
  120. package/src/lib/context/context-tracker.js +0 -273
  121. package/src/lib/context/core-four-tracker.js +0 -201
  122. package/src/lib/context/mcp-optimizer.js +0 -200
  123. package/src/lib/execution/fusion-executor.js +0 -304
  124. package/src/lib/execution/parallel-executor.js +0 -270
  125. package/src/lib/hooks/stop-hook-executor.js +0 -286
  126. package/src/lib/hops/hop-composer.js +0 -221
  127. package/src/lib/phase-chain/eligibility-checker.js +0 -243
  128. package/src/lib/threads/thread-coordinator.js +0 -238
  129. package/src/lib/threads/thread-manager.js +0 -317
  130. package/src/lib/tracking/artifact-trail.js +0 -202
  131. package/src/scanner/project-scanner.js +0 -242
  132. package/src/ui/diff-display.js +0 -91
  133. package/src/ui/interactive-wizard.js +0 -96
  134. package/src/ui/user-review.js +0 -211
  135. package/src/ui/wizard-questions.js +0 -188
  136. package/src/utils/color-utils.js +0 -70
  137. package/src/utils/process-handler.js +0 -97
@@ -1,241 +0,0 @@
1
- /**
2
- * Context Bundler — Checkpoint compression (180K → 15K)
3
- *
4
- * Compresses checkpoint state into a compact bundle for session resumption.
5
- * Saves bundles to .morph/bundles/{bundleId}.json
6
- *
7
- * A bundle contains:
8
- * - decisions[]: key architectural decisions made
9
- * - artifacts[]: paths to important generated files
10
- * - nextSteps[]: what to implement next
11
- * - metadata: original vs bundled token counts
12
- */
13
-
14
- import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
15
- import { join } from 'path';
16
- import { getOutputPath } from '../../core/paths/output-schema.js';
17
- import { randomUUID } from 'crypto';
18
-
19
- const BUNDLES_DIR = join(process.cwd(), '.morph/bundles');
20
-
21
- // ============================================================================
22
- // Bundle Creation
23
- // ============================================================================
24
-
25
- /**
26
- * Create a context bundle from checkpoint data
27
- * @param {Object} opts
28
- * @param {string} opts.feature - Feature name
29
- * @param {number} opts.checkpointNum - Checkpoint number this bundle captures
30
- * @param {Array} opts.decisions - Key decisions made: [{ id, title, summary }]
31
- * @param {Array} opts.artifacts - Important file paths: [{ path, description }]
32
- * @param {Array} opts.nextSteps - Next tasks to implement: [string]
33
- * @param {number} [opts.originalTokens=180000] - Estimated original context size
34
- * @param {Object} [opts.meta] - Additional metadata
35
- * @returns {Object} Bundle object with ID
36
- */
37
- export function createBundle({
38
- feature,
39
- checkpointNum,
40
- decisions = [],
41
- artifacts = [],
42
- nextSteps = [],
43
- originalTokens = 180000,
44
- meta = {}
45
- }) {
46
- const bundleId = `${feature}-cp${checkpointNum}-${randomUUID().substring(0, 8)}`;
47
- const now = new Date().toISOString();
48
-
49
- // Estimate bundle size (decisions + artifacts + nextSteps summary)
50
- const bundledContent = JSON.stringify({ decisions, artifacts, nextSteps, meta });
51
- const bundledTokens = Math.round(bundledContent.length / 4); // ~4 chars/token
52
-
53
- const bundle = {
54
- bundleId,
55
- feature,
56
- checkpointNum,
57
- createdAt: now,
58
- decisions,
59
- artifacts,
60
- nextSteps,
61
- meta,
62
- tokenMetrics: {
63
- originalTokens,
64
- bundledTokens,
65
- compressionRatio: Math.round(originalTokens / Math.max(bundledTokens, 1)),
66
- savingsTokens: originalTokens - bundledTokens
67
- },
68
- resumeInstructions: buildResumeInstructions(feature, checkpointNum, decisions, nextSteps)
69
- };
70
-
71
- return bundle;
72
- }
73
-
74
- /**
75
- * Save a bundle to disk
76
- * @param {Object} bundle - Bundle object (from createBundle)
77
- * @returns {string} Path to saved bundle file
78
- */
79
- export function saveBundle(bundle) {
80
- if (!existsSync(BUNDLES_DIR)) {
81
- mkdirSync(BUNDLES_DIR, { recursive: true });
82
- }
83
-
84
- const filePath = join(BUNDLES_DIR, `${bundle.bundleId}.json`);
85
- writeFileSync(filePath, JSON.stringify(bundle, null, 2), 'utf8');
86
-
87
- // Also update feature state with bundle reference
88
- try {
89
- const statePath = join(process.cwd(), '.morph/state.json');
90
- if (existsSync(statePath)) {
91
- const state = JSON.parse(readFileSync(statePath, 'utf8'));
92
- if (state.features?.[bundle.feature]) {
93
- state.features[bundle.feature].contextBundles = state.features[bundle.feature].contextBundles || [];
94
- state.features[bundle.feature].contextBundles.push({
95
- bundleId: bundle.bundleId,
96
- checkpointNum: bundle.checkpointNum,
97
- createdAt: bundle.createdAt,
98
- originalTokens: bundle.tokenMetrics.originalTokens,
99
- bundledTokens: bundle.tokenMetrics.bundledTokens,
100
- path: filePath
101
- });
102
- state.metadata = state.metadata || {};
103
- state.metadata.lastUpdated = new Date().toISOString();
104
- writeFileSync(statePath, JSON.stringify(state, null, 2), 'utf8');
105
- }
106
- }
107
- } catch {
108
- // Non-fatal if state update fails
109
- }
110
-
111
- return filePath;
112
- }
113
-
114
- /**
115
- * Load a bundle from disk
116
- * @param {string} bundleId - Bundle ID
117
- * @returns {Object|null} Bundle object or null if not found
118
- */
119
- export function loadBundle(bundleId) {
120
- const filePath = join(BUNDLES_DIR, `${bundleId}.json`);
121
-
122
- if (!existsSync(filePath)) {
123
- return null;
124
- }
125
-
126
- try {
127
- return JSON.parse(readFileSync(filePath, 'utf8'));
128
- } catch {
129
- return null;
130
- }
131
- }
132
-
133
- /**
134
- * List all bundles, optionally filtered by feature
135
- * @param {string} [feature] - Filter by feature name
136
- * @returns {Array} Array of bundle summaries
137
- */
138
- export function listBundles(feature = null) {
139
- if (!existsSync(BUNDLES_DIR)) return [];
140
-
141
- const files = readdirSync(BUNDLES_DIR).filter(f => f.endsWith('.json'));
142
- const bundles = [];
143
-
144
- for (const file of files) {
145
- try {
146
- const bundle = JSON.parse(readFileSync(join(BUNDLES_DIR, file), 'utf8'));
147
- if (!feature || bundle.feature === feature) {
148
- bundles.push({
149
- bundleId: bundle.bundleId,
150
- feature: bundle.feature,
151
- checkpointNum: bundle.checkpointNum,
152
- createdAt: bundle.createdAt,
153
- originalTokens: bundle.tokenMetrics?.originalTokens,
154
- bundledTokens: bundle.tokenMetrics?.bundledTokens,
155
- compressionRatio: bundle.tokenMetrics?.compressionRatio,
156
- nextStepsCount: bundle.nextSteps?.length || 0
157
- });
158
- }
159
- } catch {
160
- // Skip malformed files
161
- }
162
- }
163
-
164
- return bundles.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
165
- }
166
-
167
- /**
168
- * Get the latest bundle for a feature at or before a checkpoint number
169
- * @param {string} feature - Feature name
170
- * @param {number} [checkpointNum] - Target checkpoint (latest if not specified)
171
- * @returns {Object|null} Bundle or null
172
- */
173
- export function getLatestBundle(feature, checkpointNum = Infinity) {
174
- const bundles = listBundles(feature)
175
- .filter(b => b.checkpointNum <= checkpointNum)
176
- .sort((a, b) => b.checkpointNum - a.checkpointNum);
177
-
178
- if (bundles.length === 0) return null;
179
- return loadBundle(bundles[0].bundleId);
180
- }
181
-
182
- // ============================================================================
183
- // Session Replay
184
- // ============================================================================
185
-
186
- /**
187
- * Generate minimal context for session replay from a bundle
188
- * @param {Object} bundle - Bundle object
189
- * @returns {string} Compact context string (~15K tokens) for session resumption
190
- */
191
- export function generateResumeContext(bundle) {
192
- const lines = [];
193
- lines.push(`# Session Resume — ${bundle.feature} @ Checkpoint ${bundle.checkpointNum}`);
194
- lines.push(`> Bundle ID: ${bundle.bundleId} | Created: ${bundle.createdAt}`);
195
- lines.push(`> Context compression: ${bundle.tokenMetrics?.originalTokens?.toLocaleString()} → ${bundle.tokenMetrics?.bundledTokens?.toLocaleString()} tokens`);
196
- lines.push('');
197
-
198
- if (bundle.decisions?.length > 0) {
199
- lines.push('## Key Decisions Made');
200
- for (const d of bundle.decisions) {
201
- lines.push(`- **${d.id || ''}${d.id ? ':' : ''} ${d.title}** — ${d.summary}`);
202
- if (d.fullPath) lines.push(` *(Full: ${d.fullPath})*`);
203
- }
204
- lines.push('');
205
- }
206
-
207
- if (bundle.artifacts?.length > 0) {
208
- lines.push('## Created Artifacts');
209
- for (const a of bundle.artifacts) {
210
- lines.push(`- \`${a.path}\` — ${a.description || ''}`);
211
- }
212
- lines.push('');
213
- }
214
-
215
- if (bundle.nextSteps?.length > 0) {
216
- lines.push('## Next Steps (continue from here)');
217
- bundle.nextSteps.forEach((step, i) => {
218
- lines.push(`${i + 1}. ${step}`);
219
- });
220
- lines.push('');
221
- }
222
-
223
- lines.push(bundle.resumeInstructions || '');
224
-
225
- return lines.join('\n');
226
- }
227
-
228
- // ============================================================================
229
- // Helpers
230
- // ============================================================================
231
-
232
- function buildResumeInstructions(feature, checkpointNum, decisions, nextSteps) {
233
- return `## Resume Instructions
234
-
235
- 1. Load minimal standards: run \`morph-spec prime feature\`
236
- 2. Read spec: \`${getOutputPath(feature, 'spec')}\` (key sections only)
237
- 3. Check tasks: \`morph-spec state get ${feature}\`
238
- 4. Continue from: ${nextSteps[0] || `task after checkpoint ${checkpointNum}`}
239
-
240
- > This bundle was created at checkpoint ${checkpointNum}. All decisions above are final.`;
241
- }
@@ -1,212 +0,0 @@
1
- /**
2
- * Context Optimizer — Selective context loading strategy
3
- *
4
- * Provides intelligent recommendations for reducing context window usage:
5
- * - selectStandards: pick only relevant standards for a feature type
6
- * - selectTemplates: pick only relevant templates
7
- * - suggestOptimizations: compare current vs optimal context, return savings
8
- *
9
- * Connects to standards resolver and template registry.
10
- */
11
-
12
- import { readFileSync, existsSync } from 'fs';
13
- import { join } from 'path';
14
-
15
- const STANDARDS_DIR = join(process.cwd(), 'framework/standards');
16
- const TEMPLATES_REGISTRY = join(process.cwd(), 'framework/templates/REGISTRY.json');
17
-
18
- // Average token cost estimates per file type
19
- const TOKEN_ESTIMATES = {
20
- standard_file: 2000,
21
- template_file: 1500,
22
- claude_md: 23000,
23
- spec_file: 8000,
24
- decisions_file: 3000
25
- };
26
-
27
- // Feature type → relevant standards mapping
28
- const STANDARDS_BY_FEATURE_TYPE = {
29
- backend: [
30
- 'coding.md', 'architecture.md', 'dotnet10-compatibility.md',
31
- 'integration/api/rest-design.md'
32
- ],
33
- frontend: [
34
- 'coding.md', 'blazor-components.md', 'blazor-state.md',
35
- 'css-architecture.md', 'css-design-system.md'
36
- ],
37
- database: [
38
- 'coding.md', 'ef-core.md', 'architecture.md'
39
- ],
40
- infrastructure: [
41
- 'azure.md', 'bicep.md', 'devops.md'
42
- ],
43
- authentication: [
44
- 'coding.md', 'architecture.md', 'dotnet10-compatibility.md',
45
- 'integration/api/rest-design.md'
46
- ],
47
- fullstack: [
48
- 'coding.md', 'architecture.md', 'blazor-components.md',
49
- 'ef-core.md', 'dotnet10-compatibility.md'
50
- ],
51
- observability: [
52
- 'observability/monitoring.md', 'observability/logging.md',
53
- 'observability/tracing.md', 'observability/metrics.md'
54
- ],
55
- event_driven: [
56
- 'integration/event-driven/service-bus.md',
57
- 'integration/event-driven/cqrs.md'
58
- ]
59
- };
60
-
61
- // ============================================================================
62
- // Standards Selection
63
- // ============================================================================
64
-
65
- /**
66
- * Select minimal relevant standards for a given feature type
67
- * @param {string} featureType - Feature type keyword
68
- * @param {Object} [opts]
69
- * @param {string[]} [opts.extraKeywords] - Additional keywords for selection
70
- * @returns {Object} { selected: string[], skipped: string[], estimatedTokens: number }
71
- */
72
- export function selectStandards(featureType, { extraKeywords = [] } = {}) {
73
- const typeKey = detectFeatureCategory(featureType, extraKeywords);
74
- const selected = STANDARDS_BY_FEATURE_TYPE[typeKey] || STANDARDS_BY_FEATURE_TYPE.fullstack;
75
-
76
- // Check which selected files actually exist
77
- const existing = selected.filter(f => {
78
- const fullPath = join(STANDARDS_DIR, f);
79
- return existsSync(fullPath);
80
- });
81
-
82
- // Estimate all standard files count for skipped calculation
83
- const allStandards = getAllStandardsCount();
84
- const skippedCount = allStandards - existing.length;
85
-
86
- return {
87
- selected: existing,
88
- skipped: skippedCount,
89
- featureType: typeKey,
90
- estimatedTokens: existing.length * TOKEN_ESTIMATES.standard_file,
91
- fullLoadTokens: allStandards * TOKEN_ESTIMATES.standard_file,
92
- savings: skippedCount * TOKEN_ESTIMATES.standard_file
93
- };
94
- }
95
-
96
- /**
97
- * Select relevant templates for a feature type
98
- * @param {string} featureType - Feature type keyword
99
- * @returns {Object} { selected: string[], estimatedTokens: number }
100
- */
101
- export function selectTemplates(featureType) {
102
- const TEMPLATES_BY_TYPE = {
103
- backend: ['dotnet-backend-service', 'dotnet-repository', 'dotnet-api-contracts'],
104
- frontend: ['dotnet-blazor-component', 'dotnet-design-system'],
105
- database: ['dotnet-migration', 'sql-migration'],
106
- infrastructure: ['azure-container-app', 'azure-key-vault', 'azure-main-bicep'],
107
- fullstack: ['dotnet-backend-service', 'dotnet-blazor-component', 'dotnet-migration']
108
- };
109
-
110
- const typeKey = detectFeatureCategory(featureType, []);
111
- const selected = TEMPLATES_BY_TYPE[typeKey] || TEMPLATES_BY_TYPE.fullstack;
112
-
113
- // Load registry to get full template count
114
- let totalTemplates = 50;
115
- try {
116
- const registry = JSON.parse(readFileSync(TEMPLATES_REGISTRY, 'utf8'));
117
- totalTemplates = (registry.templates || []).length;
118
- } catch {
119
- // Use estimate
120
- }
121
-
122
- return {
123
- selected,
124
- skipped: totalTemplates - selected.length,
125
- estimatedTokens: selected.length * TOKEN_ESTIMATES.template_file,
126
- fullLoadTokens: totalTemplates * TOKEN_ESTIMATES.template_file,
127
- savings: (totalTemplates - selected.length) * TOKEN_ESTIMATES.template_file
128
- };
129
- }
130
-
131
- /**
132
- * Suggest context optimizations based on current vs optimal load
133
- * @param {Object} current - Current context state
134
- * @param {number} current.totalTokens - Current token count
135
- * @param {number} current.standardsCount - Number of standards currently loaded
136
- * @param {number} current.templatesCount - Number of templates currently loaded
137
- * @param {string} featureType - Feature type for optimal selection
138
- * @returns {Object} Optimization suggestions with savings estimates
139
- */
140
- export function suggestOptimizations(current, featureType) {
141
- const optimalStandards = selectStandards(featureType);
142
- const optimalTemplates = selectTemplates(featureType);
143
- const suggestions = [];
144
-
145
- // Claude.md optimization
146
- if (current.totalTokens > 50000) {
147
- suggestions.push({
148
- type: 'priming_file',
149
- title: 'Use priming file instead of full CLAUDE.md',
150
- description: 'Replace 23K token CLAUDE.md with a 500-token priming file',
151
- savings: TOKEN_ESTIMATES.claude_md - 500,
152
- priority: 'high',
153
- command: 'morph-spec prime feature'
154
- });
155
- }
156
-
157
- // Standards optimization
158
- if (current.standardsCount > optimalStandards.selected.length + 3) {
159
- suggestions.push({
160
- type: 'standards_subset',
161
- title: `Load only ${optimalStandards.selected.length} relevant standards`,
162
- description: `Currently loading ${current.standardsCount} standards. Only ${optimalStandards.selected.length} are needed for ${featureType} features.`,
163
- savings: optimalStandards.savings,
164
- priority: 'medium',
165
- selectedStandards: optimalStandards.selected
166
- });
167
- }
168
-
169
- // Context bundle for large sessions
170
- if (current.totalTokens > 100000) {
171
- suggestions.push({
172
- type: 'context_bundle',
173
- title: 'Create context bundle checkpoint',
174
- description: 'Compress current context (180K → ~15K tokens) for session resume',
175
- savings: current.totalTokens - 15000,
176
- priority: 'critical',
177
- command: 'morph-spec bundle create'
178
- });
179
- }
180
-
181
- const totalSavings = suggestions.reduce((sum, s) => sum + s.savings, 0);
182
- const optimizedTokens = Math.max(current.totalTokens - totalSavings, 5000);
183
-
184
- return {
185
- currentTokens: current.totalTokens,
186
- optimizedTokens,
187
- totalSavings,
188
- savingsPercent: Math.round(totalSavings / current.totalTokens * 100),
189
- suggestions: suggestions.sort((a, b) => b.savings - a.savings)
190
- };
191
- }
192
-
193
- // ============================================================================
194
- // Helpers
195
- // ============================================================================
196
-
197
- function detectFeatureCategory(featureType, extraKeywords) {
198
- const text = (featureType + ' ' + extraKeywords.join(' ')).toLowerCase();
199
-
200
- if (/auth|login|jwt|oauth|identity/.test(text)) return 'authentication';
201
- if (/blazor|frontend|ui|component|razor/.test(text)) return 'frontend';
202
- if (/migration|ef.core|database|entity/.test(text)) return 'database';
203
- if (/bicep|azure|infra|container|devops/.test(text)) return 'infrastructure';
204
- if (/service.bus|cqrs|event.sourcing|pub.sub/.test(text)) return 'event_driven';
205
- if (/monitor|logging|trace|metric|appinsight/.test(text)) return 'observability';
206
- if (/api|endpoint|controller|rest/.test(text)) return 'backend';
207
- return 'fullstack';
208
- }
209
-
210
- function getAllStandardsCount() {
211
- return 30; // Known approximate count
212
- }