ultra-builder-pro-cli 0.25.0 → 0.25.1
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/CHANGELOG.md +9 -0
- package/mcp-server/lib/runtime-paths.cjs +43 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.25.1] — 2026-07-31
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Published state-migration lock ownership atomically from a fully written and
|
|
15
|
+
synchronized candidate inode, so concurrent Node 22 processes cannot mistake a
|
|
16
|
+
valid publication or release window for a malformed lock. Stable malformed locks
|
|
17
|
+
remain fail-closed.
|
|
18
|
+
|
|
10
19
|
## [0.25.0] — 2026-07-31
|
|
11
20
|
|
|
12
21
|
### Added
|
|
@@ -599,15 +599,37 @@ function processIsAlive(pid) {
|
|
|
599
599
|
|
|
600
600
|
function readMigrationGate(gatePath) {
|
|
601
601
|
const stat = lstatOrNull(gatePath);
|
|
602
|
-
if (!stat
|
|
602
|
+
if (!stat) return { missing: true };
|
|
603
|
+
if (stat.isSymbolicLink() || !stat.isFile()) return null;
|
|
603
604
|
try {
|
|
604
605
|
const owner = JSON.parse(fs.readFileSync(gatePath, 'utf8'));
|
|
605
606
|
return { owner, stat };
|
|
606
|
-
} catch {
|
|
607
|
+
} catch (error) {
|
|
608
|
+
if (error.code === 'ENOENT') return { missing: true };
|
|
607
609
|
return null;
|
|
608
610
|
}
|
|
609
611
|
}
|
|
610
612
|
|
|
613
|
+
function createMigrationGateCandidate(gatePath, owner) {
|
|
614
|
+
while (true) {
|
|
615
|
+
const candidatePath = `${gatePath}.candidate-${process.pid}-${randomUUID()}`;
|
|
616
|
+
let descriptor;
|
|
617
|
+
try {
|
|
618
|
+
descriptor = fs.openSync(candidatePath, 'wx', 0o600);
|
|
619
|
+
fs.writeFileSync(descriptor, `${JSON.stringify(owner)}\n`);
|
|
620
|
+
fs.fsyncSync(descriptor);
|
|
621
|
+
return { candidatePath, descriptor };
|
|
622
|
+
} catch (error) {
|
|
623
|
+
if (descriptor !== undefined) {
|
|
624
|
+
try { fs.closeSync(descriptor); } catch { /* best effort */ }
|
|
625
|
+
}
|
|
626
|
+
fs.rmSync(candidatePath, { force: true });
|
|
627
|
+
if (error.code === 'EEXIST') continue;
|
|
628
|
+
throw error;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
611
633
|
function reclaimDeadMigrationGate(gatePath, observed) {
|
|
612
634
|
const quarantine = `${gatePath}.stale-${process.pid}-${randomUUID()}`;
|
|
613
635
|
fs.renameSync(gatePath, quarantine);
|
|
@@ -635,28 +657,28 @@ function acquireStateMigrationGate(paths, {
|
|
|
635
657
|
} = {}) {
|
|
636
658
|
const gatePath = path.join(paths.runtimeDir, 'state-migration.lock');
|
|
637
659
|
const token = randomUUID();
|
|
660
|
+
const owner = {
|
|
661
|
+
version: 2,
|
|
662
|
+
pid: process.pid,
|
|
663
|
+
owner_started_at: processStartMarker(process.pid),
|
|
664
|
+
token,
|
|
665
|
+
legacy_state_db: paths.legacyStateDbPath,
|
|
666
|
+
runtime_state_db: paths.stateDbPath,
|
|
667
|
+
};
|
|
638
668
|
const deadline = Date.now() + timeoutMs;
|
|
639
669
|
let descriptor;
|
|
640
670
|
while (descriptor === undefined) {
|
|
671
|
+
const candidate = createMigrationGateCandidate(gatePath, owner);
|
|
672
|
+
let published = false;
|
|
641
673
|
try {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
pid: process.pid,
|
|
646
|
-
owner_started_at: processStartMarker(process.pid),
|
|
647
|
-
token,
|
|
648
|
-
legacy_state_db: paths.legacyStateDbPath,
|
|
649
|
-
runtime_state_db: paths.stateDbPath,
|
|
650
|
-
})}\n`);
|
|
651
|
-
fs.fsyncSync(descriptor);
|
|
674
|
+
fs.linkSync(candidate.candidatePath, gatePath);
|
|
675
|
+
descriptor = candidate.descriptor;
|
|
676
|
+
published = true;
|
|
652
677
|
break;
|
|
653
678
|
} catch (error) {
|
|
654
|
-
if (descriptor !== undefined) {
|
|
655
|
-
try { fs.closeSync(descriptor); } catch { /* best effort */ }
|
|
656
|
-
descriptor = undefined;
|
|
657
|
-
}
|
|
658
679
|
if (error.code !== 'EEXIST') throw error;
|
|
659
680
|
const observed = readMigrationGate(gatePath);
|
|
681
|
+
if (observed?.missing) continue;
|
|
660
682
|
const ownerPid = Number(observed?.owner?.pid);
|
|
661
683
|
const live = processIsAlive(ownerPid);
|
|
662
684
|
const currentStart = live ? processStartMarker(ownerPid) : null;
|
|
@@ -684,6 +706,11 @@ function acquireStateMigrationGate(paths, {
|
|
|
684
706
|
continue;
|
|
685
707
|
}
|
|
686
708
|
reclaimDeadMigrationGate(gatePath, observed);
|
|
709
|
+
} finally {
|
|
710
|
+
fs.rmSync(candidate.candidatePath, { force: true });
|
|
711
|
+
if (!published) {
|
|
712
|
+
try { fs.closeSync(candidate.descriptor); } catch { /* best effort */ }
|
|
713
|
+
}
|
|
687
714
|
}
|
|
688
715
|
}
|
|
689
716
|
return () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra-builder-pro-cli",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "Explicitly invoked Ultra Builder Pro workflows for Claude Code, OpenCode, Codex CLI, Kimi Code, and Grok Build, with a project-local MCP persistence and safety kernel.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ultra-builder-pro-cli": "bin/install.js",
|