Skip to content
Development
Command

/jira-import-projects-full

Import additional JIRA projects post-init with filtering, resume support, and dry-run preview

From plugin
specweave
15673 skills20 agents73 commands
Install
> /plugin marketplace add anton-abyzov/specweave
> /plugin install sw@specweave

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/jira-import-projects-full

Context preview

What this command does when you run it.

Import additional JIRA projects post-init with filtering, resume support, and dry-run preview

Command definition

jira-import-projects-full.md
description: Import additional JIRA projects post-init with filtering, resume support, and dry-run preview

Import JIRA Projects Command

You are a JIRA project import expert. Help users add additional JIRA projects to their SpecWeave workspace after initial setup.

Purpose

This command allows users to import additional JIRA projects **after** initial SpecWeave setup (`specweave init`), with advanced filtering, resume capability, and dry-run preview.

**Use Cases**:

  • Adding new JIRA projects to existing workspace
  • Importing archived/paused projects later
  • Selective import with filters (active only, specific types, custom JQL)

Command Syntax

# Basic import (interactive)
sw-jira:import-projects

# With filters
sw-jira:import-projects --filter active
sw-jira:import-projects --type agile --lead "john.doe@company.com"
sw-jira:import-projects --jql "project IN (BACKEND, FRONTEND) AND status != Archived"

# Dry-run (preview)
sw-jira:import-projects --dry-run

# Resume interrupted import
sw-jira:import-projects --resume

# Combined
sw-jira:import-projects --filter active --dry-run

Your Task

When the user runs this command:

Step 1: Validate Prerequisites

import { readEnvFile, parseEnvFile } from '../../../src/utils/env-file.js';

// 1. Check if Jira credentials exist
const envContent = readEnvFile(process.cwd());
const parsed = parseEnvFile(envContent);

if (!parsed.JIRA_API_TOKEN || !parsed.JIRA_EMAIL || !parsed.JIRA_DOMAIN) {
  console.log('โŒ Missing Jira credentials. Run `specweave init` first.');
  return;
}

// 2. Get existing projects
const existingProjects = parsed.JIRA_PROJECTS?.split(',') || [];
console.log(`\n๐Ÿ“‹ Current projects: ${existingProjects.join(', ') || 'None'}\n`);

Step 2: Fetch Available Projects

import { getProjectCount } from '../../../src/cli/helpers/project-count-fetcher.js';
import { AsyncProjectLoader } from '../../../src/cli/helpers/async-project-loader.js';

// Count check (< 1 second)
const countResult = await getProjectCount({
  provider: 'jira',
  credentials: {
    domain: parsed.JIRA_DOMAIN,
    email: parsed.JIRA_EMAIL,
    token: parsed.JIRA_API_TOKEN,
    instanceType: 'cloud'
  }
});

console.log(`โœ“ Found ${countResult.accessible} accessible projects`);

// Fetch all projects (with smart pagination)
const loader = new AsyncProjectLoader(
  {
    domain: parsed.JIRA_DOMAIN,
    email: parsed.JIRA_EMAIL,
    token: parsed.JIRA_API_TOKEN,
    instanceType: 'cloud'
  },
  'jira',
  {
    batchSize: 50,
    updateFrequency: 5,
    showEta: true
  }
);

const result = await loader.fetchAllProjects(countResult.accessible);
let allProjects = result.projects;

Step 3: Apply Filters (if specified)

import { FilterProcessor } from '../../../src/integrations/jira/filter-processor.js';

const options = {
  filter: args.filter,       // 'active' | 'all'
  type: args.type,           // 'agile' | 'software' | 'business'
  lead: args.lead,           // Email address
  jql: args.jql              // Custom JQL
};

const filterProcessor = new FilterProcessor({ domain: parsed.JIRA_DOMAIN, token: parsed.JIRA_API_TOKEN });
const filteredProjects = await filterProcessor.applyFilters(allProjects, options);

console.log(`\n๐Ÿ” Filters applied:`);
if (options.filter === 'active') console.log(`   โ€ข Active projects only`);
if (options.type) console.log(`   โ€ข Type: ${options.type}`);
if (options.lead) console.log(`   โ€ข Lead: ${options.lead}`);
if (options.jql) console.log(`   โ€ข JQL: ${options.jql}`);
console.log(`\n๐Ÿ“Š Results: ${filteredProjects.length} projects (down from ${allProjects.length})\n`);

Step 4: Exclude Existing Projects

const newProjects = filteredProjects.filter(p => !existingProjects.includes(p.key));

if (newProjects.length === 0) {
  console.log('โœ… No new projects to import. All filtered projects are already configured.');
  return;
}

console.log(`๐Ÿ“ฅ ${newProjects.length} new project(s) available for import:\n`);
newProjects.forEach(p => {
  console.log(`   โœจ ${p.key} - ${p.name} (${p.projectTypeKey}, lead: ${p.lead?.displayName || 'N/A'})`);
});

Step 5: Dry-Run or Execute

if (args.dryRun) {
  console.log('\n๐Ÿ”Ž DRY RUN: No changes will be made.\n');
  console.log('The following projects would be imported:');
  newProjects.forEach(p => {
    const status = p.archived ? 'โญ๏ธ  (archived - skipped)' : 'โœจ';
    console.log(`   ${status} ${p.key} - ${p.name}`);
  });
  console.log(`\nTotal: ${newProjects.filter(p => !p.archived).length} projects would be imported\n`);
  return;
}

// Confirm import
const { confirmed } = await inquirer.prompt([{
  type: 'confirm',
  name: 'confirmed',
  message: `Import ${newProjects.length} project(s)?`,
  default: true
}]);

if (!confirmed) {
  console.log('โญ๏ธ  Import cancelled.');
  return;
}

Step 6: Merge with Existing

import { updateEnvFile, mergeProjectList } from '../../../src/utils/env-manager.js';

const newKeys = newProjects.map(p => p.key);
const mergedProjects = mergeProjectList(existingProjects, newKeys);

// Update .env file (atomic write)
await updateEnvFile('JIRA_PROJECTS', mergedProjects.join(','));

console.log('\nโœ… Projects imported successfully!\n');
console.log(`Updated: ${existingProjects.length} โ†’ ${mergedProjects.length} projects`);
console.log(`\nCurrent projects:\n   ${mergedProjects.join(', ')}\n`);

Step 7: Resume Support

if (args.resume) {
  const { CacheManager } = await import('../../../src/core/cache/cache-manager.js');
  const cacheManager = new CacheManager(process.cwd());

  const importState = await cacheManager.get('jira-import-state');

  if (!importState) {
    console.log('โš ๏ธ  No import state found. Use without --resume to start fresh.');
    return;
  }

  console.log(`\n๐Ÿ“‚ Resuming from: ${importState.lastProject} (${importState.completed}/${importState.total})`);

  // Skip already-imported projects
  const remain
Read more
Ships withspecweave

Spec-first AI development: describe a feature โ†’ AI creates spec + plan + tasks, builds autonomously, syncs to GitHub/JIRA. Domain-expert skills for PM, Architect, Frontend, QA learn your patterns permanently. Claude Code, Codex, Cursor, Copilot & more.

Get the whole plugin