/jira-import-projects-full
Import additional JIRA projects post-init with filtering, resume support, and dry-run preview
> /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.mddescription: 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 remainRead more
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 remainSpec-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.
Repo: anton-abyzov/specweave
Other commands on specweave.
- /abandon
Abandon an incomplete increment (requirements changed, obsolete)
Open command - /ado-cleanup-duplicates
Clean up duplicate Azure DevOps work items for a Feature. Finds work items with duplicate titles and closes all except the first created item.
Open command - /ado-clone
Clone Azure DevOps repositories to local workspace. Use after init if cloning was skipped, or to add repos later.
Open command - /ado-close
Close Azure DevOps work item when increment complete
Open command - /ado-create
Create Azure DevOps work item from SpecWeave increment
Open command - /ado-import-areas
Import Azure DevOps area paths from a project and map them to SpecWeave projects. Creates 2-level directory structure with area path-based organization.
Open command

