pkg-scaffold 3.3.3 โ 3.3.5
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/README.md +62 -22
- package/bin/cli.js +7 -7
- package/package.json +5 -4
- package/pnpm-workspace.yaml +2 -0
- package/src/EngineContext.js +47 -19
- package/src/ast/ASTAnalyzer.js +287 -132
- package/src/ast/BarrelParser.js +51 -19
- package/src/ast/DeadCodeDetector.js +73 -0
- package/src/ast/MagicDetector.js +111 -11
- package/src/ast/OxcAnalyzer.js +250 -79
- package/src/healing/GitSandbox.js +44 -122
- package/src/healing/SelfHealer.js +29 -130
- package/src/index.js +124 -108
- package/src/performance/WorkerTaskRunner.js +17 -5
- package/src/plugins/PluginRegistry.js +28 -1
- package/src/plugins/ecosystems/MorePlugins.js +184 -0
- package/src/plugins/ecosystems/PluginLoader.js +20 -0
- package/src/resolution/CircularDetector.js +3 -34
- package/src/resolution/ConfigLoader.js +34 -6
- package/src/resolution/DependencyProfiler.js +261 -9
- package/src/resolution/WorkSpaceGraph.js +148 -35
- package/src/performance/SecretDetector.js +0 -378
|
@@ -1,160 +1,82 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execa } from 'execa';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* Manages atomic
|
|
5
|
+
* Deterministic Version Control Guard for Structural Healing Operations.
|
|
6
|
+
* Manages atomic state rollbacks when automated refactoring breaks the build.
|
|
7
7
|
*/
|
|
8
8
|
export class GitSandbox {
|
|
9
9
|
constructor(context) {
|
|
10
10
|
this.context = context;
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
this.hasStashedChanges = false;
|
|
14
|
-
this.isGitRepository = false;
|
|
11
|
+
this.initialBranch = '';
|
|
12
|
+
this.healingBranch = `scaffold-healing-${Date.now()}`;
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
16
|
+
* Captures the current repository state before applying structural modifications.
|
|
19
17
|
*/
|
|
20
|
-
async
|
|
21
|
-
this.verifyGitRepositoryPresence();
|
|
22
|
-
if (!this.isGitRepository) return;
|
|
23
|
-
|
|
18
|
+
async captureState() {
|
|
24
19
|
try {
|
|
25
|
-
|
|
26
|
-
this.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
// Check for uncommitted working directory changes
|
|
32
|
-
const statusOutput = execSync('git status --porcelain', {
|
|
33
|
-
cwd: this.context.cwd,
|
|
34
|
-
encoding: 'utf8'
|
|
35
|
-
}).trim();
|
|
36
|
-
|
|
37
|
-
if (statusOutput.length > 0) {
|
|
38
|
-
if (this.context.verbose) {
|
|
39
|
-
console.log('๐ฆ Working tree contains uncommitted changes. Stashing before running pipeline...');
|
|
40
|
-
}
|
|
41
|
-
execSync('git stash save "pkg-scaffold: Ephemeral Checkpoint Stash"', {
|
|
42
|
-
cwd: this.context.cwd,
|
|
43
|
-
stdio: 'ignore'
|
|
44
|
-
});
|
|
45
|
-
this.hasStashedChanges = true;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Generate an isolated tracking branch name
|
|
49
|
-
this.sandboxBranch = `scaffold-heal-${Date.now()}`;
|
|
50
|
-
execSync(`git checkout -b ${this.sandboxBranch}`, {
|
|
51
|
-
cwd: this.context.cwd,
|
|
52
|
-
stdio: 'ignore'
|
|
53
|
-
});
|
|
54
|
-
|
|
20
|
+
const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: this.context.cwd });
|
|
21
|
+
this.initialBranch = stdout.trim();
|
|
22
|
+
|
|
23
|
+
// Create a temporary recovery branch
|
|
24
|
+
await execa('git', ['checkout', '-b', this.healingBranch], { cwd: this.context.cwd });
|
|
55
25
|
if (this.context.verbose) {
|
|
56
|
-
console.log(
|
|
26
|
+
console.log(`[Git] State captured in temporary branch: ${this.healingBranch}`);
|
|
57
27
|
}
|
|
58
|
-
} catch (
|
|
59
|
-
throw new Error(`Git
|
|
28
|
+
} catch (e) {
|
|
29
|
+
throw new Error(`Git state capture failed: Ensure the directory is a git repository. (${e.message})`);
|
|
60
30
|
}
|
|
61
31
|
}
|
|
62
32
|
|
|
63
33
|
/**
|
|
64
|
-
*
|
|
34
|
+
* Reverts all changes applied during the healing cycle if verification fails.
|
|
65
35
|
*/
|
|
66
|
-
async
|
|
67
|
-
if (!this.isGitRepository) return;
|
|
68
|
-
this.assertActiveIsolation();
|
|
69
|
-
|
|
36
|
+
async rollback() {
|
|
70
37
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}).trim();
|
|
78
|
-
|
|
79
|
-
if (diffIndex.length === 0) return; // No modifications to verify
|
|
80
|
-
|
|
81
|
-
execSync(`git commit -m "${commitMessage}" --no-verify`, {
|
|
82
|
-
cwd: this.context.cwd,
|
|
83
|
-
stdio: 'ignore'
|
|
84
|
-
});
|
|
85
|
-
} catch (error) {
|
|
86
|
-
throw new Error(`Failed to stage changes inside the sandbox: ${error.message}`);
|
|
38
|
+
console.log(`[Git] Rolling back structural modifications...`);
|
|
39
|
+
await execa('git', ['reset', '--hard', 'HEAD'], { cwd: this.context.cwd });
|
|
40
|
+
await execa('git', ['checkout', this.initialBranch], { cwd: this.context.cwd });
|
|
41
|
+
await execa('git', ['branch', '-D', this.healingBranch], { cwd: this.context.cwd });
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error(`[Git] Critical rollback failure: ${e.message}`);
|
|
87
44
|
}
|
|
88
45
|
}
|
|
89
46
|
|
|
90
47
|
/**
|
|
91
|
-
*
|
|
48
|
+
* Finalizes the healing cycle by merging changes back to the original branch.
|
|
92
49
|
*/
|
|
93
|
-
async
|
|
94
|
-
if (!this.isGitRepository) return;
|
|
95
|
-
this.assertActiveIsolation();
|
|
96
|
-
|
|
50
|
+
async commit() {
|
|
97
51
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
52
|
+
await execa('git', ['add', '.'], { cwd: this.context.cwd });
|
|
53
|
+
await execa('git', ['commit', '-m', 'chore: automated structural healing (pkg-scaffold)'], { cwd: this.context.cwd });
|
|
100
54
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.restorePreviousWorkingState();
|
|
111
|
-
} catch (error) {
|
|
112
|
-
throw new Error(`Failed to merge sandbox modifications into mainline branch: ${error.message}`);
|
|
55
|
+
await execa('git', ['checkout', this.initialBranch], { cwd: this.context.cwd });
|
|
56
|
+
await execa('git', ['merge', this.healingBranch], { cwd: this.context.cwd });
|
|
57
|
+
await execa('git', ['branch', '-D', this.healingBranch], { cwd: this.context.cwd });
|
|
58
|
+
|
|
59
|
+
if (this.context.verbose) {
|
|
60
|
+
console.log(`[Git] Structural modifications successfully merged into ${this.initialBranch}`);
|
|
61
|
+
}
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error(`[Git] Commit failed: ${e.message}`);
|
|
113
64
|
}
|
|
114
65
|
}
|
|
115
66
|
|
|
116
67
|
/**
|
|
117
|
-
*
|
|
68
|
+
* Runs a verification command (e.g., npm test) to ensure structural integrity.
|
|
118
69
|
*/
|
|
119
|
-
async
|
|
120
|
-
if (!this.isGitRepository) return;
|
|
121
|
-
if (!this.sandboxBranch) return;
|
|
122
|
-
|
|
70
|
+
async verifyIntegrity() {
|
|
123
71
|
try {
|
|
72
|
+
const [cmd, ...args] = this.context.testCommand.split(' ');
|
|
73
|
+
await execa(cmd, args, { cwd: this.context.cwd });
|
|
74
|
+
return true;
|
|
75
|
+
} catch (e) {
|
|
124
76
|
if (this.context.verbose) {
|
|
125
|
-
console.
|
|
77
|
+
console.warn(`[Git] Integrity verification failed: ${e.message}`);
|
|
126
78
|
}
|
|
127
|
-
|
|
128
|
-
execSync('git add . && git reset --hard HEAD', { cwd: this.context.cwd, stdio: 'ignore' });
|
|
129
|
-
execSync(`git checkout ${this.originalBranch}`, { cwd: this.context.cwd, stdio: 'ignore' });
|
|
130
|
-
execSync(`git branch -D ${this.sandboxBranch}`, { cwd: this.context.cwd, stdio: 'ignore' });
|
|
131
|
-
|
|
132
|
-
this.restorePreviousWorkingState();
|
|
133
|
-
} catch (error) {
|
|
134
|
-
console.error(`๐จ Critical Recovery Error: Failed to drop sandbox branch cleanly: ${error.message}`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
restorePreviousWorkingState() {
|
|
139
|
-
if (this.hasStashedChanges) {
|
|
140
|
-
execSync('git stash pop', { cwd: this.context.cwd, stdio: 'ignore' });
|
|
141
|
-
this.hasStashedChanges = false;
|
|
142
|
-
}
|
|
143
|
-
this.sandboxBranch = null;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
verifyGitRepositoryPresence() {
|
|
147
|
-
try {
|
|
148
|
-
execSync('git rev-parse --is-inside-work-tree', { cwd: this.context.cwd, stdio: 'ignore' });
|
|
149
|
-
this.isGitRepository = true;
|
|
150
|
-
} catch {
|
|
151
|
-
this.isGitRepository = false;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
assertActiveIsolation() {
|
|
156
|
-
if (!this.sandboxBranch) {
|
|
157
|
-
throw new Error('Git Sandbox operation error: No active sandbox tracking context exists.');
|
|
79
|
+
return false;
|
|
158
80
|
}
|
|
159
81
|
}
|
|
160
82
|
}
|
|
@@ -1,150 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from 'path';
|
|
1
|
+
import ansis from 'ansis';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Automated Structural Healing Orchestrator.
|
|
5
|
+
* Manages the lifecycle of applying structural fixes and verifying codebase health.
|
|
6
|
+
* This is a deterministic engine and does not use AI/LLMs.
|
|
7
7
|
*/
|
|
8
8
|
export class SelfHealer {
|
|
9
|
-
constructor(context,
|
|
9
|
+
constructor(context, txManager, gitSandbox) {
|
|
10
10
|
this.context = context;
|
|
11
|
-
this.
|
|
11
|
+
this.txManager = txManager;
|
|
12
12
|
this.gitSandbox = gitSandbox;
|
|
13
|
-
this.executionTimeout = 45000; // 45-second execution timeout wall
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {Function}
|
|
16
|
+
* Executes a structural healing cycle with automatic rollback on failure.
|
|
17
|
+
* @param {Function} refactorLogic - Async function that stages structural changes
|
|
19
18
|
*/
|
|
20
|
-
async runSelfHealingLifecycle(
|
|
21
|
-
console.log('
|
|
19
|
+
async runSelfHealingLifecycle(refactorLogic) {
|
|
20
|
+
console.log(ansis.bold.blue('\n๐ฉน Initiating Automated Structural Healing Cycle...'));
|
|
22
21
|
|
|
23
|
-
// Step 1: Open the transaction boundaries
|
|
24
|
-
await this.gitSandbox.establishIsolationCheckpoint();
|
|
25
|
-
await this.transactionManager.begin();
|
|
26
|
-
|
|
27
22
|
try {
|
|
28
|
-
//
|
|
29
|
-
await
|
|
23
|
+
// 1. Capture current stable state
|
|
24
|
+
await this.gitSandbox.captureState();
|
|
25
|
+
|
|
26
|
+
// 2. Execute the provided refactoring logic (staging deletions/writes)
|
|
27
|
+
await refactorLogic();
|
|
30
28
|
|
|
31
|
-
//
|
|
32
|
-
await this.
|
|
29
|
+
// 3. Commit staged changes to disk
|
|
30
|
+
await this.txManager.commitAll();
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
// 4. Verify structural integrity (e.g., run tests)
|
|
33
|
+
console.log(ansis.dim('๐งช Verifying codebase integrity...'));
|
|
34
|
+
const isHealthy = await this.gitSandbox.verifyIntegrity();
|
|
36
35
|
|
|
37
|
-
if (
|
|
38
|
-
console.log('
|
|
39
|
-
await this.
|
|
40
|
-
await this.gitSandbox.acceptAndMergeOptimizations();
|
|
41
|
-
return true;
|
|
36
|
+
if (isHealthy) {
|
|
37
|
+
console.log(ansis.bold.green('โ
Structural integrity verified. Finalizing changes.'));
|
|
38
|
+
await this.gitSandbox.commit();
|
|
42
39
|
} else {
|
|
43
|
-
console.
|
|
44
|
-
await this.
|
|
45
|
-
|
|
40
|
+
console.log(ansis.bold.red('โ Structural integrity compromised. Rolling back changes.'));
|
|
41
|
+
await this.gitSandbox.rollback();
|
|
42
|
+
this.context.metrics.securityVulnerabilitiesMitigated = 0; // Reset metrics for failed cycle
|
|
46
43
|
}
|
|
47
|
-
} catch (
|
|
48
|
-
console.error(
|
|
49
|
-
await this.
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Spawns testing processes to detect exit code alerts or compiler trace metrics.
|
|
56
|
-
* @returns {Promise<boolean>} True if the test suite runs with an exit code of 0
|
|
57
|
-
*/
|
|
58
|
-
verifyProjectHealthStatus() {
|
|
59
|
-
return new Promise((resolve) => {
|
|
60
|
-
const commandTokens = this.context.testCommand.split(' ');
|
|
61
|
-
const executionBinary = commandTokens.shift();
|
|
62
|
-
|
|
63
|
-
const processBuffer = [];
|
|
64
|
-
const testProcess = spawn(executionBinary, commandTokens, {
|
|
65
|
-
cwd: this.context.cwd,
|
|
66
|
-
shell: true
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Implement an execution timeout monitor to prevent hanging test suites from blocking the pipeline
|
|
70
|
-
const timeoutWatch = setTimeout(() => {
|
|
71
|
-
console.warn('โฑ๏ธ Test execution exceeded timeout limit. Terminating subprocess...');
|
|
72
|
-
testProcess.kill('SIGKILL');
|
|
73
|
-
}, this.executionTimeout);
|
|
74
|
-
|
|
75
|
-
testProcess.stdout.on('data', (data) => {
|
|
76
|
-
processBuffer.push(data);
|
|
77
|
-
if (this.context.verbose) {
|
|
78
|
-
process.stdout.write(data);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
testProcess.stderr.on('data', (data) => {
|
|
83
|
-
processBuffer.push(data);
|
|
84
|
-
if (this.context.verbose) {
|
|
85
|
-
process.stderr.write(data);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
testProcess.on('close', (exitCode) => {
|
|
90
|
-
clearTimeout(timeoutWatch);
|
|
91
|
-
|
|
92
|
-
if (exitCode !== 0) {
|
|
93
|
-
const fullConsoleOutput = Buffer.concat(processBuffer).toString('utf8');
|
|
94
|
-
this.diagnoseErrorOutput(fullConsoleOutput);
|
|
95
|
-
resolve(false);
|
|
96
|
-
} else {
|
|
97
|
-
resolve(true);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
testProcess.on('error', (err) => {
|
|
102
|
-
clearTimeout(timeoutWatch);
|
|
103
|
-
if (this.context.verbose) {
|
|
104
|
-
console.error(`Subprocess execution error: ${err.message}`);
|
|
105
|
-
}
|
|
106
|
-
resolve(false);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Traces error codes and console log outputs to identify the root cause of a broken build.
|
|
113
|
-
*/
|
|
114
|
-
diagnoseErrorOutput(consoleLogOutput) {
|
|
115
|
-
console.log('\n๐ [Diagnostics] Reviewing error output...');
|
|
116
|
-
|
|
117
|
-
// Scan for standard TypeScript Compilation errors
|
|
118
|
-
const tsErrorPattern = /error\s+TS(\d+):\s+([\s\S]*?)$/m;
|
|
119
|
-
const tsMatches = consoleLogOutput.match(tsErrorPattern);
|
|
120
|
-
|
|
121
|
-
if (tsMatches) {
|
|
122
|
-
console.error(`โ Mapped Type Error Code [TS${tsMatches[1]}]: ${tsMatches[2].trim()}`);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Scan for missing file imports or runtime resolution exceptions
|
|
127
|
-
const missingModulePattern = /Cannot find module '([^']+)'/i;
|
|
128
|
-
const moduleMatches = consoleLogOutput.match(missingModulePattern);
|
|
129
|
-
|
|
130
|
-
if (moduleMatches) {
|
|
131
|
-
console.error(`โ Missing Dependency Reference Pointer: Cannot locate element [${moduleMatches[1]}]`);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.error('โ Test suite execution failed. Check standard console output for details.');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Automatically executes a rollback event, restoring both file states and Git status.
|
|
140
|
-
*/
|
|
141
|
-
async revertWorkspaceToSafeState() {
|
|
142
|
-
try {
|
|
143
|
-
await this.transactionManager.rollback();
|
|
144
|
-
await this.gitSandbox.rejectAndAbortOptimizations();
|
|
145
|
-
console.log('๐ [Self-Healing] Rollback complete. Original project states restored.');
|
|
146
|
-
} catch (recoveryError) {
|
|
147
|
-
console.error(`๐จ Fatal Recovery Error: Failed to restore prior workspace configuration: ${recoveryError.message}`);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(ansis.bold.red(`\n๐จ Healing Cycle Aborted: ${error.message}`));
|
|
46
|
+
await this.gitSandbox.rollback();
|
|
148
47
|
}
|
|
149
48
|
}
|
|
150
49
|
}
|