anchor.diff:  
     bool appliesTo(list) => list.length == 1 && _appliesTo(list.first);
   
  +  bool _appliesTo(ws.Resource resource);
  +
     Job _createJob(ws.Project project);
  -
  -  bool _appliesTo(ws.Resource resource);
  -}
  -
  -class PubGetAction extends PackageGetAction {
  -  PubGetAction(Spark spark) : super(spark, "pub-get", "Pub Get");
  -
  -  Job _createJob(ws.Project project) => new PubGetJob(spark, project);
  +}
  +
  +abstract class PubAction extends PackageManagementAction {
  +  PubAction(Spark spark, String id, String name) : super(spark, id, name);
   
     bool _appliesTo(ws.Resource resource) =>
         spark.pubManager.properties.isPackageResource(resource);
   }
   
  -class BowerGetAction extends PackageGetAction {
  -  BowerGetAction(Spark spark) : super(spark, "bower-install", "Bower Install");
  -
  -  Job _createJob(ws.Project project) => new BowerGetJob(spark, project);
  +class PubGetAction extends PubAction {
  +  PubGetAction(Spark spark) : super(spark, "pub-get", "Pub Get");
  +
  +  Job _createJob(ws.Project project) => new PubGetJob(spark, project);
  +}
  +
  +class PubUpgradeAction extends PubAction {
  +  PubUpgradeAction(Spark spark) : super(spark, "pub-upgrade", "Pub Upgrade");
  +
  +  Job _createJob(ws.Project project) => new PubUpgradeJob(spark, project);
  +}
  +
  +abstract class BowerAction extends PackageManagementAction {
  +  BowerAction(Spark spark, String id, String name) : super(spark, id, name);
   
     bool _appliesTo(ws.Resource resource) =>
         spark.bowerManager.properties.isPackageResource(resource);
   }
   
  -class PubUpgradeAction extends SparkAction implements ContextAction {
  -  PubUpgradeAction(Spark spark) : super(spark, "pub-upgrade", "Pub Upgrade");
  -
  -  void _invoke([context]) {
  -    ws.Resource resource;
  -
  -    if (context == null) {
  -      resource = spark.focusManager.currentResource;
  -    } else {
  -      resource = context.first;
  -    }
  -
  -    spark.jobManager.schedule(new PubUpgradeJob(spark, resource.project));
  -  }
  -
  -  String get category => 'application';
  -
  -  bool appliesTo(list) => list.length == 1 && _appliesTo(list.first);
  -
  -  bool _appliesTo(ws.Resource resource) =>
  -      spark.pubManager.properties.isPackageResource(resource);
  +class BowerGetAction extends BowerAction {
  +  BowerGetAction(Spark spark) : super(spark, "bower-install", "Bower Install");
  +
  +  Job _createJob(ws.Project project) => new BowerGetJob(spark, project);
  +}
  +
  +class BowerUpgradeAction extends BowerAction {
  +  BowerUpgradeAction(Spark spark) : super(spark, "bower-upgrade", "Bower Upgrade");
  +
  +  Job _createJob(ws.Project project) => new BowerUpgradeJob(spark, project);
   }
   
   /**
  
positive.code:       super(spark, project, 'bower install');
  
    Future _run() => _spark.bowerManager.installPackages(_project);
  }
  
  class CompileDartJob extends Job {
  
negative.code:     if (context == null) {
        resource = spark.focusManager.currentResource;
      } else {
        // TODO(ussuri): This seems like a stop-gap solution. Should we run for
        // all elements that match?
        resource = context.first;
      }
  
  