@inoceanlee/brc 2.1.1 → 2.1.2
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/dist/cli.js +68 -16
- package/dist/cli.js.map +1 -1
- package/dist/commands/setup.d.ts +14 -0
- package/dist/commands/setup.js +57 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/config/manager.js +16 -8
- package/dist/config/manager.js.map +1 -1
- package/dist/config/settings.d.ts +5 -1
- package/dist/config/settings.js +5 -1
- package/dist/config/settings.js.map +1 -1
- package/dist/lifecycle/identity.d.ts +8 -0
- package/dist/lifecycle/identity.js +126 -0
- package/dist/lifecycle/identity.js.map +1 -0
- package/dist/lifecycle/lock-store.d.ts +28 -0
- package/dist/lifecycle/lock-store.js +204 -0
- package/dist/lifecycle/lock-store.js.map +1 -0
- package/dist/lifecycle/lock.d.ts +12 -3
- package/dist/lifecycle/lock.js +50 -74
- package/dist/lifecycle/lock.js.map +1 -1
- package/dist/lifecycle/processes.d.ts +5 -7
- package/dist/lifecycle/processes.js +106 -108
- package/dist/lifecycle/processes.js.map +1 -1
- package/dist/lifecycle/services.d.ts +1 -0
- package/dist/lifecycle/services.js +2 -5
- package/dist/lifecycle/services.js.map +1 -1
- package/dist/maintenance/cleanup.js +177 -71
- package/dist/maintenance/cleanup.js.map +1 -1
- package/dist/native/win32-x64/brc-process.exe +0 -0
- package/dist/progress.d.ts +29 -0
- package/dist/progress.js +159 -0
- package/dist/progress.js.map +1 -0
- package/dist/services/agent/cli.js +1 -2
- package/dist/services/agent/cli.js.map +1 -1
- package/dist/services/agent/core/config-field-definitions.d.ts +1 -0
- package/dist/services/agent/core/config-field-definitions.js +36 -0
- package/dist/services/agent/core/config-field-definitions.js.map +1 -1
- package/dist/services/agent/core/config-manager.d.ts +3 -5
- package/dist/services/agent/core/config-manager.js +64 -109
- package/dist/services/agent/core/config-manager.js.map +1 -1
- package/dist/services/agent/core/config-storage.d.ts +11 -0
- package/dist/services/agent/core/config-storage.js +66 -0
- package/dist/services/agent/core/config-storage.js.map +1 -0
- package/dist/services/agent/core/config.d.ts +5 -0
- package/dist/services/agent/core/config.js +5 -1
- package/dist/services/agent/core/config.js.map +1 -1
- package/dist/services/agent/core/handlers/filesystem-handlers.js +3 -2
- package/dist/services/agent/core/handlers/filesystem-handlers.js.map +1 -1
- package/dist/services/agent/core/tools/config.d.ts +3 -1
- package/dist/services/agent/core/tools/config.js +5 -66
- package/dist/services/agent/core/tools/config.js.map +1 -1
- package/dist/services/agent/core/tools/edit.js +2 -1
- package/dist/services/agent/core/tools/edit.js.map +1 -1
- package/dist/services/agent/core/tools/filesystem.js +15 -21
- package/dist/services/agent/core/tools/filesystem.js.map +1 -1
- package/dist/services/agent/core/tools/improved-process-tools.js +3 -2
- package/dist/services/agent/core/tools/improved-process-tools.js.map +1 -1
- package/dist/services/agent/core/tools/schemas.d.ts +2 -2
- package/dist/services/agent/core/tools/schemas.js +1 -1
- package/dist/services/agent/core/tools/schemas.js.map +1 -1
- package/dist/services/agent/core/utils/files/text-reader.d.ts +31 -0
- package/dist/services/agent/core/utils/files/text-reader.js +261 -0
- package/dist/services/agent/core/utils/files/text-reader.js.map +1 -0
- package/dist/services/agent/core/utils/files/text.d.ts +1 -25
- package/dist/services/agent/core/utils/files/text.js +6 -245
- package/dist/services/agent/core/utils/files/text.js.map +1 -1
- package/dist/services/agent/core/utils/fuzzySearchLogger.js +2 -2
- package/dist/services/agent/core/utils/fuzzySearchLogger.js.map +1 -1
- package/dist/services/agent/core/utils/toolHistory.d.ts +2 -1
- package/dist/services/agent/core/utils/toolHistory.js +65 -79
- package/dist/services/agent/core/utils/toolHistory.js.map +1 -1
- package/dist/services/agent/core/utils/toolHistoryStorage.d.ts +11 -0
- package/dist/services/agent/core/utils/toolHistoryStorage.js +135 -0
- package/dist/services/agent/core/utils/toolHistoryStorage.js.map +1 -0
- package/dist/services/agent/dispatcher.js +3 -5
- package/dist/services/agent/dispatcher.js.map +1 -1
- package/dist/services/agent/service.js +2 -1
- package/dist/services/agent/service.js.map +1 -1
- package/dist/services/agent/transport/pairing.js +24 -24
- package/dist/services/agent/transport/pairing.js.map +1 -1
- package/dist/services/relay/store/sqlite.d.ts +1 -6
- package/dist/services/relay/store/sqlite.js +84 -84
- package/dist/services/relay/store/sqlite.js.map +1 -1
- package/dist/traefik/core.d.ts +17 -5
- package/dist/traefik/core.js +70 -64
- package/dist/traefik/core.js.map +1 -1
- package/dist/traefik/input.d.ts +6 -7
- package/dist/traefik/input.js +46 -88
- package/dist/traefik/input.js.map +1 -1
- package/dist/traefik/manager.d.ts +13 -0
- package/dist/traefik/manager.js +64 -24
- package/dist/traefik/manager.js.map +1 -1
- package/dist/traefik/output.d.ts +9 -11
- package/dist/traefik/output.js +112 -46
- package/dist/traefik/output.js.map +1 -1
- package/dist/traefik/runtime.d.ts +1 -1
- package/dist/traefik/runtime.js +4 -3
- package/dist/traefik/runtime.js.map +1 -1
- package/node_modules/brc-shared/package.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { BrcPaths } from '../config/paths.js';
|
|
2
|
+
import type { ProcessIdentity } from './identity.js';
|
|
3
|
+
export interface LockOwner extends ProcessIdentity {
|
|
4
|
+
version: 1;
|
|
5
|
+
workspaceRoot: string;
|
|
6
|
+
token: string;
|
|
7
|
+
}
|
|
8
|
+
interface LockSnapshot {
|
|
9
|
+
owner: LockOwner;
|
|
10
|
+
contents: string;
|
|
11
|
+
dev: number;
|
|
12
|
+
ino: number;
|
|
13
|
+
birthtimeMs: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class LockStore {
|
|
16
|
+
private readonly paths;
|
|
17
|
+
readonly lockPath: string;
|
|
18
|
+
constructor(paths: BrcPaths);
|
|
19
|
+
private verifyDirectory;
|
|
20
|
+
acquire(owner: LockOwner): Promise<boolean>;
|
|
21
|
+
isMissing(): Promise<boolean>;
|
|
22
|
+
readOwner(): Promise<LockSnapshot>;
|
|
23
|
+
isolateAndDelete(snapshot: LockSnapshot, verify?: () => Promise<boolean>): Promise<void>;
|
|
24
|
+
private readMoved;
|
|
25
|
+
releaseIfOwned(token: string): Promise<void>;
|
|
26
|
+
reclaimExpired(inspect: (pid: number) => Promise<ProcessIdentity | null>): Promise<boolean>;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { lstat, mkdir, mkdtemp, readFile, rename, rmdir, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
function code(error) {
|
|
5
|
+
return error && typeof error === 'object' && 'code' in error && typeof error.code === 'string'
|
|
6
|
+
? error.code : undefined;
|
|
7
|
+
}
|
|
8
|
+
function validOwner(value, root) {
|
|
9
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
10
|
+
return false;
|
|
11
|
+
const v = value;
|
|
12
|
+
return v.version === 1 && v.workspaceRoot === root
|
|
13
|
+
&& typeof v.token === 'string' && /^[0-9a-f-]{36}$/i.test(v.token)
|
|
14
|
+
&& typeof v.pid === 'number' && Number.isSafeInteger(v.pid) && v.pid > 0
|
|
15
|
+
&& typeof v.createdAt === 'string' && v.createdAt.length > 0
|
|
16
|
+
&& typeof v.executablePath === 'string' && path.isAbsolute(v.executablePath)
|
|
17
|
+
&& typeof v.commandLine === 'string' && v.commandLine.length > 0;
|
|
18
|
+
}
|
|
19
|
+
function sameSnapshot(a, b) {
|
|
20
|
+
return a.dev === b.dev && a.ino === b.ino && a.birthtimeMs === b.birthtimeMs
|
|
21
|
+
&& a.contents === b.contents;
|
|
22
|
+
}
|
|
23
|
+
export class LockStore {
|
|
24
|
+
paths;
|
|
25
|
+
lockPath;
|
|
26
|
+
constructor(paths) {
|
|
27
|
+
this.paths = paths;
|
|
28
|
+
this.lockPath = path.join(paths.runtime, 'lifecycle.lock');
|
|
29
|
+
}
|
|
30
|
+
async verifyDirectory(dir) {
|
|
31
|
+
const info = await lstat(dir);
|
|
32
|
+
if (!info.isDirectory() || info.isSymbolicLink()) {
|
|
33
|
+
throw new Error('Lifecycle lock path is not a plain directory.');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async acquire(owner) {
|
|
37
|
+
if (!validOwner(owner, this.paths.root))
|
|
38
|
+
throw new Error('Invalid lifecycle lock owner.');
|
|
39
|
+
try {
|
|
40
|
+
await this.verifyDirectory(this.paths.root);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (code(error) !== 'ENOENT')
|
|
44
|
+
throw error;
|
|
45
|
+
await mkdir(this.paths.root, { recursive: true });
|
|
46
|
+
await this.verifyDirectory(this.paths.root);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
await mkdir(this.paths.runtime);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (code(error) !== 'EEXIST')
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
await this.verifyDirectory(this.paths.runtime);
|
|
56
|
+
const stage = await mkdtemp(path.join(this.paths.runtime, '.lifecycle-stage-'));
|
|
57
|
+
try {
|
|
58
|
+
await writeFile(path.join(stage, 'owner.json'), JSON.stringify(owner), { encoding: 'utf8', flag: 'wx', mode: 0o600 });
|
|
59
|
+
// Exclusive mkdir prevents Windows rename from replacing an existing lock file.
|
|
60
|
+
// A crash before owner publication leaves a detectable, unclaimed directory.
|
|
61
|
+
try {
|
|
62
|
+
await mkdir(this.lockPath);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (code(error) !== 'EEXIST' && code(error) !== 'EPERM' && code(error) !== 'EACCES')
|
|
66
|
+
throw error;
|
|
67
|
+
try {
|
|
68
|
+
await lstat(this.lockPath);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
catch (probe) {
|
|
72
|
+
if (code(probe) === 'ENOENT')
|
|
73
|
+
throw error;
|
|
74
|
+
throw probe;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
await rename(path.join(stage, 'owner.json'), path.join(this.lockPath, 'owner.json'));
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
try {
|
|
82
|
+
await unlink(path.join(stage, 'owner.json'));
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (code(error) !== 'ENOENT')
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await rmdir(stage);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (code(error) !== 'ENOENT')
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async isMissing() {
|
|
98
|
+
try {
|
|
99
|
+
await lstat(this.lockPath);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (code(error) === 'ENOENT')
|
|
104
|
+
return true;
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async readOwner() {
|
|
109
|
+
await this.verifyDirectory(this.paths.runtime);
|
|
110
|
+
const info = await lstat(this.lockPath);
|
|
111
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
112
|
+
throw new Error('Lifecycle lock is not a plain directory.');
|
|
113
|
+
const filename = path.join(this.lockPath, 'owner.json');
|
|
114
|
+
const fileInfo = await lstat(filename);
|
|
115
|
+
if (!fileInfo.isFile() || fileInfo.isSymbolicLink())
|
|
116
|
+
throw new Error('Lifecycle lock owner is not a plain file.');
|
|
117
|
+
const contents = await readFile(filename, 'utf8');
|
|
118
|
+
let parsed;
|
|
119
|
+
try {
|
|
120
|
+
parsed = JSON.parse(contents);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
throw new Error('Lifecycle lock owner is malformed.');
|
|
124
|
+
}
|
|
125
|
+
if (!validOwner(parsed, this.paths.root))
|
|
126
|
+
throw new Error('Lifecycle lock owner is incomplete or belongs to another data root.');
|
|
127
|
+
return { owner: parsed, contents, dev: info.dev, ino: info.ino, birthtimeMs: info.birthtimeMs };
|
|
128
|
+
}
|
|
129
|
+
async isolateAndDelete(snapshot, verify) {
|
|
130
|
+
const current = await this.readOwner();
|
|
131
|
+
if (!sameSnapshot(snapshot, current))
|
|
132
|
+
throw new Error('Lifecycle lock changed before isolation.');
|
|
133
|
+
const moved = path.join(this.paths.runtime, '.lifecycle-isolated-' + randomUUID());
|
|
134
|
+
await rename(this.lockPath, moved);
|
|
135
|
+
let safe = false;
|
|
136
|
+
try {
|
|
137
|
+
const isolated = await this.readMoved(moved);
|
|
138
|
+
if (!sameSnapshot(snapshot, isolated))
|
|
139
|
+
throw new Error('Lifecycle lock was replaced during isolation.');
|
|
140
|
+
if (verify && !await verify())
|
|
141
|
+
throw new Error('Lifecycle lock owner changed during recovery.');
|
|
142
|
+
// Refuse to remove any unexpected new files or ownership changes.
|
|
143
|
+
const final = await this.readMoved(moved);
|
|
144
|
+
if (!sameSnapshot(snapshot, final))
|
|
145
|
+
throw new Error('Lifecycle lock changed after isolation.');
|
|
146
|
+
safe = true;
|
|
147
|
+
await unlink(path.join(moved, 'owner.json'));
|
|
148
|
+
await rmdir(moved);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (!safe) {
|
|
152
|
+
try {
|
|
153
|
+
await rename(moved, this.lockPath);
|
|
154
|
+
}
|
|
155
|
+
catch { /* Preserve isolated contents for investigation. */ }
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async readMoved(dir) {
|
|
161
|
+
const info = await lstat(dir);
|
|
162
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
163
|
+
throw new Error('Isolated lock is not a plain directory.');
|
|
164
|
+
const file = path.join(dir, 'owner.json');
|
|
165
|
+
const fileInfo = await lstat(file);
|
|
166
|
+
if (!fileInfo.isFile() || fileInfo.isSymbolicLink())
|
|
167
|
+
throw new Error('Isolated owner is not a plain file.');
|
|
168
|
+
const contents = await readFile(file, 'utf8');
|
|
169
|
+
const value = JSON.parse(contents);
|
|
170
|
+
if (!validOwner(value, this.paths.root))
|
|
171
|
+
throw new Error('Isolated lock owner is invalid.');
|
|
172
|
+
return { owner: value, contents, dev: info.dev, ino: info.ino, birthtimeMs: info.birthtimeMs };
|
|
173
|
+
}
|
|
174
|
+
async releaseIfOwned(token) {
|
|
175
|
+
let snapshot;
|
|
176
|
+
try {
|
|
177
|
+
snapshot = await this.readOwner();
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
if (code(error) === 'ENOENT')
|
|
181
|
+
return;
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
if (snapshot.owner.token !== token)
|
|
185
|
+
return;
|
|
186
|
+
await this.isolateAndDelete(snapshot);
|
|
187
|
+
}
|
|
188
|
+
async reclaimExpired(inspect) {
|
|
189
|
+
const snapshot = await this.readOwner();
|
|
190
|
+
const identity = await inspect(snapshot.owner.pid);
|
|
191
|
+
if (identity) {
|
|
192
|
+
// A reused PID is not sufficient evidence to delete the previous owner's lock.
|
|
193
|
+
if (identity.createdAt !== snapshot.owner.createdAt
|
|
194
|
+
|| identity.executablePath !== snapshot.owner.executablePath
|
|
195
|
+
|| identity.commandLine !== snapshot.owner.commandLine) {
|
|
196
|
+
throw new Error('Lifecycle lock PID was reused or its owner identity changed.');
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
await this.isolateAndDelete(snapshot, async () => (await inspect(snapshot.owner.pid)) === null);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=lock-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock-store.js","sourceRoot":"","sources":["../../src/lifecycle/lock-store.ts"],"names":[],"mappings":"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"}
|
package/dist/lifecycle/lock.d.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import type { BrcPaths } from '../config/paths.js';
|
|
2
|
+
export interface LockWaitOptions {
|
|
3
|
+
waitMs?: number;
|
|
4
|
+
pollMs?: number;
|
|
5
|
+
}
|
|
2
6
|
export declare class LifecycleLock {
|
|
3
|
-
private
|
|
7
|
+
private static ownIdentity;
|
|
8
|
+
private static inspectSelf;
|
|
4
9
|
private queue;
|
|
5
10
|
private readonly context;
|
|
6
|
-
|
|
11
|
+
private readonly store;
|
|
12
|
+
private readonly paths;
|
|
13
|
+
private waitMs;
|
|
14
|
+
private pollMs;
|
|
15
|
+
constructor(paths: BrcPaths, options?: LockWaitOptions);
|
|
16
|
+
updateWaitSettings(options: LockWaitOptions): void;
|
|
7
17
|
runExclusive<T>(operation: () => Promise<T>): Promise<T>;
|
|
8
18
|
private execute;
|
|
9
|
-
private releaseIfOwned;
|
|
10
19
|
}
|
package/dist/lifecycle/lock.js
CHANGED
|
@@ -1,19 +1,37 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import { inspectProcess } from './
|
|
6
|
-
|
|
7
|
-
return error && typeof error === 'object' && 'code' in error && typeof error.code === 'string'
|
|
8
|
-
? error.code
|
|
9
|
-
: undefined;
|
|
10
|
-
}
|
|
3
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
4
|
+
import { DEFAULT_SETTINGS } from '../config/settings.js';
|
|
5
|
+
import { inspectProcess } from './identity.js';
|
|
6
|
+
import { LockStore } from './lock-store.js';
|
|
11
7
|
export class LifecycleLock {
|
|
12
|
-
|
|
8
|
+
static ownIdentity;
|
|
9
|
+
static inspectSelf() {
|
|
10
|
+
this.ownIdentity ??= inspectProcess(process.pid).then((identity) => {
|
|
11
|
+
if (!identity)
|
|
12
|
+
throw new Error('Cannot verify the CLI process identity for lifecycle locking.');
|
|
13
|
+
return identity;
|
|
14
|
+
}).catch((error) => {
|
|
15
|
+
this.ownIdentity = undefined;
|
|
16
|
+
throw error;
|
|
17
|
+
});
|
|
18
|
+
return this.ownIdentity;
|
|
19
|
+
}
|
|
13
20
|
queue = Promise.resolve();
|
|
14
21
|
context = new AsyncLocalStorage();
|
|
15
|
-
|
|
22
|
+
store;
|
|
23
|
+
paths;
|
|
24
|
+
waitMs;
|
|
25
|
+
pollMs;
|
|
26
|
+
constructor(paths, options = {}) {
|
|
16
27
|
this.paths = paths;
|
|
28
|
+
this.store = new LockStore(paths);
|
|
29
|
+
this.waitMs = options.waitMs ?? DEFAULT_SETTINGS.runtime.lockWaitMs;
|
|
30
|
+
this.pollMs = options.pollMs ?? DEFAULT_SETTINGS.runtime.lockPollMs;
|
|
31
|
+
}
|
|
32
|
+
updateWaitSettings(options) {
|
|
33
|
+
this.waitMs = options.waitMs ?? this.waitMs;
|
|
34
|
+
this.pollMs = options.pollMs ?? this.pollMs;
|
|
17
35
|
}
|
|
18
36
|
runExclusive(operation) {
|
|
19
37
|
if (this.context.getStore() === this) {
|
|
@@ -24,77 +42,35 @@ export class LifecycleLock {
|
|
|
24
42
|
return result;
|
|
25
43
|
}
|
|
26
44
|
async execute(operation) {
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const filename = path.join(this.paths.runtime, 'lifecycle.lock');
|
|
32
|
-
const id = randomUUID();
|
|
33
|
-
let handle;
|
|
34
|
-
try {
|
|
35
|
-
handle = await open(filename, 'wx', 0o600);
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
if (errorCode(error) === 'EEXIST')
|
|
39
|
-
throw new Error('Another BRC lifecycle operation is in progress.');
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
const identityOnDisk = await handle.stat();
|
|
43
|
-
let recordWritten = false;
|
|
44
|
-
try {
|
|
45
|
-
await handle.writeFile(`${JSON.stringify({ version: 1, ...identity, workspaceRoot: this.paths.root, id })}\n`, 'utf8');
|
|
46
|
-
recordWritten = true;
|
|
47
|
-
return await this.context.run(this, operation);
|
|
48
|
-
}
|
|
49
|
-
finally {
|
|
45
|
+
const identity = await LifecycleLock.inspectSelf();
|
|
46
|
+
const owner = { version: 1, ...identity, workspaceRoot: this.paths.root, token: randomUUID() };
|
|
47
|
+
const started = Date.now();
|
|
48
|
+
while (!await this.store.acquire(owner)) {
|
|
50
49
|
try {
|
|
51
|
-
await
|
|
52
|
-
|
|
53
|
-
finally {
|
|
54
|
-
await this.releaseIfOwned(filename, id, identityOnDisk, recordWritten);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
async releaseIfOwned(filename, id, identityOnDisk, recordWritten) {
|
|
59
|
-
if (recordWritten) {
|
|
60
|
-
let contents;
|
|
61
|
-
try {
|
|
62
|
-
contents = await readFile(filename, 'utf8');
|
|
50
|
+
if (await this.store.reclaimExpired(inspectProcess))
|
|
51
|
+
continue;
|
|
63
52
|
}
|
|
64
53
|
catch (error) {
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
54
|
+
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
|
55
|
+
if (await this.store.isMissing())
|
|
56
|
+
continue;
|
|
57
|
+
// A newly claimed directory may be publishing owner.json. Wait, never steal it.
|
|
58
|
+
if (Date.now() - started < this.waitMs) {
|
|
59
|
+
await sleep(this.pollMs);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw new Error('Lifecycle lock cannot be safely reclaimed.', { cause: error });
|
|
68
64
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (!record || typeof record !== 'object' || Array.isArray(record) || !('id' in record) || record.id !== id)
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
let current;
|
|
81
|
-
try {
|
|
82
|
-
current = await stat(filename);
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
if (errorCode(error) === 'ENOENT')
|
|
86
|
-
return;
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
89
|
-
if (current.dev !== identityOnDisk.dev || current.ino !== identityOnDisk.ino)
|
|
90
|
-
return;
|
|
65
|
+
if (Date.now() - started >= this.waitMs)
|
|
66
|
+
throw new Error('Another BRC lifecycle operation is in progress.');
|
|
67
|
+
await sleep(this.pollMs);
|
|
91
68
|
}
|
|
92
69
|
try {
|
|
93
|
-
await
|
|
70
|
+
return await this.context.run(this, operation);
|
|
94
71
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
throw error;
|
|
72
|
+
finally {
|
|
73
|
+
await this.store.releaseIfOwned(owner.token);
|
|
98
74
|
}
|
|
99
75
|
}
|
|
100
76
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/lifecycle/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/lifecycle/lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { BrcPaths } from '../config/paths.js';
|
|
2
2
|
import { type BrcSettings } from '../config/settings.js';
|
|
3
|
+
import { type ProcessIdentity } from './identity.js';
|
|
4
|
+
export { inspectProcess } from './identity.js';
|
|
5
|
+
export type { ProcessIdentity } from './identity.js';
|
|
3
6
|
export type ManagedServiceName = 'relay' | 'traefik' | 'agent';
|
|
4
7
|
export type ServiceState = 'stopped' | 'starting' | 'pairing' | 'running' | 'degraded';
|
|
5
8
|
export interface ServiceStatus {
|
|
@@ -17,12 +20,6 @@ export interface ManagedServiceSpec {
|
|
|
17
20
|
env?: NodeJS.ProcessEnv;
|
|
18
21
|
startupTimeoutMs?: number;
|
|
19
22
|
}
|
|
20
|
-
export interface ProcessIdentity {
|
|
21
|
-
pid: number;
|
|
22
|
-
createdAt: string;
|
|
23
|
-
executablePath: string;
|
|
24
|
-
commandLine: string;
|
|
25
|
-
}
|
|
26
23
|
export interface ManagedProcessRecord extends ProcessIdentity {
|
|
27
24
|
version: 1;
|
|
28
25
|
id: string;
|
|
@@ -39,19 +36,20 @@ export interface ProcessManagerOptions {
|
|
|
39
36
|
pollIntervalMs?: number;
|
|
40
37
|
inspectProcess?: ProcessInspector;
|
|
41
38
|
}
|
|
42
|
-
export declare function inspectProcess(pid: number): Promise<ProcessIdentity | null>;
|
|
43
39
|
export declare class ProcessManager {
|
|
44
40
|
private readonly paths;
|
|
45
41
|
private startupTimeoutMs;
|
|
46
42
|
private shutdownTimeoutMs;
|
|
47
43
|
private readonly pollIntervalMs;
|
|
48
44
|
private readonly inspect;
|
|
45
|
+
private readonly customInspector;
|
|
49
46
|
private readonly starting;
|
|
50
47
|
constructor(paths: BrcPaths, options?: ProcessManagerOptions);
|
|
51
48
|
updateRuntimeSettings(settings: Readonly<Pick<BrcSettings['runtime'], 'startupTimeoutMs' | 'shutdownTimeoutMs'>>): void;
|
|
52
49
|
start(spec: ManagedServiceSpec): Promise<void>;
|
|
53
50
|
stop(spec: ManagedServiceSpec): Promise<void>;
|
|
54
51
|
status(spec: ManagedServiceSpec): Promise<ServiceStatus>;
|
|
52
|
+
statusMany(specs: readonly ManagedServiceSpec[]): Promise<ServiceStatus[]>;
|
|
55
53
|
private inspectForStatus;
|
|
56
54
|
private waitForReady;
|
|
57
55
|
private waitForHealthy;
|