@polymorphism-tech/morph-spec 4.2.0 → 4.3.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 (132) hide show
  1. package/bin/morph-spec.js +283 -8
  2. package/bin/validate.js +4 -4
  3. package/docs/{v3.0 → next-generation}/AGENTS.md +1 -1
  4. package/docs/next-generation/CONTEXT-OPTIMIZATION.md +267 -0
  5. package/docs/next-generation/EXECUTION-FLOW.md +274 -0
  6. package/docs/next-generation/META-PROMPTS.md +235 -0
  7. package/docs/next-generation/MIGRATION-GUIDE.md +253 -0
  8. package/docs/next-generation/THREAD-MANAGEMENT.md +240 -0
  9. package/package.json +5 -5
  10. package/src/commands/agents/agents-fuse.js +96 -0
  11. package/src/commands/agents/micro-agent.js +112 -0
  12. package/src/commands/agents/spawn-team.js +69 -4
  13. package/src/commands/agents/squad-template.js +146 -0
  14. package/src/commands/analytics/analytics.js +176 -0
  15. package/src/commands/context/context-prime.js +63 -0
  16. package/src/commands/context/core-four.js +54 -0
  17. package/src/commands/mcp/mcp.js +102 -0
  18. package/src/commands/project/detect-agents.js +1 -1
  19. package/src/commands/project/doctor.js +573 -356
  20. package/src/commands/project/init.js +1 -1
  21. package/src/commands/project/update.js +1 -1
  22. package/src/commands/state/advance-phase.js +433 -416
  23. package/src/commands/templates/template-render.js +80 -1
  24. package/src/commands/threads/thread-template.js +103 -0
  25. package/src/commands/threads/threads.js +261 -0
  26. package/src/commands/trust/trust.js +205 -0
  27. package/src/{orchestrator.js → core/orchestrator.js} +8 -8
  28. package/src/core/state/state-manager.js +18 -2
  29. package/src/core/workflows/workflow-detector.js +100 -2
  30. package/src/lib/agents/micro-agent-factory.js +161 -0
  31. package/src/lib/analytics/analytics-engine.js +345 -0
  32. package/src/lib/checkpoints/checkpoint-hooks.js +293 -258
  33. package/src/lib/context/context-bundler.js +240 -0
  34. package/src/lib/context/context-optimizer.js +212 -0
  35. package/src/lib/context/context-tracker.js +273 -0
  36. package/src/lib/context/core-four-tracker.js +201 -0
  37. package/src/lib/context/mcp-optimizer.js +200 -0
  38. package/src/lib/execution/fusion-executor.js +304 -0
  39. package/src/lib/execution/parallel-executor.js +270 -0
  40. package/src/lib/generators/context-generator.js +3 -3
  41. package/src/lib/generators/recap-generator.js +2 -2
  42. package/src/lib/hooks/hook-executor.js +169 -0
  43. package/src/lib/hooks/stop-hook-executor.js +286 -0
  44. package/src/lib/hops/hop-composer.js +221 -0
  45. package/src/lib/threads/thread-coordinator.js +238 -0
  46. package/src/lib/threads/thread-manager.js +317 -0
  47. package/src/lib/tracking/artifact-trail.js +202 -0
  48. package/src/lib/trust/trust-manager.js +269 -0
  49. package/src/lib/validators/design-system/design-system-validator.js +2 -2
  50. package/src/lib/validators/validation-runner.js +6 -6
  51. package/stacks/blazor-azure/.morph/config/agents.json +72 -3
  52. package/stacks/nextjs-supabase/.morph/config/agents.json +3 -3
  53. package/CLAUDE.md +0 -993
  54. package/docs/llm-interaction-config.md +0 -735
  55. package/docs/v3.0/EXECUTION-FLOW.md +0 -1304
  56. package/src/commands/utils/migrate-state.js +0 -158
  57. package/src/commands/utils/upgrade.js +0 -346
  58. package/src/lib/validators/architecture-validator.js +0 -60
  59. package/src/lib/validators/content-validator.js +0 -164
  60. package/src/lib/validators/package-validator.js +0 -61
  61. package/src/lib/validators/ui-contrast-validator.js +0 -44
  62. package/stacks/blazor-azure/.claude/commands/morph-apply.md +0 -221
  63. package/stacks/blazor-azure/.claude/commands/morph-archive.md +0 -79
  64. package/stacks/blazor-azure/.claude/commands/morph-deploy.md +0 -529
  65. package/stacks/blazor-azure/.claude/commands/morph-infra.md +0 -209
  66. package/stacks/blazor-azure/.claude/commands/morph-preflight.md +0 -227
  67. package/stacks/blazor-azure/.claude/commands/morph-proposal.md +0 -122
  68. package/stacks/blazor-azure/.claude/commands/morph-status.md +0 -86
  69. package/stacks/blazor-azure/.claude/commands/morph-troubleshoot.md +0 -122
  70. package/stacks/blazor-azure/.claude/skills/level-0-meta/README.md +0 -7
  71. package/stacks/blazor-azure/.claude/skills/level-0-meta/code-review.md +0 -226
  72. package/stacks/blazor-azure/.claude/skills/level-0-meta/morph-checklist.md +0 -117
  73. package/stacks/blazor-azure/.claude/skills/level-0-meta/simulation-checklist.md +0 -77
  74. package/stacks/blazor-azure/.claude/skills/level-1-workflows/README.md +0 -7
  75. package/stacks/blazor-azure/.claude/skills/level-1-workflows/morph-replicate.md +0 -213
  76. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-clarify.md +0 -131
  77. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-design.md +0 -213
  78. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-setup.md +0 -106
  79. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-tasks.md +0 -164
  80. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-uiux.md +0 -169
  81. package/stacks/blazor-azure/.claude/skills/level-2-domains/README.md +0 -14
  82. package/stacks/blazor-azure/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -192
  83. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -197
  84. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -189
  85. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -320
  86. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -156
  87. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/api-designer.md +0 -59
  88. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -77
  89. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -58
  90. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -126
  91. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -45
  92. package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -210
  93. package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -154
  94. package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -191
  95. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -142
  96. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -699
  97. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -126
  98. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -131
  99. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -119
  100. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -130
  101. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -142
  102. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -108
  103. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/hangfire-orchestrator.md +0 -64
  104. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/resend-email.md +0 -119
  105. package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -235
  106. package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -126
  107. package/stacks/blazor-azure/.claude/skills/level-3-technologies/README.md +0 -7
  108. package/stacks/blazor-azure/.claude/skills/level-4-patterns/README.md +0 -7
  109. package/stacks/blazor-azure/.morph/archive/.gitkeep +0 -25
  110. package/stacks/blazor-azure/.morph/features/.gitkeep +0 -25
  111. package/stacks/blazor-azure/.morph/schemas/agent.schema.json +0 -296
  112. package/stacks/blazor-azure/.morph/schemas/tasks.schema.json +0 -220
  113. package/stacks/blazor-azure/.morph/specs/.gitkeep +0 -20
  114. package/stacks/blazor-azure/.morph/test-infra/example.bicep +0 -59
  115. package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +0 -221
  116. package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +0 -79
  117. package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +0 -529
  118. package/stacks/nextjs-supabase/.claude/commands/morph-infra.md +0 -209
  119. package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +0 -227
  120. package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +0 -122
  121. package/stacks/nextjs-supabase/.claude/commands/morph-status.md +0 -86
  122. package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +0 -122
  123. package/stacks/nextjs-supabase/.claude/settings.local.json +0 -6
  124. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +0 -244
  125. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +0 -335
  126. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +0 -189
  127. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +0 -50
  128. /package/docs/{v3.0 → next-generation}/ANALYSIS.md +0 -0
  129. /package/docs/{v3.0 → next-generation}/ARCHITECTURE.md +0 -0
  130. /package/docs/{v3.0 → next-generation}/FEATURES.md +0 -0
  131. /package/docs/{v3.0 → next-generation}/README.md +0 -0
  132. /package/docs/{v3.0 → next-generation}/ROADMAP.md +0 -0
@@ -0,0 +1,240 @@
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 { randomUUID } from 'crypto';
17
+
18
+ const BUNDLES_DIR = join(process.cwd(), '.morph/bundles');
19
+
20
+ // ============================================================================
21
+ // Bundle Creation
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Create a context bundle from checkpoint data
26
+ * @param {Object} opts
27
+ * @param {string} opts.feature - Feature name
28
+ * @param {number} opts.checkpointNum - Checkpoint number this bundle captures
29
+ * @param {Array} opts.decisions - Key decisions made: [{ id, title, summary }]
30
+ * @param {Array} opts.artifacts - Important file paths: [{ path, description }]
31
+ * @param {Array} opts.nextSteps - Next tasks to implement: [string]
32
+ * @param {number} [opts.originalTokens=180000] - Estimated original context size
33
+ * @param {Object} [opts.meta] - Additional metadata
34
+ * @returns {Object} Bundle object with ID
35
+ */
36
+ export function createBundle({
37
+ feature,
38
+ checkpointNum,
39
+ decisions = [],
40
+ artifacts = [],
41
+ nextSteps = [],
42
+ originalTokens = 180000,
43
+ meta = {}
44
+ }) {
45
+ const bundleId = `${feature}-cp${checkpointNum}-${randomUUID().substring(0, 8)}`;
46
+ const now = new Date().toISOString();
47
+
48
+ // Estimate bundle size (decisions + artifacts + nextSteps summary)
49
+ const bundledContent = JSON.stringify({ decisions, artifacts, nextSteps, meta });
50
+ const bundledTokens = Math.round(bundledContent.length / 4); // ~4 chars/token
51
+
52
+ const bundle = {
53
+ bundleId,
54
+ feature,
55
+ checkpointNum,
56
+ createdAt: now,
57
+ decisions,
58
+ artifacts,
59
+ nextSteps,
60
+ meta,
61
+ tokenMetrics: {
62
+ originalTokens,
63
+ bundledTokens,
64
+ compressionRatio: Math.round(originalTokens / Math.max(bundledTokens, 1)),
65
+ savingsTokens: originalTokens - bundledTokens
66
+ },
67
+ resumeInstructions: buildResumeInstructions(feature, checkpointNum, decisions, nextSteps)
68
+ };
69
+
70
+ return bundle;
71
+ }
72
+
73
+ /**
74
+ * Save a bundle to disk
75
+ * @param {Object} bundle - Bundle object (from createBundle)
76
+ * @returns {string} Path to saved bundle file
77
+ */
78
+ export function saveBundle(bundle) {
79
+ if (!existsSync(BUNDLES_DIR)) {
80
+ mkdirSync(BUNDLES_DIR, { recursive: true });
81
+ }
82
+
83
+ const filePath = join(BUNDLES_DIR, `${bundle.bundleId}.json`);
84
+ writeFileSync(filePath, JSON.stringify(bundle, null, 2), 'utf8');
85
+
86
+ // Also update feature state with bundle reference
87
+ try {
88
+ const statePath = join(process.cwd(), '.morph/state.json');
89
+ if (existsSync(statePath)) {
90
+ const state = JSON.parse(readFileSync(statePath, 'utf8'));
91
+ if (state.features?.[bundle.feature]) {
92
+ state.features[bundle.feature].contextBundles = state.features[bundle.feature].contextBundles || [];
93
+ state.features[bundle.feature].contextBundles.push({
94
+ bundleId: bundle.bundleId,
95
+ checkpointNum: bundle.checkpointNum,
96
+ createdAt: bundle.createdAt,
97
+ originalTokens: bundle.tokenMetrics.originalTokens,
98
+ bundledTokens: bundle.tokenMetrics.bundledTokens,
99
+ path: filePath
100
+ });
101
+ state.metadata = state.metadata || {};
102
+ state.metadata.lastUpdated = new Date().toISOString();
103
+ writeFileSync(statePath, JSON.stringify(state, null, 2), 'utf8');
104
+ }
105
+ }
106
+ } catch {
107
+ // Non-fatal if state update fails
108
+ }
109
+
110
+ return filePath;
111
+ }
112
+
113
+ /**
114
+ * Load a bundle from disk
115
+ * @param {string} bundleId - Bundle ID
116
+ * @returns {Object|null} Bundle object or null if not found
117
+ */
118
+ export function loadBundle(bundleId) {
119
+ const filePath = join(BUNDLES_DIR, `${bundleId}.json`);
120
+
121
+ if (!existsSync(filePath)) {
122
+ return null;
123
+ }
124
+
125
+ try {
126
+ return JSON.parse(readFileSync(filePath, 'utf8'));
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * List all bundles, optionally filtered by feature
134
+ * @param {string} [feature] - Filter by feature name
135
+ * @returns {Array} Array of bundle summaries
136
+ */
137
+ export function listBundles(feature = null) {
138
+ if (!existsSync(BUNDLES_DIR)) return [];
139
+
140
+ const files = readdirSync(BUNDLES_DIR).filter(f => f.endsWith('.json'));
141
+ const bundles = [];
142
+
143
+ for (const file of files) {
144
+ try {
145
+ const bundle = JSON.parse(readFileSync(join(BUNDLES_DIR, file), 'utf8'));
146
+ if (!feature || bundle.feature === feature) {
147
+ bundles.push({
148
+ bundleId: bundle.bundleId,
149
+ feature: bundle.feature,
150
+ checkpointNum: bundle.checkpointNum,
151
+ createdAt: bundle.createdAt,
152
+ originalTokens: bundle.tokenMetrics?.originalTokens,
153
+ bundledTokens: bundle.tokenMetrics?.bundledTokens,
154
+ compressionRatio: bundle.tokenMetrics?.compressionRatio,
155
+ nextStepsCount: bundle.nextSteps?.length || 0
156
+ });
157
+ }
158
+ } catch {
159
+ // Skip malformed files
160
+ }
161
+ }
162
+
163
+ return bundles.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
164
+ }
165
+
166
+ /**
167
+ * Get the latest bundle for a feature at or before a checkpoint number
168
+ * @param {string} feature - Feature name
169
+ * @param {number} [checkpointNum] - Target checkpoint (latest if not specified)
170
+ * @returns {Object|null} Bundle or null
171
+ */
172
+ export function getLatestBundle(feature, checkpointNum = Infinity) {
173
+ const bundles = listBundles(feature)
174
+ .filter(b => b.checkpointNum <= checkpointNum)
175
+ .sort((a, b) => b.checkpointNum - a.checkpointNum);
176
+
177
+ if (bundles.length === 0) return null;
178
+ return loadBundle(bundles[0].bundleId);
179
+ }
180
+
181
+ // ============================================================================
182
+ // Session Replay
183
+ // ============================================================================
184
+
185
+ /**
186
+ * Generate minimal context for session replay from a bundle
187
+ * @param {Object} bundle - Bundle object
188
+ * @returns {string} Compact context string (~15K tokens) for session resumption
189
+ */
190
+ export function generateResumeContext(bundle) {
191
+ const lines = [];
192
+ lines.push(`# Session Resume — ${bundle.feature} @ Checkpoint ${bundle.checkpointNum}`);
193
+ lines.push(`> Bundle ID: ${bundle.bundleId} | Created: ${bundle.createdAt}`);
194
+ lines.push(`> Context compression: ${bundle.tokenMetrics?.originalTokens?.toLocaleString()} → ${bundle.tokenMetrics?.bundledTokens?.toLocaleString()} tokens`);
195
+ lines.push('');
196
+
197
+ if (bundle.decisions?.length > 0) {
198
+ lines.push('## Key Decisions Made');
199
+ for (const d of bundle.decisions) {
200
+ lines.push(`- **${d.id || ''}${d.id ? ':' : ''} ${d.title}** — ${d.summary}`);
201
+ if (d.fullPath) lines.push(` *(Full: ${d.fullPath})*`);
202
+ }
203
+ lines.push('');
204
+ }
205
+
206
+ if (bundle.artifacts?.length > 0) {
207
+ lines.push('## Created Artifacts');
208
+ for (const a of bundle.artifacts) {
209
+ lines.push(`- \`${a.path}\` — ${a.description || ''}`);
210
+ }
211
+ lines.push('');
212
+ }
213
+
214
+ if (bundle.nextSteps?.length > 0) {
215
+ lines.push('## Next Steps (continue from here)');
216
+ bundle.nextSteps.forEach((step, i) => {
217
+ lines.push(`${i + 1}. ${step}`);
218
+ });
219
+ lines.push('');
220
+ }
221
+
222
+ lines.push(bundle.resumeInstructions || '');
223
+
224
+ return lines.join('\n');
225
+ }
226
+
227
+ // ============================================================================
228
+ // Helpers
229
+ // ============================================================================
230
+
231
+ function buildResumeInstructions(feature, checkpointNum, decisions, nextSteps) {
232
+ return `## Resume Instructions
233
+
234
+ 1. Load minimal standards: run \`morph-spec prime feature\`
235
+ 2. Read spec: \`.morph/project/outputs/${feature}/spec.md\` (key sections only)
236
+ 3. Check tasks: \`morph-spec state get ${feature}\`
237
+ 4. Continue from: ${nextSteps[0] || `task after checkpoint ${checkpointNum}`}
238
+
239
+ > This bundle was created at checkpoint ${checkpointNum}. All decisions above are final.`;
240
+ }
@@ -0,0 +1,212 @@
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
+ }