astrocode-workflow 0.3.3 → 0.3.4
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/package.json +1 -1
- package/src/state/repo-lock.ts +41 -16
package/package.json
CHANGED
package/src/state/repo-lock.ts
CHANGED
|
@@ -83,6 +83,7 @@ function safeUnlink(p: string) {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Reads & validates lock file defensively.
|
|
86
|
+
* Supports both v2 JSON format and legacy PID-only format for compatibility.
|
|
86
87
|
* Returns null on any parse/validation failure.
|
|
87
88
|
*/
|
|
88
89
|
function readLock(lockPath: string): LockFile | null {
|
|
@@ -91,23 +92,46 @@ function readLock(lockPath: string): LockFile | null {
|
|
|
91
92
|
if (!st.isFile()) return null;
|
|
92
93
|
if (st.size <= 0 || st.size > MAX_LOCK_BYTES) return null;
|
|
93
94
|
|
|
94
|
-
const raw = fs.readFileSync(lockPath, "utf8");
|
|
95
|
-
const parsed = JSON.parse(raw) as LockFile;
|
|
95
|
+
const raw = fs.readFileSync(lockPath, "utf8").trim();
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
// Try v2 JSON first
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(raw) as LockFile;
|
|
100
|
+
if (parsed && typeof parsed === "object" && parsed.v === LOCK_VERSION) {
|
|
101
|
+
if (typeof parsed.pid !== "number") return null;
|
|
102
|
+
if (typeof parsed.created_at !== "string") return null;
|
|
103
|
+
if (typeof parsed.updated_at !== "string") return null;
|
|
104
|
+
if (typeof parsed.repo_root !== "string") return null;
|
|
105
|
+
if (typeof parsed.instance_id !== "string") return null;
|
|
106
|
+
if (typeof parsed.lease_id !== "string") return null;
|
|
107
|
+
|
|
108
|
+
if (parsed.session_id !== undefined && typeof parsed.session_id !== "string") return null;
|
|
109
|
+
if (parsed.owner !== undefined && typeof parsed.owner !== "string") return null;
|
|
110
|
+
|
|
111
|
+
return parsed;
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
// Not JSON, try legacy format
|
|
115
|
+
}
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
|
|
117
|
+
// Legacy format: just PID as number string
|
|
118
|
+
const legacyPid = parseInt(raw, 10);
|
|
119
|
+
if (Number.isNaN(legacyPid) || legacyPid <= 0) return null;
|
|
109
120
|
|
|
110
|
-
|
|
121
|
+
// Convert legacy to v2 format
|
|
122
|
+
const now = nowISO();
|
|
123
|
+
const leaseId = crypto.randomUUID();
|
|
124
|
+
return {
|
|
125
|
+
v: LOCK_VERSION,
|
|
126
|
+
pid: legacyPid,
|
|
127
|
+
created_at: now, // Approximate
|
|
128
|
+
updated_at: now,
|
|
129
|
+
repo_root: "", // Unknown, will be filled by caller
|
|
130
|
+
instance_id: PROCESS_INSTANCE_ID, // Assume same instance
|
|
131
|
+
session_id: undefined,
|
|
132
|
+
lease_id: leaseId,
|
|
133
|
+
owner: "legacy-lock",
|
|
134
|
+
};
|
|
111
135
|
} catch {
|
|
112
136
|
return null;
|
|
113
137
|
}
|
|
@@ -453,8 +477,8 @@ export async function acquireRepoLock(opts: {
|
|
|
453
477
|
continue;
|
|
454
478
|
}
|
|
455
479
|
|
|
456
|
-
// Re-entrant by SAME PROCESS IDENTITY (pid+instance).
|
|
457
|
-
if (existing.pid === myPid && existing.instance_id === PROCESS_INSTANCE_ID) {
|
|
480
|
+
// Re-entrant by SAME PROCESS IDENTITY (pid+instance), or legacy lock with same PID.
|
|
481
|
+
if (existing.pid === myPid && (existing.instance_id === PROCESS_INSTANCE_ID || existing.owner === "legacy-lock")) {
|
|
458
482
|
const leaseId = crypto.randomUUID();
|
|
459
483
|
|
|
460
484
|
writeLockAtomicish(lockPath, {
|
|
@@ -462,6 +486,7 @@ export async function acquireRepoLock(opts: {
|
|
|
462
486
|
v: LOCK_VERSION,
|
|
463
487
|
updated_at: nowISO(),
|
|
464
488
|
repo_root: repoRoot,
|
|
489
|
+
instance_id: PROCESS_INSTANCE_ID, // Upgrade legacy
|
|
465
490
|
session_id: sessionId ?? existing.session_id,
|
|
466
491
|
owner: owner ?? existing.owner,
|
|
467
492
|
lease_id: leaseId,
|