@pcoliveira90/pdd 0.2.1-beta.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.
@@ -0,0 +1,113 @@
1
+ import { runValidation } from '../core/validator.js';
2
+ import { openPullRequest } from '../core/pr-manager.js';
3
+ import { generatePatchArtifacts } from '../core/patch-generator.js';
4
+ import { runInit } from './init-command.js';
5
+ import { runDoctor } from './doctor-command.js';
6
+ import { runStatus } from './status-command.js';
7
+ import { runResilientFixWorkflow } from '../core/fix-runner.js';
8
+
9
+ function parseFixArgs(argv) {
10
+ const issue = argv
11
+ .filter(arg => !arg.startsWith('--') && arg !== 'fix')
12
+ .join(' ')
13
+ .trim();
14
+
15
+ return {
16
+ issue,
17
+ openPr: argv.includes('--open-pr'),
18
+ dryRun: argv.includes('--dry-run'),
19
+ noValidate: argv.includes('--no-validate')
20
+ };
21
+ }
22
+
23
+ export async function runCli(argv = process.argv.slice(2)) {
24
+ const command = argv[0];
25
+ const cwd = process.cwd();
26
+
27
+ if (command === 'init') {
28
+ runInit(argv);
29
+ return;
30
+ }
31
+
32
+ if (command === 'doctor') {
33
+ runDoctor(cwd, argv);
34
+ return;
35
+ }
36
+
37
+ if (command === 'status') {
38
+ runStatus(cwd);
39
+ return;
40
+ }
41
+
42
+ if (command === 'fix') {
43
+ const { issue, openPr, dryRun, noValidate } = parseFixArgs(argv);
44
+
45
+ if (!issue) {
46
+ console.error('❌ Missing issue description.');
47
+ console.log('Use: pdd fix "description" [--open-pr] [--dry-run] [--no-validate]');
48
+ process.exit(1);
49
+ }
50
+
51
+ console.log('🔧 PDD Fix Workflow');
52
+ console.log(`Issue: ${issue}`);
53
+ console.log(`Open PR prep: ${openPr ? 'yes' : 'no'}`);
54
+ console.log(`Dry run: ${dryRun ? 'yes' : 'no'}`);
55
+ console.log(`Validation: ${noValidate ? 'skipped' : 'enabled'}`);
56
+
57
+ try {
58
+ const result = await runResilientFixWorkflow({
59
+ baseDir: cwd,
60
+ issue,
61
+ dryRun,
62
+ noValidate,
63
+ openPr,
64
+ generatePatchArtifacts,
65
+ runValidation,
66
+ openPullRequest
67
+ });
68
+
69
+ if (result.status === 'dry-run') {
70
+ console.log('📝 Dry run only. No files created.');
71
+ return;
72
+ }
73
+
74
+ if (result.changeId) {
75
+ console.log(`Tracking change: ${result.changeId}`);
76
+ }
77
+
78
+ if (Array.isArray(result.files) && result.files.length > 0) {
79
+ console.log('🧩 Patch artifacts created:');
80
+ result.files.forEach(file => console.log(`- ${file}`));
81
+ }
82
+
83
+ console.log('✅ Fix workflow finished.');
84
+ } catch (error) {
85
+ console.error(`❌ ${error.message}`);
86
+ process.exitCode = 1;
87
+ }
88
+
89
+ return;
90
+ }
91
+
92
+ if (command === 'help' || !command) {
93
+ console.log('PDD CLI');
94
+ console.log('');
95
+ console.log('Commands:');
96
+ console.log(' pdd init <project-name>');
97
+ console.log(' pdd init --here [--force] [--upgrade] [--ide=claude|cursor|copilot|claude,cursor,copilot]');
98
+ console.log(' pdd doctor [--fix]');
99
+ console.log(' pdd status');
100
+ console.log(' pdd fix "description" [--open-pr] [--dry-run] [--no-validate]');
101
+ console.log('');
102
+ console.log('Examples:');
103
+ console.log(' pdd doctor --fix');
104
+ console.log(' pdd status');
105
+ console.log(' pdd init --here --upgrade');
106
+ console.log(' pdd fix "login not saving incomeStatus" --open-pr');
107
+ console.log('');
108
+ return;
109
+ }
110
+
111
+ console.log(`❌ Unknown command: ${command}`);
112
+ console.log('Use: pdd help');
113
+ }
@@ -0,0 +1,123 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { CORE_TEMPLATES, IDE_ADAPTERS, PDD_TEMPLATE_VERSION } from '../core/template-registry.js';
4
+ import { buildTemplateUpgradePlan, applyTemplateUpgradePlan } from '../core/template-upgrade.js';
5
+
6
+ function ensureDir(filePath) {
7
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
8
+ }
9
+
10
+ function writeFile(baseDir, relativePath, content) {
11
+ const fullPath = path.join(baseDir, relativePath);
12
+ ensureDir(fullPath);
13
+ fs.writeFileSync(fullPath, content, 'utf-8');
14
+ }
15
+
16
+ function normalizeIdeList(argv) {
17
+ const ideArg = argv.find(arg => arg.startsWith('--ide='));
18
+ if (!ideArg) return [];
19
+
20
+ return ideArg
21
+ .split('=')[1]
22
+ ?.split(',')
23
+ .map(v => v.trim())
24
+ .filter(Boolean) || [];
25
+ }
26
+
27
+ function readInstalledVersion(baseDir) {
28
+ const versionFile = path.join(baseDir, '.pdd/version.json');
29
+ if (!fs.existsSync(versionFile)) return null;
30
+
31
+ try {
32
+ return JSON.parse(fs.readFileSync(versionFile, 'utf-8')).templateVersion;
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function installIdeAdapters(baseDir, ideList, force) {
39
+ const results = [];
40
+
41
+ for (const ide of ideList) {
42
+ const adapter = IDE_ADAPTERS[ide];
43
+ if (!adapter) {
44
+ results.push({ path: `adapter:${ide}`, status: 'unknown' });
45
+ continue;
46
+ }
47
+
48
+ for (const [file, content] of Object.entries(adapter)) {
49
+ const fullPath = path.join(baseDir, file);
50
+ if (!force && fs.existsSync(fullPath)) {
51
+ results.push({ path: file, status: 'skipped' });
52
+ continue;
53
+ }
54
+
55
+ writeFile(baseDir, file, content);
56
+ results.push({ path: file, status: 'written' });
57
+ }
58
+ }
59
+
60
+ return results;
61
+ }
62
+
63
+ function printUpgradeSummary(summary) {
64
+ console.log('⬆️ PDD upgraded');
65
+
66
+ summary.created.forEach(f => console.log(`✔️ created: ${f}`));
67
+ summary.updated.forEach(f => console.log(`🔁 updated: ${f}`));
68
+ summary.conflicts.forEach(f => console.log(`⚠️ conflict: ${f}`));
69
+ summary.skipped.forEach(f => console.log(`⏭️ skipped: ${f}`));
70
+
71
+ console.log('');
72
+ console.log(`Summary:`);
73
+ console.log(`- created: ${summary.created.length}`);
74
+ console.log(`- updated: ${summary.updated.length}`);
75
+ console.log(`- conflicts: ${summary.conflicts.length}`);
76
+ console.log(`- skipped: ${summary.skipped.length}`);
77
+
78
+ if (summary.conflicts.length > 0) {
79
+ console.log('👉 Run with --force to overwrite conflicts');
80
+ }
81
+ }
82
+
83
+ export function runInit(argv = process.argv.slice(2)) {
84
+ const cwd = process.cwd();
85
+ const here = argv.includes('--here');
86
+ const force = argv.includes('--force');
87
+ const upgrade = argv.includes('--upgrade');
88
+ const ideList = normalizeIdeList(argv);
89
+
90
+ const projectName = !here && argv[1] && !argv[1].startsWith('--') ? argv[1] : null;
91
+ const baseDir = here ? cwd : path.join(cwd, projectName || 'pdd-project');
92
+
93
+ if (!here && !fs.existsSync(baseDir)) {
94
+ fs.mkdirSync(baseDir, { recursive: true });
95
+ }
96
+
97
+ const installedVersion = readInstalledVersion(baseDir);
98
+
99
+ if (upgrade) {
100
+ const plan = buildTemplateUpgradePlan(baseDir, CORE_TEMPLATES);
101
+ const summary = applyTemplateUpgradePlan(baseDir, CORE_TEMPLATES, plan, force);
102
+
103
+ // always update version.json
104
+ writeFile(baseDir, '.pdd/version.json', JSON.stringify({ templateVersion: PDD_TEMPLATE_VERSION }, null, 2));
105
+
106
+ printUpgradeSummary(summary);
107
+
108
+ if (installedVersion === PDD_TEMPLATE_VERSION) {
109
+ console.log('ℹ️ Templates were already up to date.');
110
+ }
111
+
112
+ } else {
113
+ // basic init (no intelligence needed yet)
114
+ for (const [file, content] of Object.entries(CORE_TEMPLATES)) {
115
+ writeFile(baseDir, file, content);
116
+ }
117
+
118
+ console.log('🚀 PDD initialized');
119
+ }
120
+
121
+ const ideResults = installIdeAdapters(baseDir, ideList, force);
122
+ ideResults.forEach(r => console.log(`- ${r.status}: ${r.path}`));
123
+ }
@@ -0,0 +1,33 @@
1
+ import { readProjectState } from '../core/state-manager.js';
2
+
3
+ export function runStatus(baseDir = process.cwd()) {
4
+ const state = readProjectState(baseDir);
5
+
6
+ console.log('📊 PDD Status\n');
7
+
8
+ console.log(`Status: ${state.status}`);
9
+
10
+ if (state.activeChange) {
11
+ console.log(`Active change: ${state.activeChange}`);
12
+ } else {
13
+ console.log('Active change: none');
14
+ }
15
+
16
+ if (state.lastChange) {
17
+ console.log(`Last change: ${state.lastChange}`);
18
+ }
19
+
20
+ if (state.updatedAt) {
21
+ console.log(`Updated at: ${state.updatedAt}`);
22
+ }
23
+
24
+ console.log('');
25
+
26
+ if (state.status === 'in-progress') {
27
+ console.log('⚠️ A change is currently in progress');
28
+ } else if (state.status === 'failed') {
29
+ console.log('❌ Last operation failed');
30
+ } else {
31
+ console.log('✅ Project is healthy');
32
+ }
33
+ }
@@ -0,0 +1,135 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import {
4
+ readProjectState,
5
+ setActiveChange,
6
+ clearActiveChange,
7
+ writeProjectState
8
+ } from './state-manager.js';
9
+
10
+ function ensureDir(filePath) {
11
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
12
+ }
13
+
14
+ function appendText(filePath, content) {
15
+ ensureDir(filePath);
16
+ fs.appendFileSync(filePath, content, 'utf-8');
17
+ }
18
+
19
+ function writeJson(filePath, value) {
20
+ ensureDir(filePath);
21
+ fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n', 'utf-8');
22
+ }
23
+
24
+ function nowIso() {
25
+ return new Date().toISOString();
26
+ }
27
+
28
+ function buildFailurePayload({ issue, changeId, phase, error }) {
29
+ return {
30
+ issue,
31
+ changeId,
32
+ phase,
33
+ error: error?.message || String(error),
34
+ failedAt: nowIso()
35
+ };
36
+ }
37
+
38
+ function persistFailureArtifacts(baseDir, payload) {
39
+ const changeDir = path.join(baseDir, 'changes', payload.changeId);
40
+ const failureReportPath = path.join(changeDir, 'failure-report.json');
41
+ const verificationReportPath = path.join(changeDir, 'verification-report.md');
42
+
43
+ writeJson(failureReportPath, payload);
44
+ appendText(
45
+ verificationReportPath,
46
+ `\n## Failure\n- phase: ${payload.phase}\n- error: ${payload.error}\n- failedAt: ${payload.failedAt}\n`
47
+ );
48
+
49
+ return {
50
+ failureReportPath,
51
+ verificationReportPath
52
+ };
53
+ }
54
+
55
+ export async function runResilientFixWorkflow({
56
+ baseDir = process.cwd(),
57
+ issue,
58
+ dryRun = false,
59
+ noValidate = false,
60
+ openPr = false,
61
+ generatePatchArtifacts,
62
+ runValidation,
63
+ openPullRequest
64
+ }) {
65
+ const current = readProjectState(baseDir);
66
+ if (current.status === 'in-progress' && current.activeChange) {
67
+ throw new Error(`Another change is already in progress: ${current.activeChange}`);
68
+ }
69
+
70
+ if (dryRun) {
71
+ return {
72
+ status: 'dry-run',
73
+ issue
74
+ };
75
+ }
76
+
77
+ const changeId = `change-${Date.now()}`;
78
+ setActiveChange(baseDir, changeId, 'in-progress');
79
+
80
+ try {
81
+ let phase = 'patch-generation';
82
+ const patch = generatePatchArtifacts({ issue, baseDir });
83
+
84
+ if (!noValidate) {
85
+ phase = 'validation';
86
+ runValidation(baseDir);
87
+ }
88
+
89
+ if (openPr) {
90
+ phase = 'pr-preparation';
91
+ await openPullRequest({
92
+ issue,
93
+ changeId: patch.changeId,
94
+ changeDir: patch.changeDir,
95
+ baseDir
96
+ });
97
+ }
98
+
99
+ clearActiveChange(baseDir, 'completed');
100
+ writeProjectState(baseDir, {
101
+ activeChange: null,
102
+ lastChange: patch.changeId,
103
+ status: 'completed',
104
+ lastResult: 'success',
105
+ lastIssue: issue,
106
+ lastPhase: 'completed',
107
+ lastError: null
108
+ });
109
+
110
+ return {
111
+ status: 'completed',
112
+ changeId: patch.changeId,
113
+ files: patch.files
114
+ };
115
+ } catch (error) {
116
+ const phase = current.status === 'in-progress' ? current.lastPhase || 'unknown' : 'unknown';
117
+ const payload = buildFailurePayload({ issue, changeId, phase, error });
118
+ const artifacts = persistFailureArtifacts(baseDir, payload);
119
+
120
+ writeProjectState(baseDir, {
121
+ activeChange: changeId,
122
+ lastChange: changeId,
123
+ status: 'failed',
124
+ lastResult: 'failed',
125
+ lastIssue: issue,
126
+ lastPhase: phase,
127
+ lastError: payload.error,
128
+ lastFailureReport: artifacts.failureReportPath
129
+ });
130
+
131
+ const wrapped = new Error(`Fix failed during ${phase}: ${payload.error}`);
132
+ wrapped.cause = error;
133
+ throw wrapped;
134
+ }
135
+ }
@@ -0,0 +1,126 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ function ensureDir(filePath) {
5
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
6
+ }
7
+
8
+ function writeFile(filePath, content) {
9
+ ensureDir(filePath);
10
+ fs.writeFileSync(filePath, content, 'utf-8');
11
+ }
12
+
13
+ function slugify(value) {
14
+ return value
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9]+/g, '-')
17
+ .replace(/^-+|-+$/g, '')
18
+ .slice(0, 48);
19
+ }
20
+
21
+ export function generatePatchArtifacts({ issue, baseDir = process.cwd() }) {
22
+ const timestamp = Date.now();
23
+ const changeId = `change-${timestamp}-${slugify(issue || 'update')}`;
24
+ const changeDir = path.join(baseDir, 'changes', changeId);
25
+
26
+ const files = [
27
+ path.join('changes', changeId, 'delta-spec.md'),
28
+ path.join('changes', changeId, 'patch-plan.md'),
29
+ path.join('changes', changeId, 'verification-report.md')
30
+ ];
31
+
32
+ writeFile(
33
+ path.join(changeDir, 'delta-spec.md'),
34
+ `# Delta Spec
35
+
36
+ ## Change ID
37
+ ${changeId}
38
+
39
+ ## Issue
40
+ ${issue}
41
+
42
+ ## Type
43
+ bugfix | feature | refactor-safe | hotfix
44
+
45
+ ## Context
46
+
47
+ ## Current Behavior
48
+
49
+ ## Expected Behavior
50
+
51
+ ## Evidence
52
+
53
+ ## Root Cause Hypothesis
54
+
55
+ ## Impacted Areas
56
+
57
+ ## Constraints
58
+
59
+ ## Minimal Safe Delta
60
+
61
+ ## Alternatives Considered
62
+
63
+ ## Acceptance Criteria
64
+
65
+ ## Verification Strategy
66
+ `
67
+ );
68
+
69
+ writeFile(
70
+ path.join(changeDir, 'patch-plan.md'),
71
+ `# Patch Plan
72
+
73
+ ## Change ID
74
+ ${changeId}
75
+
76
+ ## Issue
77
+ ${issue}
78
+
79
+ ## Files to Inspect
80
+
81
+ ## Files to Change
82
+
83
+ ## Execution Steps
84
+ 1. Reproduce issue
85
+ 2. Confirm root cause
86
+ 3. Apply minimal change
87
+ 4. Adjust tests
88
+ 5. Run validations
89
+
90
+ ## Regression Risks
91
+
92
+ ## Rollback Strategy
93
+ `
94
+ );
95
+
96
+ writeFile(
97
+ path.join(changeDir, 'verification-report.md'),
98
+ `# Verification Report
99
+
100
+ ## Change ID
101
+ ${changeId}
102
+
103
+ ## Issue
104
+ ${issue}
105
+
106
+ ## Reproduction
107
+
108
+ ## Changes Made
109
+
110
+ ## Tests Run
111
+
112
+ ## Manual Validation
113
+
114
+ ## Residual Risks
115
+
116
+ ## Final Status
117
+ pending
118
+ `
119
+ );
120
+
121
+ return {
122
+ changeId,
123
+ changeDir,
124
+ files
125
+ };
126
+ }
@@ -0,0 +1,21 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+
5
+ function exec(command) {
6
+ execSync(command, { stdio: 'inherit' });
7
+ }
8
+
9
+ export async function openPullRequest({ issue, changeId, changeDir }) {
10
+ const branch = `pdd/${changeId}`;
11
+ const title = `fix: ${issue}`;
12
+
13
+ fs.writeFileSync(path.join(changeDir, 'pr-title.txt'), title);
14
+ fs.writeFileSync(path.join(changeDir, 'pr-body.md'), issue);
15
+
16
+ exec(`git checkout -b ${branch}`);
17
+ exec('git add .');
18
+ exec(`git commit -m "${title}"`);
19
+
20
+ console.log('PR ready (use IDE to open)');
21
+ }
@@ -0,0 +1,91 @@
1
+ export function buildDoctorRemediationPlan({ coreChecks, adapters, installedVersion, currentVersion }) {
2
+ const problems = [];
3
+
4
+ const missingCore = Object.entries(coreChecks)
5
+ .filter(([, ok]) => !ok)
6
+ .map(([key]) => key);
7
+
8
+ if (missingCore.length > 0) {
9
+ problems.push({
10
+ severity: 'high',
11
+ code: 'missing-core',
12
+ summary: 'Core PDD files are missing',
13
+ details: missingCore,
14
+ action: 'Run `pdd doctor --fix` to restore missing core files.'
15
+ });
16
+ }
17
+
18
+ if (!installedVersion) {
19
+ problems.push({
20
+ severity: 'high',
21
+ code: 'missing-version',
22
+ summary: 'Template version metadata is missing',
23
+ details: ['.pdd/version.json'],
24
+ action: 'Run `pdd doctor --fix` or `pdd init --here --force`.'
25
+ });
26
+ } else if (installedVersion !== currentVersion) {
27
+ problems.push({
28
+ severity: 'medium',
29
+ code: 'outdated-templates',
30
+ summary: `Templates are outdated (${installedVersion} → ${currentVersion})`,
31
+ details: [],
32
+ action: 'Run `pdd init --here --upgrade` to update templates safely.'
33
+ });
34
+ }
35
+
36
+ const missingAdapters = Object.entries(adapters)
37
+ .filter(([, ok]) => !ok)
38
+ .map(([key]) => key);
39
+
40
+ if (missingAdapters.length === Object.keys(adapters).length) {
41
+ problems.push({
42
+ severity: 'low',
43
+ code: 'no-adapters',
44
+ summary: 'No IDE adapters are installed',
45
+ details: missingAdapters,
46
+ action: 'Run `pdd init --here --ide=claude` (or cursor/copilot).'
47
+ });
48
+ }
49
+
50
+ const ordered = problems.sort((a, b) => rankSeverity(a.severity) - rankSeverity(b.severity));
51
+
52
+ return {
53
+ ok: ordered.length === 0,
54
+ problems: ordered,
55
+ nextAction: ordered[0]?.action || null
56
+ };
57
+ }
58
+
59
+ function rankSeverity(severity) {
60
+ switch (severity) {
61
+ case 'high':
62
+ return 0;
63
+ case 'medium':
64
+ return 1;
65
+ default:
66
+ return 2;
67
+ }
68
+ }
69
+
70
+ export function printDoctorRemediationPlan(plan) {
71
+ if (plan.ok) {
72
+ console.log('✅ No guided remediation needed.');
73
+ return;
74
+ }
75
+
76
+ console.log('');
77
+ console.log('🧭 Guided remediation');
78
+
79
+ plan.problems.forEach((problem, index) => {
80
+ console.log(`${index + 1}. [${problem.severity.toUpperCase()}] ${problem.summary}`);
81
+ if (problem.details.length > 0) {
82
+ console.log(` Details: ${problem.details.join(', ')}`);
83
+ }
84
+ console.log(` Action: ${problem.action}`);
85
+ });
86
+
87
+ if (plan.nextAction) {
88
+ console.log('');
89
+ console.log(`👉 Recommended next step: ${plan.nextAction}`);
90
+ }
91
+ }
@@ -0,0 +1,71 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ const DEFAULT_STATE = {
5
+ activeChange: null,
6
+ status: 'idle',
7
+ lastChange: null,
8
+ updatedAt: null
9
+ };
10
+
11
+ function ensureDir(filePath) {
12
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
13
+ }
14
+
15
+ function getStatePath(baseDir = process.cwd()) {
16
+ return path.join(baseDir, '.pdd/state.json');
17
+ }
18
+
19
+ export function readProjectState(baseDir = process.cwd()) {
20
+ const statePath = getStatePath(baseDir);
21
+ if (!fs.existsSync(statePath)) {
22
+ return { ...DEFAULT_STATE };
23
+ }
24
+
25
+ try {
26
+ const raw = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
27
+ return { ...DEFAULT_STATE, ...raw };
28
+ } catch {
29
+ return { ...DEFAULT_STATE };
30
+ }
31
+ }
32
+
33
+ export function writeProjectState(baseDir = process.cwd(), nextState = {}) {
34
+ const statePath = getStatePath(baseDir);
35
+ ensureDir(statePath);
36
+
37
+ const merged = {
38
+ ...DEFAULT_STATE,
39
+ ...nextState,
40
+ updatedAt: new Date().toISOString()
41
+ };
42
+
43
+ fs.writeFileSync(statePath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
44
+ return merged;
45
+ }
46
+
47
+ export function setActiveChange(baseDir = process.cwd(), changeId, status = 'in-progress') {
48
+ return writeProjectState(baseDir, {
49
+ activeChange: changeId,
50
+ lastChange: changeId,
51
+ status
52
+ });
53
+ }
54
+
55
+ export function markProjectState(baseDir = process.cwd(), status = 'idle') {
56
+ const current = readProjectState(baseDir);
57
+ return writeProjectState(baseDir, {
58
+ ...current,
59
+ status,
60
+ activeChange: status === 'in-progress' ? current.activeChange : null
61
+ });
62
+ }
63
+
64
+ export function clearActiveChange(baseDir = process.cwd(), status = 'idle') {
65
+ const current = readProjectState(baseDir);
66
+ return writeProjectState(baseDir, {
67
+ ...current,
68
+ activeChange: null,
69
+ status
70
+ });
71
+ }