@hraness/wordcell 0.26.1 → 0.26.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/README.md +4 -4
- package/dist/capture.js +2 -2
- package/dist/cli-bin.js +1 -1
- package/dist/cli.js +4 -4
- package/dist/clip/browser-profiles.js +1 -1
- package/dist/clip/cli.js +2 -2
- package/dist/evaluation-builder-bin.js +1 -1
- package/dist/{index-zbv70qmk.js → index-h9vyd03z.js} +1 -1
- package/dist/{index-5n05se68.js → index-hnvx7m1j.js} +80 -8
- package/dist/{index-8w1zsgcm.js → index-mp5y3ty3.js} +1 -1
- package/dist/{support-ym4mpf7w.js → support-9qdr4hb8.js} +3 -3
- package/package.json +1 -1
- package/skills/wordcell/SKILL.md +1 -1
- package/src/clip/browser-profiles.ts +66 -11
- /package/dist/{index-6jz050v0.js → index-82r6g4py.js} +0 -0
package/README.md
CHANGED
|
@@ -66,14 +66,14 @@ Wordcell keeps the record in Markdown files you own, rebuilds every index from t
|
|
|
66
66
|
The CLI and TypeScript SDK run with Bun. Install the versioned GitHub archive:
|
|
67
67
|
|
|
68
68
|
```sh
|
|
69
|
-
bun add --global --ignore-scripts https://github.com/hraness/wordcell/releases/download/v0.26.
|
|
69
|
+
bun add --global --ignore-scripts https://github.com/hraness/wordcell/releases/download/v0.26.2/hraness-wordcell-0.26.2.tgz
|
|
70
70
|
wordcell --help
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Prefer npm? The same release is [mirrored there](https://www.npmjs.com/package/@hraness/wordcell):
|
|
74
74
|
|
|
75
75
|
```sh
|
|
76
|
-
npm install --global --ignore-scripts @hraness/wordcell@0.26.
|
|
76
|
+
npm install --global --ignore-scripts @hraness/wordcell@0.26.2
|
|
77
77
|
wordcell --help
|
|
78
78
|
```
|
|
79
79
|
|
|
@@ -137,7 +137,7 @@ After trying the CLI, install the public Agent Skill into a compatible agent,
|
|
|
137
137
|
such as Claude Code, Codex, Cursor, or GitHub Copilot:
|
|
138
138
|
|
|
139
139
|
```sh
|
|
140
|
-
bunx skills add hraness/wordcell#v0.26.
|
|
140
|
+
bunx skills add hraness/wordcell#v0.26.2 --skill wordcell
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
Then ask:
|
|
@@ -348,7 +348,7 @@ exist. [Graph queries and proof limits](https://github.com/hraness/wordcell/blob
|
|
|
348
348
|
Add the same immutable release to a Bun project:
|
|
349
349
|
|
|
350
350
|
```sh
|
|
351
|
-
bun add --exact --ignore-scripts https://github.com/hraness/wordcell/releases/download/v0.26.
|
|
351
|
+
bun add --exact --ignore-scripts https://github.com/hraness/wordcell/releases/download/v0.26.2/hraness-wordcell-0.26.2.tgz
|
|
352
352
|
```
|
|
353
353
|
|
|
354
354
|
The SDK provides read-only vault sessions, metadata queries, search, graph
|
package/dist/capture.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
captureSummary,
|
|
6
6
|
main,
|
|
7
7
|
runCapture
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-h9vyd03z.js";
|
|
9
9
|
import"./index-hacpnaew.js";
|
|
10
10
|
import"./index-k86wepd8.js";
|
|
11
11
|
import {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
inspectClipEnvironment,
|
|
14
14
|
renderDoctorReport
|
|
15
15
|
} from "./index-nd8v7r0z.js";
|
|
16
|
-
import"./index-
|
|
16
|
+
import"./index-hnvx7m1j.js";
|
|
17
17
|
import"./index-ncwzmsge.js";
|
|
18
18
|
import"./index-cd75vky9.js";
|
|
19
19
|
import"./index-2gv8y733.js";
|
package/dist/cli-bin.js
CHANGED
package/dist/cli.js
CHANGED
|
@@ -6,17 +6,17 @@ import {
|
|
|
6
6
|
parseArguments,
|
|
7
7
|
runExecutable,
|
|
8
8
|
usage
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-mp5y3ty3.js";
|
|
10
10
|
import"./index-5h5awwh4.js";
|
|
11
11
|
import"./index-m9p2a4mj.js";
|
|
12
12
|
import"./index-9paxge84.js";
|
|
13
13
|
import"./index-j4zgmzjr.js";
|
|
14
14
|
import"./index-npg9z1a4.js";
|
|
15
|
-
import"./index-
|
|
15
|
+
import"./index-h9vyd03z.js";
|
|
16
16
|
import"./index-hacpnaew.js";
|
|
17
17
|
import"./index-k86wepd8.js";
|
|
18
18
|
import"./index-nd8v7r0z.js";
|
|
19
|
-
import"./index-
|
|
19
|
+
import"./index-hnvx7m1j.js";
|
|
20
20
|
import"./index-8pabwzqg.js";
|
|
21
21
|
import"./index-ncwzmsge.js";
|
|
22
22
|
import"./index-cd75vky9.js";
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
|
|
65
65
|
// src/cli.ts
|
|
66
66
|
async function runStandaloneCli(args = process.argv.slice(2)) {
|
|
67
|
-
const { standaloneSupportEnvironment, isUsefulSupportResult, runProductSupportCommand, showProductSupportInvitation } = await import("./support-
|
|
67
|
+
const { standaloneSupportEnvironment, isUsefulSupportResult, runProductSupportCommand, showProductSupportInvitation } = await import("./support-9qdr4hb8.js");
|
|
68
68
|
const env = standaloneSupportEnvironment();
|
|
69
69
|
if (args[0] === "support") {
|
|
70
70
|
return await runProductSupportCommand(args.slice(1), { env });
|
package/dist/clip/cli.js
CHANGED
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
captureSucceeded,
|
|
6
6
|
captureSummary,
|
|
7
7
|
main
|
|
8
|
-
} from "../index-
|
|
8
|
+
} from "../index-h9vyd03z.js";
|
|
9
9
|
import"../index-hacpnaew.js";
|
|
10
10
|
import"../index-k86wepd8.js";
|
|
11
11
|
import"../index-nd8v7r0z.js";
|
|
12
|
-
import"../index-
|
|
12
|
+
import"../index-hnvx7m1j.js";
|
|
13
13
|
import"../index-ncwzmsge.js";
|
|
14
14
|
import"../index-cd75vky9.js";
|
|
15
15
|
import"../index-2gv8y733.js";
|
|
@@ -11,13 +11,15 @@ import {
|
|
|
11
11
|
mkdirSync,
|
|
12
12
|
openSync,
|
|
13
13
|
readdirSync,
|
|
14
|
+
readlinkSync,
|
|
14
15
|
readSync,
|
|
15
16
|
realpathSync,
|
|
16
17
|
rmSync,
|
|
17
18
|
unlinkSync,
|
|
18
19
|
writeSync
|
|
19
20
|
} from "fs";
|
|
20
|
-
import {
|
|
21
|
+
import { spawnSync } from "child_process";
|
|
22
|
+
import { homedir, hostname, tmpdir } from "os";
|
|
21
23
|
import { basename, dirname, isAbsolute, join, resolve, sep } from "path";
|
|
22
24
|
var profileSkipNames = new Set([
|
|
23
25
|
"Cache",
|
|
@@ -185,15 +187,82 @@ function localStateEntry(path) {
|
|
|
185
187
|
throw new BrowserProfileSnapshotError("Chromium Local State is unavailable or unsafe");
|
|
186
188
|
}
|
|
187
189
|
}
|
|
190
|
+
var activeProfileMessage = "Chromium profile is active or retains a stale process lock; fully quit the browser and retry";
|
|
191
|
+
function assertPidAbsent(pid) {
|
|
192
|
+
try {
|
|
193
|
+
process.kill(pid, 0);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH")
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
throw new BrowserProfileSnapshotError(activeProfileMessage);
|
|
199
|
+
}
|
|
200
|
+
function assertSocketUnavailable(path) {
|
|
201
|
+
const script = `const fs = require("node:fs");
|
|
202
|
+
const net = require("node:net");
|
|
203
|
+
const socket = net.createConnection({ path: fs.readFileSync(0, "utf8") });
|
|
204
|
+
socket.setTimeout(500, () => { socket.destroy(); process.exit(1); });
|
|
205
|
+
socket.once("connect", () => { socket.destroy(); process.exit(1); });
|
|
206
|
+
socket.once("error", error => process.exit(error.code === "ENOENT" || error.code === "ECONNREFUSED" ? 0 : 1));`;
|
|
207
|
+
const result = spawnSync(process.execPath, ["--no-env-file", "--no-install", "--no-macros", "--no-addons", "--eval", script], {
|
|
208
|
+
input: path,
|
|
209
|
+
cwd: tmpdir(),
|
|
210
|
+
env: {},
|
|
211
|
+
timeout: 2000,
|
|
212
|
+
maxBuffer: 1024,
|
|
213
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
214
|
+
});
|
|
215
|
+
if (result.error || result.status !== 0)
|
|
216
|
+
throw new BrowserProfileSnapshotError(activeProfileMessage);
|
|
217
|
+
}
|
|
188
218
|
function assertChromiumUserDataIdle(userDataRoot) {
|
|
189
|
-
let names;
|
|
190
219
|
try {
|
|
191
|
-
|
|
220
|
+
const root = lstatSync(userDataRoot);
|
|
221
|
+
if (!root.isDirectory() || root.isSymbolicLink() || root.uid !== process.getuid?.())
|
|
222
|
+
throw new Error;
|
|
223
|
+
const rootProof = { dev: root.dev, ino: root.ino, ctime: root.ctimeMs };
|
|
224
|
+
const names = readdirSync(userDataRoot).filter((name) => name.startsWith("Singleton") || name === "DevToolsActivePort").sort();
|
|
225
|
+
if (names.length === 0)
|
|
226
|
+
return JSON.stringify({ root: rootProof, locks: [] });
|
|
227
|
+
if (names.join(",") !== "SingletonCookie,SingletonLock,SingletonSocket")
|
|
228
|
+
throw new Error;
|
|
229
|
+
const proof = names.map((name) => {
|
|
230
|
+
const path = join(userDataRoot, name);
|
|
231
|
+
const entry = lstatSync(path);
|
|
232
|
+
if (!entry.isSymbolicLink() || entry.uid !== process.getuid?.())
|
|
233
|
+
throw new Error;
|
|
234
|
+
return { name, target: readlinkSync(path), dev: entry.dev, ino: entry.ino, ctime: entry.ctimeMs };
|
|
235
|
+
});
|
|
236
|
+
const lock = proof.find((entry) => entry.name === "SingletonLock").target;
|
|
237
|
+
const prefix = `${hostname()}-`;
|
|
238
|
+
if (!lock.startsWith(prefix) || !/^[1-9][0-9]*$/.test(lock.slice(prefix.length)))
|
|
239
|
+
throw new Error;
|
|
240
|
+
const pid = Number(lock.slice(prefix.length));
|
|
241
|
+
if (!Number.isSafeInteger(pid) || pid > 2147483647)
|
|
242
|
+
throw new Error;
|
|
243
|
+
const socket = proof.find((entry) => entry.name === "SingletonSocket").target;
|
|
244
|
+
if (!isAbsolute(socket) || resolve(socket) !== socket || basename(socket) !== "SingletonSocket" || !socket.startsWith(`${tmpdir()}${sep}`))
|
|
245
|
+
throw new Error;
|
|
246
|
+
if (!/^[0-9]{1,32}$/.test(proof.find((entry) => entry.name === "SingletonCookie").target))
|
|
247
|
+
throw new Error;
|
|
248
|
+
assertPidAbsent(pid);
|
|
249
|
+
assertSocketUnavailable(socket);
|
|
250
|
+
assertPidAbsent(pid);
|
|
251
|
+
const finalRoot = lstatSync(userDataRoot);
|
|
252
|
+
if (!sameEntry(root, finalRoot) || finalRoot.ctimeMs !== root.ctimeMs)
|
|
253
|
+
throw new Error;
|
|
254
|
+
const finalNames = readdirSync(userDataRoot).filter((name) => name.startsWith("Singleton") || name === "DevToolsActivePort").sort();
|
|
255
|
+
if (finalNames.join(",") !== names.join(","))
|
|
256
|
+
throw new Error;
|
|
257
|
+
for (const entry of proof) {
|
|
258
|
+
const path = join(userDataRoot, entry.name);
|
|
259
|
+
const current = lstatSync(path);
|
|
260
|
+
if (!current.isSymbolicLink() || current.dev !== entry.dev || current.ino !== entry.ino || current.ctimeMs !== entry.ctime || readlinkSync(path) !== entry.target)
|
|
261
|
+
throw new Error;
|
|
262
|
+
}
|
|
263
|
+
return JSON.stringify({ root: rootProof, locks: proof });
|
|
192
264
|
} catch {
|
|
193
|
-
throw new BrowserProfileSnapshotError(
|
|
194
|
-
}
|
|
195
|
-
if (names.some((name) => name.startsWith("Singleton") || name === "DevToolsActivePort")) {
|
|
196
|
-
throw new BrowserProfileSnapshotError("Chromium profile is active or retains a stale process lock; fully quit the browser and retry");
|
|
265
|
+
throw new BrowserProfileSnapshotError(activeProfileMessage);
|
|
197
266
|
}
|
|
198
267
|
}
|
|
199
268
|
function copyBoundedLocalState(source, destination) {
|
|
@@ -289,7 +358,7 @@ function cloneBrowserProfile(source, privateDirectory) {
|
|
|
289
358
|
if (stateEntry.size > maxLocalStateBytes) {
|
|
290
359
|
throw new BrowserProfileSnapshotError("Chromium Local State exceeds its safety bound");
|
|
291
360
|
}
|
|
292
|
-
assertChromiumUserDataIdle(userDataRoot);
|
|
361
|
+
const idleProof = assertChromiumUserDataIdle(userDataRoot);
|
|
293
362
|
const userData = join(privateDirectory, "profile-user-data");
|
|
294
363
|
mkdirSync(userData, { mode: 448 });
|
|
295
364
|
chmodSync(userData, 448);
|
|
@@ -297,6 +366,9 @@ function cloneBrowserProfile(source, privateDirectory) {
|
|
|
297
366
|
try {
|
|
298
367
|
cloneProfile(selectedSource, selectedProfile);
|
|
299
368
|
copyBoundedLocalState(localState, join(userData, "Local State"));
|
|
369
|
+
if (assertChromiumUserDataIdle(userDataRoot) !== idleProof) {
|
|
370
|
+
throw new BrowserProfileSnapshotError("Chromium profile lock changed while it was copied");
|
|
371
|
+
}
|
|
300
372
|
return { userDataPath: userData, profileDirectory: "Default" };
|
|
301
373
|
} catch (error) {
|
|
302
374
|
rmSync(userData, { recursive: true, force: true });
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
parseArguments as parseArguments2,
|
|
4
4
|
parseUrlMetadataArguments
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-mp5y3ty3.js";
|
|
6
6
|
import"./index-5h5awwh4.js";
|
|
7
7
|
import {
|
|
8
8
|
parsePdfArguments
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
import"./index-9paxge84.js";
|
|
11
11
|
import"./index-j4zgmzjr.js";
|
|
12
12
|
import"./index-npg9z1a4.js";
|
|
13
|
-
import"./index-
|
|
13
|
+
import"./index-h9vyd03z.js";
|
|
14
14
|
import"./index-hacpnaew.js";
|
|
15
15
|
import"./index-k86wepd8.js";
|
|
16
16
|
import"./index-nd8v7r0z.js";
|
|
17
|
-
import"./index-
|
|
17
|
+
import"./index-hnvx7m1j.js";
|
|
18
18
|
import"./index-8pabwzqg.js";
|
|
19
19
|
import"./index-ncwzmsge.js";
|
|
20
20
|
import"./index-cd75vky9.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hraness/wordcell",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.2",
|
|
4
4
|
"description": "Wordcell keeps decisions, plans, and sources as Markdown beside your code, so coding agents can find them from the file they are about to change.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/skills/wordcell/SKILL.md
CHANGED
|
@@ -58,7 +58,7 @@ missing:
|
|
|
58
58
|
```sh
|
|
59
59
|
command -v wordcell >/dev/null 2>&1 || {
|
|
60
60
|
command -v bun >/dev/null 2>&1 || exit 1
|
|
61
|
-
bun add --global --ignore-scripts https://github.com/hraness/wordcell/releases/download/v0.26.
|
|
61
|
+
bun add --global --ignore-scripts https://github.com/hraness/wordcell/releases/download/v0.26.2/hraness-wordcell-0.26.2.tgz
|
|
62
62
|
}
|
|
63
63
|
wordcell --help
|
|
64
64
|
```
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
mkdirSync,
|
|
10
10
|
openSync,
|
|
11
11
|
readdirSync,
|
|
12
|
+
readlinkSync,
|
|
12
13
|
readSync,
|
|
13
14
|
realpathSync,
|
|
14
15
|
rmSync,
|
|
@@ -16,7 +17,8 @@ import {
|
|
|
16
17
|
unlinkSync,
|
|
17
18
|
writeSync,
|
|
18
19
|
} from "node:fs";
|
|
19
|
-
import {
|
|
20
|
+
import { spawnSync } from "node:child_process";
|
|
21
|
+
import { homedir, hostname, tmpdir } from "node:os";
|
|
20
22
|
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
21
23
|
|
|
22
24
|
const profileSkipNames = new Set([
|
|
@@ -236,17 +238,67 @@ function localStateEntry(path: string): Stats | null {
|
|
|
236
238
|
}
|
|
237
239
|
}
|
|
238
240
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
+
const activeProfileMessage = "Chromium profile is active or retains a stale process lock; fully quit the browser and retry";
|
|
242
|
+
|
|
243
|
+
function assertPidAbsent(pid: number): void {
|
|
241
244
|
try {
|
|
242
|
-
|
|
243
|
-
} catch {
|
|
244
|
-
|
|
245
|
+
process.kill(pid, 0);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH") return;
|
|
245
248
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
249
|
+
throw new BrowserProfileSnapshotError(activeProfileMessage);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function assertSocketUnavailable(path: string): void {
|
|
253
|
+
const script = `const fs = require("node:fs");
|
|
254
|
+
const net = require("node:net");
|
|
255
|
+
const socket = net.createConnection({ path: fs.readFileSync(0, "utf8") });
|
|
256
|
+
socket.setTimeout(500, () => { socket.destroy(); process.exit(1); });
|
|
257
|
+
socket.once("connect", () => { socket.destroy(); process.exit(1); });
|
|
258
|
+
socket.once("error", error => process.exit(error.code === "ENOENT" || error.code === "ECONNREFUSED" ? 0 : 1));`;
|
|
259
|
+
const result = spawnSync(process.execPath, ["--no-env-file", "--no-install", "--no-macros", "--no-addons", "--eval", script], {
|
|
260
|
+
input: path, cwd: tmpdir(), env: {}, timeout: 2000, maxBuffer: 1024, stdio: ["pipe", "pipe", "pipe"],
|
|
261
|
+
});
|
|
262
|
+
if (result.error || result.status !== 0) throw new BrowserProfileSnapshotError(activeProfileMessage);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function assertChromiumUserDataIdle(userDataRoot: string): string {
|
|
266
|
+
try {
|
|
267
|
+
const root = lstatSync(userDataRoot);
|
|
268
|
+
if (!root.isDirectory() || root.isSymbolicLink() || root.uid !== process.getuid?.()) throw new Error();
|
|
269
|
+
const rootProof = { dev: root.dev, ino: root.ino, ctime: root.ctimeMs };
|
|
270
|
+
const names = readdirSync(userDataRoot).filter((name) => name.startsWith("Singleton") || name === "DevToolsActivePort").sort();
|
|
271
|
+
if (names.length === 0) return JSON.stringify({ root: rootProof, locks: [] });
|
|
272
|
+
if (names.join(",") !== "SingletonCookie,SingletonLock,SingletonSocket") throw new Error();
|
|
273
|
+
const proof = names.map((name) => {
|
|
274
|
+
const path = join(userDataRoot, name);
|
|
275
|
+
const entry = lstatSync(path);
|
|
276
|
+
if (!entry.isSymbolicLink() || entry.uid !== process.getuid?.()) throw new Error();
|
|
277
|
+
return { name, target: readlinkSync(path), dev: entry.dev, ino: entry.ino, ctime: entry.ctimeMs };
|
|
278
|
+
});
|
|
279
|
+
const lock = proof.find((entry) => entry.name === "SingletonLock")!.target;
|
|
280
|
+
const prefix = `${hostname()}-`;
|
|
281
|
+
if (!lock.startsWith(prefix) || !/^[1-9][0-9]*$/.test(lock.slice(prefix.length))) throw new Error();
|
|
282
|
+
const pid = Number(lock.slice(prefix.length));
|
|
283
|
+
if (!Number.isSafeInteger(pid) || pid > 2147483647) throw new Error();
|
|
284
|
+
const socket = proof.find((entry) => entry.name === "SingletonSocket")!.target;
|
|
285
|
+
if (!isAbsolute(socket) || resolve(socket) !== socket || basename(socket) !== "SingletonSocket" || !socket.startsWith(`${tmpdir()}${sep}`)) throw new Error();
|
|
286
|
+
if (!/^[0-9]{1,32}$/.test(proof.find((entry) => entry.name === "SingletonCookie")!.target)) throw new Error();
|
|
287
|
+
assertPidAbsent(pid);
|
|
288
|
+
assertSocketUnavailable(socket);
|
|
289
|
+
assertPidAbsent(pid);
|
|
290
|
+
const finalRoot = lstatSync(userDataRoot);
|
|
291
|
+
if (!sameEntry(root, finalRoot) || finalRoot.ctimeMs !== root.ctimeMs) throw new Error();
|
|
292
|
+
const finalNames = readdirSync(userDataRoot).filter((name) => name.startsWith("Singleton") || name === "DevToolsActivePort").sort();
|
|
293
|
+
if (finalNames.join(",") !== names.join(",")) throw new Error();
|
|
294
|
+
for (const entry of proof) {
|
|
295
|
+
const path = join(userDataRoot, entry.name);
|
|
296
|
+
const current = lstatSync(path);
|
|
297
|
+
if (!current.isSymbolicLink() || current.dev !== entry.dev || current.ino !== entry.ino || current.ctimeMs !== entry.ctime || readlinkSync(path) !== entry.target) throw new Error();
|
|
298
|
+
}
|
|
299
|
+
return JSON.stringify({ root: rootProof, locks: proof });
|
|
300
|
+
} catch {
|
|
301
|
+
throw new BrowserProfileSnapshotError(activeProfileMessage);
|
|
250
302
|
}
|
|
251
303
|
}
|
|
252
304
|
|
|
@@ -356,7 +408,7 @@ export function cloneBrowserProfile(source: string, privateDirectory: string): C
|
|
|
356
408
|
if (stateEntry.size > maxLocalStateBytes) {
|
|
357
409
|
throw new BrowserProfileSnapshotError("Chromium Local State exceeds its safety bound");
|
|
358
410
|
}
|
|
359
|
-
assertChromiumUserDataIdle(userDataRoot);
|
|
411
|
+
const idleProof = assertChromiumUserDataIdle(userDataRoot);
|
|
360
412
|
const userData = join(privateDirectory, "profile-user-data");
|
|
361
413
|
mkdirSync(userData, { mode: 0o700 });
|
|
362
414
|
chmodSync(userData, 0o700);
|
|
@@ -364,6 +416,9 @@ export function cloneBrowserProfile(source: string, privateDirectory: string): C
|
|
|
364
416
|
try {
|
|
365
417
|
cloneProfile(selectedSource, selectedProfile);
|
|
366
418
|
copyBoundedLocalState(localState, join(userData, "Local State"));
|
|
419
|
+
if (assertChromiumUserDataIdle(userDataRoot) !== idleProof) {
|
|
420
|
+
throw new BrowserProfileSnapshotError("Chromium profile lock changed while it was copied");
|
|
421
|
+
}
|
|
367
422
|
return { userDataPath: userData, profileDirectory: "Default" };
|
|
368
423
|
} catch (error) {
|
|
369
424
|
rmSync(userData, { recursive: true, force: true });
|
|
File without changes
|