@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.
- package/bin/morph-spec.js +283 -8
- package/bin/validate.js +4 -4
- package/docs/{v3.0 → next-generation}/AGENTS.md +1 -1
- package/docs/next-generation/CONTEXT-OPTIMIZATION.md +267 -0
- package/docs/next-generation/EXECUTION-FLOW.md +274 -0
- package/docs/next-generation/META-PROMPTS.md +235 -0
- package/docs/next-generation/MIGRATION-GUIDE.md +253 -0
- package/docs/next-generation/THREAD-MANAGEMENT.md +240 -0
- package/package.json +5 -5
- package/src/commands/agents/agents-fuse.js +96 -0
- package/src/commands/agents/micro-agent.js +112 -0
- package/src/commands/agents/spawn-team.js +69 -4
- package/src/commands/agents/squad-template.js +146 -0
- package/src/commands/analytics/analytics.js +176 -0
- package/src/commands/context/context-prime.js +63 -0
- package/src/commands/context/core-four.js +54 -0
- package/src/commands/mcp/mcp.js +102 -0
- package/src/commands/project/detect-agents.js +1 -1
- package/src/commands/project/doctor.js +573 -356
- package/src/commands/project/init.js +1 -1
- package/src/commands/project/update.js +1 -1
- package/src/commands/state/advance-phase.js +433 -416
- package/src/commands/templates/template-render.js +80 -1
- package/src/commands/threads/thread-template.js +103 -0
- package/src/commands/threads/threads.js +261 -0
- package/src/commands/trust/trust.js +205 -0
- package/src/{orchestrator.js → core/orchestrator.js} +8 -8
- package/src/core/state/state-manager.js +18 -2
- package/src/core/workflows/workflow-detector.js +100 -2
- package/src/lib/agents/micro-agent-factory.js +161 -0
- package/src/lib/analytics/analytics-engine.js +345 -0
- package/src/lib/checkpoints/checkpoint-hooks.js +293 -258
- package/src/lib/context/context-bundler.js +240 -0
- package/src/lib/context/context-optimizer.js +212 -0
- package/src/lib/context/context-tracker.js +273 -0
- package/src/lib/context/core-four-tracker.js +201 -0
- package/src/lib/context/mcp-optimizer.js +200 -0
- package/src/lib/execution/fusion-executor.js +304 -0
- package/src/lib/execution/parallel-executor.js +270 -0
- package/src/lib/generators/context-generator.js +3 -3
- package/src/lib/generators/recap-generator.js +2 -2
- package/src/lib/hooks/hook-executor.js +169 -0
- package/src/lib/hooks/stop-hook-executor.js +286 -0
- package/src/lib/hops/hop-composer.js +221 -0
- package/src/lib/threads/thread-coordinator.js +238 -0
- package/src/lib/threads/thread-manager.js +317 -0
- package/src/lib/tracking/artifact-trail.js +202 -0
- package/src/lib/trust/trust-manager.js +269 -0
- package/src/lib/validators/design-system/design-system-validator.js +2 -2
- package/src/lib/validators/validation-runner.js +6 -6
- package/stacks/blazor-azure/.morph/config/agents.json +72 -3
- package/stacks/nextjs-supabase/.morph/config/agents.json +3 -3
- package/CLAUDE.md +0 -993
- package/docs/llm-interaction-config.md +0 -735
- package/docs/v3.0/EXECUTION-FLOW.md +0 -1304
- package/src/commands/utils/migrate-state.js +0 -158
- package/src/commands/utils/upgrade.js +0 -346
- package/src/lib/validators/architecture-validator.js +0 -60
- package/src/lib/validators/content-validator.js +0 -164
- package/src/lib/validators/package-validator.js +0 -61
- package/src/lib/validators/ui-contrast-validator.js +0 -44
- package/stacks/blazor-azure/.claude/commands/morph-apply.md +0 -221
- package/stacks/blazor-azure/.claude/commands/morph-archive.md +0 -79
- package/stacks/blazor-azure/.claude/commands/morph-deploy.md +0 -529
- package/stacks/blazor-azure/.claude/commands/morph-infra.md +0 -209
- package/stacks/blazor-azure/.claude/commands/morph-preflight.md +0 -227
- package/stacks/blazor-azure/.claude/commands/morph-proposal.md +0 -122
- package/stacks/blazor-azure/.claude/commands/morph-status.md +0 -86
- package/stacks/blazor-azure/.claude/commands/morph-troubleshoot.md +0 -122
- package/stacks/blazor-azure/.claude/skills/level-0-meta/README.md +0 -7
- package/stacks/blazor-azure/.claude/skills/level-0-meta/code-review.md +0 -226
- package/stacks/blazor-azure/.claude/skills/level-0-meta/morph-checklist.md +0 -117
- package/stacks/blazor-azure/.claude/skills/level-0-meta/simulation-checklist.md +0 -77
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/README.md +0 -7
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/morph-replicate.md +0 -213
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-clarify.md +0 -131
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-design.md +0 -213
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-setup.md +0 -106
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-tasks.md +0 -164
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-uiux.md +0 -169
- package/stacks/blazor-azure/.claude/skills/level-2-domains/README.md +0 -14
- package/stacks/blazor-azure/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -192
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -197
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -189
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -320
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -156
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/api-designer.md +0 -59
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -77
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -58
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -126
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -45
- package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -210
- package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -154
- package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -191
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -142
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -699
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -126
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -131
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -119
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -130
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -142
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -108
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/hangfire-orchestrator.md +0 -64
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/resend-email.md +0 -119
- package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -235
- package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -126
- package/stacks/blazor-azure/.claude/skills/level-3-technologies/README.md +0 -7
- package/stacks/blazor-azure/.claude/skills/level-4-patterns/README.md +0 -7
- package/stacks/blazor-azure/.morph/archive/.gitkeep +0 -25
- package/stacks/blazor-azure/.morph/features/.gitkeep +0 -25
- package/stacks/blazor-azure/.morph/schemas/agent.schema.json +0 -296
- package/stacks/blazor-azure/.morph/schemas/tasks.schema.json +0 -220
- package/stacks/blazor-azure/.morph/specs/.gitkeep +0 -20
- package/stacks/blazor-azure/.morph/test-infra/example.bicep +0 -59
- package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +0 -221
- package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +0 -79
- package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +0 -529
- package/stacks/nextjs-supabase/.claude/commands/morph-infra.md +0 -209
- package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +0 -227
- package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +0 -122
- package/stacks/nextjs-supabase/.claude/commands/morph-status.md +0 -86
- package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +0 -122
- package/stacks/nextjs-supabase/.claude/settings.local.json +0 -6
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +0 -244
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +0 -335
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +0 -189
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +0 -50
- /package/docs/{v3.0 → next-generation}/ANALYSIS.md +0 -0
- /package/docs/{v3.0 → next-generation}/ARCHITECTURE.md +0 -0
- /package/docs/{v3.0 → next-generation}/FEATURES.md +0 -0
- /package/docs/{v3.0 → next-generation}/README.md +0 -0
- /package/docs/{v3.0 → next-generation}/ROADMAP.md +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Micro Agent CLI command
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* morph-spec micro-agent create <name> --base-agent=<agent> --mission="..." [--standards=file1,file2]
|
|
6
|
+
* morph-spec micro-agent list
|
|
7
|
+
* morph-spec micro-agent show <name>
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import {
|
|
12
|
+
createMicroAgent, saveMicroAgent, listMicroAgents, getMicroAgent
|
|
13
|
+
} from '../../lib/agents/micro-agent-factory.js';
|
|
14
|
+
|
|
15
|
+
export async function microAgentCreateCommand(name, options) {
|
|
16
|
+
try {
|
|
17
|
+
if (!options.baseAgent) {
|
|
18
|
+
console.error(chalk.red('--base-agent is required'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
if (!options.mission) {
|
|
22
|
+
console.error(chalk.red('--mission is required'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const standards = options.standards ? options.standards.split(',').map(s => s.trim()) : [];
|
|
27
|
+
|
|
28
|
+
const agent = createMicroAgent({
|
|
29
|
+
name,
|
|
30
|
+
baseAgent: options.baseAgent,
|
|
31
|
+
standards,
|
|
32
|
+
mission: options.mission,
|
|
33
|
+
tools: options.tools ? options.tools.split(',').map(t => t.trim()) : null
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const filePath = saveMicroAgent(agent);
|
|
37
|
+
|
|
38
|
+
console.log(chalk.green(`\n ✓ Micro-agent created: ${name}`));
|
|
39
|
+
console.log(` Base agent: ${options.baseAgent}`);
|
|
40
|
+
console.log(` Standards: ${standards.length > 0 ? standards.join(', ') : '(none)'}`);
|
|
41
|
+
console.log(` Context estimate: ${agent.contextEstimate.total.toLocaleString()} tokens`);
|
|
42
|
+
console.log(` Saved to: ${chalk.gray(filePath)}`);
|
|
43
|
+
console.log('');
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function microAgentListCommand(options) {
|
|
51
|
+
try {
|
|
52
|
+
const agents = listMicroAgents();
|
|
53
|
+
|
|
54
|
+
if (agents.length === 0) {
|
|
55
|
+
console.log(chalk.gray('\n No micro-agents found. Create one with: morph-spec micro-agent create\n'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(chalk.cyan(`\n Micro-Agents (${agents.length})\n`));
|
|
60
|
+
console.log(' ' + 'Name'.padEnd(20) + ' ' + 'Base'.padEnd(20) + ' ' + 'Standards'.padEnd(12) + ' ' + 'Context');
|
|
61
|
+
console.log(' ' + '─'.repeat(70));
|
|
62
|
+
|
|
63
|
+
for (const agent of agents) {
|
|
64
|
+
console.log(
|
|
65
|
+
' ' +
|
|
66
|
+
agent.id.padEnd(20) + ' ' +
|
|
67
|
+
(agent.baseAgent || '—').padEnd(20) + ' ' +
|
|
68
|
+
String(agent.standards).padEnd(12) + ' ' +
|
|
69
|
+
`${(agent.contextEstimate / 1000).toFixed(1)}K tokens`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
console.log('');
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function microAgentShowCommand(name, options) {
|
|
80
|
+
try {
|
|
81
|
+
const agent = getMicroAgent(name);
|
|
82
|
+
if (!agent) {
|
|
83
|
+
console.error(chalk.red(`Micro-agent not found: ${name}`));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(chalk.cyan(`\n Micro-Agent: ${name}\n`));
|
|
88
|
+
console.log(` Base agent: ${agent.baseAgent}`);
|
|
89
|
+
console.log(` Domain: ${agent.domain}`);
|
|
90
|
+
console.log(` Created: ${agent.createdAt}`);
|
|
91
|
+
console.log(`\n Mission:\n ${agent.mission}`);
|
|
92
|
+
|
|
93
|
+
if (agent.standards?.length > 0) {
|
|
94
|
+
console.log('\n Standards:');
|
|
95
|
+
agent.standards.forEach(s => console.log(` - ${s}`));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log('\n Context estimate:');
|
|
99
|
+
console.log(` Standards: ${agent.contextEstimate?.standards?.toLocaleString() || 0} tokens`);
|
|
100
|
+
console.log(` Overhead: ${agent.contextEstimate?.overhead?.toLocaleString() || 0} tokens`);
|
|
101
|
+
console.log(` Total: ${agent.contextEstimate?.total?.toLocaleString() || 0} tokens`);
|
|
102
|
+
|
|
103
|
+
if (options.showPrompt) {
|
|
104
|
+
console.log(chalk.cyan('\n Generated Prompt:'));
|
|
105
|
+
console.log(agent.prompt);
|
|
106
|
+
}
|
|
107
|
+
console.log('');
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { join } from 'path';
|
|
3
4
|
import { getFeature } from '../../core/state/state-manager.js';
|
|
4
5
|
import { orchestrateTeam } from '../../lib/orchestration/team-orchestrator.js';
|
|
6
|
+
import { spawnParallel } from '../../lib/execution/parallel-executor.js';
|
|
7
|
+
import { renderHOP } from '../../lib/hops/hop-composer.js';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Spawn Team Command - Generate agent team configurations
|
|
@@ -15,6 +18,35 @@ const program = new Command();
|
|
|
15
18
|
/**
|
|
16
19
|
* Spawn team action function
|
|
17
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* Spawn team in parallel mode
|
|
23
|
+
* --parallel backend,frontend,infra
|
|
24
|
+
*/
|
|
25
|
+
export async function spawnTeamParallelCommand(featureName, squads, options = {}) {
|
|
26
|
+
const squadList = squads.split(',').map(s => s.trim());
|
|
27
|
+
const maxConcurrent = parseInt(options.maxConcurrent || '3', 10);
|
|
28
|
+
|
|
29
|
+
console.log(chalk.cyan(`\n Spawning ${squadList.length} parallel squads for: ${featureName}\n`));
|
|
30
|
+
|
|
31
|
+
const threadConfigs = squadList.map(squad => ({
|
|
32
|
+
agent: squad,
|
|
33
|
+
mission: `Implement ${squad} domain for ${featureName}`,
|
|
34
|
+
meta: { squad }
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const threads = await spawnParallel({ feature: featureName, threadConfigs, maxConcurrent });
|
|
39
|
+
console.log(chalk.green(` ✓ ${threads.length} threads spawned in parallel`));
|
|
40
|
+
for (const t of threads) {
|
|
41
|
+
console.log(` ${chalk.gray(t.id.substring(0, 8))} — ${t.agent} (${t.status})`);
|
|
42
|
+
}
|
|
43
|
+
console.log(`\n Monitor with: morph-spec threads wait-all ${featureName}\n`);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error(chalk.red(` Error: ${err.message}`));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
18
50
|
export async function spawnTeamCommand(featureName, options = {}) {
|
|
19
51
|
try {
|
|
20
52
|
// Get feature state
|
|
@@ -94,12 +126,44 @@ export async function spawnTeamCommand(featureName, options = {}) {
|
|
|
94
126
|
});
|
|
95
127
|
}
|
|
96
128
|
|
|
97
|
-
// Show Task tool usage
|
|
129
|
+
// Show Task tool usage (with HOP rendering)
|
|
98
130
|
console.log(chalk.bold('\n📝 Task Tool Usage:'));
|
|
99
131
|
console.log(chalk.gray('\nUse the following pattern to spawn the team:\n'));
|
|
100
132
|
|
|
101
|
-
|
|
102
|
-
|
|
133
|
+
// Try to render backend squad HOP if applicable
|
|
134
|
+
let hopPrompt = null;
|
|
135
|
+
const hasBackend = teamConfig.teammates.some(t => t.id.includes('dotnet') || t.id.includes('api') || t.id.includes('ef'));
|
|
136
|
+
if (hasBackend && options.useHop !== false) {
|
|
137
|
+
try {
|
|
138
|
+
const frameworkRoot = join(process.cwd(), 'framework');
|
|
139
|
+
const domainLeaders = teamConfig.teammates
|
|
140
|
+
.filter(t => t.tier === 2)
|
|
141
|
+
.map(t => `- ${t.id}: ${t.role}`)
|
|
142
|
+
.join('\n');
|
|
143
|
+
hopPrompt = renderHOP('hop-backend-squad', {
|
|
144
|
+
AGENT_ID: teamConfig.teamHierarchy.teamLead,
|
|
145
|
+
MISSION: `Implement ${featureName}`,
|
|
146
|
+
SPEC_SUMMARY: `Feature: ${featureName}. See spec.md for full details.`,
|
|
147
|
+
ADDITIONAL_LEADERS: domainLeaders,
|
|
148
|
+
TASKS: teamConfig.teammates.filter(t => t.tier === 3).map((t, i) => `- T${String(i+1).padStart(3,'0')}: ${t.role}`).join('\n'),
|
|
149
|
+
DELIVERABLES: 'See spec.md deliverables section',
|
|
150
|
+
CONSTRAINTS: 'Follow all architecture and security standards',
|
|
151
|
+
FEATURE_NAME: featureName
|
|
152
|
+
}, { frameworkRoot });
|
|
153
|
+
} catch {
|
|
154
|
+
hopPrompt = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (hopPrompt) {
|
|
159
|
+
console.log(chalk.cyan('HOP-rendered prompt (backend squad):'));
|
|
160
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
161
|
+
console.log(chalk.white(hopPrompt.substring(0, 800) + (hopPrompt.length > 800 ? '\n...[truncated]' : '')));
|
|
162
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
163
|
+
console.log(chalk.dim('\nFull HOP: morph-spec hop render hop-backend-squad output.md \'{...}\''));
|
|
164
|
+
} else {
|
|
165
|
+
console.log(chalk.cyan('```typescript'));
|
|
166
|
+
console.log(chalk.white(`{
|
|
103
167
|
subagent_type: "general-purpose",
|
|
104
168
|
description: "Implement ${featureName}",
|
|
105
169
|
prompt: \`You are the Team Lead (${teamConfig.teamHierarchy.teamLead})...
|
|
@@ -123,7 +187,8 @@ Standards to follow: [coding.md, architecture.md]
|
|
|
123
187
|
Deliverables: [list specific outputs]
|
|
124
188
|
\`
|
|
125
189
|
}`));
|
|
126
|
-
|
|
190
|
+
console.log(chalk.cyan('```\n'));
|
|
191
|
+
}
|
|
127
192
|
|
|
128
193
|
// Show individual teammates
|
|
129
194
|
console.log(chalk.bold('Individual Teammates:'));
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Squad Template CLI command
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* morph-spec squad-template list
|
|
6
|
+
* morph-spec squad-template use <template-id> --feature=<feature>
|
|
7
|
+
* morph-spec squad-template show <template-id>
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
|
|
14
|
+
const SQUAD_TEMPLATES_DIR = join(process.cwd(), 'framework/squad-templates');
|
|
15
|
+
|
|
16
|
+
function loadTemplate(id) {
|
|
17
|
+
const filePath = join(SQUAD_TEMPLATES_DIR, `${id}.json`);
|
|
18
|
+
if (!existsSync(filePath)) return null;
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function listAllTemplates() {
|
|
27
|
+
if (!existsSync(SQUAD_TEMPLATES_DIR)) return [];
|
|
28
|
+
return readdirSync(SQUAD_TEMPLATES_DIR)
|
|
29
|
+
.filter(f => f.endsWith('.json'))
|
|
30
|
+
.map(f => {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(readFileSync(join(SQUAD_TEMPLATES_DIR, f), 'utf8'));
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
.filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function squadTemplateListCommand(options) {
|
|
41
|
+
try {
|
|
42
|
+
const templates = listAllTemplates();
|
|
43
|
+
|
|
44
|
+
if (templates.length === 0) {
|
|
45
|
+
console.log(chalk.gray('\n No squad templates found.\n'));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(chalk.cyan(`\n Squad Templates (${templates.length})\n`));
|
|
50
|
+
|
|
51
|
+
for (const t of templates) {
|
|
52
|
+
console.log(` ${chalk.bold(t.id)} — ${t.name}`);
|
|
53
|
+
console.log(` ${chalk.gray(t.description)}`);
|
|
54
|
+
console.log(` Agents: ${t.agents.map(a => a.id).join(', ')}`);
|
|
55
|
+
console.log(` Parallel: ${t.parallel ? chalk.green('yes') : chalk.gray('no')} | Coordination: ${t.coordination}`);
|
|
56
|
+
console.log(` Gain: ${chalk.cyan(t.estimatedParallelGain)}`);
|
|
57
|
+
console.log('');
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function squadTemplateUseCommand(templateId, options) {
|
|
66
|
+
try {
|
|
67
|
+
if (!options.feature) {
|
|
68
|
+
console.error(chalk.red('--feature is required'));
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const template = loadTemplate(templateId);
|
|
73
|
+
if (!template) {
|
|
74
|
+
console.error(chalk.red(`Template not found: ${templateId}`));
|
|
75
|
+
console.error(chalk.gray('Run `morph-spec squad-template list` to see available templates'));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(chalk.cyan(`\n Configuring Squad Template: ${templateId}\n`));
|
|
80
|
+
console.log(` Feature: ${options.feature}`);
|
|
81
|
+
console.log(` Template: ${template.name}`);
|
|
82
|
+
console.log(` Agents: ${template.agents.length}`);
|
|
83
|
+
console.log(` Parallel: ${template.parallel ? 'yes' : 'no'}`);
|
|
84
|
+
|
|
85
|
+
// Show spawn-team configuration
|
|
86
|
+
console.log(chalk.yellow('\n To spawn this squad, use the Task tool with these configs:\n'));
|
|
87
|
+
|
|
88
|
+
for (const agent of template.agents) {
|
|
89
|
+
console.log(` Agent: ${chalk.bold(agent.id)} (${agent.role})`);
|
|
90
|
+
console.log(` Standards: ${agent.standards?.join(', ') || '(none)'}`);
|
|
91
|
+
const deliverable = template.deliverables?.[agent.id];
|
|
92
|
+
if (deliverable) {
|
|
93
|
+
console.log(` Deliverable: ${deliverable}`);
|
|
94
|
+
}
|
|
95
|
+
console.log('');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(chalk.gray(' See: morph-spec spawn-team --template=' + templateId + ' --feature=' + options.feature));
|
|
99
|
+
console.log('');
|
|
100
|
+
} catch (err) {
|
|
101
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function squadTemplateShowCommand(templateId, options) {
|
|
107
|
+
try {
|
|
108
|
+
const template = loadTemplate(templateId);
|
|
109
|
+
if (!template) {
|
|
110
|
+
console.error(chalk.red(`Template not found: ${templateId}`));
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (options.json) {
|
|
115
|
+
console.log(JSON.stringify(template, null, 2));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(chalk.cyan(`\n Squad Template: ${template.id}\n`));
|
|
120
|
+
console.log(` Name: ${template.name}`);
|
|
121
|
+
console.log(` Description: ${template.description}`);
|
|
122
|
+
console.log(` Parallel: ${template.parallel ? chalk.green('yes') : chalk.gray('no')}`);
|
|
123
|
+
console.log(` Coordinator: ${template.coordination}`);
|
|
124
|
+
console.log(` Wait all: ${template.waitForAll ? 'yes' : 'no'}`);
|
|
125
|
+
console.log(` Gain: ${template.estimatedParallelGain}`);
|
|
126
|
+
|
|
127
|
+
console.log('\n Agents:');
|
|
128
|
+
for (const agent of template.agents) {
|
|
129
|
+
console.log(` ${chalk.bold(agent.id)} — ${agent.role} (${agent.domain})`);
|
|
130
|
+
if (agent.standards?.length > 0) {
|
|
131
|
+
console.log(` Standards: ${agent.standards.join(', ')}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (template.deliverables) {
|
|
136
|
+
console.log('\n Deliverables:');
|
|
137
|
+
for (const [agent, deliverable] of Object.entries(template.deliverables)) {
|
|
138
|
+
console.log(` ${agent}: ${deliverable}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
console.log('');
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics CLI command — Metrics dashboards
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* morph-spec analytics feature <name>
|
|
6
|
+
* morph-spec analytics context <name>
|
|
7
|
+
* morph-spec analytics project [--period=30d]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import {
|
|
12
|
+
getFeatureAnalytics, getProjectAnalytics,
|
|
13
|
+
generateAsciiChart, generateTimelineChart,
|
|
14
|
+
recordEvent
|
|
15
|
+
} from '../../lib/analytics/analytics-engine.js';
|
|
16
|
+
import { readFileSync, existsSync } from 'fs';
|
|
17
|
+
import { join } from 'path';
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Feature Analytics Dashboard
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export async function analyticsFeatureCommand(featureName, options) {
|
|
24
|
+
try {
|
|
25
|
+
const analytics = getFeatureAnalytics(featureName);
|
|
26
|
+
|
|
27
|
+
console.log(chalk.cyan(`\n Feature Analytics — ${featureName}\n`));
|
|
28
|
+
console.log(' ' + '─'.repeat(50));
|
|
29
|
+
|
|
30
|
+
console.log(`\n Threads:`);
|
|
31
|
+
for (const [status, count] of Object.entries(analytics.threads)) {
|
|
32
|
+
console.log(` ${status.padEnd(12)} ${count}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log(`\n Performance:`);
|
|
36
|
+
console.log(` Checkpoint pass rate: ${analytics.checkpointPassRate}%`);
|
|
37
|
+
console.log(` Total duration: ${formatDuration(analytics.totalDuration)}`);
|
|
38
|
+
console.log(` Total tool calls: ${analytics.totalToolCalls}`);
|
|
39
|
+
console.log(` Total tokens used: ${analytics.totalTokensUsed.toLocaleString()}`);
|
|
40
|
+
console.log(` Context optimizations: ${analytics.optimizationEvents}`);
|
|
41
|
+
|
|
42
|
+
if (Object.keys(analytics.threads).length > 0) {
|
|
43
|
+
console.log('\n' + generateAsciiChart(analytics.threads, { title: 'Threads by Status' }));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('');
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Context Analytics Dashboard
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
export async function analyticsContextCommand(featureName, options) {
|
|
58
|
+
try {
|
|
59
|
+
// Load context events from JSONL
|
|
60
|
+
const contextLogPath = join(process.cwd(), '.morph/analytics/context-log.jsonl');
|
|
61
|
+
|
|
62
|
+
if (!existsSync(contextLogPath)) {
|
|
63
|
+
console.log(chalk.gray(` No context analytics found for: ${featureName}`));
|
|
64
|
+
console.log(chalk.gray(' Run a session with context tracking to populate analytics.\n'));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const lines = readFileSync(contextLogPath, 'utf8').trim().split('\n').filter(Boolean);
|
|
69
|
+
const events = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
|
|
70
|
+
const featureEvents = events.filter(e => e.feature === featureName);
|
|
71
|
+
|
|
72
|
+
const tokenSamples = featureEvents.filter(e => e.type === 'token_usage');
|
|
73
|
+
const criticalMoments = featureEvents.filter(e => e.type === 'context_critical');
|
|
74
|
+
const optimizations = featureEvents.filter(e => e.type === 'context_optimized');
|
|
75
|
+
|
|
76
|
+
console.log(chalk.cyan(`\n Context Analytics — ${featureName}\n`));
|
|
77
|
+
console.log(' ' + '─'.repeat(50));
|
|
78
|
+
|
|
79
|
+
if (tokenSamples.length === 0) {
|
|
80
|
+
console.log(chalk.gray(' No token usage data available.\n'));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const avgTokens = Math.round(tokenSamples.reduce((s, e) => s + (e.data?.tokensUsed || 0), 0) / tokenSamples.length);
|
|
85
|
+
const peakTokens = Math.max(...tokenSamples.map(e => e.data?.tokensUsed || 0));
|
|
86
|
+
const avgUtilization = Math.round(tokenSamples.reduce((s, e) => s + (e.data?.utilization || 0), 0) / tokenSamples.length * 100);
|
|
87
|
+
|
|
88
|
+
console.log(`\n Token Usage:`);
|
|
89
|
+
console.log(` Average tokens: ${avgTokens.toLocaleString()}`);
|
|
90
|
+
console.log(` Peak tokens: ${peakTokens.toLocaleString()}`);
|
|
91
|
+
console.log(` Avg utilization: ${avgUtilization}%`);
|
|
92
|
+
console.log(` Critical moments: ${criticalMoments.length}`);
|
|
93
|
+
console.log(` Optimizations applied: ${optimizations.length}`);
|
|
94
|
+
|
|
95
|
+
// Optimization opportunities
|
|
96
|
+
if (criticalMoments.length > 0) {
|
|
97
|
+
console.log(chalk.yellow('\n ⚠ Optimization Opportunities:'));
|
|
98
|
+
const recs = criticalMoments.flatMap(e => e.data?.recommendations || []);
|
|
99
|
+
const uniqueStrategies = [...new Set(recs.map(r => r.strategy))];
|
|
100
|
+
for (const strategy of uniqueStrategies) {
|
|
101
|
+
const rec = recs.find(r => r.strategy === strategy);
|
|
102
|
+
console.log(` • ${strategy}: ${rec?.description || ''}`);
|
|
103
|
+
console.log(` Savings: ${rec?.estimatedSavings || 'unknown'}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log('');
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Project-Wide Dashboard
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
export async function analyticsProjectCommand(options) {
|
|
119
|
+
try {
|
|
120
|
+
const analytics = getProjectAnalytics();
|
|
121
|
+
|
|
122
|
+
console.log(chalk.cyan(`\n Project Analytics Dashboard — ${analytics.period}\n`));
|
|
123
|
+
console.log(' ' + '═'.repeat(55));
|
|
124
|
+
|
|
125
|
+
console.log(`\n 📊 Overview`);
|
|
126
|
+
console.log(` Features tracked: ${analytics.features}`);
|
|
127
|
+
console.log(` Total threads: ${analytics.threads.total}`);
|
|
128
|
+
console.log(` Completed: ${analytics.threads.completed}`);
|
|
129
|
+
console.log(` Failed: ${analytics.threads.failed}`);
|
|
130
|
+
|
|
131
|
+
console.log(`\n ✓ Checkpoints`);
|
|
132
|
+
console.log(` Total run: ${analytics.checkpoints.total}`);
|
|
133
|
+
console.log(` Passed: ${analytics.checkpoints.passed}`);
|
|
134
|
+
console.log(` Pass rate: ${analytics.checkpoints.passRate}%`);
|
|
135
|
+
|
|
136
|
+
if (analytics.checkpoints.total > 0) {
|
|
137
|
+
const bar = buildBar(analytics.checkpoints.passRate, 30);
|
|
138
|
+
console.log(` ${bar}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(`\n ⫸ Parallelization`);
|
|
142
|
+
console.log(` Avg concurrency: ${analytics.parallelization.avgConcurrency}x`);
|
|
143
|
+
console.log(` Parallel threads: ${analytics.parallelization.parallelThreads}`);
|
|
144
|
+
|
|
145
|
+
console.log(`\n ⚡ Trust & Auto-Approval`);
|
|
146
|
+
console.log(` Auto-approvals: ${analytics.trust.autoApprovals}`);
|
|
147
|
+
console.log(` Trust level changes: ${analytics.trust.trustChanges}`);
|
|
148
|
+
|
|
149
|
+
console.log(`\n 🧠 Context`);
|
|
150
|
+
console.log(` Avg tokens/session: ${analytics.context.avgTokensPerSession.toLocaleString()}`);
|
|
151
|
+
console.log(` Optimizations: ${analytics.context.optimizations}`);
|
|
152
|
+
|
|
153
|
+
console.log('\n ' + '─'.repeat(55));
|
|
154
|
+
console.log('');
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Helpers
|
|
163
|
+
// ============================================================================
|
|
164
|
+
|
|
165
|
+
function formatDuration(seconds) {
|
|
166
|
+
if (!seconds) return '—';
|
|
167
|
+
if (seconds < 60) return `${seconds}s`;
|
|
168
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
169
|
+
return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function buildBar(pct, width) {
|
|
173
|
+
const filled = Math.round(pct / 100 * width);
|
|
174
|
+
const color = pct >= 90 ? chalk.green : pct >= 70 ? chalk.yellow : chalk.red;
|
|
175
|
+
return color('[' + '█'.repeat(filled) + '░'.repeat(width - filled) + `] ${pct}%`);
|
|
176
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Prime CLI command — Load minimal context priming files
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* morph-spec prime feature (outputs feature-prime.md to stdout)
|
|
6
|
+
* morph-spec prime bug
|
|
7
|
+
* morph-spec prime refactor
|
|
8
|
+
* morph-spec prime design
|
|
9
|
+
* morph-spec prime infra
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import { readFileSync, existsSync } from 'fs';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
|
|
16
|
+
const PRIME_FILES = {
|
|
17
|
+
feature: '.morph/context/feature-prime.md',
|
|
18
|
+
bug: '.morph/context/bug-prime.md',
|
|
19
|
+
refactor: '.morph/context/refactor-prime.md',
|
|
20
|
+
design: '.morph/context/design-prime.md',
|
|
21
|
+
infra: '.morph/context/infra-prime.md'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const PRIME_TYPES = Object.keys(PRIME_FILES);
|
|
25
|
+
|
|
26
|
+
export async function contextPrimeCommand(type, options) {
|
|
27
|
+
if (!type) {
|
|
28
|
+
console.log(chalk.cyan('\n Available prime types:\n'));
|
|
29
|
+
for (const [key, path] of Object.entries(PRIME_FILES)) {
|
|
30
|
+
const exists = existsSync(join(process.cwd(), path));
|
|
31
|
+
const status = exists ? chalk.green('✓') : chalk.red('✗');
|
|
32
|
+
console.log(` ${status} ${key.padEnd(10)} → ${path}`);
|
|
33
|
+
}
|
|
34
|
+
console.log('');
|
|
35
|
+
console.log(chalk.gray(' Usage: morph-spec prime <type>'));
|
|
36
|
+
console.log(chalk.gray(' Example: morph-spec prime feature\n'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!PRIME_TYPES.includes(type)) {
|
|
41
|
+
console.error(chalk.red(`Unknown prime type: ${type}`));
|
|
42
|
+
console.error(chalk.gray(`Valid types: ${PRIME_TYPES.join(', ')}`));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const filePath = join(process.cwd(), PRIME_FILES[type]);
|
|
47
|
+
|
|
48
|
+
if (!existsSync(filePath)) {
|
|
49
|
+
console.error(chalk.red(`Prime file not found: ${filePath}`));
|
|
50
|
+
console.error(chalk.gray('Run `morph-spec init` to initialize MORPH-SPEC files.'));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const content = readFileSync(filePath, 'utf8');
|
|
55
|
+
|
|
56
|
+
if (options.json) {
|
|
57
|
+
console.log(JSON.stringify({ type, path: filePath, content }));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Output to stdout — designed to be read into context
|
|
62
|
+
console.log(content);
|
|
63
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Four CLI command — Context/Model/Prompt/Tools dashboard
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* morph-spec core-four <feature>
|
|
6
|
+
* morph-spec core-four <feature> --json
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { getCoreFour, formatCoreFour, initCoreFour } from '../../lib/context/core-four-tracker.js';
|
|
11
|
+
import { loadState } from '../../core/state/state-manager.js';
|
|
12
|
+
|
|
13
|
+
export async function coreFourCommand(featureName, options) {
|
|
14
|
+
try {
|
|
15
|
+
// Initialize with defaults if not already set
|
|
16
|
+
initCoreFour({
|
|
17
|
+
model: 'claude-sonnet-4-6',
|
|
18
|
+
contextWindow: 200000,
|
|
19
|
+
feature: featureName
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Try to populate context breakdown from feature state
|
|
23
|
+
try {
|
|
24
|
+
const state = loadState(false);
|
|
25
|
+
if (state?.features?.[featureName]) {
|
|
26
|
+
const feature = state.features[featureName];
|
|
27
|
+
// Attempt to estimate context breakdown from known files
|
|
28
|
+
const breakdown = {
|
|
29
|
+
'CLAUDE.md': 23000,
|
|
30
|
+
standards: feature.activeAgents ? feature.activeAgents.length * 500 : 0,
|
|
31
|
+
spec: feature.outputs?.includes('spec') ? 8000 : 0,
|
|
32
|
+
conversation: 5000,
|
|
33
|
+
other: 2000
|
|
34
|
+
};
|
|
35
|
+
const { updateContextBreakdown } = await import('../../lib/context/core-four-tracker.js');
|
|
36
|
+
updateContextBreakdown(breakdown);
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// Best-effort
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (options.json) {
|
|
43
|
+
const data = getCoreFour();
|
|
44
|
+
console.log(JSON.stringify(data, null, 2));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log('\n' + formatCoreFour());
|
|
49
|
+
console.log('');
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|